返回 AiToEarn
DESIGN.md
根目录 / project / aitoearn-web / DESIGN.md
1 ---
2 name: AiToEarn Web
3 description: Calm, high-density workspace for AI-assisted multi-platform content publishing
4 colors:
5 brand-purple: 'oklch(0.74 0.17 3)'
6 brand-cyan: 'oklch(0.71 0.17 294)'
7 gradient-foreground: 'oklch(0.985 0 0)'
8 background: 'oklch(1 0 0)'
9 foreground: 'oklch(0.145 0 0)'
10 card: 'oklch(1 0 0)'
11 muted: 'oklch(0.97 0 0)'
12 muted-foreground: 'oklch(0.556 0 0)'
13 secondary: 'oklch(0.97 0 0)'
14 accent: 'oklch(0.97 0 0)'
15 border: 'oklch(0.922 0 0)'
16 destructive: 'oklch(0.577 0.245 27.325)'
17 success: 'oklch(0.65 0.2 145)'
18 warning: 'oklch(0.75 0.18 70)'
19 info: 'oklch(0.6 0.18 250)'
20 section-alt-bg: '#f8f9fa'
21 typography:
22 display:
23 fontFamily: 'Suisseintl, sans-serif'
24 fontSize: '1.5rem'
25 fontWeight: 600
26 lineHeight: 1
27 letterSpacing: '-0.01em'
28 title:
29 fontFamily: 'Suisseintl, sans-serif'
30 fontSize: '1.125rem'
31 fontWeight: 600
32 lineHeight: 1.4
33 body:
34 fontFamily: 'Suisseintl, sans-serif'
35 fontSize: '0.875rem'
36 fontWeight: 400
37 lineHeight: 1.5
38 label:
39 fontFamily: 'Suisseintl, sans-serif'
40 fontSize: '0.75rem'
41 fontWeight: 500
42 lineHeight: 1.4
43 numeric:
44 fontFamily: 'DIN, Suisseintl, sans-serif'
45 fontSize: '0.875rem'
46 fontWeight: 500
47 rounded:
48 sm: '6px'
49 md: '8px'
50 lg: '10px'
51 xl: '14px'
52 spacing:
53 xs: '4px'
54 sm: '8px'
55 md: '16px'
56 lg: '24px'
57 components:
58 button-primary:
59 backgroundColor: '{colors.brand-cyan}'
60 textColor: '{colors.gradient-foreground}'
61 rounded: '{rounded.md}'
62 padding: '8px 16px'
63 height: '36px'
64 button-outline:
65 backgroundColor: '{colors.background}'
66 textColor: '{colors.foreground}'
67 rounded: '{rounded.md}'
68 padding: '8px 16px'
69 height: '36px'
70 button-secondary:
71 backgroundColor: '{colors.secondary}'
72 textColor: '{colors.foreground}'
73 rounded: '{rounded.md}'
74 padding: '8px 16px'
75 height: '36px'
76 input-default:
77 backgroundColor: '{colors.background}'
78 textColor: '{colors.foreground}'
79 rounded: '{rounded.md}'
80 padding: '4px 12px'
81 height: '36px'
82 card-default:
83 backgroundColor: '{colors.card}'
84 textColor: '{colors.foreground}'
85 rounded: '{rounded.lg}'
86 padding: '24px'
87 ---
88
89 # Design System: AiToEarn Web
90
91 ## 1. Overview
92
93 **Creative North Star: "The Calm Growth Studio"**
94
95 AiToEarn is a professional workspace where creators and operators drive AI agents through high-volume, multi-account publishing. The interface should feel like a calm growth studio: capable and efficient, never cold or sterile. Surfaces stay quiet and neutral so dense publishing flows read clearly; the purple→cyan brand gradient appears deliberately across a small set of explicit roles to mark action, state, progress, identity, and page structure. The tool disappears into the task.
96
97 This system rejects decorative interfaces that distract from publishing, inconsistent form and modal patterns, and low-contrast controls that are hard to read in dense surfaces. It is not a marketing canvas: nothing here is drenched in brand color for its own sake. Familiarity is a feature. Forms, dialogs, tabs, and media controls follow well-known product conventions so users trust the interface mid-flow across fourteen-plus social platforms.
98
99 Depth is achieved through near-flat tonal layering, not heavy shadows. Light and dark themes are both first-class; every token resolves through semantic CSS variables so a surface is correct in either theme without a second styling pass.
100
101 **Key Characteristics:**
102
103 - Neutral grayscale surfaces; the brand gradient is the signature, deployed across action, state, progress, brand identity/frame, and seam roles while work surfaces stay neutral.
104 - High information density, with calm spacing rhythm to keep it legible.
105 - One sans family (Suisseintl) carries the whole UI; DIN for numerics, HYHanHeiJ for Chinese.
106 - Near-flat elevation via `shadow-sm` and tonal `color-mix` layering.
107 - Full light/dark parity through semantic tokens.
108
109 ## 2. Colors
110
111 A neutral grayscale foundation with a single two-stop brand gradient and a standard semantic state vocabulary.
112
113 ### Primary
114
115 - **Brand Cyan-Violet** (`oklch(0.71 0.17 294)`): The primary accent in light theme (`--primary`), the focus ring (`--ring`), and the warm stop of the brand gradient's resolved use. Carries primary actions, current selection, and sidebar active state.
116 - **Brand Magenta-Rose** (`oklch(0.74 0.17 3)`): The primary accent in dark theme and the second stop of the brand gradient (`--brand-purple`). Pairs with Brand Cyan-Violet in `--gradientBackColor` (`linear-gradient(to right in oklch, ...)`).
117 - **Gradient Foreground** (`oklch(0.985 0 0)`): Near-white text that sits on top of any brand-gradient or primary surface. The only correct foreground on the gradient.
118
119 ### Neutral
120
121 - **Ink** (`oklch(0.145 0 0)` light / `oklch(0.985 0 0)` dark): Primary text (`--foreground`).
122 - **Surface** (`oklch(1 0 0)` light / `oklch(0.145 0 0)` dark): Page and card background (`--background`, `--card`, `--popover`).
123 - **Muted Surface** (`oklch(0.97 0 0)` light / `oklch(0.269 0 0)` dark): Secondary, muted, and accent fills for panels, toolbars, hover states.
124 - **Muted Ink** (`oklch(0.556 0 0)` light / `oklch(0.708 0 0)` dark): Secondary text, placeholders, descriptions (`--muted-foreground`).
125 - **Hairline** (`oklch(0.922 0 0)` light / `oklch(1 0 0 / 10%)` dark): Borders, inputs, dividers (`--border`, `--input`).
126 - **Section Alt** (`#f8f9fa` light / `rgba(255,255,255,0.03)` dark): Alternating section background for zebra rhythm on long surfaces.
127
128 ### Tertiary (semantic states)
129
130 - **Destructive** (`oklch(0.577 0.245 27.325)`): Errors, delete actions.
131 - **Success** (`oklch(0.65 0.2 145)`): Successful publish, confirmations.
132 - **Warning** (`oklch(0.75 0.18 70)`): Pending / attention-needed states.
133 - **Info** (`oklch(0.6 0.18 250)`): Neutral informational callouts.
134
135 ### Named Rules
136
137 **The Signature Gradient Rule.** The purple→cyan brand gradient is the system's signature. It is used deliberately across a defined set of roles, never sprayed as ambient decoration. Allowed roles, and nowhere else:
138
139 1. **Action** — the primary button, key CTAs.
140 2. **State** — selected/active states: the active-nav indicator bar and its text tint, unread/count badges, the active tab indicator, a toggle/switch in its `on` state.
141 3. **Progress & emphasis** — progress-bar fills, the emphasized series in a chart or a single highlighted metric.
142 4. **Brand identity & frame** — the brand mark, 1px gradient borders (via the `padding-box / border-box` technique) on a focused field or one featured card, an avatar ring, and an empty-state icon stroke.
143 5. **Brand seam** — a single thin gradient hairline accenting a page header (a seam, not a band).
144
145 The ceiling that keeps it product-grade: **work surfaces stay neutral.** Cards, tables, forms, list rows, and panel backgrounds are never filled or backed with the gradient. If the gradient is doing more than marking action, state, progress, identity, or a single brand frame/seam, it has crossed into decoration. Hard bans, always: no gradient **text** (`background-clip: text`), no gradient **side-stripe** wider than 1px, no full-bleed gradient on a work surface.
146
147 **The Semantic-Token Rule.** Never hardcode a color (no `text-gray-900`, no `#000`, no arbitrary CSS-variable background utilities). Always use the semantic variable (`bg-background`, `text-muted-foreground`, `border-border`) so light/dark both resolve correctly.
148
149 ## 3. Typography
150
151 **Body Font:** Suisseintl (with `sans-serif` fallback)
152 **Numeric Font:** DIN (medium; metrics, counts, dates)
153 **Chinese Font:** HYHanHeiJ (`.btl-source-han-sans-cn` utility)
154
155 **Character:** One neutral, technical-humanist sans carries the entire UI. There is no display/body pairing; hierarchy comes from weight and size, not from a second typeface. DIN handles dense numerics where even-width digits aid scanning.
156
157 ### Hierarchy
158
159 - **Display** (600, 1.5rem/24px, line-height 1): Card titles, section headings, modal titles. The ceiling for in-app headings; product UI does not shout.
160 - **Title** (600, 1.125rem/18px): Sub-section and panel headers.
161 - **Body** (400, 0.875rem/14px, line-height 1.5): The base size (`body` is `text-sm`). Default for all running text and controls. Cap prose at 65–75ch.
162 - **Label** (500, 0.75rem/12px): Form labels, badges, table headers, meta text.
163 - **Numeric** (DIN 500, 0.875rem): Counts, durations, dates, metrics.
164
165 ### Named Rules
166
167 **The One-Family Rule.** Suisseintl carries headings, buttons, labels, body, and data. DIN and HYHanHeiJ are scoped tools (numerics, Chinese), not a second display voice. Display fonts in UI labels, buttons, or data are forbidden.
168
169 **The Fixed-Scale Rule.** Use the fixed rem scale, not fluid `clamp()` headings. Users view at consistent DPI; a heading that shrinks inside a sidebar looks worse, not better.
170
171 ## 4. Elevation
172
173 Near-flat by default. Depth is conveyed through tonal layering (`color-mix` blends of the brand tint into the background for sidebars and accents) far more than through shadow. The only routine shadow is a soft `shadow-sm`; the primary button adds a tinted `shadow-primary/20` that deepens on hover.
174
175 ### Shadow Vocabulary
176
177 - **Resting** (`box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05)` — Tailwind `shadow-sm`): Cards, inputs, buttons at rest.
178 - **Hover lift** (`shadow-md`): Primary button and interactive cards on hover only.
179 - **Brand glow** (`shadow-sm shadow-primary/20` → `shadow-md shadow-primary/25` on hover): Exclusive to the primary gradient button, tying elevation to brand intent.
180
181 ### Named Rules
182
183 **The Flat-By-Default Rule.** Surfaces are flat at rest. Shadows appear as a response to state (hover, focus, the primary action), never as ambient decoration. If a panel needs separation, reach for a hairline border or a tonal `color-mix` layer before a shadow.
184
185 ## 5. Components
186
187 ### Buttons
188
189 - **Shape:** Gently rounded (`rounded-md`, 8px). Default height 36px (`h-9`), padding `8px 16px`.
190 - **Primary:** Brand gradient fill (`bg-gradient-back`) with `gradient-foreground` text, `shadow-sm shadow-primary/20`. Hover deepens shadow; active scales to `0.98`. The Action role of the Signature Gradient.
191 - **Outline:** `background` fill, `input` border, `shadow-sm`; hover fills `accent`.
192 - **Secondary:** `secondary` fill; hover at 80% opacity.
193 - **Ghost:** Transparent; hover fills `accent`.
194 - **Destructive:** `destructive` fill with `destructive-foreground`.
195 - **Link:** `primary` text with underline on hover.
196 - **Loading:** inline `animate-spin` SVG ring prepended; label text is unchanged, button is disabled.
197 - **Sizes:** `sm` 32px / `default` 36px / `lg` 40px / `icon` 36×36.
198
199 ### Cards / Containers
200
201 - **Corner Style:** `rounded-lg` (10px).
202 - **Background:** `card` on `border` hairline.
203 - **Shadow Strategy:** `shadow-sm` only (see Elevation).
204 - **Internal Padding:** 24px (`p-6`); header and content share the 6-unit rhythm.
205
206 ### Inputs / Fields
207
208 - **Style:** 36px tall (`h-9`), `rounded-md`, `input` border, transparent background, `px-3 py-1`.
209 - **Focus:** 1px `ring` outline (`focus-visible:ring-1 ring-ring`), no glow.
210 - **Placeholder:** `muted-foreground` (must still clear 4.5:1).
211 - **Disabled:** `cursor-not-allowed`, 50% opacity.
212 - **Numeric inputs:** always the `NumberInput` component, never native `type="number"`.
213
214 ### Navigation (Sidebar)
215
216 - **Style:** Tonal panel — `--sidebar` is the background with ~3% brand-cyan mixed in (light) / ~7% (dark), one step cooler than the content surface.
217 - **Active state (State role):** the active row carries a `--sidebar-accent` (10–14% brand-cyan mix) fill, a flush **2px gradient indicator bar** on its leading edge, and a gradient-tinted label (the icon + text shift toward the gradient hue). The indicator bar is the only gradient stripe permitted, and only at the leading edge of an active nav row — never as a card/list side-stripe.
218 - **Foreground:** inherits `--foreground`; primary/active foreground uses `gradient-foreground`.
219
220 ### Toggles & Tabs (State role)
221
222 - **Switch `on`:** the track fills with the brand gradient (`bg-gradient-back`); the thumb stays `gradient-foreground`. The `off` track is `--input`.
223 - **Tab / segmented active:** the active segment is marked by a **2px gradient underline** (or a gradient-bordered pill for segmented controls); inactive segments stay `muted-foreground` text on a neutral track.
224
225 ### Progress & Data (Progress role)
226
227 - **Progress bar:** the filled portion uses the brand gradient on a `--muted` track. The one place a horizontal gradient run is correct, because it encodes magnitude.
228 - **Chart emphasis:** at most one emphasized series or a single highlighted metric may use the gradient (as a stroke or fill); all other series stay neutral/semantic.
229
230 ### Brand Identity & Frames (Brand-frame role)
231
232 - **Brand mark:** the product mark may use the gradient fill because it carries identity, not page decoration.
233 - **Avatar ring:** a 2px gradient ring around an account/user avatar (via the `padding-box / border-box` border technique), marking identity, not decoration.
234 - **Featured card / focused field:** a single featured card or a focused input may take a 1px gradient border — never a fill, never a side-stripe. One per surface, maximum.
235 - **Empty-state icon:** the empty-state glyph may use a gradient stroke to keep an otherwise neutral empty surface on-brand.
236
237 ### Page Header (Brand-seam role)
238
239 - A single thin (1px) gradient hairline may accent a page header as a seam between the header and the content surface. One seam per page; it is an accent line, not a band, and never repeats down the page.
240
241 ### Topic Mention (signature)
242
243 The publish editor's `@topic` / `#tag` chip: inline text with a thin brand-gradient underline (`linear-gradient(90deg, cyan, purple)` at `0.08em`), trigger character in purple-weighted bold, value in cyan-weighted semibold. On focus it gains a gradient border-box and a faint brand ring. A deliberate use of the gradient that obeys the Signature Gradient rule (it marks a live, meaningful token — a State + Brand-frame use), and notably is an underline, not gradient text.
244
245 ## 6. Do's and Don'ts
246
247 ### Do:
248
249 - **Do** deploy the brand gradient across its five defined roles — Action (primary button/CTA), State (active-nav indicator bar + tint, unread/count badge, active tab underline, switch `on`), Progress (progress fill, one emphasized metric/series), Brand identity/frame (brand mark, avatar ring, one featured card/focused-field border, empty-state icon stroke), and Brand-seam (a single page-header hairline) — the Signature Gradient Rule.
250 - **Do** keep work surfaces neutral: cards, tables, forms, list rows, and panel backgrounds are never filled or backed with the gradient.
251 - **Do** use semantic tokens (`bg-background`, `text-muted-foreground`, `border-border`) so every surface resolves in both light and dark.
252 - **Do** keep elevation near-flat: `shadow-sm` at rest, shadows only as a state response.
253 - **Do** carry the whole UI in Suisseintl; scope DIN to numerics and HYHanHeiJ to Chinese.
254 - **Do** use the `NumberInput` component for all numeric entry.
255 - **Do** verify body text and placeholders clear 4.5:1 contrast against tinted near-white surfaces.
256
257 ### Don't:
258
259 - **Don't** use the brand gradient as a work-surface background, ambient decoration, or a flourish beyond its five roles — if it isn't marking action, state, progress, or a single brand frame/seam, drop it.
260 - **Don't** render gradient **text** (`background-clip: text`), a gradient **side-stripe** wider than 1px on a card/list/alert, or any full-bleed gradient on a work surface — permanent bans regardless of role.
261 - **Don't** hardcode colors (`text-gray-900`, `#000`, `black`, `bg-[var(--primary-color)]`) — always semantic variables, Tailwind v4 `bg-(--token)` syntax.
262 - **Don't** put display fonts in UI labels, buttons, or data.
263 - **Don't** use fluid `clamp()` headings in product UI; use the fixed rem scale.
264 - **Don't** reach for a modal as the first thought — exhaust inline and progressive alternatives first.
265 - **Don't** ship inconsistent component vocabulary: the same button, input, and dialog shape must look identical across every platform's flow.
266 - **Don't** use native `<input type="number">`; it has inconsistent browser behavior (can't clear, spinners).
267 - **Don't** add gratuitous motion — transitions are 150–250ms and convey state, never choreography.
268
268 lines MARKDOWN