From 82601e104efc302ecc0826785eb6d7f9a1aaf496 Mon Sep 17 00:00:00 2001 From: Marcos Paulo Date: Sat, 5 Sep 2026 07:08:25 +0000 Subject: [PATCH] feat(blocks): add SkillList for review desk catalog Static markup-only component for the review desk's left-column listbox. Renders one button per entry with the four-row template (author, title, skill/status, package summary) and applies the 'active' class for the currently-selected entry. Click handling and URL sync are task 16. Preserves every CSS hook asserted by scripts/verify.mjs: #skill-list, .active, grid-template-columns:minmax(0,1fr), height:120px, -webkit-line-clamp:2. Visual fidelity gaps (panel surface tints) listed in the task report. Did not: extract per-row components (catalog is data, not markup); introduce client: directives (interactivity is task 16); add new tokens (design-system-keeper's job). --- src/components/blocks/SkillList.astro | 151 ++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 src/components/blocks/SkillList.astro diff --git a/src/components/blocks/SkillList.astro b/src/components/blocks/SkillList.astro new file mode 100644 index 0000000..1caacb6 --- /dev/null +++ b/src/components/blocks/SkillList.astro @@ -0,0 +1,151 @@ +--- +// SkillList — the catalog listbox of reviewed submissions. +// +// The 24 reviews are data, not 24 components. One list, one row template. +// Click handling and selection state are task 16's job; this component +// ships zero JS and just renders the rows from props. +// +// The id `#skill-list` and CSS class `active` are asserted by +// scripts/verify.mjs via the legacy stylesheet. They survive here so the +// verification engineer can re-point assertions at the new architecture +// without renaming anything. CSS hooks `grid-template-columns:minmax(0,1fr)`, +// `height:120px`, and `-webkit-line-clamp:2` are kept verbatim for the same +// reason — task 19 will diff against this baseline. + +interface SkillEntry { + /** Stable identifier used for selection and URL params. */ + id: string; + /** Display name of the submitter. */ + author: string; + /** Skill title — second row of the row template. */ + title: string; + /** Short status string ("reviewed", "draft", etc.). */ + status: string; + /** Pre-computed package summary (e.g. "1 skill · 2 refs · 1 script"). */ + summary: string; +} + +interface Props { + entries: SkillEntry[]; + /** Optional id of the currently-selected entry; the matching row gets + * `aria-selected="true"` and the `active` class. */ + selectedId?: string; +} + +const { entries, selectedId } = Astro.props; +--- + +
+ { + entries.map((entry) => ( + + )) + } +
+ +