Files
ai-video-admin-frontend/DESIGN.md
Xin Wang 571c67526f Revise design and UI components for AI video admin interface
Updated DESIGN.md to reflect a new editorial design approach with a navy palette and refined typography. Enhanced global styles in globals.css, including new color tokens and layout adjustments. Refactored components in AppShell, Sidebar, and Topbar for improved consistency and theming. Introduced a ThemeToggle component for user theme preferences and updated various pages to utilize new styles and components, ensuring a cohesive user experience across the application.
2026-06-05 13:48:42 +08:00

444 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
version: alpha
name: ai-video-admin-design
description: A quietly editorial admin surface for managing AI video assistants, rendered in a navy palette with both a dark and a light theme. The dark canvas is deep navy (`#070b16`) holding off-white ink (`#f1f5ff`); the light canvas is a cool off-white (`#f3f5fb`) holding deep-navy ink (`#0c1426`). Brand voltage is photographic, not chromatic — soft pastel atmospheric gradient orbs (mint → peach → lavender → sky → rose) drift behind hero copy as the only "color" moments. Display runs Cormorant Garamond Light at weight 300 — the editorial signature; Inter carries body, navigation, captions. CTAs are subtle pills: a deep-navy ink pill in light, inverting to an off-white pill in dark. There is no neon accent and no saturated CTA color.
colors:
primary: "#1b2741"
primary-active: "#0c1426"
ink: "#0c1426"
body: "#44516c"
body-strong: "#1b2741"
muted: "#5d6b86"
muted-soft: "#94a0bd"
hairline: "#e3e7f1"
hairline-soft: "#eef1f8"
hairline-strong: "#cbd3e4"
canvas: "#f3f5fb"
canvas-soft: "#f9fafd"
surface-card: "#ffffff"
surface-strong: "#e9edf7"
on-primary: "#ffffff"
gradient-mint: "#a7e5d3"
gradient-peach: "#f4c5a8"
gradient-lavender: "#c8b8e0"
gradient-sky: "#a8c8e8"
gradient-rose: "#e8b8c4"
semantic-error: "#dc2626"
semantic-success: "#16a34a"
colors-dark:
primary: "#e8edf9"
primary-foreground: "#0c1426"
ink: "#f1f5ff"
foreground: "#e8edf9"
body: "#a6b2cb"
muted: "#93a0bb"
muted-soft: "#6c7a96"
hairline: "#1b2740"
hairline-soft: "#141d30"
hairline-strong: "#283450"
canvas: "#070b16"
canvas-soft: "#0b1322"
surface-card: "#0e1626"
surface-strong: "#18233a"
gradient-mint: "#5fae9b"
gradient-peach: "#c08a6b"
gradient-lavender: "#8a78ad"
gradient-sky: "#5f86b8"
gradient-rose: "#b07d8c"
semantic-error: "#f87171"
semantic-success: "#4ade80"
typography:
display-mega:
fontFamily: "'Cormorant Garamond', 'Times New Roman', serif"
fontSize: clamp(2.5rem, 5vw, 4rem)
fontWeight: 300
lineHeight: 1.05
letterSpacing: -0.03em
display-xl:
fontFamily: "'Cormorant Garamond', serif"
fontSize: clamp(2rem, 4vw, 3rem)
fontWeight: 300
lineHeight: 1.08
letterSpacing: -0.02em
display-lg:
fontFamily: "'Cormorant Garamond', serif"
fontSize: 36px
fontWeight: 300
lineHeight: 1.17
letterSpacing: -0.01em
display-md:
fontFamily: "'Cormorant Garamond', serif"
fontSize: 32px
fontWeight: 300
lineHeight: 1.13
letterSpacing: -0.01em
display-sm:
fontFamily: "'Cormorant Garamond', serif"
fontSize: 24px
fontWeight: 300
lineHeight: 1.2
letterSpacing: 0
title-md:
fontFamily: "'Inter', sans-serif"
fontSize: 20px
fontWeight: 500
lineHeight: 1.35
letterSpacing: 0
title-sm:
fontFamily: "'Inter', sans-serif"
fontSize: 18px
fontWeight: 500
lineHeight: 1.44
letterSpacing: 0
body-md:
fontFamily: "'Inter', sans-serif"
fontSize: 16px
fontWeight: 400
lineHeight: 1.5
letterSpacing: 0.01em
body-strong:
fontFamily: "'Inter', sans-serif"
fontSize: 16px
fontWeight: 500
lineHeight: 1.5
letterSpacing: 0.01em
body-sm:
fontFamily: "'Inter', sans-serif"
fontSize: 15px
fontWeight: 400
lineHeight: 1.47
letterSpacing: 0.01em
caption:
fontFamily: "'Inter', sans-serif"
fontSize: 14px
fontWeight: 400
lineHeight: 1.5
letterSpacing: 0
caption-label:
fontFamily: "'Inter', sans-serif"
fontSize: 12px
fontWeight: 600
lineHeight: 1.4
letterSpacing: 0.08em
textTransform: uppercase
button:
fontFamily: "'Inter', sans-serif"
fontSize: 14px
fontWeight: 500
lineHeight: 1.0
letterSpacing: 0
nav-link:
fontFamily: "'Inter', sans-serif"
fontSize: 14px
fontWeight: 400
lineHeight: 1.4
letterSpacing: 0
rounded:
none: 0px
sm: "calc(0.75rem * 0.6)" # ~7px
md: "calc(0.75rem * 0.8)" # ~10px
lg: 0.75rem # 12px (--radius)
xl: "calc(0.75rem * 1.4)" # ~17px
2xl: "calc(0.75rem * 1.8)" # ~22px
3xl: "calc(0.75rem * 2.2)" # ~26px
pill: 9999px
full: 9999px
spacing:
xxs: 4px
xs: 8px
sm: 12px
base: 16px
md: 20px
lg: 24px
xl: 32px
xxl: 48px
section: 96px
components:
app-shell:
backgroundColor: "{colors.canvas}"
textColor: "{colors.ink}"
typography: "{typography.body-md}"
sidebar:
backgroundColor: "{colors.surface-card}"
textColor: "{colors.body}"
borderColor: "{colors.hairline}"
width: 252px
width-collapsed: 76px
topbar:
backgroundColor: "{colors.canvas}"
textColor: "{colors.ink}"
borderColor: "{colors.hairline}"
height: 81px
button-primary:
backgroundColor: "{colors.primary}"
textColor: "{colors.on-primary}"
typography: "{typography.button}"
rounded: "{rounded.pill}"
height: 40px
button-outline:
backgroundColor: transparent
textColor: "{colors.ink}"
typography: "{typography.button}"
rounded: "{rounded.pill}"
borderColor: "{colors.hairline-strong}"
height: 40px
nav-item:
backgroundColor: transparent
textColor: "{colors.muted}"
typography: "{typography.nav-link}"
rounded: "{rounded.pill}"
height: 44px
nav-item-active:
backgroundColor: "{colors.surface-strong}"
textColor: "{colors.ink}"
hero-band:
backgroundColor: "{colors.canvas-soft}"
textColor: "{colors.ink}"
typography: "{typography.display-xl}"
rounded: "{rounded.3xl}"
borderColor: "{colors.hairline}"
padding: 64px
feature-card:
backgroundColor: "{colors.surface-card}"
textColor: "{colors.ink}"
typography: "{typography.title-sm}"
rounded: "{rounded.2xl}"
borderColor: "{colors.hairline}"
padding: 24px
section-card:
backgroundColor: "{colors.surface-card}"
textColor: "{colors.ink}"
rounded: "{rounded.2xl}"
borderColor: "{colors.hairline}"
padding: 24px
icon-plate:
backgroundColor: "{colors.surface-strong}"
textColor: "{colors.ink}"
rounded: "{rounded.full}"
size: 40px
text-input:
backgroundColor: "{colors.canvas}"
textColor: "{colors.ink}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
borderColor: "{colors.hairline-strong}"
badge-pill:
backgroundColor: "{colors.surface-strong}"
textColor: "{colors.muted}"
typography: "{typography.caption-label}"
rounded: "{rounded.pill}"
padding: 4px 12px
brand-icon:
backgroundColor: "{colors.primary} + sky/lavender gradient orb overlay"
textColor: "{colors.on-primary}"
rounded: "{rounded.xl}"
size: 44px
avatar:
backgroundColor: "{colors.primary} + sky gradient orb overlay"
textColor: "{colors.on-primary}"
rounded: "{rounded.full}"
size: 32px
gradient-orb:
background: "radial-gradient with one of {colors.gradient-*}"
blur: 48-64px
opacity: 0.45-0.6
---
## Overview
AI 视频助手管理台 reads like a quietly editorial print magazine that happens to be an admin console. It ships in **two themes built from one navy palette**:
- **Dark navy** (default): deep-navy canvas `{colors-dark.canvas}` (#070b16) holding off-white ink `{colors-dark.ink}` (#f1f5ff).
- **Light navy**: cool off-white canvas `{colors.canvas}` (#f3f5fb) holding deep-navy ink `{colors.ink}` (#0c1426).
The brand voltage is **photographic, not chromatic**: soft pastel atmospheric gradient orbs (mint, peach, lavender, sky, rose) drift behind hero/feature panels as the only "color" moments. There is no neon accent, no saturated CTA color, and no cyan/blue dev-console gradient anymore.
Type pairs **Cormorant Garamond Light** (display serif at weight 300 — the open-source substitute for Waldenburg) with **Inter** for body, navigation, captions, and buttons. The display weight at 300 is the editorial signature — never bold. Latin display runs in the serif; CJK display falls back to the system serif/sans at weight 300 (still light/editorial).
CTAs are subtle pills: in light mode the primary is a deep-navy ink pill (`{component.button-primary}`); in dark mode it inverts to an off-white pill (`{colors-dark.primary}` → off-white, text `{colors-dark.primary-foreground}`). The secondary is a transparent hairline-outline pill.
**Key Characteristics:**
- One navy palette, two themes; dark is the default, persisted to `localStorage` with a no-flash bootstrap script in `layout.tsx`.
- Off-white / deep-navy ink. No saturated CTA color — ink pill only.
- Display runs Cormorant Garamond Light at weight 300 — editorial voice.
- Body runs Inter at 400/500 with subtle +0.01em tracking.
- Pastel gradient orbs (5 tokens) used as atmospheric decoration only.
- Pill geometry (`{rounded.pill}`) for every CTA, nav item, and badge; `{rounded.2xl}` for cards, `{rounded.3xl}` for hero bands.
- Hairline borders + a single soft shadow tier — no layered-surface dev-console stack.
- 96px section rhythm; ~40px page padding; 1180px max content width.
## Colors
The two `colors` / `colors-dark` blocks above are the source of truth and are wired into `globals.css` as the shadcn variables (`--background`, `--foreground`, `--card`, `--primary`, `--border`, `--muted-foreground`, …) plus editorial extras (`--ink`, `--body-text`, `--surface-strong`, `--hairline*`, `--canvas-soft`, `--gradient-*`). Tailwind utilities like `bg-background`, `text-ink`, `border-hairline`, `bg-surface-strong`, and `text-muted-foreground` resolve to the active theme automatically.
### Primary (CTA)
- **Light** `{colors.primary}` (#1b2741): deep-navy ink pill, white text. Press → `{colors.primary-active}` (#0c1426).
- **Dark** `{colors-dark.primary}` (#e8edf9): off-white pill, deep-navy text (`#0c1426`). The editorial inversion — used scarcely.
### Surfaces
- **Canvas** — page floor. Light #f3f5fb / Dark #070b16.
- **Canvas Soft** — hero/placeholder bands. Light #f9fafd / Dark #0b1322.
- **Surface Card** — content cards, popovers. Light #ffffff / Dark #0e1626.
- **Surface Strong** — icon plates, badges, active nav. Light #e9edf7 / Dark #18233a.
### Hairlines
- **Hairline** — default 1px divider/card outline. Light #e3e7f1 / Dark #1b2740.
- **Hairline Soft** — lighter divider. Light #eef1f8 / Dark #141d30.
- **Hairline Strong** — input/outline-button border. Light #cbd3e4 / Dark #283450.
### Text
- **Ink** — display & primary text. Light #0c1426 / Dark #f1f5ff.
- **Body** — running copy. Light #44516c / Dark #a6b2cb.
- **Muted** — descriptions, sub-labels. Light #5d6b86 / Dark #93a0bb.
- **Muted Soft** — captions, placeholders. Light #94a0bd / Dark #6c7a96.
### Atmospheric Gradient Orbs (signature)
Five pastel stops — `gradient-mint`, `gradient-peach`, `gradient-lavender`, `gradient-sky`, `gradient-rose`. In dark mode they shift to lower-chroma navy-compatible variants (e.g. sky #a8c8e8#5f86b8). They appear ONLY as soft, blurred radial blooms behind hero/feature/placeholder copy and as the orb overlay on the brand icon/avatar. Never as button fills, text colors, or flat card surfaces.
### Semantic
- **Success** — Light #16a34a / Dark #4ade80.
- **Error** — Light #dc2626 / Dark #f87171.
## Typography
### Font Family
**Cormorant Garamond** is the display serif (`--font-display`, weight 300) — the open-source substitute for the licensed Waldenburg Light. **Inter** carries body, navigation, captions, and buttons (`--font-sans`). **Geist Mono** is loaded for monospace. Helper classes in `globals.css`: `.font-display`, `.display-mega/-xl/-lg/-md/-sm`, `.caption-label`.
### Hierarchy
| Token | Size | Weight | Tracking | Use |
|---|---|---|---|---|
| `{typography.display-mega}` | clamp 4064px | 300 | -0.03em | Marketing-scale hero |
| `{typography.display-xl}` | clamp 3248px | 300 | -0.02em | Homepage hero h1 |
| `{typography.display-lg}` | 36px | 300 | -0.01em | Page titles |
| `{typography.display-md}` | 32px | 300 | -0.01em | Section heads |
| `{typography.display-sm}` | 24px | 300 | 0 | Card group titles |
| `{typography.title-md}` | 20px | 500 | 0 | Component titles (Inter) |
| `{typography.title-sm}` | 18px | 500 | 0 | List labels |
| `{typography.body-md}` | 16px | 400 | +0.01em | Default body |
| `{typography.body-strong}` | 16px | 500 | +0.01em | Emphasized body |
| `{typography.body-sm}` | 15px | 400 | +0.01em | Compact body |
| `{typography.caption-label}` | 12px | 600 | +0.08em, UPPER | Section labels, badges |
| `{typography.button}` | 14px | 500 | 0 | CTA pill |
| `{typography.nav-link}` | 14px | 400 | 0 | Sidebar nav |
### Principles
- **Display weight stays at 300.** Cormorant Garamond Light is the editorial signature. Never bold display copy.
- **Subtle tracking on body.** Inter at +0.01em (applied globally on `body`).
- **Negative tracking on display.** Tighter as size grows (-0.01em → -0.03em).
- **Caption labels** are the editorial section marker — uppercase, 600, +0.08em.
## Layout
### Spacing & Container
- Base unit 4px; section rhythm 96px (`{spacing.section}`).
- Page padding: `px-8 py-10`. Max content width 1180px.
- Sidebar: 252px expanded, 76px collapsed.
### Whitespace Philosophy
Generous editorial pacing. Hero bands get large internal padding (64px) with a gradient orb in a corner; content cards sit 1624px apart.
## Elevation & Depth
The system uses **hairline + soft drop**. Cards float above the canvas via a 1px hairline and a single subtle shadow tier (`shadow-sm`, deepening to `shadow-md` on hover). Atmospheric depth comes from the gradient orbs, not from layered surface steps.
| Level | Treatment | Use |
|---|---|---|
| Canvas | `{colors.canvas}` | App background, topbar |
| Card | `{colors.surface-card}` | Content cards, popovers |
| Hairline border | 1px `{colors.hairline}` | Card/input outlines |
| Soft drop | `shadow-sm``shadow-md` on hover | Card elevation |
| Gradient orb | blurred radial bloom, opacity 0.450.6 | Atmospheric depth only |
## Shapes
### Border Radius Scale (`--radius: 0.75rem` = 12px)
| Token | Approx | Use |
|---|---|---|
| `{rounded.md}` | ~10px | Form inputs |
| `{rounded.lg}` | 12px | Compact elements |
| `{rounded.xl}` | ~17px | Brand icon |
| `{rounded.2xl}` | ~22px | Feature/section cards |
| `{rounded.3xl}` | ~26px | Hero/placeholder bands |
| `{rounded.pill}` | 9999px | All buttons, nav items, badges |
| `{rounded.full}` | 9999px | Avatars, icon plates |
## Components
### App Shell
**`app-shell`** — `bg-background text-foreground`. Flex row: sidebar left, main column right (topbar + scrollable content at `px-8 py-10`).
### Sidebar
**`sidebar`** — `bg-sidebar`, border-right `{colors.hairline}`, width 252/76px. Brand block: gradient-orb brand icon + serif wordmark + uppercase `管理台` caption-label. Nav items are pill-shaped (44px); active uses `bg-sidebar-accent` with foreground text.
### Top Bar
**`topbar`** — `bg-background`, border-bottom hairline, height 81px. Right-aligned: Help outline pill, **theme toggle** (sun/moon), notification bell, user avatar pill — all hairline-outline style.
### Buttons (pills)
**`button-primary`** — ink pill (light) / off-white pill (dark), `{rounded.pill}`, height 40px (`size="lg"`).
**`button-outline`** — transparent pill, 1px `{colors.hairline-strong}` border, text ink; hover `bg-surface-strong`.
### Hero & Atmospheric
**`hero-band`** — `bg-canvas-soft`, `{rounded.3xl}`, hairline border, 64px padding, with 12 blurred gradient orbs (sky + lavender) behind editorial display copy, a caption-label eyebrow, and two CTAs.
**`gradient-orb`** — blurred radial bloom in one of the five pastel tokens; pure atmosphere, holds no content.
### Cards
**`feature-card` / `section-card`** — `bg-card`, `{rounded.2xl}`, hairline border, `shadow-sm`. Icon plate is a 40px `{colors.surface-strong}` circle with neutral foreground icon (no colored accent).
### Forms & Tags
**`text-input`** — `bg-background`, text ink, 1px `{colors.hairline-strong}` border, `{rounded.md}`; focus thickens border to ring.
**`badge-pill`** — `bg-surface-strong`, caption-label text, `{rounded.pill}`.
### Brand Elements
**`brand-icon`** / **`avatar`** — `{colors.primary}` base with a sky/lavender gradient-orb overlay, `{rounded.xl}` (icon) / `{rounded.full}` (avatar). The pastel orb replaces the old cyan→blue gradient.
## Theming
- Two themes from one palette: `.dark` toggles the variable set in `globals.css`. Dark is the default `<html className="dark">`.
- A `ThemeToggle` (sun/moon) in the topbar flips `documentElement.classList` and writes `localStorage.theme`.
- A no-flash inline script in `layout.tsx` applies the stored theme before paint (defaults to dark).
## Do's and Don'ts
### Do
- Reserve `{colors.primary}` (ink/off-white pill) for primary CTAs.
- Use Cormorant Garamond Light at weight 300 for every display headline. Never bold.
- Use Inter at +0.01em tracking for body.
- Use atmospheric gradient orbs (mint/peach/lavender/sky/rose) as decoration only.
- Use the pill shape for every CTA, nav item, and badge.
- Drive color from semantic tokens (`bg-card`, `text-ink`, `border-hairline`) so both themes work — never inline hex.
### Don't
- Don't reintroduce the cyan/blue dev-console accent or layered-navy surface stack.
- Don't bold display copy — it sits at weight 300.
- Don't use gradient orbs as button fills, text colors, or flat card backgrounds.
- Don't use sharp 0px or `{rounded.xl}` corners on CTAs — pill geometry is the brand button.
- Don't drop body Inter to weight 300 to match the serif — body stays at 400/500.
## Responsive Behavior
| Name | Width | Key Changes |
|---|---|---|
| Mobile | < 640px | Feature grid 1-up; sidebar collapsed; user name hidden; display sizes shrink via clamp |
| Tablet | 6401024px | Feature grid 2-up |
| Desktop | 10241280px | Feature grid 3-up; full sidebar |
| Wide | > 1280px | Content caps at 1180px |
### Touch Targets
- Nav items 44px; primary buttons 40px (`size="lg"`).
- Sidebar collapses to 76px icon-only via toggle.
## Known Gaps
- Cormorant Garamond covers Latin only; CJK display headings fall back to the system serif/sans at weight 300. A bundled light CJK serif (e.g. a Noto Serif SC weight) is not yet wired in.
- Several inner pages (Components, History, Test, Workflow, Profile) currently use the shared `PlaceholderPage` editorial header and await real content.
- Animation timings (orb drift, hero entrance, theme cross-fade) out of scope.
- Form validation states beyond focus not yet documented.