fefae606edb21bc55293e6309fca55f209565913
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
37616682f0 |
feat(ui): three button sizes, because the app has three kinds of button
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 10s
CI & Build / integration (push) Successful in 31s
CI & Build / TypeScript typecheck (push) Successful in 34s
CI & Build / Python tests (push) Successful in 1m4s
CI & Build / Build & push image (push) Successful in 45s
Measured before deciding: across the ~100 bespoke button rules, vertical padding does not spread — it clusters. ~27 at 0.4–0.45rem, ~28 at 0.25–0.3rem, ~23 at 0.1–0.15rem. Those are three different components that happen to share a name prefix: a page action, a row action, and an affordance that lives inside a card. Collapsing them to the single size the shared sheet had would have visibly broken every card layout, which is why the one-off migration stopped here for a decision rather than proceeding on the assumption that a button is a button. default 8px 16px page action — what the house style specifies .btn-compact 4px 12px toolbar, table row, list item controls .btn-inline 2px 4px dismiss ×, confirm tick, add-chip .btn-small and .btn-sm already sat at the compact step, so they are kept as aliases for it — no template churn, and the two spellings stop being a third thing that might drift. .btn-inline is deliberately below the spacing scale's first step on the vertical axis: 4px of padding on an 11px label already exceeds the line box these sit in. Stated in the file so it reads as a measured exception rather than someone ignoring the scale. DesignView renders all three as real specimens. A size scale described in prose is one nobody can check; rendered from the actual classes, it cannot claim something the app does not do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs |
||
|
|
1a959b1db0 |
refactor(ui): one button definition, aligned to the design system
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / TypeScript typecheck (push) Successful in 36s
CI & Build / integration (push) Successful in 39s
CI & Build / Python tests (push) Successful in 1m12s
CI & Build / Build & push image (push) Successful in 1m12s
`.btn-primary` was defined five times in five scoped stylesheets and all five had drifted: three paddings, three font sizes, three disabled opacities — and ProjectListView had no disabled style at all, so a disabled button there looked enabled. Nothing detected any of it. A scoped duplicate is not a rule violation, not a broken reference, and not a recorded snippet, so no existing check could see it (#2273). assets/components.css is now the single definition of the core four — primary, secondary, ghost, danger — plus the small modifier, in design-system tokens throughout. Operator's call to align to the system rather than to the majority of current values, so buttons move to the 8px radius and 12px label the system specifies, from the app's 4px/14.4px. Class names are unchanged, so there are no template edits: the existing surface is repurposed, not rebuilt. STAGING PROPERTY that makes this safe to land ahead of the rest: a Vue `<style scoped>` rule compiles to `.btn-primary[data-v-…]` (specificity 0,2,0) and beats a plain global selector (0,1,0). So the shared sheet changes nothing for a view still carrying its own copy, and every intermediate state of the remaining migration is coherent rather than half-applied. Two divergences corrected on the way, both worth naming: - SnippetEditorView's `.btn-secondary` was a GHOST in disguise — outline styling under the secondary name, while the house style says secondary is filled bronze. It now looks like what it is called. - SnippetDetailView and SnippetListView tinted a ghost button's label with the ACCENT on hover. The house style reserves the accent for identity and active state, never general chrome. DesignView reported "no shared button exists" as an honest gap and declined to draw a look-alike. That gap is closed, so it now renders the app's real classes — the specimens cannot drift from the app without drifting the app. Net -177 lines. Follows: the ~20 semantic one-offs (.btn-save, .btn-delete, .btn-toggle …) and the compound overrides in ProjectView, one of which puts the accent on a primary action button. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs |
||
|
|
8eef9e7845 |
fix(design-systems): the empty state's create button did nothing, and one surface
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 28s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 57s
CI & Build / Build & push image (push) Successful in 47s
Two reports, one root cause each. **The dead button.** "Create the first one" set `showCreate = true`, but the create form lived inside `<div v-else class="ds-body">` — the sibling branch of the empty state. The two are mutually exclusive, so on a fresh install the flag flipped and nothing rendered. The first action a new install can take was the one that didn't work, which is a poor way to honour "an install with zero design systems is the ordinary state". The first system now gets its own form outside the list layout, and it drops the parent picker entirely: there is nothing to inherit from yet, so it says so instead of offering an empty select. **Two surfaces, the wrong one first.** /design and /design-systems are halves of one thing — the record that decides the styling, and what the browser renders from it — and I had added them as two separate nav entries with the read-only diagnostic listed first. Backwards: the record is what you work with; the live view is the check on it. Now one nav entry pointing at the record, with a shared tab bar joining the two. The explorer is renamed "Live tokens", which is what it actually shows. The tab bar is a component rather than the same markup in both views. Two copies diverge the moment a third tab appears — and a design surface that ships duplicated markup would be arguing against itself. |
||
|
|
78489308b8 |
feat(design-systems): link /design to its editable half
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 42s
CI & Build / Build & push image (push) Successful in 40s
The two pages are halves of one surface — what the browser renders and the
record that should decide it — and only one direction was linked. Missed in
|
||
|
|
4ca3ab02c4 |
feat(design-explorer): the drift panel — rulebook says X, tokens say Y
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / TypeScript typecheck (push) Successful in 11s
CI & Build / integration (push) Successful in 15s
CI & Build / Python tests (push) Successful in 43s
CI & Build / Build & push image (push) Successful in 40s
Milestone #251 step 5 (#2262), plus the Settings control that makes it reachable. The comparison is deliberately thin — set arithmetic over live token values, which is the one thing the browser knows and the server doesn't. The hard half (prose to claims) already lives in Python where pytest can assert on it. Three claim kinds, and the third inverts the test: a `token` claim asks whether a custom property of that name exists; a `color` claim asks whether any token resolves to that value; a `prohibited_color` claim FAILS when present. normalizeColour is the client-side twin of normalize_hex and has one job the server cannot do: getComputedStyle reports colours as rgb()/rgba() regardless of how they were authored. So one colour has three spellings in play — #FFFFFF in the rulebook, #fff in the stylesheet, rgb(255,255,255) from the browser — and a comparison that misses any of them under-reports silently rather than erroring. THE PANEL STATES ITS OWN BLIND SPOT, which matters more than it sounds. This compares the rulebook against TOKENS. A literal hardcoded in a component, where a token should have been referenced, is invisible to it — the drift isn't in the tokens at all (#2275: 67 hardcoded whites against a rule forbidding pure white). Reading those would mean bundling every SFC's source into the app; the check belongs in CI and is tracked at #2277. A drift report that silently omitted a whole category would invite the reader to conclude the category is clean, so the panel says so in the panel rather than in a comment nobody reads. Findings are ranked violated → missing → ok, and `ok` rows are hidden behind a toggle. Same principle the auto-inject menu is built on: a short list that gets read beats a complete one that doesn't. Settings gains a rulebook picker. "None" is a first-class choice, not an unset error — most installs have no rulebook describing their design system, and saving empty DELETES the setting rather than storing a zero. The panel's empty state points at Settings and Settings points back at the panel, so neither is a dead end. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs |
||
|
|
3c0192d749 |
feat(design-explorer): the gallery, including what isn't there
CI & Build / Plugin hooks (push) Successful in 7s
CI & Build / integration (push) Successful in 18s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Python tests (push) Successful in 41s
CI & Build / Build & push image (push) Successful in 40s
Milestone #251 step 3 (#2260). New /design view, reachable from a Palette icon beside Trash and Settings — a meta-surface like /rules, so an icon rather than a sixth primary nav link, but not hidden either, since somewhere the design system is visible is the entire point. Renders three things, and refuses to render a fourth: - REAL components, imported not recreated: StatusBadge, PriorityBadge, TagPill. - REAL tokens, read at runtime via readTokens() so the page shows the live cascade rather than what the stylesheet claims. Grouped, swatched where the value is a colour, flagged where the token is mode-aware. - Rule 65's four button variants and rule 60's type scale, listed as SPEC and marked missing. That last part is the point of the step rather than a shortfall of it. Step 3's premise was "render the real components, not copies — a gallery of look-alikes drifts from the app within a month and then lies." Buttons have no shared implementation to import: .btn-primary is defined four separate times in four <style scoped> blocks, and 30 of 54 SFCs carry their own button CSS (#2273). Drawing a button here would have made this page the fifth copy — committing the exact drift the surface exists to catch. Same for the type scale: the three families load (rule 59) but rule 60's sizes and weights are not tokens, so there is nothing to read and a rendered specimen would be invented. So the gallery reports them as gaps. A design system nobody can point at is a design system that isn't there, and saying so is more useful than a page that looks complete. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs |