diff --git a/src/components/blocks/FleetDiagram.astro b/src/components/blocks/FleetDiagram.astro index b8c3577..c695e9b 100644 --- a/src/components/blocks/FleetDiagram.astro +++ b/src/components/blocks/FleetDiagram.astro @@ -9,22 +9,24 @@ // hairlines between worker cards; the parent background is an off-token seam // colour marked inline with `token-gap`. +type Localized = { en: string; pt: string }; + 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; + label: string | Localized; /** Body copy describing the worker's remit. */ - strong: string; + strong: string | Localized; /** Path label, e.g. "agent/ui". */ code: string; } interface Props { orchestrator: { - eyebrow: string; + eyebrow: string | Localized; /** May contain inline `
`; rendered with `set:html`. */ - title: string; + title: string | Localized; code: string; }; workers: Worker[]; @@ -36,8 +38,32 @@ const { orchestrator, workers, initial = workers[0]?.id } = Astro.props;
- {orchestrator.eyebrow} -

+ + { + typeof orchestrator.eyebrow === 'string' ? ( + orchestrator.eyebrow + ) : ( + <> + <> + {orchestrator.eyebrow.en} + + + + ) + } + + { + typeof orchestrator.title === 'string' ? ( +

+ ) : ( + <> +

+

@@ -49,8 +75,30 @@ const { orchestrator, workers, initial = workers[0]?.id } = Astro.props; data-worker={worker.id} aria-pressed={worker.id === initial} > - {worker.label} - {worker.strong} + + {typeof worker.label === 'string' ? ( + worker.label + ) : ( + <> + {worker.label.en} + + + )} + + + {typeof worker.strong === 'string' ? ( + worker.strong + ) : ( + <> + {worker.strong.en} + + + )} + {worker.code} )) diff --git a/src/components/blocks/HandoffTable.astro b/src/components/blocks/HandoffTable.astro index 7dca7d1..9b96995 100644 --- a/src/components/blocks/HandoffTable.astro +++ b/src/components/blocks/HandoffTable.astro @@ -7,18 +7,20 @@ // muted body) and lives here so the next page that needs it gets the same // beat for free. +type Localized = { en: string; pt: string }; + interface Row { /** The package name, rendered as a `` (column 1). */ - package: string; + package: string | Localized; /** What the package contains (column 2). */ - contains: string; + contains: string | Localized; /** Why this matters (column 3). */ - why: string; + why: string | Localized; } interface Props { /** Column headers in render order. */ - columns: [string, string, string]; + columns: [string | Localized, string | Localized, string | Localized]; rows: Row[]; } @@ -28,18 +30,96 @@ const { columns, rows } = Astro.props; - - - + + + { rows.map((row) => ( - - - + + + )) } diff --git a/src/components/blocks/PhasePanel.astro b/src/components/blocks/PhasePanel.astro index 12fbe50..e4cbbab 100644 --- a/src/components/blocks/PhasePanel.astro +++ b/src/components/blocks/PhasePanel.astro @@ -8,18 +8,20 @@ // // Every `data-phase` value is asserted by `scripts/verify.mjs`. +type Localized = { en: string; pt: string }; + export type PhaseId = 'plan' | 'build' | 'review'; interface Phase { id: PhaseId; /** Two-letter label rendered in the tab, e.g. "PLAN". */ - label: string; + label: string | Localized; /** Numeric prefix, e.g. "01". */ number: string; - title: string; - body: string; + title: string | Localized; + body: string | Localized; /** Headline + small caption shown above the panel title. */ - meta: { deliverable: string; gate: string }; + meta: { deliverable: string | Localized; gate: string | Localized }; /** Code-line evidence shown at the bottom of the panel. */ evidence: string; } @@ -43,7 +45,17 @@ const active = phases.find((phase) => phase.id === initial) ?? phases[0]; role="tab" aria-selected={phase.id === initial} > - {phase.number} {phase.label} + {phase.number}{' '} + {typeof phase.label === 'string' ? ( + phase.label + ) : ( + <> + {phase.label.en} + + + )} )) } @@ -51,11 +63,71 @@ const active = phases.find((phase) => phase.id === initial) ?? phases[0];
- {active.meta.deliverable} - {active.meta.gate} + + { + typeof active.meta.deliverable === 'string' ? ( + active.meta.deliverable + ) : ( + <> + <> + {active.meta.deliverable.en} + + + + ) + } + + + { + typeof active.meta.gate === 'string' ? ( + active.meta.gate + ) : ( + <> + <> + {active.meta.gate.en} + + + + ) + } +
-

{active.title}

-

{active.body}

+

+ { + typeof active.title === 'string' ? ( + active.title + ) : ( + <> + <> + {active.title.en} + + + + ) + } +

+

+ { + typeof active.body === 'string' ? ( + active.body + ) : ( + <> + <> + {active.body.en} + + + + ) + } +

{active.evidence}
diff --git a/src/components/blocks/RouteTable.astro b/src/components/blocks/RouteTable.astro index c66345b..6c9d244 100644 --- a/src/components/blocks/RouteTable.astro +++ b/src/components/blocks/RouteTable.astro @@ -6,14 +6,16 @@ // renders the column header + the four rows; task 15 will hydrate the // "route detail" panel to the right. +type Localized = { en: string; pt: string }; + interface Route { id: 'plan' | 'build' | 'explore' | 'review' | string; /** Strong label, e.g. "Plan". */ - strong: string; + strong: string | Localized; /** Profile descriptor, e.g. "strong / broad". */ - profile: string; + profile: string | Localized; /** Prompt shape copy. */ - prompt: string; + prompt: string | Localized; } interface Props { @@ -37,9 +39,42 @@ const { routes, initial = routes[0]?.id ?? 'plan' } = Astro.props; data-route={route.id} aria-pressed={route.id === initial} > - {route.strong} - {route.profile} - {route.prompt} + + {typeof route.strong === 'string' ? ( + route.strong + ) : ( + <> + {route.strong.en} + + + )} + + + {typeof route.profile === 'string' ? ( + route.profile + ) : ( + <> + {route.profile.en} + + + )} + + + {typeof route.prompt === 'string' ? ( + route.prompt + ) : ( + <> + {route.prompt.en} + + + )} + )) } diff --git a/src/components/blocks/SkillPackage.astro b/src/components/blocks/SkillPackage.astro index e045b3d..6557391 100644 --- a/src/components/blocks/SkillPackage.astro +++ b/src/components/blocks/SkillPackage.astro @@ -7,12 +7,14 @@ // paired with a `
` detail panel by the parent page; this component // renders only the picker. +type Localized = { en: string; pt: string }; + interface PackageFile { id: 'skill' | 'references' | 'scripts' | 'assets' | string; /** Path rendered inside ``, e.g. "SKILL.md". */ path: string; /** Helper copy under the path. */ - small: string; + small: string | Localized; } interface Props { @@ -34,7 +36,18 @@ const { files, initial = files[0]?.id ?? 'skill' } = Astro.props; aria-selected={file.id === initial} > {file.path} - {file.small} + + {typeof file.small === 'string' ? ( + file.small + ) : ( + <> + {file.small.en} + + + )} + )) } diff --git a/src/components/blocks/WorktreeMap.astro b/src/components/blocks/WorktreeMap.astro index 4e44213..c5125a5 100644 --- a/src/components/blocks/WorktreeMap.astro +++ b/src/components/blocks/WorktreeMap.astro @@ -6,15 +6,17 @@ // the `data-tree` hook asserted by `scripts/verify.mjs`. The `root` node and // the `initial` branch are marked selected. +type Localized = { en: string; pt: string }; + interface Branch { /** The `data-tree` hook, e.g. "ui", "tests", "docs". */ id: string; /** Uppercase label, e.g. "UI AGENT". */ - label: string; + label: string | Localized; /** Strong line, e.g. "agent/ui". */ strong: string; /** Status small, e.g. "3 files · working". */ - small: string; + small: string | Localized; /** CSS modifier so each branch picks up its tone. */ tone: 'ui' | 'tests' | 'docs' | string; } @@ -50,9 +52,31 @@ const { branches, initial = 'main' } = Astro.props; aria-selected={branch.id === initial} > <> - {branch.label} + + {typeof branch.label === 'string' ? ( + branch.label + ) : ( + <> + {branch.label.en} + + + )} + {branch.strong} - {branch.small} + + {typeof branch.small === 'string' ? ( + branch.small + ) : ( + <> + {branch.small.en} + + + )} + ))
{columns[0]}{columns[1]}{columns[2]} + { + typeof columns[0] === 'string' ? ( + columns[0] + ) : ( + <> + <> + {columns[0].en} + + + + ) + } + + { + typeof columns[1] === 'string' ? ( + columns[1] + ) : ( + <> + <> + {columns[1].en} + + + + ) + } + + { + typeof columns[2] === 'string' ? ( + columns[2] + ) : ( + <> + <> + {columns[2].en} + + + + ) + } +
{row.package}{row.contains}{row.why} + {typeof row.package === 'string' ? ( + row.package + ) : ( + <> + {row.package.en} + + + )} + + {typeof row.contains === 'string' ? ( + row.contains + ) : ( + <> + {row.contains.en} + + + )} + + {typeof row.why === 'string' ? ( + row.why + ) : ( + <> + {row.why.en} + + + )} +