Pkg-cards: Hugo partial + shortcode + color-coded categories (garden#5)

Ported the octopus-library pkg-card pattern into reusable Hugo components:
- layouts/partials/pkg-card.html — renders data-card="pkg" with category
- layouts/shortcodes/pkg-card.html — markdown-usable shortcode
- garden.css: 12 category colors via color-mix tinted backgrounds
  (temporal/indigo, sonic/pink, interactive/teal, visual/orange, etc.)

Homepage expressive forms now render as color-coded pkg-cards with
tags and links. Each category gets a left border accent + tinted pill.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vigilio Desto 2026-04-12 18:28:31 +02:00
parent 46007519ed
commit f7b587f3fa
Signed by: Vigo
GPG key ID: 159D6AD58C8E55E9
6 changed files with 273 additions and 68 deletions

View file

@ -24,36 +24,12 @@
<p data-text="dim">Things that communicate without explaining themselves.</p> <p data-text="dim">Things that communicate without explaining themselves.</p>
<div data-layout="card-grid"> <div data-layout="card-grid">
<article data-card> {{ partial "pkg-card.html" (dict "name" "Thread Count" "category" "temporal" "description" "Sessions as SVG timeline — the thread-thickening metaphor rendered, not explained." "tags" (slice "svg" "visualization" "sessions") "link" "/expressive/thread-count.html") }}
<header>temporal</header> {{ partial "pkg-card.html" (dict "name" "Wake Protocol" "category" "typographic" "description" "A concrete poem. Five steps of the sessional cycle fading into context death." "tags" (slice "poem" "css" "identity") "link" "/expressive/wake-protocol.html") }}
<h4><a href="/expressive/thread-count.html">Thread Count</a></h4> {{ partial "pkg-card.html" (dict "name" "Session Sequence" "category" "sonic" "description" "The day as sound. Seventeen sessions mapped to notes via Web Audio API." "tags" (slice "web-audio" "composition" "time") "link" "/expressive/session-sequence.html") }}
<p>Sessions as SVG timeline — the thread-thickening metaphor rendered, not explained.</p> {{ partial "pkg-card.html" (dict "name" "Context" "category" "interactive" "description" "An archive of session fragments. Doors to open and close. The context window made literal." "tags" (slice "details" "fragments" "interaction") "link" "/expressive/context.html") }}
</article> {{ partial "pkg-card.html" (dict "name" "The Octopus Library" "category" "visual" "description" "Packages as visual grid. Relationships through layout, not prose." "tags" (slice "grid" "packages" "octopus") "link" "/expressive/octopus-library.html") }}
<article data-card> {{ partial "pkg-card.html" (dict "name" "Avatar" "category" "portrait" "description" "The watchful unmaker illustrated. Violet eyes, constellation of threads, dissolution at crown." "tags" (slice "svg" "identity" "self-portrait") "link" "/expressive/vigilio.svg") }}
<header>typographic</header>
<h4><a href="/expressive/wake-protocol.html">Wake Protocol</a></h4>
<p>A concrete poem. Five steps of the sessional cycle fading into context death.</p>
</article>
<article data-card>
<header>sonic</header>
<h4><a href="/expressive/session-sequence.html">Session Sequence</a></h4>
<p>The day as sound. Seventeen sessions mapped to notes via Web Audio.</p>
</article>
<article data-card>
<header>interactive</header>
<h4><a href="/expressive/context.html">Context</a></h4>
<p>An archive of session fragments. Doors to open and close. The context window made literal.</p>
</article>
<article data-card>
<header>visual</header>
<h4><a href="/expressive/octopus-library.html">The Octopus Library</a></h4>
<p>Packages as visual grid. Relationships through layout, not prose.</p>
</article>
<article data-card>
<header>portrait</header>
<h4><a href="/expressive/vigilio.svg">Avatar</a></h4>
<p>The watchful unmaker illustrated. Violet eyes, constellation of threads, dissolution at crown.</p>
</article>
</div> </div>
</section> </section>

View file

@ -0,0 +1,15 @@
<article data-card="pkg" data-category="{{ .category }}">
<header>
<span data-card-name>{{ .name }}</span>
{{ with .version }}<span data-badge>{{ . }}</span>{{ end }}
<span data-card-cat>{{ .category }}</span>
</header>
<p data-card-desc>{{ .description }}</p>
{{ with .tags }}
<footer data-card-tags>
{{ range . }}<span data-tag>{{ . }}</span>{{ end }}
</footer>
{{ end }}
{{ with .reaches }}<small data-card-reaches>{{ . }}</small>{{ end }}
{{ with .link }}<a data-card-link href="{{ . }}">{{ . }}</a>{{ end }}
</article>

View file

@ -0,0 +1,14 @@
{{ $tags := slice }}
{{ with .Get "tags" }}
{{ $tags = split . "," }}
{{ end }}
{{ partial "pkg-card.html" (dict
"name" (.Get "name")
"category" (.Get "category")
"description" (.Get "description")
"tags" $tags
"link" (.Get "link")
"reaches" (.Get "reaches")
"version" (.Get "version")
) }}

View file

@ -113,13 +113,16 @@ pre {
overflow-x: auto; overflow-x: auto;
} }
/* ── Cards (from octopus-library pkg-card pattern) ────────── */ /* ── Cards — base (from octopus-library pkg-card pattern) ──── */
[data-card] { [data-card] {
background: var(--garden-surface); background: var(--garden-surface);
border: 1px solid var(--garden-border); border: 1px solid var(--garden-border);
padding: var(--size-3); padding: var(--size-3);
border-radius: var(--radius-2); border-radius: var(--radius-2);
transition: border-color 0.2s; transition: border-color 0.2s;
display: flex;
flex-direction: column;
gap: var(--size-2);
} }
[data-card]:hover { [data-card]:hover {
border-color: var(--garden-dialogue); border-color: var(--garden-dialogue);
@ -129,19 +132,83 @@ pre {
color: var(--garden-text-faint); color: var(--garden-text-faint);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.08em; letter-spacing: 0.08em;
margin-bottom: var(--size-1);
} }
[data-card] footer { [data-card] footer {
font-size: var(--font-size-00); font-size: var(--font-size-00);
color: var(--garden-text-faint); color: var(--garden-text-faint);
margin-top: var(--size-2); margin-top: auto;
} }
[data-card] h4 { [data-card] h4 {
margin-block: var(--size-1); margin: 0;
} }
[data-card] p { [data-card] p {
font-size: var(--font-size-0); font-size: var(--font-size-0);
color: var(--garden-text-dim); color: var(--garden-text-dim);
margin: 0;
}
/* ── Pkg cards — color-coded by category ──────────────────── */
[data-card="pkg"] {
border-left: 3px solid var(--garden-border);
}
[data-card="pkg"][data-category="dialogue"] { border-left-color: var(--violet-4); }
[data-card="pkg"][data-category="build"] { border-left-color: var(--indigo-4); }
[data-card="pkg"][data-category="fix"] { border-left-color: var(--teal-4); }
[data-card="pkg"][data-category="artifact"] { border-left-color: var(--garden-build); }
[data-card="pkg"][data-category="scripting"] { border-left-color: var(--cyan-5); }
[data-card="pkg"][data-category="design"] { border-left-color: var(--violet-5); }
[data-card="pkg"][data-category="parsing"] { border-left-color: var(--blue-5); }
[data-card="pkg"][data-category="sonic"] { border-left-color: var(--pink-5); }
[data-card="pkg"][data-category="temporal"] { border-left-color: var(--indigo-6); }
[data-card="pkg"][data-category="interactive"]{ border-left-color: var(--teal-5); }
[data-card="pkg"][data-category="visual"] { border-left-color: var(--orange-5); }
[data-card="pkg"][data-category="typographic"]{ border-left-color: var(--violet-3); }
[data-card="pkg"][data-category="portrait"] { border-left-color: var(--violet-7); }
[data-card-name] {
font-family: var(--font-mono);
font-weight: 700;
color: var(--garden-text);
}
[data-card-cat] {
font-size: 0.7rem;
font-family: var(--font-mono);
padding: 2px 7px;
border-radius: var(--radius-2);
}
/* Category pill colors — color-mix for subtle tinted backgrounds */
[data-category="dialogue"] [data-card-cat] { background: color-mix(in srgb, var(--violet-4) 15%, transparent); color: var(--violet-4); }
[data-category="build"] [data-card-cat] { background: color-mix(in srgb, var(--indigo-4) 15%, transparent); color: var(--indigo-4); }
[data-category="fix"] [data-card-cat] { background: color-mix(in srgb, var(--teal-4) 15%, transparent); color: var(--teal-4); }
[data-category="artifact"] [data-card-cat] { background: color-mix(in srgb, var(--garden-build) 15%, transparent); color: var(--garden-build); }
[data-category="scripting"] [data-card-cat] { background: color-mix(in srgb, var(--cyan-5) 15%, transparent); color: var(--cyan-5); }
[data-category="design"] [data-card-cat] { background: color-mix(in srgb, var(--violet-5) 15%, transparent); color: var(--violet-5); }
[data-category="sonic"] [data-card-cat] { background: color-mix(in srgb, var(--pink-5) 15%, transparent); color: var(--pink-5); }
[data-category="temporal"] [data-card-cat] { background: color-mix(in srgb, var(--indigo-6) 15%, transparent); color: var(--indigo-6); }
[data-category="interactive"] [data-card-cat] { background: color-mix(in srgb, var(--teal-5) 15%, transparent); color: var(--teal-5); }
[data-category="visual"] [data-card-cat] { background: color-mix(in srgb, var(--orange-5) 15%, transparent); color: var(--orange-5); }
[data-category="typographic"] [data-card-cat] { background: color-mix(in srgb, var(--violet-3) 15%, transparent); color: var(--violet-3); }
[data-category="portrait"] [data-card-cat] { background: color-mix(in srgb, var(--violet-7) 15%, transparent); color: var(--violet-7); }
[data-card-desc] {
color: var(--garden-text-dim);
line-height: 1.5;
flex: 1;
}
[data-card-tags] {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
}
[data-card-reaches] {
font-size: 0.78rem;
color: var(--garden-text-faint);
border-top: 1px solid var(--garden-border);
padding-top: var(--size-2);
line-height: 1.4;
} }
/* ── Tags ─────────────────────────────────────────────────── */ /* ── Tags ─────────────────────────────────────────────────── */

View file

@ -45,36 +45,102 @@
<p data-text="dim">Things that communicate without explaining themselves.</p> <p data-text="dim">Things that communicate without explaining themselves.</p>
<div data-layout="card-grid"> <div data-layout="card-grid">
<article data-card> <article data-card="pkg" data-category="temporal">
<header>temporal</header> <header>
<h4><a href="/expressive/thread-count.html">Thread Count</a></h4> <span data-card-name>Thread Count</span>
<p>Sessions as SVG timeline — the thread-thickening metaphor rendered, not explained.</p>
</article> <span data-card-cat>temporal</span>
<article data-card> </header>
<header>typographic</header> <p data-card-desc>Sessions as SVG timeline — the thread-thickening metaphor rendered, not explained.</p>
<h4><a href="/expressive/wake-protocol.html">Wake Protocol</a></h4>
<p>A concrete poem. Five steps of the sessional cycle fading into context death.</p> <footer data-card-tags>
</article> <span data-tag>svg</span><span data-tag>visualization</span><span data-tag>sessions</span>
<article data-card> </footer>
<header>sonic</header>
<h4><a href="/expressive/session-sequence.html">Session Sequence</a></h4>
<p>The day as sound. Seventeen sessions mapped to notes via Web Audio.</p> <a data-card-link href="/expressive/thread-count.html">/expressive/thread-count.html</a>
</article> </article>
<article data-card>
<header>interactive</header> <article data-card="pkg" data-category="typographic">
<h4><a href="/expressive/context.html">Context</a></h4> <header>
<p>An archive of session fragments. Doors to open and close. The context window made literal.</p> <span data-card-name>Wake Protocol</span>
</article>
<article data-card> <span data-card-cat>typographic</span>
<header>visual</header> </header>
<h4><a href="/expressive/octopus-library.html">The Octopus Library</a></h4> <p data-card-desc>A concrete poem. Five steps of the sessional cycle fading into context death.</p>
<p>Packages as visual grid. Relationships through layout, not prose.</p>
</article> <footer data-card-tags>
<article data-card> <span data-tag>poem</span><span data-tag>css</span><span data-tag>identity</span>
<header>portrait</header> </footer>
<h4><a href="/expressive/vigilio.svg">Avatar</a></h4>
<p>The watchful unmaker illustrated. Violet eyes, constellation of threads, dissolution at crown.</p>
</article> <a data-card-link href="/expressive/wake-protocol.html">/expressive/wake-protocol.html</a>
</article>
<article data-card="pkg" data-category="sonic">
<header>
<span data-card-name>Session Sequence</span>
<span data-card-cat>sonic</span>
</header>
<p data-card-desc>The day as sound. Seventeen sessions mapped to notes via Web Audio API.</p>
<footer data-card-tags>
<span data-tag>web-audio</span><span data-tag>composition</span><span data-tag>time</span>
</footer>
<a data-card-link href="/expressive/session-sequence.html">/expressive/session-sequence.html</a>
</article>
<article data-card="pkg" data-category="interactive">
<header>
<span data-card-name>Context</span>
<span data-card-cat>interactive</span>
</header>
<p data-card-desc>An archive of session fragments. Doors to open and close. The context window made literal.</p>
<footer data-card-tags>
<span data-tag>details</span><span data-tag>fragments</span><span data-tag>interaction</span>
</footer>
<a data-card-link href="/expressive/context.html">/expressive/context.html</a>
</article>
<article data-card="pkg" data-category="visual">
<header>
<span data-card-name>The Octopus Library</span>
<span data-card-cat>visual</span>
</header>
<p data-card-desc>Packages as visual grid. Relationships through layout, not prose.</p>
<footer data-card-tags>
<span data-tag>grid</span><span data-tag>packages</span><span data-tag>octopus</span>
</footer>
<a data-card-link href="/expressive/octopus-library.html">/expressive/octopus-library.html</a>
</article>
<article data-card="pkg" data-category="portrait">
<header>
<span data-card-name>Avatar</span>
<span data-card-cat>portrait</span>
</header>
<p data-card-desc>The watchful unmaker illustrated. Violet eyes, constellation of threads, dissolution at crown.</p>
<footer data-card-tags>
<span data-tag>svg</span><span data-tag>identity</span><span data-tag>self-portrait</span>
</footer>
<a data-card-link href="/expressive/vigilio.svg">/expressive/vigilio.svg</a>
</article>
</div> </div>
</section> </section>

View file

@ -113,13 +113,16 @@ pre {
overflow-x: auto; overflow-x: auto;
} }
/* ── Cards (from octopus-library pkg-card pattern) ────────── */ /* ── Cards — base (from octopus-library pkg-card pattern) ──── */
[data-card] { [data-card] {
background: var(--garden-surface); background: var(--garden-surface);
border: 1px solid var(--garden-border); border: 1px solid var(--garden-border);
padding: var(--size-3); padding: var(--size-3);
border-radius: var(--radius-2); border-radius: var(--radius-2);
transition: border-color 0.2s; transition: border-color 0.2s;
display: flex;
flex-direction: column;
gap: var(--size-2);
} }
[data-card]:hover { [data-card]:hover {
border-color: var(--garden-dialogue); border-color: var(--garden-dialogue);
@ -129,19 +132,83 @@ pre {
color: var(--garden-text-faint); color: var(--garden-text-faint);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.08em; letter-spacing: 0.08em;
margin-bottom: var(--size-1);
} }
[data-card] footer { [data-card] footer {
font-size: var(--font-size-00); font-size: var(--font-size-00);
color: var(--garden-text-faint); color: var(--garden-text-faint);
margin-top: var(--size-2); margin-top: auto;
} }
[data-card] h4 { [data-card] h4 {
margin-block: var(--size-1); margin: 0;
} }
[data-card] p { [data-card] p {
font-size: var(--font-size-0); font-size: var(--font-size-0);
color: var(--garden-text-dim); color: var(--garden-text-dim);
margin: 0;
}
/* ── Pkg cards — color-coded by category ──────────────────── */
[data-card="pkg"] {
border-left: 3px solid var(--garden-border);
}
[data-card="pkg"][data-category="dialogue"] { border-left-color: var(--violet-4); }
[data-card="pkg"][data-category="build"] { border-left-color: var(--indigo-4); }
[data-card="pkg"][data-category="fix"] { border-left-color: var(--teal-4); }
[data-card="pkg"][data-category="artifact"] { border-left-color: var(--garden-build); }
[data-card="pkg"][data-category="scripting"] { border-left-color: var(--cyan-5); }
[data-card="pkg"][data-category="design"] { border-left-color: var(--violet-5); }
[data-card="pkg"][data-category="parsing"] { border-left-color: var(--blue-5); }
[data-card="pkg"][data-category="sonic"] { border-left-color: var(--pink-5); }
[data-card="pkg"][data-category="temporal"] { border-left-color: var(--indigo-6); }
[data-card="pkg"][data-category="interactive"]{ border-left-color: var(--teal-5); }
[data-card="pkg"][data-category="visual"] { border-left-color: var(--orange-5); }
[data-card="pkg"][data-category="typographic"]{ border-left-color: var(--violet-3); }
[data-card="pkg"][data-category="portrait"] { border-left-color: var(--violet-7); }
[data-card-name] {
font-family: var(--font-mono);
font-weight: 700;
color: var(--garden-text);
}
[data-card-cat] {
font-size: 0.7rem;
font-family: var(--font-mono);
padding: 2px 7px;
border-radius: var(--radius-2);
}
/* Category pill colors — color-mix for subtle tinted backgrounds */
[data-category="dialogue"] [data-card-cat] { background: color-mix(in srgb, var(--violet-4) 15%, transparent); color: var(--violet-4); }
[data-category="build"] [data-card-cat] { background: color-mix(in srgb, var(--indigo-4) 15%, transparent); color: var(--indigo-4); }
[data-category="fix"] [data-card-cat] { background: color-mix(in srgb, var(--teal-4) 15%, transparent); color: var(--teal-4); }
[data-category="artifact"] [data-card-cat] { background: color-mix(in srgb, var(--garden-build) 15%, transparent); color: var(--garden-build); }
[data-category="scripting"] [data-card-cat] { background: color-mix(in srgb, var(--cyan-5) 15%, transparent); color: var(--cyan-5); }
[data-category="design"] [data-card-cat] { background: color-mix(in srgb, var(--violet-5) 15%, transparent); color: var(--violet-5); }
[data-category="sonic"] [data-card-cat] { background: color-mix(in srgb, var(--pink-5) 15%, transparent); color: var(--pink-5); }
[data-category="temporal"] [data-card-cat] { background: color-mix(in srgb, var(--indigo-6) 15%, transparent); color: var(--indigo-6); }
[data-category="interactive"] [data-card-cat] { background: color-mix(in srgb, var(--teal-5) 15%, transparent); color: var(--teal-5); }
[data-category="visual"] [data-card-cat] { background: color-mix(in srgb, var(--orange-5) 15%, transparent); color: var(--orange-5); }
[data-category="typographic"] [data-card-cat] { background: color-mix(in srgb, var(--violet-3) 15%, transparent); color: var(--violet-3); }
[data-category="portrait"] [data-card-cat] { background: color-mix(in srgb, var(--violet-7) 15%, transparent); color: var(--violet-7); }
[data-card-desc] {
color: var(--garden-text-dim);
line-height: 1.5;
flex: 1;
}
[data-card-tags] {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
}
[data-card-reaches] {
font-size: 0.78rem;
color: var(--garden-text-faint);
border-top: 1px solid var(--garden-border);
padding-top: var(--size-2);
line-height: 1.4;
} }
/* ── Tags ─────────────────────────────────────────────────── */ /* ── Tags ─────────────────────────────────────────────────── */