diff --git a/DESIGN-SYSTEM.md b/DESIGN-SYSTEM.md new file mode 100644 index 00000000..efc25270 --- /dev/null +++ b/DESIGN-SYSTEM.md @@ -0,0 +1,474 @@ +# OpenWork Design System + +This document turns the visual direction in `DESIGN-LANGUAGE.md` into an implementation system that can unify: + +- `apps/app` (OpenWork app) +- `ee/apps/den-web` (OpenWork Cloud / Den web surfaces) +- `ee/apps/landing` (marketing + product storytelling) + +The goal is not to create three similar styles. The goal is one OpenWork design system with a few environment-specific expressions. + +--- + +## 1. Why this exists + +Today the product already has the beginnings of a system, but it is split across: + +- app-specific CSS variables in `apps/app/src/app/index.css` +- Tailwind theme setup in `apps/app/tailwind.config.ts` +- Radix color tokens in `apps/app/src/styles/colors.css` +- repeated utility-class decisions across app, Cloud, and landing + +That creates three problems: + +1. the app and Cloud can feel related but not identical +2. visual decisions are made at the screen level instead of the system level +3. tokens, primitives, and page composition rules are not clearly separated + +This file defines the missing structure. + +--- + +## 2. System model + +OpenWork should use a three-layer design system: + +### Layer 1: Foundations + +Raw design tokens: + +- color +- typography +- spacing +- radius +- shadow +- motion + +These are the only values components should depend on directly. + +### Layer 2: Semantic tokens + +Product-meaning tokens: + +- `surface.page` +- `surface.panel` +- `surface.sidebar` +- `text.primary` +- `text.secondary` +- `border.subtle` +- `action.primary.bg` +- `state.hover` +- `state.selected` + +These should map foundation tokens into product meaning. + +### Layer 3: Component primitives + +Reusable building blocks: + +- Button +- Card +- Input +- Modal shell +- Sidebar shell +- List row +- Status pill +- Section header +- Empty state + +Pages should mostly compose these primitives, not invent their own visual logic. + +--- + +## 3. Relationship to existing docs + +- `DESIGN-LANGUAGE.md` = visual philosophy and qualitative rules +- `DESIGN-SYSTEM.md` = implementation structure and migration plan + +If there is a conflict: + +1. `DESIGN-LANGUAGE.md` decides what the product should feel like +2. `DESIGN-SYSTEM.md` decides how to encode that in tokens and primitives + +--- + +## 4. Core principle: one system, three expressions + +OpenWork has three main UI contexts: + +1. **App expression** — denser, flatter, operational +2. **Cloud expression** — still operational, slightly more editorial and roomy +3. **Landing expression** — more atmospheric, but still clearly the same product family + +These should differ mostly in: + +- spacing density +- shell scale +- amount of atmosphere +- page composition + +They should **not** differ in: + +- brand color logic +- button language +- border philosophy +- type hierarchy +- selection behavior + +--- + +## 5. Canonical token architecture + +We should converge on a small token set that works everywhere. + +### 5.1 Foundation color tokens + +Use Radix as the raw palette source, but not as the public API for product styling. + +Raw palette source: + +- Radix gray/slate/sage for neutrals +- Radix red/amber/green/blue for semantic states + +### 5.2 Semantic color tokens + +Canonical semantic token set: + +- `--ow-color-page` +- `--ow-color-surface` +- `--ow-color-surface-subtle` +- `--ow-color-surface-sidebar` +- `--ow-color-border` +- `--ow-color-border-strong` +- `--ow-color-text` +- `--ow-color-text-muted` +- `--ow-color-text-subtle` +- `--ow-color-accent` +- `--ow-color-accent-hover` +- `--ow-color-hover` +- `--ow-color-active` +- `--ow-color-success` +- `--ow-color-warning` +- `--ow-color-danger` + +These should become the shared API across app and Cloud. + +### 5.3 Current mapping from app tokens + +Existing app tokens already point in the right direction: + +- `--dls-app-bg` -> `--ow-color-page` +- `--dls-surface` -> `--ow-color-surface` +- `--dls-sidebar` -> `--ow-color-surface-sidebar` +- `--dls-border` -> `--ow-color-border` +- `--dls-text-primary` -> `--ow-color-text` +- `--dls-text-secondary` -> `--ow-color-text-muted` +- `--dls-accent` -> `--ow-color-accent` +- `--dls-accent-hover` -> `--ow-color-accent-hover` + +We should migrate by aliasing first, not by breaking everything at once. + +--- + +## 6. Typography system + +Typography should be systemized into roles, not ad hoc text sizes. + +### Roles + +- **display** — rare marketing or hero usage +- **headline** — page and section headers +- **title** — card and object titles +- **body** — default reading text +- **meta** — labels, helper copy, secondary information +- **micro** — pills, badges, tiny metadata + +### Shared rules + +- one main sans family across product surfaces +- medium weight does the majority of hierarchy work +- muted text is the default support color +- avoid large type jumps inside the app + +--- + +## 7. Spacing system + +OpenWork should use a consistent spacing scale instead of one-off values. + +Recommended base scale: + +- 4 +- 8 +- 12 +- 16 +- 20 +- 24 +- 32 +- 40 +- 48 +- 64 + +### Usage guidance + +- micro control padding: 8–12 +- row padding: 12–16 +- card padding: 20–24 +- major section padding: 32–48 +- page rhythm: 48–64 on roomy surfaces, 24–32 in dense app surfaces + +--- + +## 8. Radius system + +Canonical radius roles: + +- `--ow-radius-control` — small controls and rows +- `--ow-radius-card` — cards and panels +- `--ow-radius-shell` — sidebars, large grouped containers, modal shells +- `--ow-radius-pill` — buttons, tabs, chips + +Suggested mapping: + +- control: 12px +- card: 16px +- shell: 24px–32px +- pill: 9999px + +--- + +## 9. Shadow system + +Shadow should be a named system with very few levels. + +- `--ow-shadow-none` +- `--ow-shadow-control` +- `--ow-shadow-card` +- `--ow-shadow-shell` + +Default behavior: + +- app: mostly `none` or `control` +- Cloud: mostly `none`, `control`, occasional `card` +- landing: selective `card` or `shell` + +--- + +## 10. Component primitive families + +We should explicitly define a small primitive set shared across product surfaces. + +### 10.1 Action primitives + +- Primary button +- Secondary button +- Ghost button +- Destructive button +- Segmented pill / tab item + +### 10.2 Structure primitives + +- Page shell +- Sidebar shell +- Card +- Quiet card +- Modal shell +- Section divider + +### 10.3 Input primitives + +- Text input +- Textarea +- Select +- Checkbox/radio treatment +- Inline field group + +### 10.4 Navigation primitives + +- Sidebar row +- List row +- Topbar item +- Breadcrumb / section tab + +### 10.5 Feedback primitives + +- Status pill +- Banner +- Empty state +- Toast + +--- + +## 11. System-first implementation rules + +### Rule 1: prefer semantic tokens over raw utility colors + +Prefer: + +- `bg-[var(--ow-color-surface)]` +- `text-[var(--ow-color-text-muted)]` + +Over: + +- `bg-white` +- `text-gray-500` + +Raw grays are still acceptable for temporary legacy usage, but new primitives should use semantic tokens. + +### Rule 2: page code should not define new visual language + +Page files can compose primitives and choose layouts. +They should not invent new button styles, new shadow rules, or new selection patterns. + +### Rule 3: Radix stays underneath the system + +Radix is the palette source. +OpenWork tokens are the product API. + +### Rule 4: app and Cloud should share primitives even if frameworks differ + +Even when implementations differ, the primitive names and behaviors should match. + +Example: + +- `Button` in app +- `Button` in den-web + +Both should resolve to the same token logic and visual rules. + +--- + +## 12. Migration strategy + +Do not redesign everything at once. +Use this sequence. + +### Phase 1: lock the foundations + +1. create canonical semantic tokens +2. alias current app tokens to the new token names +3. document primitive families and approved variants + +### Phase 2: unify the most reused primitives + +Start with: + +1. Button +2. Card +3. Input +4. Sidebar row +5. Modal shell + +These give the largest visual consistency gain. + +### Phase 3: unify shell patterns + +Standardize: + +- page background +- sidebar shell +- panel/card shell +- list row selection +- headers and section spacing + +### Phase 4: refactor high-traffic screens + +Prioritize: + +- workspace/session surfaces in `apps/app` +- Cloud dashboard shells in `ee/apps/den-web` +- share/package/connect flows in `apps/app` + +### Phase 5: remove local style drift + +As primitives stabilize: + +- reduce repeated one-off class recipes +- replace raw gray classes in repeated patterns +- collapse duplicate card/button/input styles into primitives + +--- + +## 13. Recommended initial source of truth files + +If we implement this system, the likely canonical files should be: + +- `DESIGN-LANGUAGE.md` — philosophy +- `DESIGN-SYSTEM.md` — system rules and migration plan +- `apps/app/src/app/index.css` — initial token host for app runtime +- `apps/app/tailwind.config.ts` — Tailwind token exposure +- `apps/app/src/app/components/button.tsx` — canonical action primitive start +- `apps/app/src/app/components/card.tsx` — canonical surface primitive start +- `apps/app/src/app/components/text-input.tsx` — canonical field primitive start + +Later, a shared package may make sense, but not before the token model is stable. + +--- + +## 14. Recommended file plan for the next step + +The smallest safe implementation path is: + +### Step A + +Introduce canonical `--ow-*` aliases in `apps/app/src/app/index.css` without removing `--dls-*` yet. + +### Step B + +Refactor `Button`, `Card`, and `TextInput` to consume shared semantic tokens. + +### Step C + +Use the Den dashboard shell as the reference for: + +- sidebar shell +- row selection +- neutral panel rhythm + +### Step D + +Restyle one OpenWork app screen fully using the system to prove the direction. + +Recommended pilot screens: + +- `apps/app/src/app/pages/settings.tsx` +- session/workspace sidebar surfaces +- share workspace modal + +--- + +## 15. What a successful system looks like + +We will know this is working when: + +1. app, Cloud, and landing feel obviously from the same product family +2. a new screen can be built mostly from existing primitives +3. visual changes happen by adjusting tokens or primitives, not by editing many pages +4. selection, buttons, cards, and inputs behave consistently everywhere +5. raw color classes become uncommon outside truly local exceptions + +--- + +## 16. Anti-goals + +This system should not: + +- introduce a trendy visual reboot disconnected from the current product +- replace the OpenWork mood described in `DESIGN-LANGUAGE.md` +- depend on a large new dependency just to manage styling +- force a shared package too early +- block incremental improvements until a perfect system exists + +The correct approach is a strong design system built through small, boring, compounding steps. + +--- + +## 17. Immediate next recommendation + +If continuing from this doc, the best next change is: + +1. add `--ow-*` semantic token aliases in `apps/app/src/app/index.css` +2. standardize `Button`, `Card`, and `TextInput` +3. then restyle one app shell to match the calmer Den dashboard direction + +That gives a real system foothold without a broad rewrite.