Foundations
App audit
Every component in the app on main, and what happens to it. This is the list the
migration is driven from, and the reason the library grew a Layout and a Marketing category:
the landing nav, the app nav and four sidebars had each independently decided what a header is.
App components
50
Audited
Already covered
16
Delete the app copy
New library parts
15
Built for this
Compose in the app
8
No new CSS
“Stays in the app” is not a lesser verdict. A design system that ships your editorial planner has stopped being a design system. What changes for those rows is that none of them should write CSS any more — every one is expressible as library parts plus layout, and that is the actual test of whether this library is finished.
Site chrome
The marketing shell. Every one of these was hand-written CSS against global classes defined in a stylesheet somewhere else, which is why the landing nav and the app nav had drifted into two different ideas of what a header is.
| In the app | Verdict | Use |
|---|---|---|
| SiteNav The burger menu was a non-modal <dialog> with a hand-rolled scrim button and no focus containment. Now showModal, so Escape and the top layer come from the platform. | New in the library | SiteHeader |
| SiteFooter Link columns become data. The oversized wordmark keeps its aria-hidden; the link colour comes up from 45% white to a token that passes. | New in the library | SiteFooter |
| LegalFooter | Compose in the app | SiteFooter legal snippet |
| CookieBanner Reject now matches Accept in size, variant and weight at every width — including the narrow one, where banners usually start cheating. | New in the library | CookieBar |
| LangToggle | Already covered | Select or SegmentedControl |
| TopbarCta | Compose in the app | Button + SiteHeader cta snippet |
| PageHead Meta tags. Not a UI component at all. | Stays in the app | — |
App shell
Five components were splitting one job between them: two sidebars, two mobile navs and a top bar, each with its own collapse logic and its own idea of which element scrolls.
| In the app | Verdict | Use |
|---|---|---|
| AppSidebar, DashboardSidebar, BrandsSidebar, SettingsSidebar Four rails, one component. Collapse is a width change on a variable rather than four different trees. | New in the library | Sidebar + SidebarSection + SidebarItem |
| DashboardMobileNav, BrandsMobileNav The drawer is the same rail, not a second component to keep in sync. | New in the library | Sidebar overlay |
| PageTopBar The overflow-into-a-menu behaviour was the good idea worth keeping; it now measures its own width rather than the viewport, because the bar is the sidebar’s complement. | New in the library | TopBar |
| LegalLayout, ToolPage | Compose in the app | AppShell + TopBar |
| WorkbenchTabBar | Already covered | Tabs + TabPanels |
| BrandProjectSwitcher, ScopePicker | Compose in the app | Menu + MenuItem + Avatar |
| AppEntryShimmer, WorkbenchPageShimmer | Already covered | Skeleton |
Micro components
The small ones, where a library earns most of its keep: each was five to forty lines in the app, each got one accessibility or typographic detail wrong, and each was about to be written a second time.
| In the app | Verdict | Use |
|---|---|---|
| AnimatedNum, PlanStatNum, StatsTiles, PerfCards, ToolStats Tabular figures, a delta that names both its direction and whether that direction is welcome, and an optional Sparkline at the same width. | New in the library | Stat (+ Counter) |
| PresenceStack Same two-face cap, but the overflow count is now derived from the same array as the faces, so "+3" cannot disagree with what is rendered. | New in the library | AvatarGroup |
| status pill (in SiteFooter), WarningCenter dots A bare coloured dot fails SC 1.4.1. The label is now mandatory; labelHidden moves it out of the layout, never out of the accessibility tree. | New in the library | StatusDot |
| ToolKeywordTable, PostRow, MediaReviewStatsPanel Native markup, wrapped. The scroll region is focusable and labelled, which is what lets a keyboard user reach an off-screen column. | New in the library | Table |
| (none — this was missing everywhere) | New in the library | Breadcrumb |
| (empty lists were ad-hoc paragraphs) | New in the library | EmptyState |
| VideoScoreRing | Already covered | CircularProgress |
| PlatformMixBars, LeadsTrend A ranked list is a horizontal bar with the label on the same line, not a div with an inline width — that version loses the value column and the meter semantics. | New in the library | RankBars, LineChart |
| PublishHeatmap Sequential ramp, a scale legend, and empty cells that are visibly not zero. | New in the library | Heatmap |
| ChatQueueChip | Already covered | Chip + Dialog |
| IconRow | Compose in the app | Chip + Tooltip |
| BrandMark, PlatformGlyph, AiSurfaceGlyph, PixelPattern Brand assets. A design system should not ship somebody’s logo. | Stays in the app | — |
Chat
Done in the previous pass — the app’s own chat was the reference the library components were rebuilt against.
| In the app | Verdict | Use |
|---|---|---|
| ChatPrompt | Already covered | PromptInput |
| ChatColumn, ChatWidget | Compose in the app | ChatMessage + AppShell |
| ChatToolChips | Already covered | ChatToolCall |
| ChatLiveStatus | Already covered | ChatThinking + ChatToolCall |
| ChatMessageActions, ChatUserMessageActions | Already covered | ChatMessage actions snippet |
| compaction divider (in the thread page) | Already covered | ChatCompaction |
| ChatImageLightbox A zoomable lightbox is a Dialog with one image in it. | Compose in the app | Dialog |
| ChatSessionMemory, ChatSources, ChatPlanCard, ChatQuestionsCard | Stays in the app | Accordion, Card, List |
Overlays, forms and feedback
Mostly already covered. The app is on shadcn-svelte primitives here, so the migration is a rename plus deleting the wrapper.
| In the app | Verdict | Use |
|---|---|---|
| ui/dialog, ui/sheet | Already covered | Dialog, BottomSheet |
| ui/dropdown-menu | Already covered | Menu + MenuItem |
| ui/tooltip, ui/collapsible, ui/tabs | Already covered | Tooltip, Accordion, Tabs |
| ui/input, ui/label, ui/select | Already covered | TextField, Field, Select |
| ui/badge, ui/card, ui/avatar, ui/separator, ui/skeleton | Already covered | Badge, Card, Avatar, Divider, Skeleton |
| ui/sidebar The shadcn sidebar carries its own context, provider and cookie persistence. Replaced wholesale. | New in the library | Sidebar |
| SetupDialog, DeleteBrandDialog, ConnectClaudeDialog, CreateContentModal | Compose in the app | Dialog + Field + Button |
| PromptHistoryDrawer | Already covered | BottomSheet or Sidebar overlay |
| PageTipsBubble, GuidedTour, OnboardingChecklist | Stays in the app | Popover, List, Progress |
Product surfaces
These stay in the app: they are business logic, and a design system that ships them stops being a design system. What changes is that none of them should write CSS any more — every one is now expressible as library parts plus layout.
| In the app | Verdict | Use |
|---|---|---|
| PostCard, PostRow, TopPostCard, PostEditor | Stays in the app | Card, Table, Field |
| EditorialPlanCards, PlanCards, PlanDocumentView, PlanSidePanel | Stays in the app | Card, List, BottomSheet |
| AdsOverview, AdsCampaignList, AdsStats, AdsReadiness | Stays in the app | Stat, Table, Progress |
| GrowthReadiness, HubOverview, HubOverviewCard, StrategyTabs | Stays in the app | Card, Tabs, Stat |
| KnowledgeGraph, KnowledgeConnectors, PublishHeatmap | Stays in the app | Custom viz on tokens |
| VideoReviewPanel, VideoScoreNote, MediaReviewStatsPanel | Stays in the app | CircularProgress, Table |
| DashboardMockup, ServiceMockup, SocialPostMockup, HowItWorks, WhyUs, PainLanding, LandingFaq Page-specific marketing copy and layout. The showcase pages demonstrate the pattern; the content is not the library’s business. | Stays in the app | Marketing sections |
What is still open
Named honestly rather than quietly skipped. None of these blocked a row above; all of them would earn their place.
- Donut / part-to-whole — deliberately not built yet. Every caller so far is
comparing close values, which is the one thing a donut is worst at;
RankBarswithshareanswers the same question and can be read. It goes in when a real at-a-glance split of ≤ 4 segments turns up. - Drawer — a side sheet for desktop.
Sidebar overlaycovers the navigation case, andBottomSheetcovers the phone case, but a right-hand inspector panel is neither. - Steps — onboarding checklists and guided tours. Three app components want it; none of them agree on what a step is yet, which is a reason to wait.
- FileDropzone — the upload surfaces share no code today, and each one handles drag state slightly differently.
- PricingCard —
PlanCardsis the only caller, so it is a marketing section for now, not a component.