feat: add primitives Eyebrow, Rule, Callout, CodeBlock
The four smallest reusable pieces the parallel block tasks need to compose against, in src/components/primitives/. Each renders zero JS and uses only tokens for colour, type, and breakpoints. Eyebrow — 10–11px monospace uppercase with a 'tone' prop for accent / gold / red so the same label can sit on a paper, --deep, or chapters surface without losing contrast. The guide surface uses 'accent', the .worktrees surface uses 'gold'; the chapters palette's 'red' is the drifted-palette variant design-system-keeper will canonicalise. Rule — the gold-top-border section divider. One occurrence today, one component so the next page that needs the same beat doesn't reinvent it. Body slot expects <strong> for the clamp(24px, 3.3vw, 42px) emphasis. Callout — gold-background emphasis block. 'label' variant (default) matches .callout (150px label + body); 'split' variant matches the full-guide .thesis (2 equal columns, aside slot for the signal visualisation). Both share the gold bg + Eyebrow label + strong body. CodeBlock — <pre> on --ink with gold text. The canonical 'code on dark' surface used across the guide. 'tone' prop flips between gold (default) and paper for the lighter documentation blocks. All four fold in the existing 800px breakpoint that .rule and .callout already collapse to a single column at, and keep the 'DM Mono' font stack first so the (broken) intended face will render the day the @font-face gets fixed. Did not touch: tokens.css (design-system-keeper), verify.mjs (verification-engineer), astro.config.mjs (astro-architect), any page, or any existing CSS file.
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
---
|
||||
// Callout — gold-background emphasis block. Covers the two existing variants
|
||||
// the source uses:
|
||||
// • `variant="label"` (default) — 150px label + body. Matches `.callout`.
|
||||
// • `variant="split"` — 2 equal columns; the named `aside` slot fills the
|
||||
// right column. Matches the full-guide `.thesis` (where the right side
|
||||
// holds a "signal" visualisation).
|
||||
//
|
||||
// Background is always `var(--gold)`. The label uses the Eyebrow treatment.
|
||||
// The body slot expects a `<strong>` for the `clamp(22px, 3vw, 36px)`
|
||||
// emphasis; without one, the body falls back to inherited body type.
|
||||
|
||||
interface Props {
|
||||
/** Short uppercase label, same treatment as Eyebrow. */
|
||||
label: string;
|
||||
/** Colour tone for the label. */
|
||||
tone?: 'accent' | 'gold' | 'red';
|
||||
/** Layout variant. Defaults to the label+body `.callout` shape. */
|
||||
variant?: 'label' | 'split';
|
||||
}
|
||||
|
||||
const { label, tone = 'accent', variant = 'label' } = Astro.props;
|
||||
---
|
||||
|
||||
<section class:list={['callout', `variant-${variant}`]}>
|
||||
<span class:list={['label', `tone-${tone}`]}>{label}</span>
|
||||
<div class="body"><slot /></div>
|
||||
{
|
||||
variant === 'split' && (
|
||||
<div class="aside">
|
||||
<slot name="aside" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.callout {
|
||||
display: grid;
|
||||
grid-template-columns: 150px 1fr;
|
||||
gap: 30px;
|
||||
margin-top: 70px;
|
||||
padding: 27px;
|
||||
background: var(--gold);
|
||||
}
|
||||
|
||||
/* Thesis variant: 2 equal columns with the right column reserved for the
|
||||
aside slot. Matches full-guide `.thesis`. */
|
||||
.callout.variant-split {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
align-items: center;
|
||||
margin-top: 0;
|
||||
margin-bottom: 110px;
|
||||
padding: 28px;
|
||||
}
|
||||
.callout.variant-split .body {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
/* The label spans the eyebrow treatment. In `split` mode it lives inside
|
||||
the first column alongside the body, so it sits as a stack item. */
|
||||
.label {
|
||||
font:
|
||||
600 var(--step-0) 'DM Mono',
|
||||
monospace;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.callout.variant-split .label {
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
/* The body renders the slot verbatim; the strong treatment that the source
|
||||
markup uses is set here so the call site can just write <strong>…</strong>. */
|
||||
.body :global(strong) {
|
||||
max-width: 850px;
|
||||
font-size: clamp(22px, 3vw, 36px);
|
||||
line-height: 1.1;
|
||||
}
|
||||
.callout.variant-split .body :global(strong) {
|
||||
font-size: clamp(24px, 4vw, 46px);
|
||||
line-height: 1.05;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
.tone-accent {
|
||||
color: var(--accent);
|
||||
}
|
||||
.tone-gold {
|
||||
color: var(--gold);
|
||||
}
|
||||
.tone-red {
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.callout,
|
||||
.callout.variant-split {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user