mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-15 15:26:59 +10:00
a28e3baa61
* chore(design-sync): add Reactive Resume UI sync inputs Sync inputs for the claude.ai/design "Reactive Resume" project — the @reactive-resume/ui design system (39 primary components). - .design-sync/config.json — converter config (synth-entry, 202->39 card prune, overlay/grid cardMode overrides, cssEntry, tsconfig, buildCmd) - .design-sync/build-css.mjs + tw-entry.css — compile Tailwind v4 globals.css to a self-contained stylesheet (inlined IBM Plex font), emit real .d.ts, and create the workspace self-symlink the converter needs - .design-sync/previews/*.tsx — 39 authored preview compositions - .design-sync/conventions.md — design-agent usage header (readmeHeader) - .design-sync/NOTES.md — re-sync notes, gotchas, and risks - packages/ui/tsconfig.emit.json — declaration emit for real prop contracts Build artifacts (dist/types, .ds-compiled.css, ds-bundle, .cache) are gitignored. Claude-Session: https://claude.ai/code/session_01R8Aq8F1nTuvJwfut7g3DVE * chore(knip): ignore .design-sync inputs and drop stale es-toolkit ignore - Ignore .design-sync/** (design-sync tooling: build-css.mjs + authored previews are standalone, not part of the app import graph — knip --fix was deleting them and failing the autofix job). - Remove es-toolkit from apps/server ignoreDependencies: it's now really used (apps/server/src/http/health.ts imports withTimeout), so the ignore is stale. Claude-Session: https://claude.ai/code/session_01R8Aq8F1nTuvJwfut7g3DVE
8.1 KiB
8.1 KiB
design-sync notes — @reactive-resume/ui
Syncs to Claude Design project Reactive Resume (3c0f6556-050a-41e5-9886-c3f1ea950517).
Repo shape / build
@reactive-resume/uiis source-consumed (pnpm workspace, nodist, exports point atsrc/components/*.tsx). Runs in the converter's synth-entry mode (no--entry).buildCmd=node .design-sync/build-css.mjs. That one script does three things, all required before every converter run:- Creates the workspace self-symlink
packages/ui/node_modules/@reactive-resume/ui -> ../../../ui(pnpm doesn't self-install it; the converter resolves the DS asnode_modules/<pkg>and esbuild needs it for@reactive-resume/ui/components/*self-imports). - Emits real
.d.tstopackages/ui/dist/typesviatsc -p packages/ui/tsconfig.emit.json. Without this, synth-entry mode gives weak{[key]: unknown}prop contracts; with it the converter'sfindTypesRootpicks updist/typesand every component gets real props (variant/size unions, inherited Base UI props). - Compiles Tailwind v4
globals.css→ self-containedpackages/ui/.ds-compiled.css(cfg.cssEntry): inlines the IBM Plex Sans latin variable woff2 as a data-URI and strips all other@font-face(extra scripts + the Phosphor icon web font, which previews don't use — components render Phosphor as inline React SVGs). This is why previews are fully styled with tokens + brand font and there are zero dangling font URLs.
- Creates the workspace self-symlink
- CSS entry scans
.design-sync/tw-entry.csswhich@imports globals.css and adds@source "./previews/*.tsx"so utility classes used in authored previews are compiled. Preview layout wrappers use inline styles anyway (so subagents needn't recompile the shared CSS); only component-level utility classes need the recompile.
Card scope
- The package exports 202 symbols (39 primary components + 163 compound sub-parts). User chose ~40 primary cards:
cfg.componentSrcMapnulls the 163 sub-parts. All 202 stay importable fromwindow.RRUI(the bundle exports everything regardless of the card list), so previews compose sub-parts (RRUI.DialogContent, etc.) freely. - Multi-primary files represented by one card:
combobox.tsx→ComboboxRoot,form.tsx→FormItem,resizable.tsx→ResizableGroup,sonner.tsx→Toaster.
Preview authoring conventions (calibrated on Button / Alert / Dialog)
- Import naturally:
import { Button } from "@reactive-resume/ui/components/button"— converter rule 2 redirects any exported-component module towindow.RRUI, and sub-parts resolve too. - Icons:
@phosphor-icons/reactwith the*Iconsuffix (e.g.PlusIcon,TrashIcon,WarningIcon). Bundles into the preview. - Base UI compose pattern:
render={<Button variant="outline" />}on*.Trigger/*.Closeetc. - Layout wrappers: inline
style={{ display:"flex", gap, padding }}— not Tailwind (keeps fan-out from needing CSS recompiles). - Overlays (Dialog, and expect the same for AlertDialog/Sheet/Popover/HoverCard/DropdownMenu/ContextMenu/Tooltip/Command-dialog): render open via
defaultOpen, and setcfg.overrides.<Name> = {cardMode:"single", primaryStory:"<export>", viewport:"WxH"}. Use viewport width ≥ 640 sosm:breakpoint styles (e.g. horizontal dialog footer) engage — Dialog uses760x440. - Realistic resume-app content (resumes, sections, publish/export/share), never foo/bar.
Component composition notes (from the authoring wave)
- Real
.d.tscontracts require the barrel (see build step 2 +publishConfig.types). Base UI prop names differ from Radix/native: SwitchdefaultChecked+size; ToggledefaultPressed+variant+size; SliderdefaultValuearray ([n]single /[a,b]range). Use uncontrolleddefault*props in previews to avoid controlled-without-onChange warnings. - BrandIcon renders the app's own logo/icon (
variant="logo"|"icon"), NOT a social/brand-slug icon. It<img src>s/logo/*.svg+/icon/*.svg, which the preview server (servingds-bundle/) 404s. The BrandIcon preview inlines the realapps/web/public/{logo,icon}/light.svgas base64srcoverrides (component spreads{...props}after its ownsrc, so the override wins). - Overlays handled by the orchestrator with
cfg.overrides(cardMode single + primaryStory Open + viewport): Dialog, AlertDialog, Sheet, Popover, Tooltip, HoverCard, DropdownMenu, ContextMenu, ComboboxRoot. Command renders inline (cmdk, no overlay); Sidebar usescollapsible="none"to render inline (default offcanvas is fixed-positioned); Toaster fires aduration:Infinitytoast on mount. - Providers composed in-preview (no cfg.provider): Tooltip→TooltipProvider, Sidebar→SidebarProvider, MessageScroller→MessageScrollerProvider (+ explicit container height — Root is
size-full min-h-0and collapses otherwise), FormItem carries its own context. - Accordion opens statically via
defaultValue={[...itemValues]}(the--accordion-panel-heightwarn is a non-issue — panels measure fine). Tabs viadefaultValue. ScrollArea/ResizableGroup/InputGroup need an inline container height/width. Separator vertical needs an explicit height. - Chat/attachment components (Attachment, Bubble, Message, MessageScroller, Marker) are all used only in
apps/web/src/routes/agent/-components/agent-chat.tsx— the canonical composition source.
Build/verify gotchas (learned the hard way)
- A full
package-buildtakes ~3-4 minutes — not a hang.@phosphor-icons/reactis a giant barrel, so each icon-importing preview costs ~10-20s of esbuild parse, and 30+ authored previews compile serially. Always run it in a real background task (not a 120s-capped foreground shell) and wait for completion. - Do NOT add a barrel
index.d.ts+publishConfig.typesto get rich props for inline-param-typed components: it makes ts-morph resolve all 200+ inline Base UI param types and hangs the build for many minutes. Tried and reverted. Result: components with a named<Name>Propssource type (Button) get real props; the rest get honest{[key]: unknown}. - Base UI menu Labels must be inside a Group:
DropdownMenuLabel/ContextMenuLabelthrowMenuGroupContext is missingunless wrapped inDropdownMenuGroup/ContextMenuGroup. Same likely for other*Label/*GroupLabelmenu parts. [RENDER_THIN](height 0px) is benign for fixed-position overlays (Dialog, AlertDialog, Sheet): the content isposition:fixedso it measures 0 in normal flow, butrootEmpty:falseand the screenshot is correct. Confirmed via review sheets — not a failure.[GRID_OVERFLOW]wide →cfg.overrides.<Name> = {cardMode:"column"}applied to: Accordion, Attachment, Bubble, FormItem, InputGroup, Marker, Message, ResizableGroup, Tabs, Textarea. Toaster (portal escape) →{cardMode:"single", primaryStory:"Notification"}.
Known render warns (triaged, not failures)
[TOKENS_MISSING]:--active-tab-{top,left,height,width}(Base UI tab indicator sets these at runtime),--accordion-panel-height(Base UI accordion runtime),--tw(Tailwind internal), plus app-level--resume-preview-page-gap/--page-primary-color(defined by apps/web, not this package). All expected absent from the shipped stylesheet — components set them at runtime. Do not chase.--font-headingis referenced (DialogTitlefont-heading) but not defined in the UI package tokens (app-level). Falls back to--font-body(IBM Plex). Cosmetic only.- Unauthored primitives render near-empty floor cards (
[RENDER_BLANK]for empty Button/Input/etc.) — resolved once authored.
Re-sync risks
packages/ui/dist/types,packages/ui/.ds-compiled.css,packages/ui/.ds-tw-raw.css, and the self-symlink are all gitignored build artifacts regenerated bybuildCmd— always runnode .design-sync/build-css.mjsbefore the converter/driver.- The inlined IBM Plex font path in
build-css.mjsis pinned to@fontsource-variable/ibm-plex-sans/files/ibm-plex-sans-latin-wght-normal.woff2; if that dep moves, the font inline breaks (previews fall back to system sans). tsconfig.emit.jsonis committed; if the package adds a real build later, prefer pointing the converter at that dist and drop the emit step.