diff options
| author | Danilo M. <danix@danix.xyz> | 2026-06-26 18:13:36 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-06-26 18:13:36 +0200 |
| commit | 9073908fb5e33c895b162d0418d6e67246af539e (patch) | |
| tree | d8beaa5f5c58eacee91870af7a7cdcc94b2fff7a | |
| parent | 91eeea0d6b61b652a0bc3b16a137609da59da69f (diff) | |
| parent | 9244ad0666c4859569801508348fa83c6e4648f4 (diff) | |
| download | danixxyz-theme-9073908fb5e33c895b162d0418d6e67246af539e.tar.gz danixxyz-theme-9073908fb5e33c895b162d0418d6e67246af539e.zip | |
Merge slackware-projects: project pages, submenu, image roles
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| -rw-r--r-- | assets/css/main.min.css | 91 | ||||
| -rw-r--r-- | layouts/index.json | 3 | ||||
| -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 | ||||
| -rw-r--r-- | layouts/slackware/list.html | 28 | ||||
| -rw-r--r-- | layouts/slackware/single.html | 17 |
8 files changed, 341 insertions, 9 deletions
diff --git a/assets/css/main.min.css b/assets/css/main.min.css index 2d09220..048b8e7 100644 --- a/assets/css/main.min.css +++ b/assets/css/main.min.css @@ -1648,6 +1648,21 @@ button, /* Legacy type-* classes for compatibility (with badge styling) */ +.type-life { + color: var(--type-life); + background-color: rgba(245, 158, 11, 0.1); +} + +.type-quote { + color: var(--type-quote); + background-color: rgba(0, 255, 136, 0.1); +} + +.type-link { + color: var(--type-link); + background-color: rgba(56, 189, 248, 0.1); +} + /* Card component */ .card { @@ -2409,6 +2424,10 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.menu-overlay { margin-bottom: 0.25rem; } +.mb-10 { + margin-bottom: 2.5rem; +} + .mb-12 { margin-bottom: 3rem; } @@ -2441,6 +2460,10 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.menu-overlay { margin-left: 0.5rem; } +.ml-auto { + margin-left: auto; +} + .mt-0\.5 { margin-top: 0.125rem; } @@ -2527,6 +2550,10 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.menu-overlay { display: none; } +.aspect-\[3\/2\] { + aspect-ratio: 3/2; +} + .aspect-video { aspect-ratio: 16 / 9; } @@ -2563,6 +2590,10 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.menu-overlay { height: auto; } +.h-full { + height: 100%; +} + .h-screen { height: 100vh; } @@ -2705,6 +2736,12 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.menu-overlay { cursor: pointer; } +.select-none { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + .resize-none { resize: none; } @@ -2725,10 +2762,18 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.menu-overlay { flex-wrap: wrap; } +.items-start { + align-items: flex-start; +} + .items-center { align-items: center; } +.items-stretch { + align-items: stretch; +} + .justify-center { justify-content: center; } @@ -2757,6 +2802,10 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.menu-overlay { gap: 1rem; } +.gap-6 { + gap: 1.5rem; +} + .gap-8 { gap: 2rem; } @@ -2803,6 +2852,10 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.menu-overlay { border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); } +.self-start { + align-self: flex-start; +} + .overflow-hidden { overflow: hidden; } @@ -3037,6 +3090,10 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.menu-overlay { padding-left: 0.75rem; } +.pl-4 { + padding-left: 1rem; +} + .pl-6 { padding-left: 1.5rem; } @@ -3102,6 +3159,11 @@ article.border.border-border\/30.rounded-lg.overflow-hidden.group.menu-overlay { line-height: 1; } +.text-base { + font-size: 1rem; + line-height: 1.5rem; +} + .text-lg { font-size: 1.125rem; line-height: 1.75rem; @@ -5037,6 +5099,11 @@ html.theme-light .hero-name { line-height: 2.25rem; } +.hover\:-translate-y-1:hover { + --tw-translate-y: -0.25rem; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + .hover\:bg-surface:hover { background-color: var(--surface); } @@ -5207,6 +5274,14 @@ html.theme-light .hero-name { height: 12rem; } + .md\:h-64 { + height: 16rem; + } + + .md\:w-1\/3 { + width: 33.333333%; + } + .md\:w-48 { width: 12rem; } @@ -5219,6 +5294,14 @@ html.theme-light .hero-name { grid-template-columns: repeat(3, minmax(0, 1fr)); } + .md\:flex-row { + flex-direction: row; + } + + .md\:flex-row-reverse { + flex-direction: row-reverse; + } + .md\:gap-6 { gap: 1.5rem; } @@ -5242,6 +5325,14 @@ html.theme-light .hero-name { font-size: 6rem; line-height: 1; } + + .group\/header:focus-within .md\:group-focus-within\/header\:flex { + display: flex; + } + + .group\/header:hover .md\:group-hover\/header\:flex { + display: flex; + } } @media (prefers-color-scheme: dark) { diff --git a/layouts/index.json b/layouts/index.json index e17e31e..891641a 100644 --- a/layouts/index.json +++ b/layouts/index.json @@ -1,5 +1,6 @@ {{- $articles := where .Site.RegularPages "Section" "articles" -}} -{{- $articles = $articles.ByDate.Reverse -}} +{{- $projects := where .Site.RegularPages "Section" "slackware" -}} +{{- $articles = ($articles | append $projects).ByDate.Reverse -}} [ {{- range $index, $article := $articles -}} { 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> diff --git a/layouts/slackware/list.html b/layouts/slackware/list.html new file mode 100644 index 0000000..ac89356 --- /dev/null +++ b/layouts/slackware/list.html @@ -0,0 +1,28 @@ +{{ define "main" }} +<section class="mx-auto px-4 py-12 max-w-7xl"> + <div class="content-grid"> + {{ partial "breadcrumb.html" . }} + + <div class="mb-10"> + <h1 class="text-5xl md:text-6xl font-bold mb-4 text-accent font-oxanium animate-fade-in"> + {{ i18n "slackwareTitle" }} + </h1> + <p class="text-xl text-text-dim animate-fade-in-delay"> + {{ i18n "slackwareSubtitle" }} + </p> + </div> + + {{ with .Content }} + <div class="prose dark:prose-invert max-w-none mb-12"> + {{ . }} + </div> + {{ end }} + + <div class="flex flex-col gap-8"> + {{ range $index, $p := .Pages }} + {{ partial "project-row.html" (dict "page" $p "index" $index) }} + {{ end }} + </div> + </div> +</section> +{{ end }} diff --git a/layouts/slackware/single.html b/layouts/slackware/single.html new file mode 100644 index 0000000..6efb3e2 --- /dev/null +++ b/layouts/slackware/single.html @@ -0,0 +1,17 @@ +{{ define "main" }} +<article class="mx-auto px-4 py-12 max-w-7xl"> + <div class="content-grid"> + {{ partial "breadcrumb.html" . }} + + {{ partial "project-header.html" . }} + + <div class="prose dark:prose-invert max-w-none mb-12"> + {{ .Content }} + </div> + + <div class="mb-12"> + {{ partial "social-share.html" (dict "page" . "mode" "inline") }} + </div> + </div> +</article> +{{ end }} |
