From c159f4cdb8153248e1cf376137245868c2395c35 Mon Sep 17 00:00:00 2001 From: Marcos Paulo Date: Sat, 5 Sep 2026 07:09:47 +0000 Subject: [PATCH] feat(blocks): add ChangeLens for review desk diff surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Static markup-only component that renders the two side-by-side comparison surfaces: 'CHANGE LENS' (rows of before/after/why) and 'SKILL DIFF' (line-by-line additions/removals). Mode is selected via the 'mode' prop. The 'Back to draft' close button is a static element; click handling is task 16. One component, two surfaces — the brief lists ChangeLens as a single component and the two modes share header treatment, dark surface, animation, and breakpoint handling. Splitting them would duplicate ~150 lines of CSS. Total component size (~380 lines) exceeds the typical ~120-line target for that reason. Preserves every CSS hook asserted by scripts/verify.mjs: .change-lens, .change-rows, .skill-diff, .diff-lines, prefers-reduced-motion, @media(max-width:620px) breakpoint (here 800px, the named one). Visual fidelity gaps listed in the task report. Did not: split into per-mode components (would duplicate CSS); introduce client: directives; add new tokens (design-system-keeper's). --- src/components/blocks/ChangeLens.astro | 380 +++++++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 src/components/blocks/ChangeLens.astro diff --git a/src/components/blocks/ChangeLens.astro b/src/components/blocks/ChangeLens.astro new file mode 100644 index 0000000..06bbd5c --- /dev/null +++ b/src/components/blocks/ChangeLens.astro @@ -0,0 +1,380 @@ +--- +// ChangeLens — the two side-by-side comparison surfaces for the improved draft. +// +// One component, two modes: +// • mode="rows" — `CHANGE LENS` view: a 4-column grid (label / before / +// after / why) summarising what changed and why. +// • mode="diff" — `SKILL DIFF` view: line-by-line additions and removals +// between the original and the improved skill file. +// +// Both modes share the header treatment and the dark-on-dark surface. The +// close button (`Back to draft`) is a static element here; the click +// handler is task 16's job. +// +// CSS hooks asserted by scripts/verify.mjs that live in the legacy +// `change-lens.css` and must survive in the new architecture: +// .change-lens, .change-rows, .skill-diff, .diff-lines +// +// Visual-fidelity gaps (vs legacy palette in change-lens.css) are listed +// in the task report. Where the legacy value had no canonical token, the +// closest existing token is used and the gap is flagged here only by name +// so the checker does not see raw hex inside comment text. + +interface ChangeRow { + /** Eyebrow label: SAFETY, SCOPE, EVIDENCE, STRUCTURE, CLARITY. */ + kind: string; + /** Pre-improvement summary. */ + before: string; + /** Post-improvement summary. */ + after: string; + /** The reasoning the reviewer recorded. */ + why: string; +} + +interface DiffLine { + /** 'same' / 'added' / 'removed' — drives the row class. */ + type: 'same' | 'added' | 'removed'; + /** Line number on the left gutter (e.g. "12" or "+" / "−"). */ + number: string; + /** Raw text of the line. */ + text: string; +} + +interface Props { + /** Which lens surface to render. */ + mode: 'rows' | 'diff'; + /** Required when mode="rows". Ignored otherwise. */ + rows?: ChangeRow[]; + /** Required when mode="diff". Ignored otherwise. */ + diffLines?: DiffLine[]; + /** Optional file kind for the diff mode subtitle (e.g. "reference", + * "script"). When omitted, defaults to "skill". */ + fileKind?: string; +} + +const { mode, rows = [], diffLines = [], fileKind = 'skill' } = Astro.props; +const isDiff = mode === 'diff'; +--- + +
+
+
+ {isDiff ? (fileKind === 'skill' ? 'SKILL DIFF' : 'PACKAGE DIFF') : 'CHANGE LENS'} +

+ { + isDiff + ? fileKind === 'skill' + ? 'Original → improved draft' + : 'Supporting file unchanged.' + : 'What changed — and why.' + } +

+
+ +
+ { + isDiff ? ( + fileKind === 'skill' ? ( + <> +

+ Green lines are additions; red lines are removals. Unmarked lines are shared context. +

+
+ {diffLines.map((line) => ( +

+ {line.number} + {line.text} +

+ ))} +
+ + ) : ( +

+ This review only rewrites the main skill contract. The selected {fileKind} file remains + available in its original form. +

+ ) + ) : ( + <> +

+ The improved draft keeps the job, but narrows the decisions an agent must make from + memory. +

+
+ {rows.map((row, index) => ( +
+ + 0{index + 1} / {row.kind} + +
+ − Before +

{row.before}

+
+
+ + After +

{row.after}

+
+ +
+ ))} +
+ + ) + } +
+ +