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,128 @@
|
||||
---
|
||||
// PhasePanel — the three-step "Click a phase / see the handoff" block.
|
||||
//
|
||||
// Static shell: the tab buttons and the panel markup are server-rendered.
|
||||
// The `initial` phase's content is shown by default; the other tabs still
|
||||
// carry the `data-phase` hook so the interactive island (task 15) can swap
|
||||
// the panel on click.
|
||||
//
|
||||
// Every `data-phase` value is asserted by `scripts/verify.mjs`.
|
||||
|
||||
export type PhaseId = 'plan' | 'build' | 'review';
|
||||
|
||||
interface Phase {
|
||||
id: PhaseId;
|
||||
/** Two-letter label rendered in the tab, e.g. "PLAN". */
|
||||
label: string;
|
||||
/** Numeric prefix, e.g. "01". */
|
||||
number: string;
|
||||
title: string;
|
||||
body: string;
|
||||
/** Headline + small caption shown above the panel title. */
|
||||
meta: { deliverable: string; gate: string };
|
||||
/** Code-line evidence shown at the bottom of the panel. */
|
||||
evidence: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
phases: Phase[];
|
||||
/** Initial active phase. Defaults to the first entry. */
|
||||
initial?: PhaseId;
|
||||
}
|
||||
|
||||
const { phases, initial = phases[0]?.id ?? 'plan' } = Astro.props;
|
||||
const active = phases.find((phase) => phase.id === initial) ?? phases[0];
|
||||
---
|
||||
|
||||
<div class="phase-tabs" role="tablist" aria-label="Workflow phases">
|
||||
{
|
||||
phases.map((phase) => (
|
||||
<button
|
||||
class:list={['phase-tab', { active: phase.id === initial }]}
|
||||
data-phase={phase.id}
|
||||
role="tab"
|
||||
aria-selected={phase.id === initial}
|
||||
>
|
||||
<b>{phase.number}</b> {phase.label}
|
||||
</button>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<article class="phase-panel" id="phase-panel" aria-live="polite">
|
||||
<div class="phase-meta">
|
||||
<span>{active.meta.deliverable}</span>
|
||||
<small>{active.meta.gate}</small>
|
||||
</div>
|
||||
<h3>{active.title}</h3>
|
||||
<p>{active.body}</p>
|
||||
<code>{active.evidence}</code>
|
||||
</article>
|
||||
|
||||
<style>
|
||||
.phase-tabs {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.phase-tab {
|
||||
display: grid;
|
||||
grid-template-columns: 42px 1fr;
|
||||
gap: 10px;
|
||||
padding: 15px;
|
||||
border: 1px solid var(--line);
|
||||
color: var(--ink);
|
||||
background: transparent;
|
||||
font:
|
||||
500 var(--step-0) 'DM Mono',
|
||||
monospace;
|
||||
letter-spacing: 0.07em;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
.phase-tab b {
|
||||
color: var(--accent);
|
||||
}
|
||||
.phase-tab.active {
|
||||
color: var(--paper);
|
||||
border-color: var(--ink);
|
||||
background: var(--ink);
|
||||
}
|
||||
|
||||
.phase-panel {
|
||||
min-height: 260px;
|
||||
padding: 30px;
|
||||
color: var(--paper);
|
||||
background: var(--accent);
|
||||
}
|
||||
.phase-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 15px;
|
||||
color: var(--gold);
|
||||
font:
|
||||
500 var(--step-0) 'DM Mono',
|
||||
monospace;
|
||||
}
|
||||
.phase-meta small {
|
||||
color: var(--paper);
|
||||
opacity: 0.7;
|
||||
}
|
||||
.phase-panel h3 {
|
||||
margin: 44px 0 12px;
|
||||
font-size: var(--step-5);
|
||||
line-height: 1.05;
|
||||
}
|
||||
.phase-panel p {
|
||||
line-height: 1.6;
|
||||
opacity: 0.82;
|
||||
}
|
||||
.phase-panel code {
|
||||
display: block;
|
||||
margin-top: 26px;
|
||||
color: var(--gold);
|
||||
font:
|
||||
500 var(--step-0) 'DM Mono',
|
||||
monospace;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user