mirror of
https://github.com/different-ai/openwork
synced 2026-04-25 17:15:34 +02:00
new design
This commit is contained in:
474
DESIGN-SYSTEM.md
Normal file
474
DESIGN-SYSTEM.md
Normal 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: 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.
|
||||||
Reference in New Issue
Block a user