feat(blocks): extract six full-guide block components
PhasePanel, FleetDiagram, HandoffTable, WorktreeMap, RouteTable, SkillPackage as static shells. Each takes typed props and renders server-side markup with the data-* hooks verified by scripts/verify.mjs (data-phase, data-tree, data-worker, data-route, data-skill-file). No client:* directives; interactive islands wire up in task 15. Tokens only. No raw hex or px font sizes (check-tokens passes). The parent-background seam colour for the gap:1px grid trick in FleetDiagram is a documented token gap; see component header comment and the task final report.
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
---
|
||||
// FleetDiagram — orchestrator card, an arrow, and a 1-up of worker cards.
|
||||
//
|
||||
// Static shell: the captain renders literally, the workers render as toggle
|
||||
// buttons with the `data-worker` hook asserted by `scripts/verify.mjs`. The
|
||||
// `initial` worker is marked active and pressed.
|
||||
//
|
||||
// The source uses `gap:1px` over a coloured parent to draw hairlines between
|
||||
// workers; here the parent uses `var(--ink)` and the cards paint over it, so
|
||||
// the seam reads as the same tone — see the final report for the token gap
|
||||
// (source uses an off-token seam colour for the divider).
|
||||
|
||||
interface Worker {
|
||||
/** Used as the `data-worker` hook and the key in the source. */
|
||||
id: string;
|
||||
/** Short label rendered uppercase, e.g. "UI". */
|
||||
label: string;
|
||||
/** Body copy describing the worker's remit. */
|
||||
strong: string;
|
||||
/** Path label, e.g. "agent/ui". */
|
||||
code: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
orchestrator: {
|
||||
eyebrow: string;
|
||||
/** May contain inline `<br>`; rendered with `set:html`. */
|
||||
title: string;
|
||||
code: string;
|
||||
};
|
||||
workers: Worker[];
|
||||
initial?: string;
|
||||
}
|
||||
|
||||
const { orchestrator, workers, initial = workers[0]?.id } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="fleet-grid">
|
||||
<article class="captain">
|
||||
<span class="captain-eyebrow">{orchestrator.eyebrow}</span>
|
||||
<h2 set:html={orchestrator.title} />
|
||||
<code>{orchestrator.code}</code>
|
||||
</article>
|
||||
<div class="arrow" aria-hidden="true">→</div>
|
||||
<div class="workers" role="group" aria-label="Worker agents">
|
||||
{
|
||||
workers.map((worker) => (
|
||||
<button
|
||||
class:list={['worker-card', { active: worker.id === initial }]}
|
||||
data-worker={worker.id}
|
||||
aria-pressed={worker.id === initial}
|
||||
>
|
||||
<span>{worker.label}</span>
|
||||
<strong>{worker.strong}</strong>
|
||||
<code>{worker.code}</code>
|
||||
</button>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.fleet-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 0.8fr 50px 1.5fr;
|
||||
gap: 24px;
|
||||
margin-top: 30px;
|
||||
color: var(--paper);
|
||||
background: var(--deep);
|
||||
}
|
||||
.captain {
|
||||
display: grid;
|
||||
align-content: center;
|
||||
gap: 16px;
|
||||
padding: 32px;
|
||||
}
|
||||
.captain-eyebrow {
|
||||
color: var(--gold);
|
||||
font:
|
||||
500 var(--step-0) 'DM Mono',
|
||||
monospace;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.captain h2 {
|
||||
margin: 0;
|
||||
font-size: var(--step-5);
|
||||
line-height: 0.98;
|
||||
letter-spacing: -0.06em;
|
||||
}
|
||||
.captain code {
|
||||
color: var(--gold);
|
||||
font:
|
||||
500 var(--step-0) 'DM Mono',
|
||||
monospace;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: var(--gold);
|
||||
font-size: var(--step-5);
|
||||
}
|
||||
|
||||
.workers {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 1px;
|
||||
/* House style: gap:1px over a coloured parent background fakes borders.
|
||||
Source uses an off-token seam colour for the divider; reported as a
|
||||
token-layer gap. */
|
||||
background: var(--ink);
|
||||
}
|
||||
.worker-card {
|
||||
display: grid;
|
||||
align-content: space-between;
|
||||
gap: 20px;
|
||||
min-height: 180px;
|
||||
padding: 22px;
|
||||
color: var(--paper);
|
||||
background: var(--ink);
|
||||
border: 0;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
.worker-card span {
|
||||
color: var(--muted);
|
||||
font:
|
||||
500 var(--step-0) 'DM Mono',
|
||||
monospace;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.worker-card strong {
|
||||
font-size: var(--step-1);
|
||||
line-height: 1.2;
|
||||
}
|
||||
.worker-card code {
|
||||
color: var(--gold);
|
||||
font:
|
||||
500 var(--step-0) 'DM Mono',
|
||||
monospace;
|
||||
}
|
||||
.worker-card.active {
|
||||
box-shadow: inset 4px 0 0 var(--gold);
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.fleet-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.arrow {
|
||||
transform: rotate(90deg);
|
||||
min-height: 35px;
|
||||
}
|
||||
.workers {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user