# 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) ```css :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"]`) ```css [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:** `