Files
GMW/docs/superpowers/specs/2026-07-05-frontend-overhaul-design.md
T

16 KiB
Raw Blame History

Frontend Overhaul — IMPHNEN Dashboard

Date: 2026-07-05 Status: Spec (approved design, pre-implementation)


1. Goals

  1. Visual redesign — Elevate the dashboard from "functional prototype" to "premium monitoring tool" using the Neuform-inspired dark design language (AeroNet, Nexus Capital, Summit references from design/).
  2. Code restructure — Split oversized files, modularize CSS, eliminate inline styles, and add consistent state handling across all components.

2. Scope

Two sequential phases, both targeting the Leptos 0.9.0-alpha WASM frontend at services/frontend/frontend/.

Phase Focus Deliverables
Fase 1 Code Restructure File splits, CSS modules, inline→classes, state consistency
Fase 2 Visual Redesign Palette, layout, all panels, UI primitives

3. File Splitting (Fase 1)

3.1 message_card.rs (453 lines → 4 files)

New file Content Lines (est.)
message_card.rs Main component — card layout orchestration ~100
message_embed.rs Discord embed rendering (title, fields, images, footer) ~120
message_meta.rs Author row, timestamp, channel badge, AI status chip ~100
message_actions.rs Reanalyze button, moderate action, expand/collapse ~80

3.2 messages/mod.rs (397 lines → 3 files)

New file Content Lines (est.)
mod.rs Panel orchestrator — wires FilterBar + MessageList ~60
filter_bar.rs Channel picker, search input, status filter chips, live count ~150
message_list.rs Infinite scroll logic, pagination, skeleton/empty/error states ~180

3.3 ws/socket.rs (227 lines → 2 files)

New file Content Lines (est.)
connection.rs WebSocket lifecycle (connect, reconnect, heartbeat, close) ~120
handlers.rs Event dispatch — maps WS event types to signal updates ~100

3.4 Dashboard (dashboard/mod.rs, 276 lines)

Already well-split (stats_overview.rs, channel_summary_list.rs, user_summary_list.rs are separate). Extract orchestrator wiring from mod.rs into a focused panel component. No further splitting needed.


4. CSS Architecture (Fase 1)

4.1 File Structure

src/styles/
├── main.css          @import hub — imported by index.html
├── tokens.css        CSS custom properties (dark + light)
├── reset.css         Reset, base elements, scrollbar, selection
├── utilities.css     Utility classes (flex, gap, grid, w-full, etc.)
├── layout.css        App shell, sidebar, topbar, content area, mobile tab
├── ui.css            Button, card, input, select, modal, badge,
│                     skeleton, tabs, scroll area, toast, status badge
├── messages.css      Message card, feed, embed, image grid, filter bar
├── live.css          Voice connection, speakers, visualizer, mic meter,
│                     music player, screen share, recordings, waveform
├── dashboard.css     Stats overview, channel/user summary lists
└── polish.css        Particle background, theme toggle, mascot chatbot

4.2 Bundling

index.html links to src/styles/main.css. Trunk resolves @import statements and bundles into a single CSS file in the build output. Ordering is guaranteed by @import sequence.

4.3 Design Tokens (tokens.css)

Dark theme (default — :root without attribute selector)

:root {
  --surface-base: #050510;
  --surface-raised: #0a0a1a;
  --surface-overlay: #12122a;
  --surface-container: #1a1a35;
  --surface-border: rgba(255, 255, 255, 0.06);
  --surface-hover: rgba(59, 130, 246, 0.06);
  --surface-glass: rgba(5, 5, 16, 0.78);

  --text-primary: #f1f1f9;
  --text-secondary: #9d9db5;
  --text-tertiary: #5c5c78;
  --text-inverse: #050510;

  --color-primary: #3b82f6;
  --color-primary-hover: #60a5fa;
  --color-primary-active: #2563eb;
  --color-primary-muted: rgba(59, 130, 246, 0.12);
  --gradient-primary: linear-gradient(135deg, #3b82f6 0%, #6366f1 100%);
  --gradient-brand: linear-gradient(135deg, #3b82f6 0%, #5865f2 50%, #6366f1 100%);

  --color-success: #10b981;
  --color-warning: #f59e0b;
  --color-error: #ef4444;
  --color-info: #3b82f6;

  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35);
  --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.4);

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 23px;
  --radius-pill: 9999px;

  --sidebar-width: 240px;
  --header-height: 0px; /* header dihapus */
}

Light theme ([data-theme="light"])

