Files
tessera/docs/web-redesign-spec.md

5.9 KiB

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