diff options
Diffstat (limited to 'docs/superpowers/plans/2026-06-26-slackware-projects-section.md')
| -rw-r--r-- | docs/superpowers/plans/2026-06-26-slackware-projects-section.md | 78 |
1 files changed, 52 insertions, 26 deletions
diff --git a/docs/superpowers/plans/2026-06-26-slackware-projects-section.md b/docs/superpowers/plans/2026-06-26-slackware-projects-section.md index 8213367..7a1ac79 100644 --- a/docs/superpowers/plans/2026-06-26-slackware-projects-section.md +++ b/docs/superpowers/plans/2026-06-26-slackware-projects-section.md @@ -273,11 +273,14 @@ In `header.html`, replace the desktop menu block (the `<div class="hidden md:fle {{ $isActive := eq $menuPath $currentPath }} {{ $isExternal := .Params.external }} {{ if .HasChildren }} + {{/* CSS-only hover/focus popup. No ARIA menu roles: we do not + implement arrow-key menu semantics, so claiming role="menu" + would lie to AT. focus-within gives keyboard reveal; the + parent stays a plain navigable link. */}} <div class="relative group"> <a href="{{ .URL }}" - class="text-sm transition-colors inline-flex items-center gap-1 {{ if $isActive }}text-accent font-bold{{ else }}hover:text-accent{{ end }}" - aria-haspopup="true" + 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 }} @@ -285,14 +288,13 @@ In `header.html`, replace the desktop menu block (the `<div class="hidden md:fle </a> <!-- Submenu: padding-top bridges the hover gap --> <div class="absolute left-1/2 -translate-x-1/2 top-full pt-3 hidden group-hover:flex group-focus-within:flex"> - <ul class="frosted-bar border border-border rounded-lg px-4 py-3 flex flex-col gap-2 min-w-max shadow-lg" role="menu"> + <ul class="frosted-bar border border-border rounded-lg px-4 py-3 flex flex-col gap-2 min-w-max shadow-lg"> {{ range .Children }} {{ $childExternal := .Params.external }} - <li role="none"> + <li> <a href="{{ .URL }}" - role="menuitem" - class="block text-sm whitespace-nowrap hover:text-accent transition-colors" + class="block text-sm whitespace-nowrap hover:text-accent transition-colors rounded focus:outline-none focus:ring-2 focus:ring-accent" {{ if $childExternal }}target="_blank" rel="noopener noreferrer"{{ end }} > {{ if $childExternal }}{{ .Name }}{{ else }}{{ i18n .Name }}{{ end }} @@ -344,13 +346,19 @@ Renders the light-schema header (tagline, status badge, repo link, optional imag - [ ] **Step 1: Write the partial** +A11y/house-style note: status colors map to the existing theme-aware +`--type-*` vars (each ships a matched WCAG-AA `-text` color), archived uses +`--text-dim` bg with `--bg` text. No literal hex, no theme-breaking. Tag +links and the repo link get the project's standard focus-ring pattern. + `themes/danix-xyz-hacker/layouts/partials/project-header.html`: ```html {{ $status := .Params.status | default "active" }} -{{ $statusColor := "var(--color-accent, #a855f7)" }} -{{ if eq $status "maintained" }}{{ $statusColor = .Site.Params.secondaryAccent }}{{ end }} -{{ if eq $status "wip" }}{{ $statusColor = "#f59e0b" }}{{ end }} -{{ if eq $status "archived" }}{{ $statusColor = "#9ca3af" }}{{ end }} +{{/* status -> theme-aware bg/text var pair (all defined in main.css) */}} +{{ $bgVar := "--type-tech" }}{{ $txtVar := "--type-tech-text" }} +{{ if eq $status "maintained" }}{{ $bgVar = "--type-quote" }}{{ $txtVar = "--type-quote-text" }}{{ end }} +{{ if eq $status "wip" }}{{ $bgVar = "--type-life" }}{{ $txtVar = "--type-life-text" }}{{ end }} +{{ if eq $status "archived" }}{{ $bgVar = "--text-dim" }}{{ $txtVar = "--bg" }}{{ end }} {{ $imageURL := "" }} {{ if .Params.image }} @@ -365,7 +373,7 @@ Renders the light-schema header (tagline, status badge, repo link, optional imag <div class="flex flex-wrap items-center gap-3 mb-2"> <h1 class="text-4xl md:text-5xl font-bold text-accent font-oxanium">{{ .Title }}</h1> - <span class="px-3 py-1 rounded-full text-xs font-semibold" style="background-color: {{ $statusColor }}; color: #0b0b0b;"> + <span class="px-3 py-1 rounded-full text-xs font-semibold" style="background-color: var({{ $bgVar }}); color: var({{ $txtVar }});"> {{ i18n (printf "status-%s" $status) }} </span> </div> @@ -379,12 +387,13 @@ Renders the light-schema header (tagline, status badge, repo link, optional imag <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"> {{ range . }} - <li><a href="/tags/{{ . | urlize }}/" class="px-2 py-1 rounded text-xs bg-surface text-text-dim hover:text-accent transition-colors">{{ . }}</a></li> + <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 }} @@ -486,7 +495,7 @@ In `hamburger-menu.html`, replace the `{{ range .Site.Menus.main }}…{{ end }}` <a href="{{ .URL }}" @click="menuOpen = false" - class="block py-3 text-base text-text-dim hover:text-accent transition-colors" + 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 }} > {{ if $childExternal }}{{ .Name }}{{ else }}{{ i18n .Name }}{{ end }} @@ -525,16 +534,23 @@ One full-width hub row: option #3 shape (alternating image side), option #2 styl Receives a dict: `{ "page": <Page>, "index": <int> }`. Even index → image left; odd → image right. +A11y/house-style note: same theme-aware `--type-*` status mapping as the +header partial; row heading is `h2` (direct child of the hub `h1`, no skipped +level); the decorative glyph link is `aria-hidden` (the titled link carries +the name); tech pills use full-contrast `text-text`; the repo link gets a +focus ring + sr-only new-tab notice. + `themes/danix-xyz-hacker/layouts/partials/project-row.html`: ```html {{ $p := .page }} {{ $reverse := eq (mod .index 2) 1 }} {{ $status := $p.Params.status | default "active" }} -{{ $statusColor := "var(--color-accent, #a855f7)" }} -{{ if eq $status "maintained" }}{{ $statusColor = $p.Site.Params.secondaryAccent }}{{ end }} -{{ if eq $status "wip" }}{{ $statusColor = "#f59e0b" }}{{ end }} -{{ if eq $status "archived" }}{{ $statusColor = "#9ca3af" }}{{ end }} +{{/* status -> theme-aware bg/text var pair (all defined in main.css) */}} +{{ $bgVar := "--type-tech" }}{{ $txtVar := "--type-tech-text" }} +{{ if eq $status "maintained" }}{{ $bgVar = "--type-quote" }}{{ $txtVar = "--type-quote-text" }}{{ end }} +{{ if eq $status "wip" }}{{ $bgVar = "--type-life" }}{{ $txtVar = "--type-life-text" }}{{ end }} +{{ if eq $status "archived" }}{{ $bgVar = "--text-dim" }}{{ $txtVar = "--bg" }}{{ end }} {{ $imageURL := "" }} {{ if $p.Params.image }} @@ -544,10 +560,10 @@ Receives a dict: `{ "page": <Page>, "index": <int> }`. Even index → image left {{ $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 --> - <a href="{{ $p.RelPermalink }}" tabindex="-1" class="md:w-1/3 flex-shrink-0 flex items-center justify-center bg-bg/40 min-h-[10rem]"> + <!-- 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 flex items-center justify-center bg-bg/40 min-h-[10rem]"> {{ if $imageURL }} - <img src="{{ $imageURL }}" alt="{{ $p.Title }}" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-200" loading="lazy" /> + <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 }} @@ -556,10 +572,10 @@ Receives a dict: `{ "page": <Page>, "index": <int> }`. Even index → image left <!-- Body --> <div class="flex-1 p-6 flex flex-col gap-3"> <div class="flex items-start justify-between gap-3"> - <h3 class="text-2xl font-bold font-oxanium"> - <a href="{{ $p.RelPermalink }}" class="group-hover:text-accent transition-colors">{{ $p.Title }}</a> - </h3> - <span class="flex-shrink-0 px-3 py-1 rounded-full text-xs font-semibold" style="background-color: {{ $statusColor }}; color: #0b0b0b;"> + <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="background-color: var({{ $bgVar }}); color: var({{ $txtVar }});"> {{ i18n (printf "status-%s" $status) }} </span> </div> @@ -571,7 +587,7 @@ Receives a dict: `{ "page": <Page>, "index": <int> }`. Even index → image left {{ 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-dim">{{ . }}</li> + <li class="px-2 py-1 rounded text-xs bg-bg/60 text-text">{{ . }}</li> {{ end }} </ul> {{ end }} @@ -582,9 +598,10 @@ Receives a dict: `{ "page": <Page>, "index": <int> }`. Even index → image left <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"> + <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> @@ -776,3 +793,12 @@ Per CLAUDE.md: `git checkout production && git merge master && git push origin p - **Type/name consistency:** status color logic and `status-<x>` i18n keys identical in project-header (T5) and project-row (T8); `dict "page" … "index" …` produced in T9 matches `.page`/`.index` consumed in T8; `slackwareTitle`/`slackwareSubtitle`/`viewRepo`/`status-*` defined in T2 and used in T5/T6/T8/T9. - **Discovered simplification:** menu rename is i18n-value-only (labels render via `i18n .Name`); no `name=` churn needed. Captured in T2. - **Bonus fix:** T4 corrects a pre-existing desktop-bar bug where external items lacked `target="_blank"` and wrongly ran `i18n .Name`. + +### A11y + design review fixes folded in (2026-06-26) +- **Status badges (T5/T8):** use theme-aware `--type-*` vars with their matched WCAG-AA `-text` colors (active→type-tech, maintained→type-quote, wip→type-life, archived→text-dim/`--bg`). No literal hex, no broken light/dark, no `--color-accent` (doesn't exist). +- **Tech pills (T5/T8):** `text-text` (full contrast) instead of `text-text-dim` — dim-on-dim 11px failed AA. +- **Focus rings:** added `focus:outline-none focus:ring-2 focus:ring-accent` to all bare interactive links (desktop submenu T4, mobile children T7, tag links T5, title + repo links T8) matching the project's existing focus pattern. +- **Honest ARIA (T4):** dropped `role="menu"/menuitem"/aria-haspopup` — CSS-only popup doesn't implement arrow-key menu semantics; `focus-within` provides keyboard reveal on plain links. +- **Heading hierarchy (T8):** row heading is `h2` (under hub `h1`), no skipped level. +- **Decorative glyph (T8):** visual link is `aria-hidden="true"` + `tabindex="-1"`, image `alt=""`; the titled `h2` link carries the accessible name (no duplicate/empty link announced). +- **New-tab notice:** external repo links get `sr-only` "opensInNewTab" (key exists both langs). |
