From 0221603766ccbb2d5abc184147b0281015eb4c38 Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Mon, 20 Apr 2026 21:20:35 -0400 Subject: [PATCH] library: portal ornaments + inter-shelf divider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each shelf gets a dingbat keyed by portal slug: laurel (research), quill (nonfiction), open book (fiction), lyre (poetry), plus the existing clef / ai / tech / trefoil glyphs for the remaining four. Rendered via mask-image with currentColor so a single SVG per portal inherits whatever color its heading carries. Between rendered shelves, a centered fleuron flanked by thin rules (library-divider.svg) sits via CSS adjacent-sibling so hidden sections leave no orphan dividers. The template swaps its Unicode placeholder for a data-ornament span, wires a '\$library-intro\$' slot above the shelves, and renders a "More on this shelf →" link when has-more gates fire. Co-Authored-By: Claude Opus 4.7 (1M context) --- static/css/library.css | 103 +++++++++++++++++++++ static/images/dingbats/fiction.svg | 5 + static/images/dingbats/library-divider.svg | 7 ++ static/images/dingbats/nonfiction.svg | 6 ++ static/images/dingbats/poetry.svg | 8 ++ static/images/dingbats/research.svg | 6 ++ templates/library.html | 46 +++++++-- 7 files changed, 173 insertions(+), 8 deletions(-) create mode 100644 static/images/dingbats/fiction.svg create mode 100644 static/images/dingbats/library-divider.svg create mode 100644 static/images/dingbats/nonfiction.svg create mode 100644 static/images/dingbats/poetry.svg create mode 100644 static/images/dingbats/research.svg diff --git a/static/css/library.css b/static/css/library.css index 55a835e..f3b6fcf 100644 --- a/static/css/library.css +++ b/static/css/library.css @@ -164,6 +164,109 @@ margin-bottom: 0.5rem; } +/* Per-shelf ornament sitting before the heading text. SVGs in + /images/dingbats/ painted via mask-image so they inherit + currentColor (→ the same muted tone as the heading). */ +.library-section-ornament { + display: inline-block; + width: 1em; + height: 1em; + margin-right: 0.5em; + background-color: currentColor; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + -webkit-mask-repeat: no-repeat; + -webkit-mask-position: center; + -webkit-mask-size: contain; + vertical-align: -0.12em; +} + +.library-section-ornament[data-ornament="research"] { + mask-image: url('/images/dingbats/research.svg'); + -webkit-mask-image: url('/images/dingbats/research.svg'); +} +.library-section-ornament[data-ornament="nonfiction"] { + mask-image: url('/images/dingbats/nonfiction.svg'); + -webkit-mask-image: url('/images/dingbats/nonfiction.svg'); +} +.library-section-ornament[data-ornament="fiction"] { + mask-image: url('/images/dingbats/fiction.svg'); + -webkit-mask-image: url('/images/dingbats/fiction.svg'); +} +.library-section-ornament[data-ornament="poetry"] { + mask-image: url('/images/dingbats/poetry.svg'); + -webkit-mask-image: url('/images/dingbats/poetry.svg'); +} +.library-section-ornament[data-ornament="music"] { + mask-image: url('/images/dingbats/clef.svg'); + -webkit-mask-image: url('/images/dingbats/clef.svg'); +} +.library-section-ornament[data-ornament="ai"] { + mask-image: url('/images/dingbats/ai.svg'); + -webkit-mask-image: url('/images/dingbats/ai.svg'); +} +.library-section-ornament[data-ornament="tech"] { + mask-image: url('/images/dingbats/tech.svg'); + -webkit-mask-image: url('/images/dingbats/tech.svg'); +} +.library-section-ornament[data-ornament="miscellany"] { + mask-image: url('/images/dingbats/trefoil.svg'); + -webkit-mask-image: url('/images/dingbats/trefoil.svg'); +} + +/* Inter-shelf divider. Adjacent-sibling selector renders between + actually-emitted sections — a section hidden by its $if$ gate + leaves no orphan divider because it never hits the DOM. */ +.library-section + .library-section::before { + content: ""; + display: block; + width: 240px; + max-width: 60%; + height: 24px; + margin: 2.5rem auto; + color: var(--text-faint); + background-color: currentColor; + mask-image: url('/images/dingbats/library-divider.svg'); + -webkit-mask-image: url('/images/dingbats/library-divider.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + -webkit-mask-repeat: no-repeat; + -webkit-mask-position: center; + -webkit-mask-size: contain; +} + +/* "More on this shelf →" link, shown when the portal has more + items than the shelf's cap. Right-aligned, italic, subdued. */ +.library-more { + text-align: right; + font-family: var(--font-serif); + font-style: italic; + font-size: 0.9rem; + color: var(--text-muted); + margin: 0.65rem 0 0; +} + +.library-more a { + color: inherit; + text-decoration: underline; + text-decoration-color: var(--border); + text-decoration-thickness: 0.08em; + text-underline-offset: 0.2em; + transition: color var(--transition-fast), text-decoration-color var(--transition-fast); +} + +.library-more a:hover { + color: var(--text); + text-decoration-color: var(--border-muted); +} + +/* Leading blockquote above the shelves, lifted from content/library.md. */ +.library-intro { + margin: 0.5rem 0 2rem; +} + .library-section h2 a { color: inherit; text-decoration: none; diff --git a/static/images/dingbats/fiction.svg b/static/images/dingbats/fiction.svg new file mode 100644 index 0000000..44a3fee --- /dev/null +++ b/static/images/dingbats/fiction.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/static/images/dingbats/library-divider.svg b/static/images/dingbats/library-divider.svg new file mode 100644 index 0000000..f5c3076 --- /dev/null +++ b/static/images/dingbats/library-divider.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/static/images/dingbats/nonfiction.svg b/static/images/dingbats/nonfiction.svg new file mode 100644 index 0000000..e31b6f3 --- /dev/null +++ b/static/images/dingbats/nonfiction.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/static/images/dingbats/poetry.svg b/static/images/dingbats/poetry.svg new file mode 100644 index 0000000..3c9f580 --- /dev/null +++ b/static/images/dingbats/poetry.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/static/images/dingbats/research.svg b/static/images/dingbats/research.svg new file mode 100644 index 0000000..7695c1e --- /dev/null +++ b/static/images/dingbats/research.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/templates/library.html b/templates/library.html index 2eb008d..13a06c9 100644 --- a/templates/library.html +++ b/templates/library.html @@ -1,95 +1,125 @@

Library

+$if(library-intro)$ +
+$library-intro$ +
+$endif$ + $if(research-entries)$
-

Research

+

Research

    $for(research-entries)$ $partial("templates/partials/item-card.html")$ $endfor$
+$if(research-has-more)$ +

More on this shelf →

+$endif$
$endif$ $if(nonfiction-entries)$
-

Nonfiction

+

Nonfiction

    $for(nonfiction-entries)$ $partial("templates/partials/item-card.html")$ $endfor$
+$if(nonfiction-has-more)$ +

More on this shelf →

+$endif$
$endif$ $if(fiction-entries)$
-

Fiction

+

Fiction

    $for(fiction-entries)$ $partial("templates/partials/item-card.html")$ $endfor$
+$if(fiction-has-more)$ +

More on this shelf →

+$endif$
$endif$ $if(poetry-entries)$
-

Poetry

+

Poetry

    $for(poetry-entries)$ $partial("templates/partials/item-card.html")$ $endfor$
+$if(poetry-has-more)$ +

More on this shelf →

+$endif$
$endif$ $if(music-entries)$
-

Music

+

Music

    $for(music-entries)$ $partial("templates/partials/item-card.html")$ $endfor$
+$if(music-has-more)$ +

More on this shelf →

+$endif$
$endif$ $if(ai-entries)$
-

AI

+

AI

    $for(ai-entries)$ $partial("templates/partials/item-card.html")$ $endfor$
+$if(ai-has-more)$ +

More on this shelf →

+$endif$
$endif$ $if(tech-entries)$
-

Tech

+

Tech

    $for(tech-entries)$ $partial("templates/partials/item-card.html")$ $endfor$
+$if(tech-has-more)$ +

More on this shelf →

+$endif$
$endif$ $if(miscellany-entries)$
-

Miscellany

+

Miscellany

    $for(miscellany-entries)$ $partial("templates/partials/item-card.html")$ $endfor$
+$if(miscellany-has-more)$ +

More on this shelf →

+$endif$
$endif$