Skip to content

DOL Platform Evolution - Centralized UI & Components

in-progressUpdated

Status: Phase P1 + P1.1 shipped. P2 pending cross-repo approval. Scope: Cross-repo architecture (DS-Token, Wiki, Playground, Design System Studio). Authority: Design System owner, per Approval Matrix in workspace CLAUDE.md. Canonical product name: Design System Studio (locked 2026-04-24). Short form “DS Studio” acceptable in casual context. Package (@dol/ds-studio), folder (studio/), URL (/design-system/) unchanged. Every user-facing string (HTML title, in-app logo, dev-server banner, README, CHANGELOG) updated on rename day.

“Các component và UI tái sử dụng được tập trung vào một nơi. Các product khác tham khảo từ đó để xây dựng → đồng bộ thiết kế giữa các product khác nhau.” - user direction, 2026-04-24

Design System Studio is the single destination for:

  • browsing every design token,
  • reading every DS guideline,
  • referencing every shared component,
  • and - in the long term - the home of the shared UI layer itself.

Every DOL product (Wiki, Playground, future apps) consumes from the DS-Token repo; Design System Studio is the human-readable face of that source of truth.

  • Design tokens - DS-Token/tokens/v4/ → propagated to Wiki, Playground, Studio via generate-subset.js. Any token change reaches every consumer on next build. Proven path.
AssetWhere it livesPain
General UI components (15)dol-edu-playground/components/ui/*.tsxWiki can’t import - they’d rebuild Button/Card from scratch.
KID components (9)dol-edu-playground/components/Domains/DolKid/ui/*.tsxSame - Kid UI is Playground-locked.
Doc page shell (sidebar, TOC, article)DOL Wiki/site/src/components/ClientSidebar.tsx + [[...slug]]/page.tsxStudio’s docs surface duplicated every piece in vanilla JS.
Prose stylesStudio’s .prose-docs + Wiki’s .docx-resourceTwo implementations of the same intent - drift risk.
Doc corpus (MD files)DS-Token/design-guideline/**/*.md (25 files)✓ lives with DS-Token, but no consumer besides Studio knows about them.

Root cause: each repo treats “UI reusability” as its local concern. No repo is positioned as the host.

DOL-DS-token/ ← single source of truth
├── tokens/ (existing - token layer)
├── components/ (NEW - React component layer)
│ ├── ui/ 15 general UI primitives
│ ├── kid/ 9 KID-domain components
│ └── doc-shell/ sidebar, article, TOC, breadcrumb (extracted from Wiki)
├── ui-css/ (NEW - shared CSS layer)
│ ├── prose.css .dol-prose - doc article body
│ ├── doc-shell.css layout for sidebar/article/TOC
│ └── code-block.css copy button + language label
├── design-guideline/ (existing - doc corpus)
├── studio/ (existing - catalog + preview)
└── dist/
├── tokens-data.json (existing)
├── components/ (NEW - built React + types)
└── ui-css/ (NEW - shared CSS bundles)
Consumers:
Wiki → import { Button, Card, DocShell } from '@dol/ds-token/components'
→ import '@dol/ds-token/ui-css/prose.css'
Playground → same imports; stops HOSTING, just references
Studio → catalog-renders from DS-Token component manifest
Future apps → default path is DS-Token import

Key shift: Playground transitions from host of shared components → consumer of them. Its role narrows to “spec → demo pipeline + domain-specific logic”.

Each phase ships independently + is reversible. Estimated cost + blast radius tagged. Stop at any gate if the trade-off becomes wrong.

✅ P1 - Extract shared CSS (shipped 2026-04-24)

Section titled “✅ P1 - Extract shared CSS (shipped 2026-04-24)”

