docs: add gateway UI redesign implementation plan
10-task plan covering Tailwind migration, responsive mobile nav, and page-by-page rewrites with Inter font and modern dark theme. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,434 @@
|
||||
# Gateway UI Responsive Redesign — Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Redesign the Flynn gateway web frontend with Tailwind CSS, modern sans-serif typography, and swipeable mobile navigation optimized for dashboard monitoring.
|
||||
|
||||
**Architecture:** Replace the existing 1740-line `style.css` with Tailwind utility classes applied directly in JS page renderers. Add CSS scroll-snap horizontal navigation for mobile (<768px). Desktop keeps a refined sidebar. All changes are in `src/gateway/ui/` — vanilla JS, no build step.
|
||||
|
||||
**Tech Stack:** Tailwind CSS (CDN), Inter font (Google Fonts), vanilla JS ES modules.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Update HTML Shell and Add Dependencies
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/gateway/ui/index.html`
|
||||
- Modify: `src/gateway/ui/manifest.webmanifest`
|
||||
|
||||
**Step 1: Rewrite index.html with Tailwind CDN, fonts, and new shell structure**
|
||||
|
||||
Replace the entire file:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="theme-color" content="#09090b">
|
||||
<title>Flynn</title>
|
||||
<link rel="manifest" href="manifest.webmanifest">
|
||||
<link rel="icon" type="image/svg+xml" href="flynn-icon.svg">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||
mono: ['"JetBrains Mono"', '"Fira Code"', 'monospace'],
|
||||
},
|
||||
colors: {
|
||||
zinc: {
|
||||
950: '#09090b',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
</head>
|
||||
<body class="bg-zinc-950 text-zinc-50 font-sans antialiased h-screen w-screen overflow-hidden">
|
||||
<!-- Desktop: sidebar + content. Mobile: top bar + swipe pages -->
|
||||
<div id="app-shell" class="flex h-screen overflow-hidden">
|
||||
<!-- Sidebar (desktop/tablet only) -->
|
||||
<nav id="sidebar" class="hidden md:flex w-16 lg:w-56 flex-col bg-zinc-900 border-r border-zinc-800 shrink-0 transition-all">
|
||||
<div class="p-4 border-b border-zinc-800 flex items-center gap-2">
|
||||
<span class="text-blue-500 font-bold text-lg">Flynn</span>
|
||||
</div>
|
||||
<div class="flex-1 py-2">
|
||||
<a href="#/" class="nav-link flex items-center gap-3 px-4 py-2.5 text-zinc-400 hover:text-zinc-50 hover:bg-zinc-800 transition-colors border-l-2 border-transparent" data-page="dashboard">
|
||||
<span class="text-base w-5 text-center shrink-0">■</span>
|
||||
<span class="hidden lg:inline text-sm">Dashboard</span>
|
||||
</a>
|
||||
<a href="#/chat" class="nav-link flex items-center gap-3 px-4 py-2.5 text-zinc-400 hover:text-zinc-50 hover:bg-zinc-800 transition-colors border-l-2 border-transparent" data-page="chat">
|
||||
<span class="text-base w-5 text-center shrink-0">✉</span>
|
||||
<span class="hidden lg:inline text-sm">Chat</span>
|
||||
</a>
|
||||
<a href="#/sessions" class="nav-link flex items-center gap-3 px-4 py-2.5 text-zinc-400 hover:text-zinc-50 hover:bg-zinc-800 transition-colors border-l-2 border-transparent" data-page="sessions">
|
||||
<span class="text-base w-5 text-center shrink-0">☰</span>
|
||||
<span class="hidden lg:inline text-sm">Sessions</span>
|
||||
</a>
|
||||
<a href="#/usage" class="nav-link flex items-center gap-3 px-4 py-2.5 text-zinc-400 hover:text-zinc-50 hover:bg-zinc-800 transition-colors border-l-2 border-transparent" data-page="usage">
|
||||
<span class="text-base w-5 text-center shrink-0">★</span>
|
||||
<span class="hidden lg:inline text-sm">Usage</span>
|
||||
</a>
|
||||
<a href="#/settings" class="nav-link flex items-center gap-3 px-4 py-2.5 text-zinc-400 hover:text-zinc-50 hover:bg-zinc-800 transition-colors border-l-2 border-transparent" data-page="settings">
|
||||
<span class="text-base w-5 text-center shrink-0">⚙</span>
|
||||
<span class="hidden lg:inline text-sm">Settings</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="p-3 border-t border-zinc-800">
|
||||
<span id="conn-status" class="flex items-center gap-2 text-xs text-zinc-500">
|
||||
<span id="conn-dot" class="w-2 h-2 rounded-full bg-red-500 shrink-0"></span>
|
||||
<span id="conn-text" class="hidden lg:inline">Disconnected</span>
|
||||
</span>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Mobile top bar (shown below md) -->
|
||||
<div id="mobile-chrome" class="md:hidden fixed top-0 left-0 right-0 z-50 bg-zinc-900 border-b border-zinc-800">
|
||||
<div class="flex items-center justify-between px-4 h-12">
|
||||
<span class="text-blue-500 font-bold text-base">Flynn</span>
|
||||
<span id="conn-status-mobile" class="flex items-center gap-1.5 text-xs text-zinc-500">
|
||||
<span id="conn-dot-mobile" class="w-2 h-2 rounded-full bg-red-500 shrink-0"></span>
|
||||
</span>
|
||||
</div>
|
||||
<!-- Page pill indicator -->
|
||||
<div id="page-pills" class="flex justify-center gap-1 pb-2 px-4">
|
||||
<button class="page-pill px-2.5 py-1 text-xs rounded-full transition-colors bg-zinc-800 text-zinc-400" data-hash="#/">Dashboard</button>
|
||||
<button class="page-pill px-2.5 py-1 text-xs rounded-full transition-colors bg-zinc-800 text-zinc-400" data-hash="#/chat">Chat</button>
|
||||
<button class="page-pill px-2.5 py-1 text-xs rounded-full transition-colors bg-zinc-800 text-zinc-400" data-hash="#/sessions">Sessions</button>
|
||||
<button class="page-pill px-2.5 py-1 text-xs rounded-full transition-colors bg-zinc-800 text-zinc-400" data-hash="#/usage">Usage</button>
|
||||
<button class="page-pill px-2.5 py-1 text-xs rounded-full transition-colors bg-zinc-800 text-zinc-400" data-hash="#/settings">Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main content -->
|
||||
<main id="content" class="flex-1 overflow-y-auto md:p-6">
|
||||
<!-- Mobile: add top padding for fixed bar -->
|
||||
<!-- Pages rendered here by router -->
|
||||
</main>
|
||||
</div>
|
||||
<script type="module">
|
||||
import { registerPage, initRouter, initStatusIndicator } from './app.js';
|
||||
import { DashboardPage } from './pages/dashboard.js';
|
||||
import { ChatPage } from './pages/chat.js';
|
||||
import { SessionsPage } from './pages/sessions.js';
|
||||
import { UsagePage } from './pages/usage.js';
|
||||
import { SettingsPage } from './pages/settings.js';
|
||||
|
||||
registerPage('/', DashboardPage);
|
||||
registerPage('/chat', ChatPage);
|
||||
registerPage('/sessions', SessionsPage);
|
||||
registerPage('/usage', UsagePage);
|
||||
registerPage('/settings', SettingsPage);
|
||||
|
||||
initStatusIndicator();
|
||||
initRouter();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
**Step 2: Update manifest theme color**
|
||||
|
||||
In `manifest.webmanifest`, change `background_color` and `theme_color` to `#09090b`.
|
||||
|
||||
**Step 3: Verify build**
|
||||
|
||||
Run: `pnpm build`
|
||||
Expected: Clean build (UI files are just copied).
|
||||
|
||||
**Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add src/gateway/ui/index.html src/gateway/ui/manifest.webmanifest
|
||||
git commit -m "feat(gateway-ui): add Tailwind CDN, Inter font, responsive shell"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Replace style.css with Minimal Base
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/gateway/ui/style.css`
|
||||
|
||||
**Step 1: Replace style.css with minimal overrides**
|
||||
|
||||
Tailwind handles 90% of styling. Keep only: scrollbar customization, animations (spin, blink), hljs overrides, and a few component styles Tailwind can't cover (scroll-snap, streaming cursor).
|
||||
|
||||
Write a new `style.css` (~120 lines) that covers:
|
||||
- Custom scrollbar (webkit)
|
||||
- `@keyframes spin` and `@keyframes blink`
|
||||
- `.streaming-cursor::after` blinking cursor
|
||||
- `.tool-event-body` toggle (display none/block)
|
||||
- `.nav-link.active` state (since Tailwind can't do `[data-active]` easily in vanilla)
|
||||
- Code block overrides for hljs inside messages
|
||||
- Scroll-snap container for mobile swipe (future-proofed but not yet wired)
|
||||
- Any remaining custom utility classes not covered by Tailwind
|
||||
|
||||
**Step 2: Verify build**
|
||||
|
||||
Run: `pnpm build`
|
||||
Expected: Clean copy.
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add src/gateway/ui/style.css
|
||||
git commit -m "refactor(gateway-ui): replace monolithic CSS with Tailwind-compatible base"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Rewrite App Router for Responsive Navigation
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/gateway/ui/app.js`
|
||||
|
||||
**Step 1: Rewrite app.js**
|
||||
|
||||
The router needs to:
|
||||
- Keep hash-based routing
|
||||
- Update desktop sidebar active states using Tailwind classes (`bg-blue-500/10 text-blue-500 border-l-blue-500`)
|
||||
- Update mobile pill indicator (active pill gets `bg-blue-500 text-white`, others `bg-zinc-800 text-zinc-400`)
|
||||
- Add mobile top padding to content area when mobile chrome is visible
|
||||
- Wire pill click → `location.hash` navigation
|
||||
- Keep page lifecycle (teardown/render) identical
|
||||
|
||||
Connection status indicator needs to update both desktop and mobile elements.
|
||||
|
||||
**Step 2: Verify build**
|
||||
|
||||
Run: `pnpm build`
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add src/gateway/ui/app.js
|
||||
git commit -m "feat(gateway-ui): responsive router with mobile pill navigation"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Rewrite Dashboard Page with Tailwind
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/gateway/ui/pages/dashboard.js`
|
||||
|
||||
**Step 1: Rewrite all HTML template strings to use Tailwind classes**
|
||||
|
||||
Key changes:
|
||||
- Page title: `<h1 class="text-2xl font-semibold text-zinc-50 mb-6">`
|
||||
- Section titles: `<h2 class="text-lg font-semibold text-zinc-50 mb-4 mt-8 pb-2 border-b border-zinc-800">`
|
||||
- Stat cards: `<div class="bg-zinc-900 border border-zinc-800 rounded-lg p-4 hover:border-zinc-600 transition-colors">`
|
||||
- Stats grid: `<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4 mb-8">`
|
||||
- Section collapsible on mobile: wrap sections in `<details>` element with styled `<summary>` on small screens, open by default on desktop
|
||||
- Tables: Tailwind classes for `<table>`, `<th>`, `<td>` — horizontal scroll wrapper for mobile: `<div class="overflow-x-auto">`
|
||||
- Event stream: `<div class="max-h-72 overflow-y-auto bg-zinc-900 border border-zinc-800 rounded-lg p-2 font-mono text-xs">`
|
||||
- Service cards grid: responsive grid
|
||||
- Assistant health chips: compact grid with Tailwind
|
||||
- All stat values use `font-mono` for numbers
|
||||
|
||||
Keep all JS logic (fetching, timers, event handlers) identical. Only change the HTML template strings and class names.
|
||||
|
||||
**Step 2: Verify build**
|
||||
|
||||
Run: `pnpm build`
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add src/gateway/ui/pages/dashboard.js
|
||||
git commit -m "feat(gateway-ui): rewrite dashboard with Tailwind responsive layout"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Rewrite Chat Page with Tailwind
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/gateway/ui/pages/chat.js`
|
||||
|
||||
**Step 1: Rewrite all HTML template strings to use Tailwind classes**
|
||||
|
||||
Key changes:
|
||||
- Chat layout: `flex flex-col h-[calc(100vh-48px)] md:h-[calc(100vh-48px)] max-w-3xl`
|
||||
- Chat header: `flex items-center gap-3 pb-3 border-b border-zinc-800 mb-3 flex-wrap`
|
||||
- Messages container: `flex-1 overflow-y-auto flex flex-col gap-3 py-3`
|
||||
- User messages: `self-end bg-blue-500/15 border border-blue-500/25 rounded-lg px-3.5 py-2.5 max-w-[85%]`
|
||||
- Assistant messages: `self-start bg-zinc-900 border border-zinc-800 rounded-lg px-3.5 py-2.5 max-w-[85%]`
|
||||
- On mobile (<md): messages go full width `md:max-w-[85%]`
|
||||
- Chat input: `flex gap-2 pt-3 border-t border-zinc-800`
|
||||
- Textarea: Inter font, `bg-zinc-900 text-zinc-50 border border-zinc-800 rounded-lg px-3 py-2.5 text-sm focus:border-blue-500 outline-none resize-none`
|
||||
- Send button: `bg-blue-500 text-zinc-950 font-semibold px-4 py-2.5 rounded-lg hover:opacity-85 disabled:opacity-40`
|
||||
- Slash popup: `absolute bottom-full left-0 right-0 mb-1 bg-zinc-900 border border-zinc-800 rounded-lg max-h-60 overflow-y-auto z-50 shadow-lg`
|
||||
- Tool event groups: compact with Tailwind
|
||||
- Action buttons (search, attach): pill-shaped with Tailwind
|
||||
- Message actions (copy, edit): small icon buttons
|
||||
|
||||
Keep all JS logic identical.
|
||||
|
||||
**Step 2: Verify build**
|
||||
|
||||
Run: `pnpm build`
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add src/gateway/ui/pages/chat.js
|
||||
git commit -m "feat(gateway-ui): rewrite chat page with Tailwind responsive layout"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Rewrite Sessions Page with Tailwind
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/gateway/ui/pages/sessions.js`
|
||||
|
||||
**Step 1: Rewrite all HTML template strings to use Tailwind classes**
|
||||
|
||||
Key changes:
|
||||
- Desktop: table layout with horizontal scroll wrapper
|
||||
- Mobile: card-based layout using media query detection in JS (check `window.innerWidth < 768`)
|
||||
- Each session as a card: `bg-zinc-900 border border-zinc-800 rounded-lg p-4`
|
||||
- Session ID, frontend badge, message count, last activity in card
|
||||
- View/Delete buttons at bottom of card
|
||||
- Filter controls: `flex items-center gap-3 mb-4 flex-wrap`
|
||||
- Select: `bg-zinc-900 text-zinc-50 border border-zinc-800 rounded-lg px-3 py-1.5 text-sm`
|
||||
- Session detail view: card-based message history with scrollable container
|
||||
|
||||
**Step 2: Verify build**
|
||||
|
||||
Run: `pnpm build`
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add src/gateway/ui/pages/sessions.js
|
||||
git commit -m "feat(gateway-ui): rewrite sessions page with Tailwind card layout"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 7: Rewrite Usage Page with Tailwind
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/gateway/ui/pages/usage.js`
|
||||
|
||||
**Step 1: Rewrite all HTML template strings to use Tailwind classes**
|
||||
|
||||
Key changes:
|
||||
- Summary stats: horizontally scrollable strip on mobile (flex with overflow-x-auto, snap), grid on desktop
|
||||
- Per-session table: horizontal scroll wrapper, or stacked cards on mobile
|
||||
- Stats grid: `grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4`
|
||||
- Table: `overflow-x-auto` wrapper, standard Tailwind table classes
|
||||
- Refresh button: secondary button style
|
||||
|
||||
**Step 2: Verify build**
|
||||
|
||||
Run: `pnpm build`
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add src/gateway/ui/pages/usage.js
|
||||
git commit -m "feat(gateway-ui): rewrite usage page with Tailwind responsive layout"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 8: Rewrite Settings Page with Tailwind
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/gateway/ui/pages/settings.js`
|
||||
|
||||
**Step 1: Rewrite all HTML template strings to use Tailwind classes**
|
||||
|
||||
Key changes:
|
||||
- Each settings section in its own card: `bg-zinc-900 border border-zinc-800 rounded-lg p-4 md:p-6 mb-6`
|
||||
- Toggle switches: styled checkbox with label, `min-h-[44px]` touch target
|
||||
- Text inputs: `w-full bg-zinc-950 text-zinc-50 border border-zinc-800 rounded-lg px-3 py-2 text-sm focus:border-blue-500 outline-none`
|
||||
- Hook pattern textareas: same input styling but multi-line
|
||||
- Tool table: horizontal scroll wrapper
|
||||
- Services grid: responsive card grid
|
||||
- Config JSON view: `bg-zinc-950 border border-zinc-800 rounded-lg p-4 max-h-96 overflow-y-auto font-mono text-xs text-zinc-400`
|
||||
- Button styles: primary (`bg-blue-500 text-zinc-950`), secondary (`bg-zinc-800 text-zinc-50`), danger (`bg-red-500/15 text-red-500`)
|
||||
|
||||
**Step 2: Verify build**
|
||||
|
||||
Run: `pnpm build`
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add src/gateway/ui/pages/settings.js
|
||||
git commit -m "feat(gateway-ui): rewrite settings page with Tailwind form cards"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 9: Update Service Worker Cache Version
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/gateway/ui/sw.js`
|
||||
|
||||
**Step 1: Bump service worker cache name**
|
||||
|
||||
Change cache name from `flynn-webchat-v2` to `flynn-webchat-v3` so browsers pick up the new assets.
|
||||
|
||||
**Step 2: Commit**
|
||||
|
||||
```bash
|
||||
git add src/gateway/ui/sw.js
|
||||
git commit -m "chore(gateway-ui): bump service worker cache version for redesign"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 10: Final Build Verification and Cleanup
|
||||
|
||||
**Step 1: Run full build**
|
||||
|
||||
Run: `pnpm build`
|
||||
Expected: Clean build, no errors.
|
||||
|
||||
**Step 2: Run typecheck**
|
||||
|
||||
Run: `pnpm typecheck`
|
||||
Expected: No errors (UI files are plain JS, but ensure no regressions).
|
||||
|
||||
**Step 3: Run full test suite**
|
||||
|
||||
Run: `pnpm test:run`
|
||||
Expected: All tests pass (UI has no unit tests, but ensure nothing else broke).
|
||||
|
||||
**Step 4: Check the dist output**
|
||||
|
||||
Run: `ls dist/gateway/ui/` and verify all files present.
|
||||
|
||||
**Step 5: Commit any cleanup**
|
||||
|
||||
If any adjustments needed, commit them.
|
||||
|
||||
---
|
||||
|
||||
## Notes for Implementer
|
||||
|
||||
- **No TDD for this task** — UI files are vanilla JS with no existing test infrastructure. Verification is build + visual.
|
||||
- **Tailwind CDN** — The `cdn.tailwindcss.com` script is the Play CDN for development. It works without a build step but should not be used for production long-term. This is acceptable for now.
|
||||
- **Mobile padding** — The mobile top bar is `fixed`, so content needs `pt-[calc(3rem+2rem)]` (48px bar + 32px pills) top padding on mobile. Handle this in `app.js`.
|
||||
- **Preserve all business logic** — Only change HTML templates and CSS classes. Do not modify API calls, event handlers, data fetching, or page lifecycle management.
|
||||
- **`escapeHtml()` calls** — Keep all existing `escapeHtml()` calls. Security is unchanged.
|
||||
- **Font loading** — Inter is loaded from Google Fonts CDN. JetBrains Mono was already loaded by the browser for users who have it installed; no CDN needed (Tailwind `font-mono` falls back to system monospace).
|
||||
Reference in New Issue
Block a user