[data-theme="light"] {
  --surface-base: #f4f6fb;
  --surface-raised: #ffffff;
  --surface-overlay: #eeeff4;
  --surface-container: #dde0e8;
  --surface-border: rgba(0, 0, 0, 0.06);
  --surface-hover: rgba(35, 161, 235, 0.05);
  --surface-glass: rgba(255, 255, 255, 0.72);

  --text-primary: #0f172a;
  --text-secondary: #475569;
  --text-tertiary: #94a3b8;
  --text-inverse: #ffffff;

  --color-primary: #2563eb;
  --color-primary-hover: #3b82f6;
  --color-primary-active: #1d4ed8;
  --color-primary-muted: rgba(37, 99, 235, 0.1);
  --gradient-primary: linear-gradient(135deg, #2563eb 0%, #6366f1 100%);
  --gradient-brand: linear-gradient(135deg, #2563eb 0%, #5865f2 50%, #6366f1 100%);

  /* reuse same semantic tokens */
  --color-success: #10b981;
  --color-warning: #f59e0b;
  --color-error: #ef4444;
  --color-info: #2563eb;

  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.04);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.06);
  --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.08);
}

5. Layout Architecture (Fase 2)

5.1 Current → Proposed

// Current (app.rs)
app-shell
├── app-header           (brand + ThemeToggle + WS status — redundant)
├── app-main
│   ├── app-sidebar     (TabButton × 3 — no icons, inline styles)
│   └── app-content     (tab panel)

// Proposed
app-shell
├── app-sidebar
│   ├── brand           (◉ IMPHNEN + "Guild Watcher" subtitle)
│   ├── nav             (3 items with lucide icons + active indicator)
│   └── footer          (WS status dot + compact ThemeToggle)
└── app-content
    └── tab-panel       (no header wrapper — full height)

5.2 Sidebar Specifics

  • Width: 240px, full viewport height, sticky/fixed
  • Brand area: 60px tall, logo placeholder (◉) + "IMPHNEN" bold + subtitle "Guild Watcher" (JetBrains Mono 11px)
  • Nav items: icon (lucide-leptos) + label, 40px tall, border-radius 10px on hover/active
    • Active state: 3px left border indicator + var(--surface-overlay) background
  • Footer: separated by a subtle divider, WS dot + status text + ThemeToggle icon-button
  • Mobile: sidebar collapses or slides overlay, MobileTabBar at bottom

5.3 Content Area

  • Full remaining width, scrollable, padding 24px (desktop)
  • Max-width 1400px for readability
  • No header at top — brand is in sidebar

6. Components Redesign (Fase 2)

6.1 Messages Panel

FilterBar:

  • Channel picker: <select> redesigned — card-style dropdown with active channel name displayed, chevron icon
  • Search: input with magnifying glass icon (lucide), compact height (36px)
  • Status chips: pill-style toggle buttons — "All", "Clean", "Warn", "Flagged", "Error" — active chip gets primary background
  • Live count: --text-tertiary label "X,XXX pesan" next to heading

MessageCard:

┌─────────────────────────────────────────────┐
│ @username · #channel · 12:34            ◉   │  ← meta row
├─────────────────────────────────────────────┤
│ Message content — Inter 14px,              │
│ line-height 1.5, wraps naturally           │
│                                             │
│ [Embed card-in-card]                        │
│ ┌───────────────────────────────────────┐   │
│ │ Embed title (semibold)                │   │
│ │ Embed description                     │   │
│ │ [thumbnail]                           │   │
│ └───────────────────────────────────────┘   │
├─────────────────────────────────────────────┤
│ ● Clean  98%   [⟳]  [⚙]                    │  ← actions bar
└─────────────────────────────────────────────┘
  • Card: surface-raised, border 1px solid border, radius --radius-md
  • Meta row: JetBrains Mono 12px, text-secondary
  • AI badge: chip dengan soft background (--color-primary-muted atau --color-success variant), 6px radius
  • Content: Inter 14px, max 6 lines with fade gradient overflow
  • Actions bar: icon-only buttons, visible always (not on hover)
  • Timestamp: relative (baru dimodalin — "2m ago", "1h ago")
  • Shadow: --shadow-sm

States:

State Component
Loading 3-5 skeleton cards, each with pulse animation (gradient shimmer)
Empty Icon + "Belum ada pesan" + "Coba ubah filter atau channel"
Error Error icon + error message + "Coba lagi" button
Success Normal message list

6.2 Live Panel (Bento Grid)

2-column grid with gap: --space-4:

┌──────────────────────┬──────────────────────┐
│ VoiceConnectionCard  │ ActiveSpeakers        │
├──────────────────────┼──────────────────────┤
│ AudioVisualizer      │ MicLevelMeter         │
├──────────────────────┴──────────────────────┤
│ MusicPlayer (NowPlaying + controls)         │
├──────────────────────┬──────────────────────┤
│ ScreenSubPanel       │ RecordingsSubPanel    │
└──────────────────────┴──────────────────────┘

VoiceConnectionCard:

  • Shows channel name, connection status (dot + text), connect/disconnect button
  • States: disconnected (picker CTA), connecting (pulse), connected (info)

AudioVisualizer + MicLevelMeter:

  • Canvas 2D with glass card background
  • Waveform rendering yang lebih smooth

