mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
23 KiB
23 KiB
Phase 1 Notes: Foundation PR
Implementation
Step 1: Tailwind foundations
apps/web/package.json/pnpm-lock.yaml- added Tailwind v4 foundation dependencies:tailwindcss,@tailwindcss/postcss, andpostcss.apps/web/postcss.config.mjs- added the web-local PostCSS config that loads@tailwindcss/postcss.scripts/guard.ts- allowlisted the exact PostCSS config path with a compatibility-format comment so the residual JavaScript guard continues to fail on unplanned project-owned JavaScript.apps/web/src/index.css- added Tailwind theme/utilities layered imports, kept Preflight excluded, added the local base-layer border-style reset, and recorded the cascade policy for retained element/reset rules before component migration.
Step 2: Open Design Tailwind tokens
apps/web/src/index.css- added the CSS-first@themeblock that clears Tailwind default colors and exposes the project-approved color namespace for surfaces, borders, text, accent, semantic status, interaction overlays, radius, shadows, fonts, and exact compact UI text-size aliases.apps/web/src/index.css- added missing runtime source variables for--accent-wash,--accent-foreground,--warning-border, modal overlay, selection overlays, and inspect overlays so Tailwind utilities resolve through the same CSS-variable token path as existing styles.apps/web/src/index.css- documented the token utility vocabulary next to the@themeblock, including representative border/radius/shadow examples and the no-Preflight border reset expectation forborder border-border.- Token resolution remains CSS-variable-first: light, dark, and system modes update the existing token variables through
:root,[data-theme="dark"], andhtml:not([data-theme]); custom accent continues to update--accent*variables through the pre-hydration script andapplyAppearanceToDocument().
Step 3: Base style guardrails
scripts/guard.ts- added thestyle policyguard check for app UI files underapps/web/app/andapps/web/src/.scripts/guard.ts- added default Tailwind palette utility rejection for classes such astext-red-500,bg-white,border-zinc-200,from-orange-500, and related color utility namespaces so app UI uses Open Design token utilities.scripts/guard.ts- added hardcoded UI color detection scaffolding for hex,rgb()/rgba(),hsl()/hsla(), and named colors. Phase 1 enforcement is wired to scoped guard fixtures while existing app hardcoded colors stay classified as migration inventory or explicit exceptions until the relevant migration slices tighten enforcement.scripts/guard.ts- added a structured hardcoded-color allowlist with path pattern, value pattern, and reason fields for global token CSS, brand/accent choices, SVG illustrations, sketch/canvas data, file/inspect/user-authored colors, legacy UI fallback colors, and tests/fixtures.scripts/guard.ts- exempted CSS-wide and special color keywordstransparent,currentColor/currentcolor,inherit,initial,unset, andrevertby semantics.
Step 4: Migration inventory and visual comparison prep
- Migration inventory method: compared literal class tokens referenced from
apps/web/src/**/*.tsxagainst class selectors defined inapps/web/src/index.css. Current scan covers 59 TSX files, 1,492 literal class tokens, and 1,334 literal TSX class tokens with matchingindex.cssdefinitions. The remaining 158 literal tokens are Tailwind-ready local values, data/status words, generated strings, or classes defined outsideindex.css; migration slices must re-run the scan after rebase and classify any changed class at implementation time. - High-volume TSX sources for global class migration:
Area / file Matching index.cssclass countRepresentative classes Settings dialog and settings sections: apps/web/src/components/SettingsDialog.tsx,McpClientSection.tsx,SkillsSection.tsx,MemorySection.tsx,DesignSystemsSection.tsx,PrivacySection.tsx430+ modal-backdrop,modal,modal-settings,settings-chrome,settings-section,section-head,hint,agent-card,library-toolbar,filter-pillFile viewer / inspect / edit surfaces: apps/web/src/components/FileViewer.tsx,ManualEditPanel.tsx,FileWorkspace.tsx208+ viewer,viewer-toolbar,viewer-action,viewer-body,viewer-tab,manual-edit-panel-head,ws-tabs-shellProject creation / project panels / examples / designs: NewProjectPanel.tsx,DesignFilesPanel.tsx,ConnectorsBrowser.tsx,DesignsTab.tsx,ExamplesTab.tsx,DesignSystemsTab.tsx,PromptTemplatesTab.tsx330+ newproj,entry,df-file-row,connector-logo,tab-panel-toolbar,design-card,example-card,ds-cardShell, chat, composer, common controls: ProjectView.tsx,AppChromeHeader.tsx,ChatPane.tsx,ChatComposer.tsx,AssistantMessage.tsx,EntryView.tsx,ConversationsMenu.tsx,AvatarMenu.tsx,QuickSwitcher.tsx230+ app,app-chrome-header,pane,chat-log,composer-shell,msg,assistant,entry-shell,conv-menu,avatar-popover,qs-paletteSketch, runtime, pet, loading, feedback, modals: SketchEditor.tsx,PetRail.tsx,PetSettings.tsx,PetOverlay.tsx,Loading.tsx,ToolCard.tsx,MessageFeedback.tsx,PromptTemplatePreviewModal.tsx,QuestionForm.tsx,runtime/markdown.tsx190+ sketch-editor,pet-rail,pet-codex-thumb,loading-spinner,skeleton-shimmer,op-card,message-feedback,prompt-template-modal,md-p - Class classification:
Classification Current inventory Migration action Component-level migratable styles Most referenced global classes, including app shell, settings, project panels, viewer chrome, chat/composer, cards, buttons, popovers, modals, pet UI, sketch editor chrome, live artifact cards, and status surfaces. Replace with static token-first Tailwind utility strings during the owning phase, then delete the migrated selector from index.css. Usetoken.mdaliases such asbg-panel,text-muted,border-border,rounded-card,rounded-panel,rounded-token-pill,shadow-token-sm,shadow-token-md,font-mono, and exacttext-ui-*sizes when needed for parity.Global base styles :roottokens, theme overrides,*,html, body, #root,body, sharedinput/textarea/select, and content-neutralcode. Sources:apps/web/src/index.css:1-306,367-428.Retain as global/token source or move into @layer basebefore affected utilities migrate. Component slices may remove/constrain base selectors when they would override migrated utility properties.Loading shell od-loading-shell, used by the client-only loading path. Sources:apps/web/app/[[...slug]]/client-app.tsx:5-13;apps/web/src/index.css:308-315.Retain global because it renders before the SPA tree is available. Token utility migration happens inside loaded TSX components. Keyframes / animation skeleton-shimmer, modal/settings transitions, spinner rules, and keyframes. Representative source:apps/web/src/components/Loading.tsx:42;apps/web/src/index.css:1121-1143,12049.Retain keyframes globally. Migrate the element box/color/layout class around an animation to Tailwind while keeping the animation name global until a later animation utility strategy exists. Content-level / third-party boundary styles Markdown/runtime/viewer content classes such as markdown-rendered,markdown-status,prose-block,viewer-source,viewer-body,viewer-empty,md-p,md-code, and file/rendering boundaries. Sources:apps/web/src/components/FileViewer.tsx:6407-6412;apps/web/src/runtime/markdown.tsx:112-196;apps/web/src/index.css:9754-9779,10149-10153.Retain or migrate only the app chrome around the boundary. User-authored content, generated HTML, syntax/file previews, iframes, and external documents stay in retained exception scopes. Retained exceptions Brand icons, SVG illustrations, sketch/canvas user data, user accent controls, file/user-authored colors, test fixtures, and token definitions. Sources: scripts/guard.ts:503-534.Keep a narrow allowlist entry with a path pattern, value pattern, and reason. Revisit each exception in its owning migration phase. - Unlayered selector resolution before migration:
Selector Source Resolution button,button.primary,button.primary-ghost,button.ghost,button.subtle,button.icon-btn,button:disabledapps/web/src/index.css:317-365Phase 2 migrates button variants to token utilities. Move shared reset-only behavior such as font: inherit, focus outline, disabled opacity/cursor into@layer baseor a constrained primitive scope; remove variant visuals from global CSS after TSX callers migrate.input,textarea,select, placeholder/focus/select chevron rulesapps/web/src/index.css:367-419Phase 2 migrates controls where they are component chrome. Retain native select chevron/base reset in @layer baseor constrain by form scope before utility-driven inputs rely on their own borders, radius, padding, and focus rings.codeapps/web/src/index.css:421-428Treat as content/base code styling; migrate component-local code chips to Tailwind utilities and retain global codeonly for rich-text/content boundaries. - Token-first migration note patterns for component classes:
Existing visual pattern Utility combination to prefer Panel/card surfaces with border, radius, shadow bg-panel border border-border rounded-card shadow-token-sm text-textorbg-elevated rounded-panel shadow-token-mdfor overlaysMuted copy, labels, metadata, hints text-muted,text-soft,text-faint, plustext-ui-11,text-ui-12_5, ortext-xsbased on measured parityPrimary/accent actions bg-accent text-accent-foreground border border-accent hover:bg-accent-hover rounded-controlGhost/subtle controls bg-transparent text-text border border-border hover:bg-control-hover hover:border-border-strong rounded-controlorbg-subtle hover:bg-control-activeStatus pills and banners bg-success-surface text-success border-success-border,bg-info-surface text-info border-info-border,bg-danger-surface text-danger border-danger-border,bg-warning-surface text-warning border-warning-borderInspect/comment overlays bg-selection-overlay border-selection-outline ring-selection-outlineandbg-inspect-overlayPopovers/modals bg-elevated text-text border border-border rounded-panel shadow-token-lgplusbg-overlayfor scrimsCode/file path text font-mono text-ui-12_5 bg-subtle text-text rounded-controlunless the content boundary needs retained global rich-text CSS - Style guard allowlist and promotion policy:
Scope Pattern Reason / follow-up apps/web/src/index.cssHex, RGB(A), HSL(A) CSS variable token definitions, shadows, overlays, and retained migration inventory remain the source of truth until cleanup. AgentIcon,PaletteTweaks,PetSettings,SettingsDialogHex, RGB(A), HSL(A) Brand accents, user accent choices, and legacy token fallbacks; each owning phase must either migrate to tokens or keep a narrower exception. SketchEditor,SketchPreview,NewProjectPanelHex, RGB(A), HSL(A), none,currentColor,transparentSketch/canvas user data and SVG illustrations; migrate app chrome colors, retain user/illustration data colors. FileViewer,ManualEditPanelHex, RGB(A), HSL(A) User-authored file, inspect, editable style, and runtime content colors; app chrome migrates in Phase 4. MemorySection,MemoryModelInline,MemoryToastHex, RGB(A), HSL(A) Legacy memory UI fallback colors; migrate or narrow in the settings/project phases. apps/web/tests/Any Tests and fixtures may assert rejected colors explicitly. Repeated arbitrary app UI colors Any unregistered hardcoded color after the second real app UI use Promote to a named Open Design token before migration. One-off brand/user-content/illustration data keeps a reasoned allowlist entry. - Inventory verification: the Step 4 scan produced complete coverage for literal class tokens by cross-checking TSX references against
index.cssclass selector definitions. Migration slices remain responsible for dynamic class maps and classes changed after rebase.
Step 5: Dual-worktree agent visual comparison workflow
- Baseline worktree:
/Users/william/projects/open-designonmain; candidate worktree:/Users/william/projects/open-design-wt-tailwind-phase-1ontailwind-phase-1. - Fixed service assignments for Phase 1 and follow-up migration slices:
Role Namespace Daemon port Web port URL Baseline tailwind-baseline1811018111http://127.0.0.1:18111Candidate tailwind-candidate1812018121http://127.0.0.1:18121 - Startup commands:
# In /Users/william/projects/open-design pnpm tools-dev run web --namespace tailwind-baseline --daemon-port 18110 --web-port 18111 # In /Users/william/projects/open-design-wt-tailwind-phase-1 pnpm tools-dev run web --namespace tailwind-candidate --daemon-port 18120 --web-port 18121 - Scenario list for the agent comparison record:
Scenario Route / state Required evidence Dashboard / app shell /with the same local data state in both worktreesFull-viewport screenshots and notes on shell spacing, page background, nav/header controls, text color, and accent buttons. Project detail Open the same project in both services, seeded or selected through the production HTTP/UI flow Screenshots of the project header, chat pane, composer, side panels, status surfaces, and shared controls. Settings dialog Open settings from the app UI in both services Screenshots of modal scrim, modal radius/shadow, settings chrome, sections, buttons, form controls, pills, and disabled states. File viewer / inspect overlay Open the same file or artifact in both services and enable inspect/edit overlay state where available Screenshots of viewer toolbar/body, tabs, overlays, selection/comment affordances, code/file text, and any source preview boundaries. Sketch editor Open the same sketch surface or fixture project in both services Screenshots of editor chrome, canvas-adjacent controls, toolbar buttons, popovers, and user-content color boundaries. Live artifact card Open the same artifact/runtime surface in both services Screenshots of card shell, iframe/runtime boundary, refreshing/failed/success status badges, and action controls. Modal / popover / control states Trigger representative menus, quick switcher/avatar/conversation menus, confirmation/question modals, hover/focus/disabled states where practical Paired screenshots and drift notes for overlay elevation, radius, border color, focus ring, and hover state. - Viewport and browser state: use
1440x1000viewport at device scale factor1; compare the same scroll position and the same opened dialogs/popovers; avoid mixed zoom or retained browser state between baseline and candidate sessions. - Theme/accent matrix:
Mode Required state Light data-theme="light", default accent.Dark data-theme="dark", default accent.System Clear explicit data-theme; run with a recorded OS/browser color-scheme setting.Custom accent Apply the same custom accent in both services through the real settings UI or the same documented localStorage/document-token setup before capture. - Fixture data policy: seed through product UI or production HTTP APIs only; record project/artifact/file IDs or fixture creation steps in the phase note. Do not use source-level test backdoors for visual acceptance fixtures.
- Screenshot artifact requirements: store captures under
.tmp/visual-comparison/<phase>/<scenario>/<theme>/in the candidate worktree, with paired names likebaseline-dashboard-light.pngandcandidate-dashboard-light.png; include any annotated screenshots only as supporting artifacts. The phase note must list artifact paths, service URLs, viewport, theme/accent state, fixture identifiers, drift decisions, and approved deviations. - Component source inspection guidance: use screenshots as the primary acceptance artifact. Inspect component source only when a screenshot shows drift or a migrated global class needs traceability to its token-first utility replacement; cite the component path/class or selector and record whether the fix was made or deviation approved.
- Drift handling: layout offsets, token color changes, radius/shadow changes, focus/hover changes, or theme/accent state mismatches must be fixed in the migration slice or listed as an approved deviation with owner/reason. Missing fixture data is a failed comparison setup, so stop and seed the shared data rather than accepting empty screenshots.
- Phase notes format for each visual slice:
### Agent visual comparison - Baseline: <worktree>, namespace `<name>`, URL `<url>`, command `<command>` - Candidate: <worktree>, namespace `<name>`, URL `<url>`, command `<command>` - Viewport: 1440x1000 @1x - Fixture data: <project/artifact/file IDs or setup steps> - Matrix covered: <scenarios × themes/accent states> - Screenshot artifacts: <paths> - Component source inspected: <paths/selectors and reason> - Drift found: <items> - Fixes made / approved deviations: <items>
Implementation requirements
- Tailwind no-Preflight setup must use the official layered CSS imports in
apps/web/src/index.css:@layer theme, base, utilities; @import "tailwindcss/theme.css" layer(theme); @import "tailwindcss/utilities.css" layer(utilities); @layer base { *, ::before, ::after, ::backdrop, ::file-selector-button { border: 0 solid; } } - Keep Preflight excluded in Phase 1 and retain the project-owned border reset from Tailwind's Preflight contract in the base layer so
border border-*token utilities render solid borders from the later utilities layer. - Record the cascade-layer policy for retained
index.csselement/reset rules: any rule that can override migrated Tailwind utilities must move into@layer base, be constrained to non-migrated scopes, or be removed before the affected component migration lands.
Verification
pnpm install- passed; pnpm emitted existing workspace bin/link warnings for missing daemon dist CLI during install.pnpm guard- passed; residual JavaScript allowlist acceptsapps/web/postcss.config.mjs.pnpm --filter @open-design/web build- passed with Next.js 16/Turbopack.pnpm --filter @open-design/web build- passed after adding the Open Design@themetoken aliases and source variables.pnpm guard- passed after adding the style policy check; known Phase 1 hardcoded color migration inventory remains classified and does not fail the guard.- Temporary sample
apps/web/src/__guard_tailwind_palette_sample.tsxwithclassName="text-red-500"plus temporary samplescripts/guard-style-policy-fixtures/hardcoded-color-sample.tsxwithcolor: "#ff0000"madepnpm guardfail with both expected style policy violations; the sample also includedtransparent,currentColor,currentcolor,inherit,initial,unset, andrevert, which stayed exempt. Temporary samples were removed. - Temporary sample
scripts/guard-style-policy-fixtures/named-color-sample.tsxwithcolor: "red"madepnpm guardfail with the expected unregistered named color violation while CSS-wide/special keywords in the same fixture stayed exempt. Temporary sample was removed. pnpm guard- passed after removing the temporary style policy samples.pnpm --filter @open-design/web test- passed; 99 files / 925 tests.pnpm typecheck- passed.pnpm guard- passed after adding the Step 4 migration inventory and guard allowlist policy notes.pnpm typecheck- passed after adding the Step 4 documentation.pnpm --filter @open-design/web test- passed; 99 files / 925 tests.pnpm --filter @open-design/web build- passed with Next.js 16/Turbopack.- Dual-worktree services started successfully for the Phase 1 workflow smoke run:
- Baseline:
/Users/william/projects/open-design, namespacetailwind-baseline, daemonhttp://127.0.0.1:18110, webhttp://127.0.0.1:18111, commandpnpm tools-dev run web --namespace tailwind-baseline --daemon-port 18110 --web-port 18111. - Candidate:
/Users/william/projects/open-design-wt-tailwind-phase-1, namespacetailwind-candidate, daemonhttp://127.0.0.1:18120, webhttp://127.0.0.1:18121, commandpnpm tools-dev run web --namespace tailwind-candidate --daemon-port 18120 --web-port 18121.
- Baseline:
pnpm tools-dev status --namespace tailwind-baseline --jsonandpnpm tools-dev status --namespace tailwind-candidate --json- both reported daemon/web running; desktop remained idle, which is expected for web-only comparison.- Agent visual comparison smoke run:
- Tooling: agent-browser CLI opened both web URLs in isolated sessions and captured paired Dashboard/app shell screenshots; Chrome DevTools MCP captured a candidate accessibility snapshot and paired Dashboard/app shell screenshots at a 1440x1000 viewport.
- Scenario/theme covered in Phase 1 smoke run: Dashboard/app shell, light/default accent, empty local data state in both worktrees.
- agent-browser artifacts:
.tmp/visual-comparison/phase1/dashboard/light/baseline-dashboard-light.pngand.tmp/visual-comparison/phase1/dashboard/light/candidate-dashboard-light.png. - Chrome DevTools MCP artifacts:
.tmp/visual-comparison/phase1/dashboard/light/baseline-dashboard-light-devtools-1440x1000.png,.tmp/visual-comparison/phase1/dashboard/light/candidate-dashboard-light-devtools-1440x1000.png, and.tmp/visual-comparison/phase1/dashboard/light/candidate-devtools-snapshot.txt. sips -g pixelWidth -g pixelHeight ... && cmp -s ...- passed for the agent-browser screenshots and the Chrome DevTools MCP screenshots; dimensions matched and the captured Dashboard/app shell images were byte-identical for the Phase 1 smoke run.- Drift found: none in the covered smoke scenario.
- Approved deviations: none.
- Full scenario/theme/accent coverage is now defined as the required gate for migration slices. Phase 1 recorded the startup parameters, artifact contract, fixture policy, scenario matrix, theme/accent matrix, and notes format; later phases must seed the same project/artifact/file data in both services before checking project detail, settings, file viewer/inspect, sketch editor, live artifact, modal/popover, dark/system, and custom-accent states.
pnpm guard- passed after recording the dual-worktree visual comparison workflow.pnpm typecheck- passed after recording the dual-worktree visual comparison workflow.