docs: full specs for automation engine, sender policy, activity log, privacy monitor, UI overhaul
Clean.Email-parity feature build-out plus a Stripe/Notion-style UI rebuild on Tailwind + shadcn-style primitives. Locks the hybrid-automation, Gmail-only, light+dark, incremental-rollout decisions and lays out the backend/frontend build sequence. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
# Spec: UI Overhaul — Stripe/Notion aesthetic, Tailwind + shadcn-style, light+dark
|
||||
|
||||
A full visual rebuild: clean, airy, modern, light-first with a polished dark mode.
|
||||
Rolled out **incrementally** — design system first, then page-by-page — so the app
|
||||
keeps working throughout.
|
||||
|
||||
## 1. Stack
|
||||
|
||||
Add to `frontend`:
|
||||
|
||||
- **tailwindcss** (+ `postcss`, `autoprefixer`) — utility styling.
|
||||
- **Radix UI primitives** (`@radix-ui/react-*`: dialog, dropdown-menu, tabs, tooltip,
|
||||
switch, popover, toast, separator, scroll-area) — accessible behavior.
|
||||
- **class-variance-authority** + **tailwind-merge** + **clsx** — the shadcn component pattern.
|
||||
- **lucide-react** — icon set (clean, consistent; replaces ad-hoc emoji where it helps).
|
||||
|
||||
Config:
|
||||
- `tailwind.config.js` — content globs over `index.html` + `src/**/*.{js,jsx}`; theme
|
||||
extends map to CSS variables (below); `darkMode: 'class'`.
|
||||
- `postcss.config.js`. A `src/index.css` with `@tailwind base/components/utilities` +
|
||||
the token `:root` / `.dark` blocks. Keep the old `styles.css` importing until a page is
|
||||
migrated, then drop per-page.
|
||||
|
||||
## 2. Design tokens (CSS variables, HSL)
|
||||
|
||||
Defined once in `src/index.css`; Tailwind theme references them so `bg-background`,
|
||||
`text-foreground`, `bg-primary`, etc. just work and flip with `.dark`.
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Neutrals — warm-tinted slate (Notion-ish paper) */
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222 22% 12%;
|
||||
--card: 0 0% 100%;
|
||||
--muted: 220 16% 96%;
|
||||
--muted-foreground: 220 9% 46%;
|
||||
--border: 220 16% 90%;
|
||||
--input: 220 16% 90%;
|
||||
--ring: 245 75% 60%;
|
||||
|
||||
/* Brand accent — indigo/iris (modern SaaS, Stripe-blurple cousin) */
|
||||
--primary: 245 75% 59%; /* #5b5bf0-ish */
|
||||
--primary-foreground: 0 0% 100%;
|
||||
|
||||
/* Semantic */
|
||||
--success: 152 56% 40%;
|
||||
--warning: 38 92% 50%;
|
||||
--danger: 0 72% 51%;
|
||||
--danger-foreground: 0 0% 100%;
|
||||
|
||||
--radius: 0.625rem; /* soft, modern corners */
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 224 32% 9%; /* deep slate, not pure black */
|
||||
--foreground: 220 18% 92%;
|
||||
--card: 224 28% 12%;
|
||||
--muted: 223 22% 17%;
|
||||
--muted-foreground: 220 12% 64%;
|
||||
--border: 223 20% 20%;
|
||||
--input: 223 20% 22%;
|
||||
--ring: 245 80% 66%;
|
||||
--primary: 245 80% 67%;
|
||||
--primary-foreground: 224 32% 9%;
|
||||
--success: 152 50% 50%;
|
||||
--warning: 38 92% 58%;
|
||||
--danger: 0 70% 60%;
|
||||
}
|
||||
```
|
||||
|
||||
### Proposed palette (for sign-off)
|
||||
|
||||
| Token | Light | Dark | Use |
|
||||
|-------|-------|------|-----|
|
||||
| Primary (accent) | **Indigo `#5b5bf0`** | `#7c7cf5` | buttons, links, active nav, focus ring |
|
||||
| Background | `#ffffff` | `#11151f` | app canvas |
|
||||
| Card/surface | `#ffffff` | `#161b27` | panels, cards |
|
||||
| Muted surface | `#f3f5f9` | `#1f2533` | subtle fills, hover |
|
||||
| Border | `#e3e8ef` | `#2b3242` | hairlines |
|
||||
| Text | `#191e2b` | `#e7eaf2` | body |
|
||||
| Muted text | `#6b7280` | `#9aa3b2` | secondary |
|
||||
| Success | `#2f9e6b` | `#3dbd86` | healthy, succeeded |
|
||||
| Warning | `#f5a623` | `#f7b84b` | caution, pending |
|
||||
| Danger | `#e23b3b` | `#ef5a5a` | destructive, failed |
|
||||
|
||||
> **Alternatives if indigo isn't your taste** (pick one and I'll swap the single token):
|
||||
> Emerald `#10b981` (calm, "clean"), Violet `#7c3aed` (premium), Teal `#0d9488` (fresh),
|
||||
> Blue `#2563eb` (classic/trustworthy). Logo stays as-is; accent just needs to sit well beside it.
|
||||
|
||||
## 3. Component library (`src/components/ui/`)
|
||||
|
||||
Hand-built shadcn-style primitives, each a thin `cva` wrapper over Tailwind + (where
|
||||
interactive) a Radix primitive:
|
||||
|
||||
`button`, `card`, `input`, `textarea`, `select`, `checkbox`, `switch`, `badge`,
|
||||
`dialog`, `sheet` (side drawer), `dropdown-menu`, `tabs`, `tooltip`, `toast` (+ a
|
||||
`useToast` hook to replace ad-hoc toast state), `table`, `skeleton`, `separator`,
|
||||
`avatar`, `empty-state`.
|
||||
|
||||
Plus app-level shells: `PageHeader`, `Sidebar`, `Topbar`, `StatCard`,
|
||||
`ThemeToggle` (writes `.dark` on `<html>`, persists to `localStorage`).
|
||||
|
||||
## 4. Layout language
|
||||
|
||||
- **Sidebar**: 248px, `bg-card`, hairline border, grouped nav with section labels
|
||||
(Overview · Cleanup · Automation · Account). Lucide icons. Active item = soft primary
|
||||
tint pill. Collapsible to icon-rail on narrow widths.
|
||||
- **Topbar**: page title + breadcrumbs left; sync status, theme toggle, digest toggle,
|
||||
pending-review badge, "Sync now", avatar right. Sticky, subtle bottom border.
|
||||
- **Content**: max-width container, generous padding (`p-6`/`p-8`), cards with
|
||||
`rounded-[--radius]`, `border`, soft shadow (`shadow-sm`), 16–24px gaps.
|
||||
- **Density**: comfortable default; tables get a compact variant for big lists.
|
||||
- **Motion**: 150–200ms ease transitions on hover/expand; Radix-driven enter/exit on
|
||||
dialogs/sheets/toasts. Respect `prefers-reduced-motion`.
|
||||
|
||||
## 5. Page-by-page migration map
|
||||
|
||||
| Order | Page | Notes |
|
||||
|-------|------|-------|
|
||||
| 0 | **Tooling + tokens + primitives** | no visual swap yet; build the system |
|
||||
| 1 | **App shell** (`Layout.jsx`) | sidebar + topbar + theme toggle — biggest immediate lift |
|
||||
| 2 | **Dashboard** | StatCards, chart cards restyled (keep chart.js, theme its colors via tokens) |
|
||||
| 3 | **Senders** | list/detail split, new email rows, policy dropdown (ties to sender-policy spec) |
|
||||
| 4 | **Unsubscribe** | table → new `table` primitive, confidence as colored `badge`/meter |
|
||||
| 5 | **Search / Folders / Cleanup** | shared list components, filter bar, bulk toolbar restyle |
|
||||
| 6 | **New feature pages** | Rules, Review queue, Screener, Activity, Privacy, Read-Later — built native |
|
||||
| 7 | **Landing** | polish to match the new system |
|
||||
| 8 | **Retire `styles.css`** | delete once nothing imports it |
|
||||
|
||||
Each increment: convert the page, verify `npm run build`, screenshot/sanity-check, commit.
|
||||
|
||||
## 6. Accessibility & quality bar
|
||||
|
||||
- Radix primitives give focus management, ESC/overlay behavior, ARIA for free — don't
|
||||
hand-roll dialogs/menus.
|
||||
- Visible focus ring (`--ring`) on all interactive elements.
|
||||
- Color is never the only signal (icons/labels alongside semantic colors).
|
||||
- Contrast ≥ WCAG AA in both themes for text and primary buttons.
|
||||
- Keyboard shortcuts (already present) preserved and surfaced in a `?` cheat-sheet dialog.
|
||||
|
||||
## 7. Out of scope
|
||||
|
||||
- No logo redesign (keeping current `Logo.jsx`).
|
||||
- No mobile-dedicated layouts beyond responsive degradation (desktop-first decision).
|
||||
- No new charting library (theme the existing chart.js).
|
||||
Reference in New Issue
Block a user