www-from-model/layouts/_partials/header/hybrid.html
Stephan Heunis 175054e4f6
All checks were successful
Deploy on webserver / Build site and deploy on success (push) Successful in 1m29s
Customize header to render submenu dropdowns
Our previous approach to allow menu item grouping, a.k.a. submenus, was to
create a menu item with a 'pageRef', and to link to other pages from that
associated content page. E.g. the 'outputs' menu links to '/outputs' and that
page links to e.g. '/instruments' and '/datasets' which aren't menu items
themselves. While functional, this approach has the drawback that the top-level,
or parent, menu item needs a 'pageRef', which means that namespace is taken and
cannot be used for a different purpose.

This new approach uses Hugo's support for submenus along with a customized
version of congo's hybrid header template and new custom CSS in order to define
parent and child menu items that are rendered as dropdown groups. Importantly,
the parent menu item needs the 'identifier' property (e.g. 'identifier = outputs')
such that its children menu items can refer to it as their parent (e.g. 'parent
= outputs'). The 'hybrid.html' template is updated for both the hamburger and
basic menu sections (which render on narrow and wide screens respectively). For
the basic menu, the parent icon will show and the dropdown will appear on hover,
containing the icons and names of all of its children menus. For the hamburger
menu, the parent is ignored and all children are rendered.

In this commit, the 'datasets' and 'instruments' menu items are created as submenus
of the 'outputs' menu item, which now has no 'pageRef' specified anymore.
2026-05-28 22:41:37 +02:00

284 lines
14 KiB
HTML

<header class="py-6 font-semibold text-neutral-900 dark:text-neutral sm:py-10 print:hidden">
<nav class="flex items-start justify-between sm:items-center">
{{/* Site logo/title */}}
<div class="z-40 flex flex-row items-center">
{{ partial "logo.html" . }}
</div>
{{ if or .Site.Menus.main (.Site.Params.enableSearch | default false) }}
{{/* Hamburger menu */}}
<label id="menu-button" for="menu-controller" class="block sm:hidden">
<input type="checkbox" id="menu-controller" class="hidden" />
<div class="cursor-pointer hover:text-primary-600 dark:hover:text-primary-400">
{{ partial "icon.html" "bars" }}
</div>
<div
id="menu-wrapper"
class="invisible fixed inset-0 z-30 m-auto h-full w-full cursor-default overflow-auto bg-neutral-100/50 opacity-0 backdrop-blur-sm transition-opacity dark:bg-neutral-900/50"
>
<ul
class="mx-auto flex w-full max-w-7xl list-none flex-col overflow-visible px-6 py-6 text-end sm:px-14 sm:py-10 sm:pt-10 md:px-24 lg:px-32"
>
<li class="mb-1">
<span class="cursor-pointer hover:text-primary-600 dark:hover:text-primary-400"
>{{ partial "icon.html" "xmark" }}</span
>
</li>
{{ if .Site.Menus.main }}
{{ range .Site.Menus.main }}
{{ if and (eq .Params.action "locale") (or (not page.IsTranslated) (not hugo.IsMultilingual)) }}
{{ continue }}
{{ end }}
<!-- For the hamburger menu, show children menus and not their parents -->
{{ if .HasChildren }}
{{ range .Children }}
<li class="group mb-1 ml-4">
<a
href="{{ .URL }}"
title="{{ .Title }}"
onclick="close_menu()"
{{ with .Params.rel }}rel="{{ . }}"{{ end }}
{{ with .Params.target }}target="{{ . }}"{{ end }}
>{{ with .Params.icon }}
<span
class="group-dark:hover:text-primary-400 transition-colors group-hover:text-primary-600"
>
{{- partial "icon.html" . -}}
</span>
{{- end -}}{{- if .Params.showName | default true -}}
<span
class="decoration-primary-500 group-hover:underline group-hover:decoration-2 group-hover:underline-offset-2"
>{{ .Name | markdownify | emojify }}</span
>
{{ end }}
</a>
</li>
{{ end }}
{{ else }}
<li class="group mb-1">
{{ if eq .Params.action "search" }}
{{ $.Scratch.Add "searchCount" 1 }}
{{ if $.Site.Params.enableSearch | default false }}
<button
id="search-button-{{ $.Scratch.Get "searchCount" }}"
title="{{ .Title | default (i18n "search.open_button_title") }}"
>
{{ with .Params.icon | default "search" }}
<span
class="group-dark:hover:text-primary-400 transition-colors group-hover:text-primary-600"
>
{{- partial "icon.html" . -}}
</span>
{{- end -}}{{- if .Params.showName | default true -}}
<span
class="decoration-primary-500 group-hover:underline group-hover:decoration-2 group-hover:underline-offset-2"
>{{ .Name | markdownify | emojify }}</span
>
{{ end }}
</button>
{{ end }}
{{ else if eq .Params.action "appearance" }}
{{ $.Scratch.Add "switchCount" 1 }}
<button
id="appearance-switcher-{{ $.Scratch.Get "switchCount" }}"
type="button"
aria-label="appearance switcher"
>
<span
class="group-dark:hover:text-primary-400 inline transition-colors group-hover:text-primary-600 dark:hidden"
title="{{ i18n "footer.dark_appearance" }}"
>
{{ with .Params.icon | default "moon" }}
{{- partial "icon.html" . -}}
{{- end -}}
{{- if .Params.showName | default true -}}
<span
class="decoration-primary-500 group-hover:underline group-hover:decoration-2 group-hover:underline-offset-2"
>{{ .Name | markdownify | emojify }}</span
>
{{ end }}
</span>
<span
class="group-dark:hover:text-primary-400 hidden transition-colors group-hover:text-primary-600 dark:inline"
title="{{ i18n "footer.light_appearance" }}"
>
{{ with .Params.icon | default "sun" }}
{{- partial "icon.html" . -}}
{{- end -}}
{{- if .Params.showName | default true -}}
<span
class="decoration-primary-500 group-hover:underline group-hover:decoration-2 group-hover:underline-offset-2"
>{{ .Name | markdownify | emojify }}</span
>
{{ end }}
</span>
</button>
{{ else if eq .Params.action "locale" }}
{{ $.Scratch.Add "localeCount" 1 }}
{{ partial "translations.html" . }}
{{ else }}
<a
href="{{ .URL }}"
title="{{ .Title }}"
onclick="close_menu()"
{{ with .Params.rel }}rel="{{ . }}"{{ end }}
{{ with .Params.target }}target="{{ . }}"{{ end }}
>{{ with .Params.icon }}
<span
class="group-dark:hover:text-primary-400 transition-colors group-hover:text-primary-600"
>
{{- partial "icon.html" . -}}
</span>
{{- end -}}{{- if .Params.showName | default true -}}
<span
class="decoration-primary-500 group-hover:underline group-hover:decoration-2 group-hover:underline-offset-2"
>{{ .Name | markdownify | emojify }}</span
>
{{ end }}
</a>
{{ end }}
</li>
{{ end }}
{{ end }}
{{ if and ($.Site.Params.enableSearch | default false) (eq ($.Scratch.Get "searchCount") 0) }}
<li class="group mb-1">
<button id="search-button-m0" title="{{ i18n "search.open_button_title" }}">
<span
class="group-dark:hover:text-primary-400 transition-colors group-hover:text-primary-600"
>
{{ partial "icon.html" "search" }}
</span>
</button>
</li>
{{ end }}
{{ end }}
</ul>
</div>
</label>
{{/* Basic menu */}}
<ul class="hidden list-none flex-row text-end sm:flex">
{{ if .Site.Menus.main }}
{{ range .Site.Menus.main }}
{{ if and (eq .Params.action "locale") (or (not page.IsTranslated) (not hugo.IsMultilingual)) }}
{{ continue }}
{{ end }}
<li class="group mb-1 sm:mb-0 sm:me-7 sm:last:me-0">
{{ if eq .Params.action "search" }}
{{ $.Scratch.Add "searchCount" 1 }}
{{ if $.Site.Params.enableSearch | default false }}
<button
id="search-button-{{ $.Scratch.Get "searchCount" }}"
title="{{ .Title | default (i18n "search.open_button_title") }}"
>
{{ with .Params.icon | default "search" }}
<span
class="group-dark:hover:text-primary-400 transition-colors group-hover:text-primary-600"
>
{{- partial "icon.html" . -}}
</span>
{{- end -}}{{- if .Params.showName | default true -}}
<span
class="decoration-primary-500 group-hover:underline group-hover:decoration-2 group-hover:underline-offset-2"
>{{ .Name | markdownify | emojify }}</span
>
{{ end }}
</button>
{{ end }}
{{ else if eq .Params.action "appearance" }}
{{ $.Scratch.Add "switchCount" 1 }}
<button
id="appearance-switcher-{{ $.Scratch.Get "switchCount" }}"
type="button"
aria-label="appearance switcher"
>
<span
class="group-dark:hover:text-primary-400 inline transition-colors group-hover:text-primary-600 dark:hidden"
title="{{ i18n "footer.dark_appearance" }}"
>
{{ with .Params.icon | default "moon" }}
{{- partial "icon.html" . -}}
{{- end -}}
{{- if .Params.showName | default true -}}
<span
class="decoration-primary-500 group-hover:underline group-hover:decoration-2 group-hover:underline-offset-2"
>{{ .Name | markdownify | emojify }}</span
>
{{ end }}
</span>
<span
class="group-dark:hover:text-primary-400 hidden transition-colors group-hover:text-primary-600 dark:inline"
title="{{ i18n "footer.light_appearance" }}"
>
{{ with .Params.icon | default "sun" }}
{{- partial "icon.html" . -}}
{{- end -}}
{{- if .Params.showName | default true -}}
<span
class="decoration-primary-500 group-hover:underline group-hover:decoration-2 group-hover:underline-offset-2"
>{{ .Name | markdownify | emojify }}</span
>
{{ end }}
</span>
</button>
{{ else if eq .Params.action "locale" }}
{{ $.Scratch.Add "localeCount" 1 }}
{{ partial "translations.html" . }}
{{ else }}
<a
href="{{ .URL }}"
title="{{ .Title }}"
{{ with .Params.rel }}rel="{{ . }}"{{ end }}
{{ with .Params.target }}target="{{ . }}"{{ end }}
>{{ with .Params.icon }}
<span
class="group-dark:hover:text-primary-400 transition-colors group-hover:text-primary-600"
>
{{- partial "icon.html" . -}}
</span>
{{- end -}}{{- if .Params.showName | default true -}}
<span
class="decoration-primary-500 group-hover:underline group-hover:decoration-2 group-hover:underline-offset-2"
>{{ .Name | markdownify | emojify }}</span
>
{{ end }}</a
>
{{ end }}
{{ if .HasChildren }}
<ul class="submenu">
<li class="submenu-heading">
{{ .Name }}
</li>
{{ range .Children }}
<li><a href="{{ .URL }}">
{{ with .Params.icon }}
<span
class="group-dark:hover:text-primary-400 transition-colors group-hover:text-primary-600"
>
{{- partial "icon.html" . -}}
</span>
{{- end -}}
{{ .Name }}
</a></li>
{{ end }}
</ul>
{{ end }}
</li>
{{ end }}
{{ if and ($.Site.Params.enableSearch | default false) (eq ($.Scratch.Get "searchCount") 0) }}
<li class="group mb-1 sm:mb-0 sm:me-7 sm:last:me-0">
<button id="search-button-m1" title="{{ i18n "search.open_button_title" }}">
<span
class="group-dark:hover:text-primary-400 transition-colors group-hover:text-primary-600"
>
{{ partial "icon.html" "search" }}
</span>
</button>
</li>
{{ end }}
{{ end }}
</ul>
{{ end }}
</nav>
</header>