NowPlaying / MusicPlayer:

  • Track info (thumbnail/icon + title + artist)
  • Progress bar + time
  • Controls: prev/play-pause/next + volume + stop

States:

State Display
No voice connected CTA card: "Connect to a voice channel" with guild/channel picker
Connecting Animated pulse on status indicator
Connected, no speakers Empty state: "Waiting for speakers..."
Music idle "No track playing" + queue button
All normal Full grid

6.3 Dashboard Panel

StatsOverview (4-column grid):

┌──────────┬──────────┬──────────┬──────────┐
│ Metrics  │ Metrics  │ Metrics  │ Metrics  │
│ 12,458   │ 3,201    │ 89       │ 24       │
│ Messages │ Users    │ Channels │ Flagged  │
│ +12%     │ Active   │ Total    │ ↑3      │
└──────────┴──────────┴──────────┴──────────┘
  • Each stat card: 140px tall, number in JetBrains Mono 28px bold, label in Inter 12px secondary, trend line in 11px
  • Trend: green for positive/neutral, red for negative

ChannelSummaryList / UserSummaryList:

  • Row cards (border-bottom yang subtle, hover background)
  • Channel: # icon + name + message count + last active tooltip
  • User: avatar initial circle + username + message count + trust score badge
  • Loading: 5 skeleton rows
  • Empty: "Belum ada data"

7. UI Primitives Upgrade (Fase 2)

Component Upgrade
Button Pill radius (--radius-pill), icon slot via children, loading spinner overlay, hover lift (translateY -1px + shadow-md), variants: primary/ghost/destructive/icon
Card --radius-md, border 1px solid border, shadow-sm, optional interactive hover (shadow-md + border-primary)
Badge --radius-sm, soft background (opacity variant), compact padding 4px 8px
Skeleton Gradient shimmer (base → highlight → base sliding), --radius-sm
Modal Backdrop blur (8px), enter transition (scale 0.95→1 + fade), exit reverse
Input --radius-sm, focus ring 2px --color-primary + subtle glow, border 1px solid border → primary on focus
Select Same as input, custom chevron icon
Toast Fixed bottom-right, enter slide-in right, progress bar for auto-dismiss, variants: success/error/info
Tabs Underline indicator (2px primary), no fill

8. State Handling Convention

Every data-fetching component MUST handle these four states:

// Pattern (pseudocode)
match loading, data, error {
    (true, _, _) => render_skeleton(),
    (false, Some(data), _) => render_success(data),
    (false, None, Some(err)) => render_error(err, retry_fn),
    (false, None, None) => render_empty(empty_msg, icon),
}

List of components requiring state audit:

  • MessageList (messages) — skeleton needed, empty/error exist?
  • VoiceConnectionCard (live) — exists partially
  • ActiveSpeakers (live) — empty state needed
  • RecordingsSubPanel (live) — loading/empty needed
  • MusicSubPanel (live) — idle/loading needed
  • StatsOverview (dashboard) — skeleton needed
  • ChannelSummaryList (dashboard) — loading/empty needed
  • UserSummaryList (dashboard) — loading/empty needed
  • ImageGrid (messages) — loading/empty needed
  • MascotChatbot (polish) — loading needed

9. Inline Styles → CSS Classes (Fase 1)

Files with style= props that must be extracted:

File Inline styles Action
sidebar.rs style:width, style:background, style:color on NavItem Extract to .sidebar, .nav-item, .nav-item.is-active
header.rs (being removed) style: for header layout, status dot Style moves to layout.css
mobile_tab_bar.rs style:color, flex on buttons Extract to .mobile-tab-bar, .mobile-tab-item
auth.rs Inline button style, close button Extract to .auth-box, .auth-close-btn

10. Implementation Order

Fase 1 — Code Restructure (dilakukan duluan biar Fase 2 punya fondasi bersih)

  1. CSS modular: buat src/styles/ dan pindahkan CSS dari app.css
  2. File splitting: message_card.rs → 4 files, messages/mod.rs → 3 files, ws/socket.rs → 2 files
  3. Inline style → CSS classes: sidebar, mobile_tab_bar, auth
  4. State audit: tambah loading/empty/error states ke komponen yang kurang
  5. Dead code cleanup, verify build still works

Fase 2 — Visual Redesign

  1. Update design tokens (tokens.css) — new palette, dark default
  2. Layout restructure: hapus header, rebuild sidebar as primary nav
  3. UI primitives upgrade (button, card, modal, etc.)
  4. Messages Panel redesign (FilterBar, MessageCard)
  5. Live Panel redesign (bento grid)
  6. Dashboard Panel redesign (stat cards, row lists)
  7. Polish: transitions, micro-interactions, responsive

11. Out of Scope

  • Leptos version upgrade (staying on 0.9.0-alpha)
  • New features or panels (pure overhaul of existing surface)
  • Backend changes
  • Performance optimization beyond CSS/rendering
  • Test coverage (separate effort)