Conversation
Two assertions still expected every render in the flat top level `Exports/`. Since #17 a timeline cut from one game lands in `<Game>/Exports/` and belongs to that game, which is what both tests build, so both failed whenever the suite ran. The full suite had not run since #17 merged, which is how they went unnoticed. `features.spec.ts` and `measure.spec.ts`: 13 passed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Closes #37. `class-variance-authority`, and `cn()` over `clsx` plus the `tailwind-merge` that was already a dependency and used by nothing. The rule, decided once and written into CLAUDE.md: anything that comes in kinds is a recipe in `Base/variants.ts`, anything with one look is a constant in `Base/geometry.ts`. **One button.** `BaseButton` on `buttonVariants`: `tone` (default, strong, quiet, danger, success), `size` (md, sm, dense), `icon-only`, `reserve-icon`. All 34 `BUTTON*` string call sites across 13 files moved to it and the strings are deleted. The hand-written `switch` it used to carry is gone, and with it the disagreement: `geometry.ts` refused a danger tone while `BaseButton` had a filled one. **Danger is now a tone, outlined and never filled**, which is what every destructive button already hand-wrote (`border-danger text-danger-ink hover:bg-danger/10`); a filled red button beside the filled accent is two primaries. `strong` stays the only filled accent. A caller's `class` goes through `cn`, so `class="px-2"` means `px-2`. **Icon buttons are `BaseButton icon-only`**, not a second component: 14 hand-rolled ones in 7 files, in four greys and three disabled opacities, now share one quiet glyph recipe. The clip menu's Reka trigger calls the recipe directly. **Menu rows are `menuItemVariants`** on Reka's own items (16 rows). The destructive rows had drifted to `gap-2 px-3 py-2` against everybody else's `gap-2.5 h-[34px] px-2.5`, so Delete sat off the label column; they share one geometry now and a tone is only a colour. Rows gained a `data-[highlighted]` style, so arrowing through a menu finally shows where you are, and `:disabled` replaces the `opacity-50 pointer-events-none` each busy row carried, which also takes it out of the keyboard order. **`BasePanel`** for six bordered panels (one had drifted to `p-4`), **`BaseChip`** for six labels over video, and **`BaseEmptyState`** on cva with `size="page" | "panel"`, a tone for the icon and an `actions` slot, now used by the six empty states Storage Saver and Publisher had hand-rolled. **Ternaries that are really variants became variants**: the status dot (4 sites), the wizard step bar (2), the switch's track and thumb, the editor's two pressed toolbar toggles, and the Connections button that turns green once registered (`tone="success"`). The rest stay, because they are layout switches (`compact`, `flush`, `block`), animation states (`open ? 'rotate-180'`, collapsing `grid-rows`, fades) or one-off emphasis, and a variant nobody else asks for is a second place to look. `useClipActions.ts` loses a `variant` field nothing read, and the `ButtonVariant` and `PopoverAction` types go with it. **A guard, because this broke once while it was being done.** A `Base*` component used without an import renders as `<basebutton>` and nothing fails: `vue-tsc` accepts unknown tags. The card's drag grip did exactly that until a pixel diff of the card title (a few pixels wider) caught it. `tests/unit/renderer/baseImports.spec.ts` now fails on any template using a Base component it does not import (proved by removing the import), and holds the recipe rules: one filled accent, danger never filled, icon-only square at every size, a caller's padding wins, and menu rows share one geometry. Gates: - `npm run check`: green; `npm run build`: green. - `screens.spec.ts`: 8 passed, both palettes, 581 text runs measured, nothing changes size on hover or focus. - 11 UI specs (features, primitives, pager, modals, focus, measure, libraryHeader, overflow, compress, editor, safety): 47 passed; the two failures were stale export paths from #17, fixed in the commit before this one. - Before and after screenshots of 26 steps across every route: settings, stats, tag patterns, publisher and storage differ by 10 pixels, a sidebar game icon loading at a different moment. The rest is the intended quiet glyph grey on icon buttons (editor controls, theme toggle). Nothing moved. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #37. Two commits: a stale e2e fix from #17, then the refactor.
The rule (now in CLAUDE.md)
Anything that comes in kinds is a
cvarecipe inBase/variants.ts. Anything with one look is a constant inBase/geometry.ts.cn()=clsx+ thetailwind-mergethat was installed but unused.What moved
BUTTON*strings +BaseButtonswitchBaseButtononbuttonVariants(tone,size,icon-only,reserve-icon)BaseButton icon-only(one component, not two)h-[34px] px-2.5menuItemVariantson Reka itemsBasePanelBaseChip(numeric)BaseEmptyState size="panel"+actionsslot + icon tonetone="success"Decisions the issue asked for
strongis still the only filled accent (unit-tested).BaseButton icon-only, noBaseIconButton.none). Thep-4outlier was normalised.compact,flush,block, fullscreen), animation states (open ? 'rotate-180', collapsinggrid-rows, fades, editor preview slots), and one-off text emphasis (muted vs foreground on a single label). A variant nobody else asks for is a second place to look.Visible changes (intended)
gap-2 px-3 py-2, off the label column).:disabled, so the keyboard skips them too.muted-500) and disabled opacity (50%). The editor controls weremuted-600before.ClipStarButtonand the clip menu trigger now haverounded-mdcorners, like every other icon button, instead ofrounded-sm.Found while doing it
A
Base*component used without an import renders as<basebutton>, and nothing catches it:vue-tscaccepts unknown tags. The card's drag grip did exactly that. A pixel diff caught it (the card title was a few px wider).tests/unit/renderer/baseImports.spec.tsnow fails on that (proved by removing the import), and also holds the recipe rules.Gates
npm run check: 844 tests.npm run build: green.screens.spec.ts: 8 passed. Both palettes, 581 text runs, nothing changes size on hover or focus.h-[34px] px-2.5in components, 0BUTTON_*, 0 chip or panel recipes left inline. The onepy-8 text-centerleft is the end-of-list line inClipsListFooter, which is not an empty state.🤖 Generated with Claude Code