diff --git a/docs/web-redesign-spec.md b/docs/web-redesign-spec.md new file mode 100644 index 0000000..81bdddc --- /dev/null +++ b/docs/web-redesign-spec.md @@ -0,0 +1,121 @@ +Redesign the Tessera frontend completely. The current version is functional but has poor UX. This is a complete rewrite of the visual design and layout — keep the existing API client (web/src/lib/api.ts) and types (web/src/lib/types.ts), rewrite everything else. + +## DESIGN SYSTEM: Linear-inspired dark mode + +Use the exact design tokens from the Linear design system: +- Background: #08090a (canvas), #0f1011 (panels), #191a1b (cards) +- Text: #f7f8f8 (primary), #d0d6e0 (secondary), #8a8f98 (tertiary) +- Border: rgba(255,255,255,0.08) (standard), rgba(255,255,255,0.05) (subtle) +- Accent: #5e6ad2 (primary), #7170ff (interactive), #828fff (hover) +- Font: Inter (from next/font/google), weight 400/510/590 +- No pure white anywhere (#f7f8f8 is max brightness) +- No color besides indigo/violet accent and status colors + +Status colors: new=#8a8f98, open=#7170ff, in_progress=#f59e0b, resolved=#22c55e, closed=#6b7280 + +## PAGES TO REWRITE + +### 1. Layout (web/src/app/layout.tsx) +- Full-height app shell: sidebar + main content +- LEFT SIDEBAR (240px, fixed): + - "Tessera" brand at top (indigo gradient text or icon) + - Saved views section with counts: + - All tickets (count) + - My tickets (count) + - Unassigned (count) + - Recently updated (count) + - Queues section (dynamic list with counts) + - Bottom: Admin link (gear icon), user avatar placeholder +- Sidebar styling: bg-[#0f1011], border-r border-[rgba(255,255,255,0.05)] +- Active view: bg-[rgba(255,255,255,0.05)], text-white +- Inactive view: text-[#8a8f98] hover:text-[#d0d6e0] +- Each nav item: flex justify-between, icon + label left, count badge right + +### 2. Ticket List — the main view (web/src/app/page.tsx) +This is THE primary technician view. It must be fast and scannable. + +- TOP BAR: search input (full width, bg-[#0f1011], border-b), "New ticket" button (indigo) +- Below: filter chips row — "All", "Open", "In progress", "Resolved", "My tickets", "Unassigned" — clickable pills +- TICKET LIST (not a heavy data table — a sleek list): + - Each row: colored status dot (8px circle) + ticket ID (first 8 chars, monospace, muted) + subject (primary text) + queue badge + assignee avatar + relative time + - Hover: subtle bg change, show quick actions (assign, change status) + - Click: navigate to detail + - Loading: skeleton rows (pulsing bg-[#191a1b]) + - Empty: "No tickets match your filters" with illustration +- Bottom: "Load more" or pagination + +- CREATE TICKET DIALOG: modal with subject input + queue select + description textarea + submit + +### 3. Ticket Detail — two-panel layout (web/src/app/tickets/[id]/page.tsx) +This is the heart of the product. Conversation-centric. + +LAYOUT: +- LEFT (60%): Conversation thread + reply box +- RIGHT (40%): Properties sidebar + +CONVERSATION THREAD: +- Each entry is a message bubble, not a table row +- Customer messages: left-aligned, lighter bg +- Agent replies: right-aligned or indigo-tinted +- System events (status changes, assignments): centered, muted, small text, no bubble — inline timeline entries like "Gjermund changed status from open → in_progress · 2 minutes ago" +- Timestamps: relative (formatDistanceToNow from date-fns), absolute on hover +- Avatars: initials circle (first letter of name), colored by hash + +REPLY BOX (sticky at bottom of thread): +- Textarea with placeholder "Reply to this ticket..." +- Toggle: "Reply" (public) vs "Internal note" (private) — tab-like toggle +- Send button (indigo) + attachment button (paperclip icon, disabled for now) + +PROPERTIES SIDEBAR (right panel, bg-[#0f1011], border-l): +- Status selector: large, prominent dropdown with color indicator +- Priority: not yet implemented, show placeholder +- Assignee: dropdown to assign/change owner +- Queue: display name +- Custom fields: name: value pairs, editable inline +- Created/Updated: display dates + +STATUS CHANGE: +- Click status in sidebar → dropdown shows allowed transitions (from lifecycle) +- Selecting a new status shows preview of scrips that will fire (inline, not modal) +- Confirm button: "Apply — 2 scrips will fire" +- After apply: show scrip results inline (success/error with message) + +### 4. Admin (web/src/app/admin/page.tsx) +- Same sidebar layout (no changes) +- Content area: tabs across top (Queues, Lifecycles, Scrips, Custom Fields) +- Each tab: clean card-based layout, not data tables +- Add button in each section header +- Forms in slide-over sheets (from right), not dialogs — sheets feel more professional +- Delete/edit: subtle icon buttons on hover + +### 5. COMMAND PALETTE (new — web/src/components/command-palette.tsx) +- Trigger: Cmd+K or Ctrl+K +- Modal overlay with search input +- Actions: "New ticket", "Go to tickets", "Go to admin", search tickets by subject +- Keyboard navigation: arrow keys + enter +- Dimmed backdrop with bg-black/60 + +## IMPLEMENTATION NOTES + +- Keep web/src/lib/api.ts and web/src/lib/types.ts as-is (they work) +- Delete all current page files and rewrite from scratch +- Delete current layout.tsx, page.tsx, tickets/[id]/page.tsx, admin/page.tsx +- Install: bun add cmdk (command palette library) or build simple one with shadcn Dialog +- All shadcn/ui components import from @/components/ui/... — reuse what's there +- Sidebar needs to be a client component with state for active view +- Use next/navigation for routing +- Loading states: skeleton everywhere (not spinners) +- Error states: inline red text with retry +- Empty states: helpful text + action button + +## VERIFICATION +1. `cd web && bun run build` — zero TypeScript errors +2. Start backend on 9876, frontend on 3000-something +3. Verify: sidebar renders with saved views, ticket list shows real data, ticket detail has conversation thread + sidebar, admin has tabs in sheets +4. Commit each major section + +## RULES +- All code via OpenCode. Hermes orchestrates. +- Rewrite is complete — do not keep old components +- Linear design tokens must be used exactly — verify colors match spec +- No placeholders that look broken — every state must render properly