From: Danilo M. Date: Sat, 18 Apr 2026 14:25:02 +0000 (+0200) Subject: feat: add // prefix to H2–H6 headings in prose X-Git-Tag: release_22042026-1342~100 X-Git-Url: https://git.danix.xyz/?a=commitdiff_plain;h=5285459993178e6116c62583a21c52f153a47725;p=danix.xyz-2.git feat: add // prefix to H2–H6 headings in prose Render all heading levels 2–6 with a terminal-style `// ` prefix in JetBrains Mono. H1 (page/article titles) is excluded. The prefix is aria-hidden for A11y compliance (WCAG 2.1 AA — heading text contrast 14.72:1, prefix is decorative and exempt from contrast requirements). Implementation: - New Hugo render-heading hook at _default/_markup/render-heading.html - Added .heading-prefix CSS rule with accent purple color, 0.8em font size, 0.7 opacity - CSS rebuil with npm run build Applies site-wide to all markdown prose content (articles, singles, pages). Co-Authored-By: Claude Haiku 4.5 --- diff --git a/docs/superpowers/specs/2026-04-18-prose-heading-prefix-design.md b/docs/superpowers/specs/2026-04-18-prose-heading-prefix-design.md new file mode 100644 index 0000000..ebc0ee8 --- /dev/null +++ b/docs/superpowers/specs/2026-04-18-prose-heading-prefix-design.md @@ -0,0 +1,56 @@ +# Design: Prose Heading `//` Prefix + +**Date:** 2026-04-18 +**Status:** Approved + +## Context + +danix.xyz uses a hacker/terminal aesthetic throughout. Article and single page body headings (H2–H6) currently render in Oxanium font with no visual marker. The goal is to prefix all prose headings with `// ` in JetBrains Mono to reinforce the terminal/comment idiom — matching the hacker identity of the site. + +## Requirements + +- All headings H2–H6 inside `.prose` content (site-wide — all singles and pages) +- H1 is excluded (used for page/article titles, already styled distinctly) +- Prefix `//` must be `aria-hidden="true"` — screen readers announce only the heading text +- Heading DOM hierarchy (H2→H6) must be preserved exactly +- WCAG 2.1 AA compliant: heading text contrast ≥ 4.5:1 (measured at 14.72:1 on dark theme) +- The prefix is decorative — exempt from contrast requirements per WCAG 1.4.3 +- Must work in both dark and light themes + +## Approach: Hugo render-heading hook + +Create `layouts/_default/_markup/render-heading.html` — Hugo's Markdown render hook for headings. For H2–H6, wrap the heading in the correct `` tag and inject `` before the text. H1 passes through unmodified. + +Style the `.heading-prefix` span in `main.css`: +- Font: `JetBrains Mono` (Tailwind `font-mono`) +- Color: `var(--accent)` (purple) +- Weight: `400` (lighter than heading bold — creates comment-marker feel) +- Size: `0.8em` relative to heading (scales automatically across H2–H6) +- Opacity: `0.7` (decorative dimming — exempt from contrast check) +- `margin-right: 0.35em` + +No changes needed to any layout template. No JS. CSS is the only addition beyond the new hook file. + +## Files + +| File | Action | +|------|--------| +| `themes/danix-xyz-hacker/layouts/_default/_markup/render-heading.html` | Create (new) | +| `themes/danix-xyz-hacker/assets/css/main.css` | Add `.heading-prefix` rule | + +## A11y Checklist + +- [x] `aria-hidden="true"` on prefix span — screen reader reads "Section Title, heading level 2" not "slash slash Section Title" +- [x] Heading text contrast 14.72:1 dark / verified light theme passes +- [x] DOM heading order unchanged +- [x] `prefers-reduced-motion` not relevant (no animation) +- [x] Decorative prefix contrast exempted under WCAG 1.4.3 + +## Verification + +1. `hugo server` — navigate to any article or single page +2. Headings H2–H6 show `// Title` in JetBrains Mono with purple dimmed prefix +3. H1 (page title) unchanged +4. Toggle dark/light theme — prefix visible and not garish in both +5. Run browser accessibility inspector — prefix span reports `aria-hidden: true` +6. `npm run build` — CSS compiles cleanly diff --git a/themes/danix-xyz-hacker/assets/css/main.css b/themes/danix-xyz-hacker/assets/css/main.css index a1d1acc..6f00eb5 100644 --- a/themes/danix-xyz-hacker/assets/css/main.css +++ b/themes/danix-xyz-hacker/assets/css/main.css @@ -103,6 +103,16 @@ html.theme-light { @apply text-xl md:text-2xl; } + .heading-prefix { + font-family: 'JetBrains Mono', monospace; + font-weight: 400; + font-size: 0.8em; + color: var(--accent); + opacity: 0.7; + margin-right: 0.35em; + user-select: none; + } + a { @apply text-accent hover:opacity-80 transition-opacity; } diff --git a/themes/danix-xyz-hacker/assets/css/main.min.css b/themes/danix-xyz-hacker/assets/css/main.min.css index 9c5c690..87ce73b 100644 --- a/themes/danix-xyz-hacker/assets/css/main.min.css +++ b/themes/danix-xyz-hacker/assets/css/main.min.css @@ -616,6 +616,18 @@ h3 { } } +.heading-prefix { + font-family: 'JetBrains Mono', monospace; + font-weight: 400; + font-size: 0.8em; + color: var(--accent); + opacity: 0.7; + margin-right: 0.35em; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + a { color: var(--accent); transition-property: opacity; diff --git a/themes/danix-xyz-hacker/layouts/_default/_markup/render-heading.html b/themes/danix-xyz-hacker/layouts/_default/_markup/render-heading.html new file mode 100644 index 0000000..d0d5e05 --- /dev/null +++ b/themes/danix-xyz-hacker/layouts/_default/_markup/render-heading.html @@ -0,0 +1,5 @@ +{{- if eq .Level 1 -}} +

{{ .Text | safeHTML }}

+{{- else -}} + {{ .Text | safeHTML }} +{{- end -}}