You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The dashboard has accumulated 9 distinct button styles across views, 3 separate modal implementations, and 6 different status indicators that mean the same thing. The audit found:
Buttons: .btn, .btn-p, .btn-danger, .ops-btn, .steer-sticky-btn, .tp-stop-btn, .cp-restore, .send-btn, .sess-toggle-btn, .banner-btn, .ft-btn, .cta — at least 9 styles, all hand-rolled per view.
Modals: pairing modal in app.ts (own classes), <crowclaw-fork-modal> (own implementation), <crowclaw-modal> component exists at components/modal.ts:185 but isn't used by the other two.
Status dots: .led, .tag.ok/.er/.wn/.ac, .sf-dot, .sess-active-dot, .tp-tool-dot, .indicator — 6+ status indicator styles.
Form inputs: formStyles.form-input defined once but redefined inline in 6 places (auth-box, sess-hdr, search-overlay, steer-overlay, rename-overlay, etc.)
Build a real component library. Target milestone: v0.8.1.
Why this matters (no shortcut)
Visual inconsistency reads as amateur hour. A user clicking three buttons in a row that all look slightly different concludes nobody owned the design.
Every new feature today requires "and then style the button". With a component library, every new feature gets the right button by default.
Shortcut: leave the existing styles, just add a coat of CSS variables. Don't take it — the divergence is in markup structure (different classnames, different DOM hierarchies), not just colors. CSS variables can't bridge that.
Source / reference points
shadcn/ui — the component-library philosophy, even if we don't use React.
components/modal.ts — already exists, just unused everywhere.
Vercel UI primitives, Linear's design system docs.
status: 'running' | 'ok' | 'warn' | 'error' | 'idle' | 'paused', optional pulse for active states
packages/web/ui/src/components/input.ts
<crowclaw-input>
label slot, error slot, hint slot, all standard input props, integrates with form a11y
packages/web/ui/src/components/icon.ts
<crowclaw-icon>
name: string, size: number = 16, ships a sprite-based or import-on-demand icon set (Lucide icons recommended — MIT, ~1KB per icon, tree-shakeable)
Files to refactor
File
Change
packages/web/ui/src/views/chat-view.ts
Replace ~9 distinct button classes with <crowclaw-button>. Replace inline status indicators with <crowclaw-status-dot>. Replace inline SVGs and Unicode glyphs (..., ✕, ☰) with <crowclaw-icon>.
packages/web/ui/src/views/connect-view.ts
Same refactor.
packages/web/ui/src/views/automate-view.ts
Same.
packages/web/ui/src/views/settings-view.ts
Same.
packages/web/ui/src/views/agent-view.ts
Same.
packages/web/ui/src/app.ts
Replace pairing-modal bespoke classes with <crowclaw-modal> slot pattern. Replace icon-button glyphs with <crowclaw-icon>.
packages/web/ui/src/components/fork-modal.ts
Refactor to use <crowclaw-modal> as its outer shell rather than its own DOM.
packages/web/ui/src/lib/shared-styles.ts
Remove .btn, .btn-p, .btn-danger, formStyles.form-input — they're superseded by components. Keep only generic utility classes.
What must NOT change
The visual identity at the per-element level — buttons should look approximately the same as the current .btn-p after migration. The component library is a refactor, not a redesign. (The redesign happens in dashboard issue feat: CrowClaw v0.2.0 — infrastructure, agent loop, gateway #5 below.)
Existing keyboard shortcuts, form-submit semantics, escape-to-close on modals.
Component lifecycle and accessibility — every new component must have proper ARIA roles, focus management, keyboard support.
Acceptance criteria
All 9 distinct button styles in the codebase are replaced by <crowclaw-button> calls. Verified by grep -rE "\.btn|\.btn-|\.ops-btn|\.send-btn" returning only the component definition itself.
All 3 modal implementations (app.ts pairing, fork-modal, <crowclaw-modal>) consolidate into one — <crowclaw-modal> with slots.
All status indicator usages migrate to <crowclaw-status-dot>. The 6+ inline status styles are removed.
All inline <svg> icon definitions and Unicode glyph hacks (..., ☰, ✕) replaced with <crowclaw-icon>. Verified count: zero raw SVG elements remaining outside components/icon.ts.
No regression in keyboard / focus / a11y behavior. Tab order in modals matches current. Escape closes.
CSS lint rule (custom Vitest test) prevents new files from defining .btn-* or .dot-* classes.
Performance target
Bundle size after consolidation: ≤ current size + 5KB gzipped. Component overhead is offset by removing duplicated styles.
Component render: < 1ms for typical button/dot/icon.
Summary
The dashboard has accumulated 9 distinct button styles across views, 3 separate modal implementations, and 6 different status indicators that mean the same thing. The audit found:
.btn,.btn-p,.btn-danger,.ops-btn,.steer-sticky-btn,.tp-stop-btn,.cp-restore,.send-btn,.sess-toggle-btn,.banner-btn,.ft-btn,.cta— at least 9 styles, all hand-rolled per view.app.ts(own classes),<crowclaw-fork-modal>(own implementation),<crowclaw-modal>component exists atcomponents/modal.ts:185but isn't used by the other two..led,.tag.ok/.er/.wn/.ac,.sf-dot,.sess-active-dot,.tp-tool-dot,.indicator— 6+ status indicator styles.formStyles.form-inputdefined once but redefined inline in 6 places (auth-box,sess-hdr,search-overlay,steer-overlay,rename-overlay, etc.)Build a real component library. Target milestone: v0.8.1.
Why this matters (no shortcut)
Source / reference points
components/modal.ts— already exists, just unused everywhere.Scope
Files to create
packages/web/ui/src/components/button.ts<crowclaw-button>variant: 'primary' | 'secondary' | 'ghost' | 'danger',size: 'sm' | 'md' | 'lg',loading?: boolean,disabled?: boolean, slot for icon, slot for labelpackages/web/ui/src/components/status-dot.ts<crowclaw-status-dot>status: 'running' | 'ok' | 'warn' | 'error' | 'idle' | 'paused', optionalpulsefor active statespackages/web/ui/src/components/input.ts<crowclaw-input>packages/web/ui/src/components/icon.ts<crowclaw-icon>name: string,size: number = 16, ships a sprite-based or import-on-demand icon set (Lucide icons recommended — MIT, ~1KB per icon, tree-shakeable)Files to refactor
packages/web/ui/src/views/chat-view.ts<crowclaw-button>. Replace inline status indicators with<crowclaw-status-dot>. Replace inline SVGs and Unicode glyphs (...,✕,☰) with<crowclaw-icon>.packages/web/ui/src/views/connect-view.tspackages/web/ui/src/views/automate-view.tspackages/web/ui/src/views/settings-view.tspackages/web/ui/src/views/agent-view.tspackages/web/ui/src/app.ts<crowclaw-modal>slot pattern. Replace icon-button glyphs with<crowclaw-icon>.packages/web/ui/src/components/fork-modal.ts<crowclaw-modal>as its outer shell rather than its own DOM.packages/web/ui/src/lib/shared-styles.ts.btn,.btn-p,.btn-danger,formStyles.form-input— they're superseded by components. Keep only generic utility classes.What must NOT change
.btn-pafter migration. The component library is a refactor, not a redesign. (The redesign happens in dashboard issue feat: CrowClaw v0.2.0 — infrastructure, agent loop, gateway #5 below.)Acceptance criteria
<crowclaw-button>calls. Verified bygrep -rE "\.btn|\.btn-|\.ops-btn|\.send-btn"returning only the component definition itself.app.tspairing,fork-modal,<crowclaw-modal>) consolidate into one —<crowclaw-modal>with slots.<crowclaw-status-dot>. The 6+ inline status styles are removed.<svg>icon definitions and Unicode glyph hacks (...,☰,✕) replaced with<crowclaw-icon>. Verified count: zero raw SVG elements remaining outsidecomponents/icon.ts..btn-*or.dot-*classes.Performance target
Out of scope
04-visual-system-reset).Labels:
enhancement,priority/warning,architecture,ux,polish,source/audit