Files
ai-for-dummies/src/components/blocks/SkillList.astro
T
Marcos Paulo 6bfae2033e refactor(styles): resolve token gaps and expand typography scale
Extended the typography `--step-*` scale to cover the ad-hoc pixel values
used across components (10px to 48px). Added overlay tokens `--white-14`,
`--white-23`, `--white-25`, `--white-31`.

Canonicalized one-off legacy color hex values in `ReviewDetail`,
`ChangeLens`, `PreviewPane`, `RulesInteractive`, and `SkillPackageExplorer`
to map to the core semantic palette (`--deep`, `--ink`, `--line`, `--paper`,
`--muted`).

Replaced ad-hoc max-width media query boundaries (520px, 530px, 600px, 620px)
with the closest approved named tokens (`560px`, `800px`, `1100px`).
2026-09-05 22:53:56 +00:00

151 lines
4.0 KiB
TypeScript

---
// 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;
---
<div id="skill-list" role="listbox" aria-label="Submitted skills">
{
entries.map((entry) => (
<button
type="button"
role="option"
aria-selected={entry.id === selectedId}
class={entry.id === selectedId ? 'active' : ''}
data-id={entry.id}
>
<span>AUTHOR · {entry.author}</span>
<strong>{entry.title}</strong>
<small>
SKILL · {entry.id} · {entry.status}
</small>
<em>{entry.summary}</em>
</button>
))
}
</div>
<style>
/* The listbox grid: one column, four rows. The fixed height + ellipsis
is what keeps 24 rows scannable; this is the row template. */
#skill-list {
display: grid;
gap: 1px;
border-top: 1px solid var(--line);
}
#skill-list button {
display: grid;
grid-template-columns: minmax(0, 1fr);
grid-template-rows: 14px 36px 13px 13px;
gap: 4px;
height: 120px;
overflow: hidden;
padding: 14px;
border: 0;
border-bottom: 1px solid var(--line);
color: var(--ink);
background: transparent;
text-align: left;
cursor: pointer;
}
/* Author line: top eyebrow. Truncates to a single line. */
#skill-list button span {
color: var(--muted);
font: 10px monospace;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Title: two-line clamp so a long title doesn't push other rows. */
#skill-list button strong {
font-size: var(--step-13);
line-height: 18px;
max-height: 36px;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow-wrap: anywhere;
}
/* SKILL · status: short status line. */
#skill-list button small {
display: block;
color: var(--red);
font: 9px monospace;
text-transform: uppercase;
max-height: 13px;
line-height: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Package summary: monospace, single line. */
#skill-list button em {
display: block;
max-height: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 13px;
color: var(--blue);
/* token-gap: no --step-* covers 9px; owner design-system-keeper */
font:
9px / 13px ui-monospace,
monospace;
font-style: normal;
}
/* Hover and selected states flip the row to the dark surface. */
#skill-list button:hover,
#skill-list button.active {
color: var(--paper);
background: var(--ink);
}
#skill-list button.active span,
#skill-list button.active small {
color: var(--gold);
}
#skill-list button:focus-visible {
outline: 3px solid var(--red);
outline-offset: 2px;
}
</style>