Skip to content

Added new shortcodes + partials to support custom landing page #273

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions assets/css/f5-hugo.css
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,16 @@ h3.card-title {
font-weight: 400;
}

/* Landing page cards */
.text-content .card-layout {
.card-section {
margin-bottom: 1rem;

strong {
font-weight: 500;
}
}
}
#f5-related,
#nginx-products {
width: 100%;
Expand Down
30 changes: 29 additions & 1 deletion assets/css/v2/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,6 @@ nav {

h2 {
font-size: 1.5rem;
margin: 1rem 0 0rem 0;
}

hr {
Expand Down Expand Up @@ -1188,6 +1187,35 @@ h6:has(a):hover {
color: oklch(var(--color-brand));
}

/* Landing page cards */

.text-content .card-layout {
grid-column: 1 / -1;

.card-section {
margin-bottom: 1rem;

strong {
font-weight: 500;
}
}
}

/* Optional grid layout */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 500px));
gap: 1.5rem;
margin-top: 1rem;

.card-container {
border: 1px solid oklch(var(--color-codeblock-border));
box-shadow: 3px 3px 0px oklch(var(--color-shadow));
padding: 1rem 2rem 2rem 2rem;
margin-bottom: 1.5rem;
}
}

/* MARK: Tables
*/
table {
Expand Down
22 changes: 22 additions & 0 deletions exampleSite/content/test-product/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,26 @@
description: Test pages for nginx-hugo-theme
title: Test pages
weight: 100
hasCustomContent: true
---
<!-- <card-layout> - Available params: title (required: string)-->
{{< card-layout >}}
<!-- <card-section> - Available params: title (required: string), showAsCards (optional: boolean, default false) -->
<!-- If there is no "title" for <card-section>, it is implied it is the main content section and not a new content section -->
{{< card-section >}}
{{< card title="Call Out usages" >}}
<!-- <card> - Available params: title (required: string), titleUrl (optional: string, relative path or absolute URL (e.g. https://google.com)) -->
Examples for call-out shortcode
{{</ card >}}
{{< card title="Code Block usages" >}}
Examples for codeblock shortcode
{{</ card >}}
{{</ card-section >}}

# Other Products on ExampleSite
{{< card-section title="NGINX" showAsCards="true" >}}
{{< card title="NGINX Plus" titleUrl="/nginx/" >}}
Installing NGINX
{{</ card >}}
{{</ card-section >}}
{{</ card-layout >}}
19 changes: 12 additions & 7 deletions layouts/_default/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,22 @@
{{ end }}
</section>
<h1>{{ .Title }}</h1>
{{ .Content }}

{{ partial "banner" . }}

{{ if (lt .WordCount 1) }}
{{ range .Pages.ByWeight }}
<h2>
<a href="{{ if .Params.url}}{{ .Params.url}}{{else}}{{ .Permalink }}{{end}}">{{ .Title }}</a>
</h2>
{{ $hasCustomContent := .Params.hasCustomContent | default false }}
{{ if $hasCustomContent }}
{{ .Page.Scratch.Set "custom-landing-page-file-name" "custom-landing-page.html" }}
{{ .Page.Scratch.Set "custom-landing-page-context" . }}
{{ .Content }}
{{ else }}
{{ .Content }}
{{ range .Pages.ByWeight }}
<h2>
<a href="{{ if .Params.url}}{{ .Params.url}}{{else}}{{ .Permalink }}{{end}}">{{ .Title }}</a>
</h2>
{{ end }}
{{ end }}
{{end}}

<hr>
{{ if .Page.Lastmod }}
Expand Down
48 changes: 48 additions & 0 deletions layouts/partials/custom-landing-page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{{ $cards := .Page.Scratch.Get "cards" }}
{{ $showAsCards := index ( .Page.Scratch.Get "showAsCards") "main" }}
{{ $class := "card-grid wide"}}

<div class="{{ if eq $showAsCards "true" }}{{ $class }}{{ end }}">
<!-- Old frame -->
<section data-mf="false">
<div class="row">
<div class="card-deck">
{{ range .Pages.GroupBy "Section" }}
{{ range .Pages.ByWeight }}
{{ $title := .Title }}
<div class="col-md-5 card">
<div class="card-body">
<h3 class="card-title" style="display: flex; align-items: center; gap: 5px;">
<i class="fas fa-{{if eq .Kind "page"}}file-alt{{else}}book{{end}} fa-lg card-img-top"></i>
<a href="{{ if .Params.url}}{{ .Params.url}}{{else}}{{ .Permalink }}{{end}}">{{ .Title }}</a>
</h3>
{{ range $cards }}
{{ if eq .title $title }}
<p>{{ .content }}</p>
{{ end }}
{{ end }}
</div>
</div>
{{ end }}
{{ end }}
</div>
</div>
</section>

<!-- Mainframe -->
<div data-mf="true" style="display: none;">
{{ range .Pages.ByWeight }}
{{ $title := .Title }}
<div class="card-container">
<h2>
<a href="{{ if .Params.url}}{{ .Params.url}}{{else}}{{ .Permalink }}{{end}}">{{ $title }}</a>
</h2>
{{ range $cards }}
{{ if eq .title $title }}
<p>{{- .content -}}</p>
{{ end }}
{{ end }}
</div>
{{ end }}
</div>
</div>
106 changes: 24 additions & 82 deletions layouts/partials/list-main.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,91 +10,33 @@ <h1 class="bd-title">
{{ .Description | markdownify }}
</p>
{{ end}}
{{ if .Content }}
<p>
{{ .Content | markdownify }}
</p>
{{ end }}

{{ partial "banner" .}}
</div>
</div>

{{ if or (lt .WordCount 1) (eq $PageTitle "F5 NGINX One Console") (eq $PageTitle "F5 NGINX App Protect DoS") (eq $PageTitle "F5 NGINX Plus") }}
<section>
<div class="row">
<div class="card-deck">
{{ range .Pages.GroupBy "Section" }}
{{ range .Pages.ByWeight }}
<div class="col-md-5 card">
<div class="card-body">
{{ $hasCustomContent := .Params.hasCustomContent | default false }}
{{ if $hasCustomContent }}
{{ .Page.Scratch.Set "custom-landing-page-file-name" "custom-landing-page.html" }}
{{ .Page.Scratch.Set "custom-landing-page-context" . }}
{{ .Content }}
{{ else }}
<section data-mf="false">
<div class="row">
<div class="card-deck">
{{ range .Pages.GroupBy "Section" }}
{{ range .Pages.ByWeight }}
{{ $title := .Title }}
<div class="col-md-5 card">
<div class="card-body">
<h3 class="card-title" style="display: flex; align-items: center; gap: 5px;">
<i class="fas fa-{{if eq .Kind "page"}}file-alt{{else}}book{{end}} fa-lg card-img-top"></i>
<a href="{{ if .Params.url}}{{ .Params.url}}{{else}}{{ .Permalink }}{{end}}">{{ .Title }}</a>
<i class="fas fa-{{if eq .Kind "page"}}file-alt{{else}}book{{end}} fa-lg card-img-top"></i>
<a href="{{ if .Params.url}}{{ .Params.url}}{{else}}{{ .Permalink }}{{end}}">{{ .Title }}</a>
</h3>
{{ if and (eq $PageTitle "F5 NGINX One Console") (eq .Title "How-to guides") }}
<ul style="padding-top: 10px;">
{{ range .Pages }}
{{ if eq .Kind "section" }}
{{ range .Pages }}
<li><a href="{{ .Permalink }}"> {{ .Title }}</a></li>
{{ end }}
{{ end }}
{{ end }}
</ul>
{{ end }}
{{ if and (eq $PageTitle "F5 NGINX One Console") (eq .Title "API")}}
<ul style="padding-top: 10px;">
{{ range .Pages }}
<li><a href="{{ .Permalink }}"> {{ .Title }}</a></li>
{{ end }}
</ul>
{{ end }}
{{ if and (eq $PageTitle "F5 NGINX One Console") (eq .Title "Changelog") }}
{{ partial "changelog-date.html" . }}
{{ end }}
</div>
</div>
</div>
{{ end }}
{{ end }}
{{ end }}
</div>
{{ if eq $PageTitle "F5 NGINX One Console" }}
<h1 class="bd-title" style="margin-top: 15px;">Other Products</h1>
{{ $nginxProducts := slice
(dict "title" "NGINX Instance Manager" "url" "/nginx-instance-manager" "imgSrc" "NGINX-Instance-Manager-product-icon" "type" "local-console-option" "description" "Track and control NGINX Open Source and NGINX Plus instances.")
(dict "title" "NGINX Ingress Controller" "url" "/nginx-ingress-controller" "imgSrc" "NGINX-Ingress-Controller-product-icon" "type" "kubernetes-solutions" "description" "Kubernetes traffic management with API gateway, identity, and observability features.")
(dict "title" "NGINX Gateway Fabric" "url" "/nginx-gateway-fabric" "imgSrc" "NGINX-product-icon" "type" "kubernetes-solutions" "description" "Next generation Kubernetes connectivity using the Gateway API.")
(dict "title" "NGINX App Protect WAF" "url" "/nginx-app-protect-waf" "imgSrc" "NGINX-App-Protect-WAF-product-icon" "type" "security" "description" "Lightweight, high-performance, advanced protection against Layer 7 attacks on your apps and APIs.")
(dict "title" "NGINX App Protect DoS" "url" "/nginx-app-protect-dos" "imgSrc" "NGINX-App-Protect-DoS-product-icon" "type" "security" "description" "Defend, adapt, and mitigate against Layer 7 denial-of-service attacks on your apps and APIs.")
(dict "title" "NGINX Plus" "url" "/nginx" "imgSrc" "NGINX-Plus-product-icon-RGB" "type" "modern-app-delivery" "description" "The all-in-one load balancer, reverse proxy, web server, content cache, and API gateway.")
(dict "title" "NGINX Open Source" "url" "https://nginx.org/en/docs/" "imgSrc" "NGINX-product-icon" "type" "modern-app-delivery" "description" "The open source all-in-one load balancer, content cache, and web server")
}}
{{ $groupedProducts := dict
"local-console-option" (where $nginxProducts "type" "local-console-option")
"kubernetes-solutions" (where $nginxProducts "type" "kubernetes-solutions")
"security" (where $nginxProducts "type" "security")
"modern-app-delivery" (where $nginxProducts "type" "modern-app-delivery")
}}
{{ range $type, $products := $groupedProducts }}
<div class="card-deck">
<p style="margin-left: 15px; width: 100%; font-weight: bold;">{{ $type | humanize | title }}</p>
{{ range $products }}
<div class="card" style="margin-top: 0px; {{ if eq (len $products) 1 }}max-width: calc(50% - 30px);{{ else }}min-width: 40%;{{ end }}">
<div class="card-body">
<h3 class="card-title" style="display: flex; align-items: center;">
<img class="card-img-top" src="{{ .Site.BaseURL }}/images/icons/{{ .imgSrc }}.png"/>
<a href="{{ if eq .title "NGINX Open Source" }}{{ .url }}{{ else }}{{ .Site.BaseURL }}{{ .url }}{{ end }}">{{ .title }}</a>
</h3>
<p >
{{ if .description }}{{ .description | markdownify }}{{ end }}
</p>
</div>
</div>
{{ end }}
</div>
{{ end }}
{{ end }}
</div>
</section>
{{end}}
</div>
</div>
</section>
{{ end }}
</div>
</div>
</div>
5 changes: 5 additions & 0 deletions layouts/shortcodes/card-layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!-- Render the main content first with modifications, then render the custom content -->
{{ $customLandingPageFileName := .Page.Scratch.Get "custom-landing-page-file-name" }}
{{ $customLandingPageContext := .Page.Scratch.Get "custom-landing-page-context" }}
{{ partial $customLandingPageFileName $customLandingPageContext }}
<div class="card-layout">{{- .Inner | markdownify -}}</div>
28 changes: 28 additions & 0 deletions layouts/shortcodes/card-section.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{{ $title := .Get "title" }}
{{ $showAsCardsParam := .Get "showAsCards" | default "false"}}
{{- /* Validate the parameter strictly */ -}}
{{- if not (in (slice "true" "false") $showAsCardsParam) -}}
{{- warnf "The '<card-section>' Shortcode parameter 'showAsCards' must be 'true' or 'false', but got: '%s'. This will now default to 'false'" $showAsCardsParam -}}
{{- end -}}
{{- $showAsCards := cond (eq $showAsCardsParam "true") "true" "false" -}}
{{- $current := .Page.Scratch.Get "showAsCards" | default (dict) -}}
{{- $newShowAsCards := dict ($title | default "main") ($showAsCards) -}}
{{- .Page.Scratch.Set "showAsCards" (merge $current ($newShowAsCards)) -}}
{{- $class := "card-grid wide" -}}
{{- /* Validate that the parent is card-layout */ -}}
{{ if eq .Parent.Name "card-layout"}}
<div class="card-section" data-mf="true" style="display: none;">
{{- if $title -}}
<strong class="card-section-title">{{- $title -}}</strong>
<div class="card-section-content{{ if eq $showAsCards "true" }} {{ $class }} {{ end }}">{{- .Inner -}}</div>
{{ end }}
</div>
<div class="row" data-mf="false">
{{- if $title -}}
<strong class="card-section-title">{{- $title -}}</strong>
<div class="card-section-content{{ if eq $showAsCards "true" }} {{ $class }} {{ end }} card-deck">{{- .Inner -}}</div>
{{ end }}
</div>
{{ else }}
{{ errorf "The '<card-section>' must be nested directly inside the shortcode '<card-layout>'. Please see the exampleSite for an example of usage." }}
{{ end }}
38 changes: 38 additions & 0 deletions layouts/shortcodes/card.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{{- $title := .Get "title" -}}
{{- $titleUrl := .Get "titleUrl" | default "/" -}}
{{- $icon := .Get "icon" | default "NGINX-product-icon" -}}
{{- $current := .Page.Scratch.Get "cards" | default (slice) -}}
{{- $newCard := dict "title" ($title) "content" (.Inner) -}}
{{- .Page.Scratch.Set "cards" ($current | append $newCard) -}}
{{- /* Validate that the parent is card-section */ -}}
{{- if eq .Parent.Name "card-section" -}}
<div class="card-container" style="display: none;" data-mf="true">
{{- if $title -}}
{{- if $titleUrl -}}
<h2 class="card-title"><a href="{{- $titleUrl -}}">{{- $title -}}</a></h2>
{{- else -}}
<h2 class="card-title">{{- $title -}}</h2>
{{- end -}}
{{- else -}}
{{ errorf "Mainframe: Missing param 'title'" }}
{{- end -}}
<p>{{- .Inner -}}</p>
</div>
<div class="col-md-5 card" data-mf="false">
<div class="card-body">
<h3 class="card-title" style="display: flex; align-items: center; gap: 5px;">
{{- if $icon -}}
<img class="card-img-top" src="{{ .Site.BaseURL }}/images/icons/{{ $icon }}.png"/>
{{- end -}}
{{- if ($title) -}}
<a href="{{- $titleUrl -}}">{{- $title -}}</a>
{{- else -}}
{{ errorf "Old theme: Missing param 'title'" }}
{{- end -}}
</h3>
<p>{{- .Inner -}}</p>
</div>
</div>
{{- else -}}
{{ errorf "The '<card>' must be nested directly inside the shortcode '<card-section>'. Please see the exampleSite for an example of usage." }}
{{- end -}}
1 change: 1 addition & 0 deletions layouts/shortcodes/changelog-dates.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ partial "changelog-date.html" . }}
Loading