# MailHub UI Visual Redesign Design ## Goal 全面升级 MailHub 管理台与登录/注册页的视觉系统,使其从「默认 Ant Design 后台模板」提升为辨识度高的 Modern SaaS 控制台,同时**不改动后端 API、权限模型、业务状态机与核心信息架构**。 ## Confirmed Product Decisions | Decision | Choice | |----------|--------| | Scope | Full visual system redesign (theme + layout shell + component patterns + key pages) | | Auth pages | Included; same visual language as admin console | | Visual style | Modern SaaS — light canvas, indigo primary, airy product feel (Resend / Railway-like) | | Shell | Dark left sidebar (full text labels) + light top bar + content canvas | | Density | Comfortable — larger type, generous whitespace, breathable cards | | Implementation approach | Design system + shell upgrade on existing React + Ant Design v5 | | Dark mode | Out of scope for this redesign | ## Non-Goals - New features, new routes, or new API endpoints - Replacing Ant Design / React / Vite stack - Full custom component library rebuild - Dark mode theme - Changing domain DNS workflow semantics, token lifecycle, or admin permissions - Rewriting analytics models or i18n message semantics (minor chrome strings only) ## Architecture Continue the current React admin app (`src/frontend/`, `src/layouts/`, `src/pages/`, `src/components/`) built by Vite into `public/`. Visual upgrades land as: 1. **Design tokens** — CSS custom properties + Ant Design `ConfigProvider` theme tokens 2. **Shell redesign** — `AdminLayout` and auth shell (`AuthApp`) 3. **Shared presentation components** — PageHeader, MetricCard, SectionCard, StatusPill, EmptyState, CodeBlock 4. **Page restyles** — recompose existing page markup around the new patterns without changing data loading or handlers Business logic remains in existing model modules (`*-model.js`), `api.ts`, and page containers. Admin and auth are **separate Vite entry points** (`src/frontend/main.tsx` → `App.tsx`, `src/frontend/auth/main.tsx` → `AuthApp`). Each mounts its own `ConfigProvider`. Extract a **shared theme/token module** (e.g. `src/frontend/theme.ts` + CSS variables in `styles.css`) and apply it in both entry trees so brand stays consistent without implying a single React tree. ```text theme.ts + styles.css (shared tokens) ├── Auth entry: ConfigProvider → I18nProvider → AuthApp └── Admin entry: ConfigProvider → I18nProvider → App └── AdminLayout (sider + header + content) └── pages (Dashboard, Domains, …) └── shared presentation components ``` ## Visual System (Tokens) ### Color | Role | Value | Usage | |------|-------|-------| | Primary | `#4F46E5` | Primary buttons, links, active nav accent | | Primary hover | `#4338CA` | Hover / pressed primary | | Primary soft | `#EEF2FF` | Soft fills, selected chips | | Ink / Sider | `#0F172A` | Sidebar background, primary text | | Text secondary | `#64748B` | Labels, helper text | | Text muted | `#94A3B8` | Meta / placeholders | | Canvas | `#F4F6FB` | App background | | Surface | `#FFFFFF` | Cards, header, auth form card | | Border | `#E2E8F0` | Dividers, card borders | | Success | `#16A34A` (+ soft green bg) | Healthy / accepted | | Warning | `#D97706` (+ soft amber bg) | Pending / DNS issues | | Danger | `#DC2626` (+ soft red bg) | Failed / destructive | ### Shape, Type, Space - **Radius:** controls `10px`, cards `14px`, pills `999px` - **Shadow:** light elevation — thin border + soft ambient (`0 1px 2px` + `0 8px 24px` slate-tinted) - **Spacing rhythm:** 8-based (`8 / 16 / 24 / 32`); content padding `24–32px` - **Type scale:** page title `22–24px`, metric value `28–32px`, body `14px` - **Font stack:** Inter preferred, with system-ui / -apple-system / Segoe UI fallbacks - **Inter loading:** prefer **system stack only** or **self-hosted** font files if Inter is added later; avoid third-party CDN font loads for self-hosted deploy reliability. Default implementation may use system-ui stack without shipping Inter files. ### Ant Design Theme Mapping Map tokens into `ConfigProvider` at least for: - `colorPrimary`, `colorSuccess`, `colorWarning`, `colorError` - `colorBgLayout`, `colorBgContainer`, `colorBorderSecondary`, `colorText`, `colorTextSecondary` - `borderRadius`, `borderRadiusLG` - Component overrides for `Card`, `Table` (comfortable cell padding), `Button`, `Menu` (sider), `Tag` or custom StatusPill preference Default Ant blue `#1677ff` must not remain as brand primary. ## Shell Design ### AdminLayout - Sticky dark sider width **248px**, background ink `#0F172A` - Brand block: gradient MH mark + title `MailHub` + subtitle `Email Delivery` - Navigation **groups** (labels only; routes unchanged): - **Overview** — Dashboard, Domains, DNS API - **Delivery** — SMTP, API Tokens, Sending Logs, Webhooks - **System** — Admin (admin role only), Settings - Active item: primary-soft indigo wash + light text (custom sider styles; avoid stock dark-menu look) - Header: white surface, border bottom, page title / breadcrumb, language select, refresh, primary CTA **Add domain**, user dropdown - Content: canvas background, comfortable padding - Responsive: below `lg`, collapse sider to drawer-style behavior (existing Ant Layout breakpoint pattern) - Optional light account summary at sider bottom is allowed; primary account actions stay in header dropdown ### Auth (Login / Register / Forgot / Reset / Resend) - Same tokens as admin - Desktop split: - **Left:** ink brand panel — logo, headline, short value prop, 2–3 capability signals - **Right:** soft canvas/indigo wash + elevated white form card - Mobile: single column; brand panel compressed on top - Keep existing auth modes and API calls; restyle forms, alerts, segmented control, and spacing only ## Shared Presentation Components | Component | Responsibility | |-----------|----------------| | `PageHeader` | Title, optional subtitle/description, right-side actions (one primary action per region) | | `MetricCard` | Label, large value, optional trend pill / soft icon tile | | `SectionCard` | Standard content card (14px radius, light shadow, consistent header/body padding) | | `StatusPill` | Semantic soft status chip (success / warning / error / info / neutral) | | `EmptyState` | Icon, message, optional primary CTA for empty lists/charts | | `CodeBlock` | Mono, wrap-safe long values (DNS/token samples) with copy affordance | Prefer placing these under `src/components/common/` (or equivalent) and reusing across pages. Existing `StatusTag` may be adapted into or replaced by `StatusPill` for visual consistency. ## Key Page Treatments ### Dashboard - Keep security alert (default admin password) at top when applicable - Condense the metric strip to **exactly four primary MetricCards**: 1. **今日发送** (today sent) 2. **成功率** (success rate) 3. **已验证域名** (verified domains) 4. **DNS 问题** (DNS issues count) - Place remaining current summary fields as secondary, not equal-weight cards: - **Bounce rate / complaint rate** — show as captions or mini stats under success-rate card, or in status distribution context - **Last sent at** — meta line under recent-sends SectionCard header or toolbar - **SMTP status** — compact readiness chip in PageHeader extra area or a small readiness row above charts - Chart row: trend + status distribution in SectionCards; recolor plots to token palette - **Retain existing secondary panels** (domain ranking, hourly heatmap, domain health list / recent failures if present) — restyle with SectionCard chrome; do not drop them from the layout inventory - Recent sends table inside SectionCard - No analytics model API changes ### Domains list - PageHeader + toolbar (search, status filter, add domain) - Table inside SectionCard; domain name as emphasized link control - Status via StatusPill; comfortable row padding ### Domain detail - Upgrade `DomainHealthCard` to a **hero block**: domain title, status pill, key stats, DNS progress, primary action stack (apply DNS / check / test / edit) - Tabs and two-column DNS records layout remain - DNS record cards use CodeBlock + StatusPill + consistent action buttons - No change to DNS apply/check/test flows ### Other pages (SMTP, Tokens, Logs, DNS API, Settings, Admin, Webhooks placeholder) - Apply PageHeader + SectionCard + table/form spacing polish - Do not redesign information architecture or form field sets beyond visual hierarchy - Token create modal / secret-once warning keeps existing behavior with improved visual emphasis ## Engineering Boundaries ### In scope files (expected) - `src/frontend/App.tsx` — theme provider tokens - `src/frontend/styles.css` — CSS variables + shell/page styles - `src/frontend/auth/AuthApp.tsx` (+ auth-related styles) - `src/layouts/AdminLayout.tsx` - `src/components/common/*` (new or updated shared UI) - `src/components/domain/*` (visual structure only) - `src/pages/**` (composition / classNames / shared components; handlers stay) ### Out of scope - `src/server.js`, `src/db.js`, mailer/submission/DNS provider logic - Model pure functions unless a pure presentation helper is needed - Docker / deploy scripts ### i18n - Reuse existing keys for page meaning - May add short chrome keys (nav group labels, empty-state titles) in both locales already supported by the app ### Testing & verification - Existing `npm test` suite must remain green (models, i18n, server APIs unchanged) - Add tests only if new pure helpers are introduced - Manual / build verification: `npm run build` (and UI smoke of login + dashboard + domain detail) ## Delivery Order 1. Design tokens (CSS vars + ConfigProvider) 2. AdminLayout shell + nav groups 3. Auth shell restyle 4. Shared presentation components 5. Dashboard 6. Domains list + domain detail / health / DNS cards 7. Remaining pages sweep 8. Build + test gate ## Success Criteria - Brand primary is indigo-based, not default Ant blue - Admin and auth feel like one product - Layout remains dark sidebar + comfortable density as approved - All existing navigation destinations and primary workflows remain reachable - No intentional API or auth behavior regressions - `npm test` and `npm run build` pass ## Open Questions None blocking. Optional later (explicitly out of this spec): dark mode, illustration pack, custom icon set beyond `@ant-design/icons`.