diff options
Diffstat (limited to 'layouts/partials')
| -rw-r--r-- | layouts/partials/hamburger-menu.html | 25 | ||||
| -rw-r--r-- | layouts/partials/header.html | 69 | ||||
| -rw-r--r-- | layouts/partials/project-header.html | 45 | ||||
| -rw-r--r-- | layouts/partials/project-row.html | 72 |
4 files changed, 203 insertions, 8 deletions
diff --git a/layouts/partials/hamburger-menu.html b/layouts/partials/hamburger-menu.html index 55bb2a6..0280ecb 100644 --- a/layouts/partials/hamburger-menu.html +++ b/layouts/partials/hamburger-menu.html @@ -42,6 +42,31 @@ {{ if $isExternal }}{{ .Name }}{{ else }}{{ i18n .Name }}{{ end }} {{ if $isExternal }}<span class="sr-only">{{ i18n "opensInNewTab" }}</span>{{ end }} </a> + {{ if .HasChildren }} + <div class="pl-4 border-l-2 border-accent/40 ml-2"> + {{ range .Children }} + {{ $childExternal := .Params.external }} + {{ $label := "" }} + {{ if $childExternal }} + {{ $label = .Name }} + {{ else if and .Name (i18n .Name) }} + {{ $label = i18n .Name }} + {{ else if .Page }} + {{ $label = .Page.LinkTitle }} + {{ else }} + {{ $label = .Name }} + {{ end }} + <a + href="{{ .URL }}" + @click="menuOpen = false" + class="block py-3 text-base text-text-dim hover:text-accent transition-colors rounded focus:outline-none focus:ring-2 focus:ring-accent" + {{ if $childExternal }}target="_blank" rel="noopener noreferrer"{{ end }} + > + {{ $label }} + </a> + {{ end }} + </div> + {{ end }} {{ end }} </nav> diff --git a/layouts/partials/header.html b/layouts/partials/header.html index 603f779..4ef817e 100644 --- a/layouts/partials/header.html +++ b/layouts/partials/header.html @@ -1,4 +1,4 @@ -<header class="fixed top-0 left-0 right-0 z-50 frosted-bar border-b"> +<header class="fixed top-0 left-0 right-0 z-50 frosted-bar border-b group/header"> <nav class="container mx-auto px-4 py-4 flex items-center justify-between"> <!-- Logo and Site Name --> {{ $homeLink := "/" }} @@ -16,13 +16,30 @@ {{ range .Site.Menus.main }} {{ $menuPath := strings.TrimSuffix "/" .URL }} {{ $isActive := eq $menuPath $currentPath }} - <a - href="{{ .URL }}" - class="text-sm transition-colors {{ if $isActive }}text-accent font-bold{{ else }}hover:text-accent{{ end }}" - {{ if $isActive }}aria-current="page"{{ end }} - > - {{ i18n .Name }} - </a> + {{ $isExternal := .Params.external }} + {{ if .HasChildren }} + {{/* Parent link only here; its children render as a full-width + second row below the bar (see the submenu band after </nav>). + No ARIA menu roles: CSS-only hover/focus, not an arrow-key menu; + group-focus-within on the header gives keyboard reveal. */}} + <a + href="{{ .URL }}" + class="text-sm transition-colors inline-flex items-center gap-1 rounded focus:outline-none focus:ring-2 focus:ring-accent {{ if $isActive }}text-accent font-bold{{ else }}hover:text-accent{{ end }}" + {{ if $isActive }}aria-current="page"{{ end }} + > + {{ i18n .Name }} + <i data-feather="chevron-down" class="w-3 h-3" aria-hidden="true"></i> + </a> + {{ else }} + <a + href="{{ .URL }}" + class="text-sm transition-colors {{ if $isActive }}text-accent font-bold{{ else }}hover:text-accent{{ end }}" + {{ if $isActive }}aria-current="page"{{ end }} + {{ if $isExternal }}target="_blank" rel="noopener noreferrer"{{ end }} + > + {{ if $isExternal }}{{ .Name }}{{ else }}{{ i18n .Name }}{{ end }} + </a> + {{ end }} {{ end }} </div> @@ -89,6 +106,42 @@ </div> </nav> + <!-- Desktop submenu: second row inside the same frosted glass, revealed on + hover/focus of the bar (no separate background — header expands) --> + {{ range .Site.Menus.main }} + {{ if .HasChildren }} + <div class="hidden md:group-hover/header:flex md:group-focus-within/header:flex"> + <ul class="container mx-auto px-4 py-3 flex items-center justify-center gap-8"> + {{ range .Children }} + {{ $childExternal := .Params.external }} + {{/* Curated entries (Packages) carry an i18n key as .Name; project + pages added via front-matter have no name, so fall back to the + page title. */}} + {{ $label := "" }} + {{ if $childExternal }} + {{ $label = .Name }} + {{ else if and .Name (i18n .Name) }} + {{ $label = i18n .Name }} + {{ else if .Page }} + {{ $label = .Page.LinkTitle }} + {{ else }} + {{ $label = .Name }} + {{ end }} + <li> + <a + href="{{ .URL }}" + class="text-sm whitespace-nowrap text-text-dim hover:text-accent transition-colors rounded focus:outline-none focus:ring-2 focus:ring-accent" + {{ if $childExternal }}target="_blank" rel="noopener noreferrer"{{ end }} + > + {{ $label }} + </a> + </li> + {{ end }} + </ul> + </div> + {{ end }} + {{ end }} + <!-- Mobile hamburger overlay menu --> {{ partial "hamburger-menu.html" . }} </header> diff --git a/layouts/partials/project-header.html b/layouts/partials/project-header.html new file mode 100644 index 0000000..17fe7db --- /dev/null +++ b/layouts/partials/project-header.html @@ -0,0 +1,45 @@ +{{ $status := .Params.status | default "active" }} +{{/* status -> theme-aware bg/text var pair (all defined in main.css). + active=green, maintained=blue, wip=amber, archived=muted. */}} +{{ $bgVar := "--type-quote" }}{{ $txtVar := "--type-quote-text" }} +{{ if eq $status "maintained" }}{{ $bgVar = "--type-link" }}{{ $txtVar = "--type-link-text" }}{{ end }} +{{ if eq $status "wip" }}{{ $bgVar = "--type-life" }}{{ $txtVar = "--type-life-text" }}{{ end }} +{{ if eq $status "archived" }}{{ $bgVar = "--text-dim" }}{{ $txtVar = "--bg" }}{{ end }} +{{ $badgeStyle := printf "background-color: var(%s); color: var(%s);" $bgVar $txtVar | safeCSS }} + +{{/* Full-width banner: page resource named header.* in the project bundle. */}} +{{ $headerImg := .Resources.GetMatch "header.*" }} + +<header class="mb-10"> + {{ with $headerImg }} + <img src="{{ .RelPermalink }}" alt="" class="w-full h-48 md:h-64 object-cover rounded-lg mb-6" loading="lazy" /> + {{ end }} + + <div class="flex flex-wrap items-center justify-between gap-3 mb-2"> + <h1 class="text-4xl md:text-5xl font-bold text-accent font-oxanium">{{ .Title }}</h1> + <span class="flex-shrink-0 px-3 py-1 rounded-full text-xs font-semibold" style="{{ $badgeStyle }}"> + {{ i18n (printf "status-%s" $status) }} + </span> + </div> + + {{ with .Params.tagline }} + <p class="text-xl text-text-dim mb-4">{{ . }}</p> + {{ end }} + + <div class="flex flex-wrap items-center justify-between gap-3"> + {{ with .Params.repo_url }} + <a href="{{ . }}" target="_blank" rel="noopener noreferrer" class="btn btn-sm inline-flex items-center gap-2"> + {{ i18n "viewRepo" }} + <i data-feather="external-link" class="w-4 h-4" aria-hidden="true"></i> + <span class="sr-only">{{ i18n "opensInNewTab" }}</span> + </a> + {{ end }} + {{ with .Params.tags }} + <ul class="flex flex-wrap gap-2 ml-auto"> + {{ range . }} + <li><a href="/tags/{{ . | urlize }}/" class="px-2 py-1 rounded text-xs bg-surface text-text hover:text-accent transition-colors focus:outline-none focus:ring-2 focus:ring-accent">{{ . }}</a></li> + {{ end }} + </ul> + {{ end }} + </div> +</header> diff --git a/layouts/partials/project-row.html b/layouts/partials/project-row.html new file mode 100644 index 0000000..7a1e209 --- /dev/null +++ b/layouts/partials/project-row.html @@ -0,0 +1,72 @@ +{{ $p := .page }} +{{ $reverse := eq (mod .index 2) 1 }} + +{{ $status := $p.Params.status | default "active" }} +{{/* status -> theme-aware bg/text var pair (all defined in main.css). + active=green, maintained=blue, wip=amber, archived=muted. */}} +{{ $bgVar := "--type-quote" }}{{ $txtVar := "--type-quote-text" }} +{{ if eq $status "maintained" }}{{ $bgVar = "--type-link" }}{{ $txtVar = "--type-link-text" }}{{ end }} +{{ if eq $status "wip" }}{{ $bgVar = "--type-life" }}{{ $txtVar = "--type-life-text" }}{{ end }} +{{ if eq $status "archived" }}{{ $bgVar = "--text-dim" }}{{ $txtVar = "--bg" }}{{ end }} +{{ $badgeStyle := printf "background-color: var(%s); color: var(%s);" $bgVar $txtVar | safeCSS }} + +{{/* Row thumbnail (2:3): page resource named thumbnail.* in the project + bundle; fall back to an `image` param, else a mono-glyph block. */}} +{{ $imageURL := "" }} +{{ $thumb := $p.Resources.GetMatch "thumbnail.*" }} +{{ if $thumb }} + {{ $imageURL = $thumb.RelPermalink }} +{{ else if $p.Params.image }} + {{ $res := $p.Resources.GetMatch $p.Params.image }} + {{ if $res }}{{ $imageURL = $res.RelPermalink }}{{ else }}{{ $imageURL = $p.Params.image }}{{ end }} +{{ end }} +{{ $glyph := substr (upper $p.Title) 0 2 }} + +<article class="group flex flex-col md:flex-row {{ if $reverse }}md:flex-row-reverse{{ end }} gap-6 items-stretch border-l-4 border-accent bg-surface/30 rounded-lg overflow-hidden transition-all duration-200 hover:-translate-y-1 hover:shadow-lg hover:bg-surface/50"> + <!-- Visual (decorative duplicate of the title link; hidden from AT) --> + <a href="{{ $p.RelPermalink }}" tabindex="-1" aria-hidden="true" class="md:w-1/3 flex-shrink-0 self-start flex items-center justify-center bg-bg/40 aspect-[3/2] overflow-hidden"> + {{ if $imageURL }} + <img src="{{ $imageURL }}" alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-200" loading="lazy" /> + {{ else }} + <span class="text-5xl font-bold font-oxanium text-accent/80 select-none">{{ $glyph }}</span> + {{ end }} + </a> + + <!-- Body --> + <div class="flex-1 p-6 flex flex-col gap-3"> + <div class="flex items-start justify-between gap-3"> + <h2 class="text-2xl font-bold font-oxanium"> + <a href="{{ $p.RelPermalink }}" class="group-hover:text-accent transition-colors rounded focus:outline-none focus:ring-2 focus:ring-accent">{{ $p.Title }}</a> + </h2> + <span class="flex-shrink-0 px-3 py-1 rounded-full text-xs font-semibold" style="{{ $badgeStyle }}"> + {{ i18n (printf "status-%s" $status) }} + </span> + </div> + + {{ with $p.Params.tagline }} + <p class="text-text-dim">{{ . }}</p> + {{ end }} + + {{ with $p.Params.tags }} + <ul class="flex flex-wrap gap-2 mt-1"> + {{ range . }} + <li class="px-2 py-1 rounded text-xs bg-bg/60 text-text">{{ . }}</li> + {{ end }} + </ul> + {{ end }} + + <div class="flex flex-wrap items-center gap-3 mt-auto pt-2"> + <a href="{{ $p.RelPermalink }}" class="btn btn-sm inline-flex items-center gap-2"> + {{ i18n "readMore" }} + <i data-feather="arrow-right" class="w-4 h-4" aria-hidden="true"></i> + </a> + {{ with $p.Params.repo_url }} + <a href="{{ . }}" target="_blank" rel="noopener noreferrer" class="text-sm text-text-dim hover:text-accent inline-flex items-center gap-1 transition-colors rounded focus:outline-none focus:ring-2 focus:ring-accent"> + {{ i18n "viewRepo" }} + <i data-feather="external-link" class="w-3 h-3" aria-hidden="true"></i> + <span class="sr-only">{{ i18n "opensInNewTab" }}</span> + </a> + {{ end }} + </div> + </div> +</article> |