Moved Design System Studio’s .prose-docs, code-block decorator, doc-shell layout → DS-Token/ui-css/*.css with canonical class .dol-prose + backward-compat alias. Studio imports via @import '../../../ui-css/...'.

  • Landed files: ui-css/prose.css, ui-css/README.md, studio/src/styles/tailwind.css (imports), studio/index.html (class rename)
  • Shipped also: ui-css/palette-remap-invariant.css (auto-generated compatibility variant for Tailwind-convention consumers - see lesson on double-flip bug that surfaced this need)
  • Next consumers ready to opt in: Wiki (P3), Playground (P2)

✅ P1.1 - Doc-shell layout extraction (shipped 2026-04-24)

Section titled “✅ P1.1 - Doc-shell layout extraction (shipped 2026-04-24)”

Extracted the 3-column reading layout (sidebar + article + TOC) as canonical classes in ui-css/doc-shell.css - .dol-doc-layout, .dol-doc-sidebar, .dol-doc-main, .dol-doc-article-wrap, .dol-doc-article-header, .dol-doc-toc. Wiki + Playground can adopt these in a single import when doing P3/P4.

P1.2 - Dark-variant tech debt purge (1 day, when scheduled)

Section titled “P1.2 - Dark-variant tech debt purge (1 day, when scheduled)”

Canonical DOL convention = auto-flipping neutrals, NO dark:*-color-* variants. Studio currently has 232 dark:*-slate-* + ~359 total color dark variants. The invariant palette shim makes them work; removing them (and letting auto-flip handle theme) aligns Studio with Wiki + DOL canon.

  • Files touched: 10+ (index.html, controllers, components)
  • Blast radius: Studio visual (every surface)
  • Verification gate: every screen identical in light + dark after purge
  • Pre-req: visual diff tooling OR careful manual pass

⏸ P2 - Move components to DS-Token (3–5 days, cross-repo - needs approval)

Section titled “⏸ P2 - Move components to DS-Token (3–5 days, cross-repo - needs approval)”

Relocate Playground/components/ui/* + Playground/components/Domains/DolKid/ui/*DS-Token/components/. Playground updates import paths to reference DS-Token via workspace link (file: dep) or internal package.

  • Files touched: DS-Token (new), Playground (import rewrites × ~24 files)
  • Blast radius: Playground (all consumers of moved components)
  • Verification gate: Playground dev + prod build pass; visual unchanged
  • Reversibility: git revert; path aliases keep working both ways
  • Enables: Wiki + future products to import from DS-Token
  • Blocker: workspace CLAUDE.md approval matrix requires explicit plan-approval for cross-repo destructive changes. Awaiting user greenlight.

P3 - Wiki consumes DS-Token components (5–7 days, higher risk)

Section titled “P3 - Wiki consumes DS-Token components (5–7 days, higher risk)”

Inventory Wiki’s site/src/components/*.tsx. Categorize:

  • Truly generic (Button, Card, etc.) → migrate consumption to DS-Token

  • Wiki-specific (GraphClient, AiMarkdown, CitationSpanChip, etc.) → stay in Wiki

  • Doc shell (ClientSidebar, Header, [[...slug]]/page.tsx layout) → extract to DS-Token’s components/doc-shell/ so Studio + future doc surfaces reuse

  • Files touched: Wiki (import rewrites + extraction), DS-Token (new doc-shell)

  • Blast radius: Wiki - all pages using affected components

  • Verification gate: Wiki dev + CI + visual regression

  • Reversibility: extractions are additive; old components remain until gate passes

P4 - Design System Studio’s Docs surface = Wiki-served (3–5 days, low-medium risk)

Section titled “P4 - Design System Studio’s Docs surface = Wiki-served (3–5 days, low-medium risk)”

Wiki hosts /design-system/docs/* using the shared doc-shell components now in DS-Token. Studio’s Docs tab navigates there; user stays under same URL root.

  • Prerequisites: P3 doc-shell extraction done (so Wiki’s doc page uses the shared shell that matches Studio’s visual language)
  • Files touched: Wiki (new route + content-provider config to read DS-Token/design-guideline/), Studio (Docs tab becomes redirect)
  • Blast radius: Studio’s Docs surface (removed) + Wiki (new routes)
  • Verification gate: URL routing + content rendering + shell consistency
  • Answers Q1/Q2/Q3 from the previous message - see §7 below

P5 - Component live previews unified (1–2 weeks, delayed)

Section titled “P5 - Component live previews unified (1–2 weeks, delayed)”

Replace Studio’s inline HTML approximations (Path A from F4) with actual rendered DS-Token React components via iframe or SSG capture.

  • Prerequisites: P2 + P3 (components centralized)
  • Blast radius: Studio (preview mechanism swap)
  • Deferred until: P1–P4 stable + users ask for real previews
PhaseStatusEffortRiskValue
P1✅ shipped1 dayLowShared CSS baseline (ui-css/prose.css)
P1.1✅ shipped0.5 dayLowShared doc-shell layout (ui-css/doc-shell.css)
P1.2⏸ tech debt1 dayLowPurge dark:*-color-* variants, adopt auto-flip
P2⏸ needs approval3–5 daysMediumComponents move Playground → DS-Token
P3⏸ downstream5–7 daysHigherWiki consumes DS-Token components + doc-shell
P4⏸ downstream3–5 daysLow-MedDocs tab delegated to Wiki
P5⏸ future1–2 weeksMediumLive component previews (replace Path A)

Total remaining (P1.2 + P2 + P3 + P4): ~2–3 weeks. P5 is additive later.

Explicitly out-of-scope to keep the plan tractable:

  • No public npm publishing. Workspace-link consumption is enough for private use.
  • No new repo. DS-Token expands in scope, not count.
  • No framework change. Each app keeps its stack (Wiki = Next.js, Playground = Vite+React, Studio = Vite+vanilla).
  • No immediate rewrite of Wiki-specific features (graph, AI search, citations).
  • No forced component rename. Import paths change; public APIs stay stable.

These 4 questions shape the spec. Best answered by the owner before P1 begins.

D1 - Package form: DS-Token consumed by other repos as…

  • (a) Workspace-link ("@dol/ds-token": "file:../DOL-DS-token") + symlink. Simplest.
  • (b) Private npm registry publish per release. More overhead.
  • (c) Git submodule. Rare in DOL workspace. Discouraged.

Default if silent: (a). Low risk, reversible to (b) later.

D2 - Component file convention: components in DS-Token/components/ are…

  • (a) TSX files, consumed directly. Consumer apps handle compilation.
  • (b) Pre-built (vite-plugin-dts + tsc) at DS-Token, consumers import compiled output.
  • (c) Both - source for type-checking, build for runtime.

Default if silent: (a). Matches Playground’s current setup.

D3 - MD source for Wiki docs (from previous message’s Q2): Wiki reads DS-Token’s guideline corpus via…

  • (a) FS provider reading ../DOL-DS-token/design-guideline/. Workspace-local.
  • (b) GitHub provider (HTTPS) reading from DOL-DS-token repo. Prod-compatible.
  • (c) Files move into Wiki. DS-Token loses them.

Default if silent: (a) for dev, (b) for prod. Wiki’s provider already supports both.

D4 - Visual shell consistency on Wiki-served docs: /design-system/docs/* shows…

  • (a) Studio’s tab nav (Tokens / Docs / Components) at top + Wiki’s shell below. Unified UX.
  • (b) Wiki’s native header only. Simpler but user feels “moved to Wiki”.

Default if silent: (a). Aligns with “single platform” vision.

P1 begins when any 1 of 4 decisions has a non-default answer (worth stopping to confirm) OR when owner explicitly greenlights defaults. If none arrive within a reasonable window, proceed with defaults and note each choice in the P1 commit message for reviewability.

  • Design System Studio (canonical product name, locked 2026-04-24): the SPA at dol-wiki.khoajak.design/design-system/. Single destination for tokens, docs, components. Short form “DS Studio” acceptable in casual context. Package @dol/ds-studio, folder studio/.
  • DS-Token: the DOL-DS-token/ repo - host of tokens + docs corpus + ui-css/ shared styles + (future P2) components/ shared React components. Design System Studio lives inside this repo as studio/ subfolder.
  • Wiki: the Next.js site at dol-wiki.khoajak.design/wiki/ - DOL’s knowledge hub. Future P3 consumer of DS-Token components. Future P4 host of Design System Studio’s Docs tab.
  • Playground: dol-edu-playground/ - runtime demo + spec mapping source. Current home of 24 shared components; P2 moves them to DS-Token.
  • Doc shell: sidebar + article + TOC + breadcrumb - the chrome around rendered doc content. Canonical layout classes in ui-css/doc-shell.css.
  • ui-css/: shared CSS layer at DS-Token root. Framework-agnostic (vanilla JS, React, Next.js all consume). Currently: prose.css, doc-shell.css, palette-remap-invariant.css.
  • Auto-flip convention: DOL canonical theme-flipping pattern - designer writes text-slate-900 alone; neutrals flip per [data-theme="dark"] automatically via palette-remap’s alias chain. NO dark:*-slate-*.
  • Invariant palette: compatibility variant (palette-remap-invariant.css) for products using Tailwind’s explicit dark: convention. Prevents double-flip when code has both conventions competing.