Repository navigation
chore(ui): design system refactor — close gap with Craft Agents #406
Description
Problem
Audited Maka's frontend against Craft Agents OSS (same stack: Electron + React + Tailwind v4 + shadcn-like). Both projects share --radius: 0rem and 15px base font. The gap is not tech selection; it is governance execution.
Maka already defines many of the right primitives, tokens, and renderer contracts, but the system is still too easy to drift:
- overlapping primitive/component layers still exist in places;
- color tokens have had undefined references and too many ad-hoc derivation styles;
- decorative enter/exit motion still leaks through Base UI primitives;
- radius values were spread across hardcoded CSS, arbitrary Tailwind values, and competing token aliases;
--accenthas been overloaded across CTA, control, focus, link, live/status, toast, and navigation roles;- hard
border:declarations are used where shadow-ring recipes should own visual outlines; - Storybook has product regression fixtures, but the CSS/token foundation itself is not yet exposed as a complete governance surface.
This issue tracks the design-system refactor needed to close that governance gap. Each PR below should be independently reviewable and should preserve existing product behavior unless its section explicitly calls out a visual correction.
PR plan
PR1. Dead primitive cleanup
Clean up the remaining shadcn leftovers and zero-usage primitives so future governance applies to one real component layer, not dead branches.
Keep: Maka-specific primitives
chat.tsx, alert.tsx, item.tsx, menu.tsx, empty.tsx, accordion.tsx, choice-card.tsx, settings-segmented.tsx, settings-select.tsx, settings-switch.tsx, input-group.tsx, badge.tsx, tabs.tsx, spinner.tsx, kbd.tsx, toolbar.tsx
Delete or migrate: overlapping shadcn leftovers
| File | Overlaps | Action |
|---|---|---|
button.tsx |
ui.tsx Button |
migrate the remaining consumer to ui.tsx Button, then delete |
input.tsx |
ui.tsx Input |
delete if still unused |
separator.tsx |
ui.tsx Separator |
delete if still unused |
sheet.tsx |
ui.tsx Sheet* |
delete if still unused |
skeleton.tsx |
ui.tsx Skeleton |
delete if still unused |
textarea.tsx |
ui.tsx Textarea |
delete if still unused |
tooltip.tsx |
ui.tsx TooltipTrigger/Popup |
delete if still unused |
Delete: zero-usage primitives
frame.tsx, pagination.tsx, table.tsx, command.tsx, drawer.tsx, preview-card.tsx, sidebar.tsx, group.tsx, plus their barrel exports if still present.
Also remove: dead .maka-button[data-variant="primary"] CSS if it still has no production usage.
Acceptance: production imports resolve through ui.tsx or kept Maka-specific primitives; dead primitive exports are gone; relevant dead-export/primitive contracts pass.
PR2. Color token closure
Close the color token system so every referenced token exists and each derivation style has a clear purpose.
Scope:
- Map every undefined foreground/accent token reference to an existing tier or explicit alpha use.
- Keep foreground tiers intentionally small and documented; do not let every one-off opacity become a named tier.
- Ensure Tailwind
@theme inlineexposes the supported renderer tokens. - Keep Storybook
Design System/Tokensuseful as a quick visual audit of the supported color roles.
Acceptance: no undefined var(--foreground-*) or var(--accent-*) references remain; contracts catch future undefined token references; Storybook shows the supported semantic color roles and representative foreground tiers.
PR3. Motion governance
Remove decorative mount/unmount motion from primitives and keep only functional motion.
Goal: popovers, dialogs, sheets, menus, and tooltips should appear/disappear without Base UI enter/exit animation. Keep spinner, status pulse, streaming caret, shimmer, and other functional progress/status motion.
Scope:
- Strip
data-starting-style,data-ending-style,@starting-style, and decorative near-duplicate keyframes from non-whitelisted primitives/CSS. - Keep motion tokens (
--duration-*,--ease-*) for feedback/status motion. - Extend the Storybook Animation Catalog so retained motion is visible and named.
Acceptance: contract bans unapproved enter/exit animation patterns; retained functional motion is visible in Storybook; no product flow relies on decorative mount/unmount animation.
PR4. Radius governance
Converge radius to one component-type scale and remove hardcoded pixel drift.
Target scale:
| Component type | Token | Value |
|---|---|---|
| button / input / compact chip | --radius-control |
6px |
| card / popover / code block | --radius-surface |
8px |
| modal / composer-scale surface | --radius-modal |
12px |
| badge / pill / dot | --radius-pill |
999px |
| flat panel / full-bleed surface | none / 0 |
0 |
Scope:
- Remove competing radius token aliases where possible.
- Replace hardcoded CSS
border-radius: Npxand TSX arbitraryrounded-[Npx]values with the canonical tokens. - Classify intermediate historical values by component type, not nearest numeric value.
Acceptance: radius contract rejects new bare pixel radius values except intentional exemptions; Storybook Design System/Tokens/Radius reflects the canonical scale; current focused PR: #418.
PR5. Primary/accent semantic split
Split --accent into semantic roles so one green no longer controls unrelated UI meanings.
Rejected direction: flipping --color-primary to var(--foreground) just copies Craft's black/white button look and only fixes one contrast case. It leaves checkbox/switch/radio/progress and other selected states tied to the same low-contrast green.
Target roles:
--action/--action-foreground: solid CTA fills such as primary button, submit, send, apply, done.--control/--control-foreground: selected/on/progress states such as checkbox, radio, switch, progress, tabs underline.- Thin emphasis aliases:
--link,--focus-ring,--status-running,--nav-active,--toast-accent.
Scope:
- Call sites stop writing raw
var(--accent)when the intent is action/control/link/focus/status/nav/toast. - Darken
actionandcontrolfills enough for white text to clear the contrast target in light and dark modes. - Keep initial aliases visually close unless a contrast fix is explicitly required.
Acceptance: computed contrast contract protects action/control foreground pairs; semantic-token contract catches raw accent usage in governed contexts; Storybook shows the semantic roles separately even when several currently alias the same value.
PR6. Borders as shadows
Move visual-only hard borders to shadow-ring recipes while preserving layout borders.
Problem: hard border: occupies layout space. Replacing every border blindly can shift geometry by 2px and break tight layouts.
Strategy:
- Migrate visual-only outlines first: cards, popovers, tool cards, toast-like surfaces, code/table wrappers where layout does not depend on border width.
- Keep layout borders where the border is structural: sidebar divider, titlebar divider, modal header/footer dividers, list separators, table rules where spacing depends on the line.
- Use the existing shadow recipes:
--shadow-minimal,--shadow-minimal-flat,--shadow-medium,--shadow-modal.
Acceptance: governed surfaces use shadow-ring recipes; geometry-sensitive layout borders are explicitly retained; contract protects the distinction and catches accidental broad border reintroduction.
PR7. Storybook foundation governance acceptance
Make the design-system foundation visible, reviewable, and lockable in Storybook. This is the acceptance pass for #406, not a new low-level gap.
Scope:
- Add or extend
Design System/*stories for foundation governance, not more Product pages:- semantic color roles;
- full theme/palette matrix;
- typography / Markdown / code;
- spacing / density / layout;
- elevation / borders / shadow rings;
- motion tokens and retained functional motion;
- layering / z-index / overlay stack;
- interaction states.
- Show primitive token consumers only where they prove foundation rules: buttons/actions, form controls, surfaces/overlays, navigation/feedback/data primitives.
- Use the real renderer Storybook substrate: renderer CSS, light/dark globals, and every palette id from
THEME_PALETTES. - Add a focused Storybook governance contract that locks required story exports, palette toolbar completeness, and token-reference usage. Prefer structure/token assertions over fragile pixel assertions.
- Keep existing Product stories as regression fixtures; do not expand them as part of this governance pass.
Non-goals: no token value changes, no primitive behavior changes, no Storybook addon/docs-site work, no token JSON/style-dictionary export, and no Product surface expansion.
Acceptance: Storybook becomes the visible review surface for PR2-PR6 foundation rules; npm run -w @maka/desktop build-storybook passes; Storybook contracts lock the foundation story structure and palette coverage.
Dependency order
PR1 + PR2 can land early as cleanup/token closure
↓
PR3 motion governance and PR4 radius governance can proceed after dead primitive cleanup
↓
PR5 semantic action/control split depends on color token closure
PR6 borders-as-shadows depends on radius/shadow-ring clarity
↓
PR7 Storybook foundation governance is the final acceptance pass, but pieces may be built earlier when their tokens are ready
Global acceptance
#406 can close when:
- dead/overlapping primitives are removed or migrated;
- color tokens are closed and undefined-token references are contract-protected;
- decorative enter/exit motion is removed from governed primitives;
- radius values converge to the canonical scale;
- action/control/emphasis color semantics are split and contrast-protected;
- visual-only borders use shadow-ring recipes while layout borders remain intentional;
- Storybook exposes the governed CSS/token foundation clearly enough for review without driving the desktop app into product states;
- the relevant desktop/UI contract tests, typecheck, and focused Storybook build pass.
References
- Craft Agents OSS: https://github.com/craft-ai-agents/craft-agents-oss
- Previous sidebar polish: PR refactor(ui): migrate sidebar visual properties to cva variants #403
- Git history direction:
42e7cd44(deleted 27 dead shadcn primitives),193d7d66(deleted 26 dead ui.tsx exports), feat(ui): govern chat conversation-flow display onto @maka/ui Base UI primitives #332/feat(ui): govern chat bubble/row shell onto @maka/ui chat primitives #334/feat(ui): migrate chat turn markers onto @maka/ui Marker primitive (#332) #337 series (built Maka-specific primitives)
Activity
[-]chore(ui): delete dead primitive files and dead CSS[/-][+]chore(ui): design system refactor — close gap with Craft Agents[/+]somewan820 commentedon Jul 1, 2026
Is anyone actively working on this issue? If not, I'd like to give it a try.
Astro-Han commentedon Jul 1, 2026
I'm working on 1 and 2, feel free to take anything else~
refactor(ui): delete dead shadcn primitives and fix undefined color t…
refactor(ui): delete dead shadcn primitives and fix undefined color t…
refactor(ui): delete dead shadcn primitives and fix undefined color t…
Astro-Han commentedon Jul 1, 2026
Follow-up for gap 4 radius governance: PR #416 intentionally does not attempt the full
packages/ui/src/primitives/chat.tsxradius migration. This PR only converts the preview/load-tool radii it already touches. The remaining historical arbitrary pixel radii inchat.tsxshould be handled in a later focused pass under this issue, mapped to the new radius token vocabulary (--radius-control,--radius-surface,--radius-modal,--radius-pill) without mixing in unrelated motion/shadow work.Astro-Han commentedon Jul 2, 2026
Added Storybook foundation governance acceptance criteria to the issue body.
No separate tracking issue needed: this should land as a focused PR under #406, covering the Design System foundation stories plus a small Storybook governance contract. Scope stays intentionally narrow: no token value changes, no primitive behavior changes, no Product story expansion, and no Storybook addon/docs-site work.
feat(storybook): foundation governance stories (#406 PR7) (#426)
fix(radius): harden CSS scanner against case/whitespace edge cases
refactor(ui): govern all border-radius via --radius-* tokens (#406 ga…
fix(radius): harden CSS scanner against case/whitespace edge cases
refactor(ui): govern all border-radius via --radius-* tokens (apache#406
2 remaining items
Fix/startup white screen (#429)
refactor(ui): split --accent into semantic aliases, lock call-site go…
feat(design): P-INSET input step-down + P-RADIUS concentric corners (#…
feat(design): waiting-state spectrum 1 — toast overshoot + streaming …
feat(design): toast exit window + lucide stroke governance (D5/D6) (#483
fix(design-system): repoint residual hardcoded greens to logo blue
feat(design-system): migrate default color system from sage green to …
fix(ui): theme palette leaks — derive surfaces and CTA family from ba…
fix(ui): theme palette leaks — derive surfaces and CTA family from ba…
fix(ui): purge residual brand-green — skills banner now follows --bra…
refactor(ui): SectionHeader primitive — three section-header dialects…
docs(desktop): stop citing contracts that no longer exist
docs(desktop): stop citing contracts that no longer exist
feat(desktop): collapse the session rail into a continuous 48px icon …