new design

This commit is contained in:
Benjamin Shafii
2026-03-27 12:38:00 -07:00
parent 9d5b14b4f4
commit 76d00d34d5

474
DESIGN-SYSTEM.md Normal file
View File

@@ -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: 812
- row padding: 1216
- card padding: 2024
- major section padding: 3248
- page rhythm: 4864 on roomy surfaces, 2432 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: 24px32px
- 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.