summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-06-26 18:13:36 +0200
committerDanilo M. <danix@danix.xyz>2026-06-26 18:13:36 +0200
commit9073908fb5e33c895b162d0418d6e67246af539e (patch)
treed8beaa5f5c58eacee91870af7a7cdcc94b2fff7a
parent91eeea0d6b61b652a0bc3b16a137609da59da69f (diff)
parent9244ad0666c4859569801508348fa83c6e4648f4 (diff)
downloaddanixxyz-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.css91
-rw-r--r--layouts/index.json3
-rw-r--r--layouts/partials/hamburger-menu.html25
-rw-r--r--layouts/partials/header.html69
-rw-r--r--layouts/partials/project-header.html45
-rw-r--r--layouts/partials/project-row.html72
-rw-r--r--layouts/slackware/list.html28
-rw-r--r--layouts/slackware/single.html17
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 }}