feat(serve): built-in web remote UI with live SSE updates - #5
pseudoshell wants to merge 7 commits into
Conversation
Serve a self-contained, zero-dependency web remote from torhunt serve. The shell (src/daemon/assets/ui.html) mirrors the TUI's Electric Cyan design language and works on desktop and mobile: add magnets or info hashes, watch live progress with per-torrent speed/peers/ETA, pause/resume/delete downloads, stop seeding, and browse the completed archive. Server side: new src/daemon/webui.ts holds the asset locator, the server-sent-event stream manager (initial snapshot + push-on-update + keepalive + self-cleanup), and an Origin-vs-Host cross-site guard for state-changing requests. serve.ts gains GET / and /ui (secretless HTML shell), token-authenticated GET /events (EventSource-friendly query-param token), and read-only GET /history; statusPayload now includes totalBytes/downloadedBytes/eta additively. The request handler is extracted into createServeHandler so tests can drive a real HTTP server against a fake runtime. The TUI is untouched. postbuild ships dist/ui.html beside the bundle; runServe delegates to the shared handler. 45 daemon tests pass (9 new webui unit tests, 10 new integration tests); full suite 348 green; typecheck clean.
The web remote could only accept magnets; searching still required the terminal. This wires the same source adapters the TUI uses into the headless server. New src/daemon/websearch.ts runs every source in parallel under one deadline (15s per source, matching the TUI hook), dedupes shared infoHashes keeping the healthiest row, orders seeders-first like the results view, caps the payload at 60 rows, and degrades unreachable sources to a per-source `failed` list instead of failing the request. serve.ts gains GET /search?q=&cat= (auth-protected, category validated against Games/Movies/TV/Anime), with both handleApi and createServeHandler taking an injectable search function so tests never touch the network. The web UI gets a Search tab as its default view: query input, category select, results with size/seeder/leecher/source metadata, and one-click Download buttons that enqueue via POST /add and flip to "Queued". Unreachable sources are reported inline in the status line. 9 new tests (6 websearch unit tests, 3 search API/integration); full suite 357 green; typecheck clean.
Three web remote polish fixes: - Font: load JetBrains Mono from Google Fonts (400/500/700, swap) with the previous ui-monospace stack kept as an offline fallback. - Background: the radial glow tiled every 1200x500px because background images repeat by default — scrolling showed duplicated glow blocks. The body backgrounds are now no-repeat and viewport-fixed, with a solid shade-deep fallback color beneath. Also theme-matched scrollbars (webkit + scrollbar-color). - Layout: long release names could push a row wider than its panel and clip the action buttons. row-top is now a contained flex box (min-width:0, max-width:100%, nowrap) with the name ellipsized inside it, and action buttons can neither grow nor force overflow (flex:none, wrap allowed as last resort). Completed-tab rows no longer show a misleading PAUSED chip; they get a neutral done chip.
The web remote leaned on emoji where it should have used real UI elements. All of them are gone: - The header bolt emoji is replaced by a geometric download-tray SVG mark inside the accent tile; the token gate drops its padlock; search results label seeders/leech in plain text instead of triangle glyphs; the queued button reads "Queued" instead of a check character. - Header: tighter type scale, uppercase letterspaced subtitle, and the connection indicator becomes a bordered pill that tints green when live. - Panels: titles gain a small glowing accent tick before the label. - Chips: subtle tinted backgrounds per state instead of bare outlines; stats use tabular numerals with smaller tracked labels. - Rows get a faint hover response; meters slim to 5px; tabs dim when inactive with hover feedback.
Complete visual rebuild of the web remote shell around a proper design token system instead of the TUI-derived neon theme. Same single file, same zero dependencies, same instant load. Tokens: shadcn-style zinc scale as CSS custom properties (--background, --foreground, --card, --muted, --border, --ring, --primary, semantic success/warning/destructive/blue), with full light and dark palettes. Theme follows prefers-color-scheme on first load, persists the user's explicit choice, and is applied pre-paint by an inline head script so there is no flash. A header icon button toggles sun/moon. Components, hand-rolled in the same idiom: hairline-bordered cards with xs shadows and section headers with live counts; solid high-contrast primary buttons plus outline/small/destructive variants (destructive keeps its two-step confirm); segmented control tabs; badge component with dot + tinted variants per status; 5px progress meters that fill with foreground and turn red on failure; focused inputs with ring shadows; inverted toast; centered modal for the token gate. Typography: Geist sans for UI, JetBrains Mono kept only where monospace is meaningful (the magnet input, source tags). Tabular numerals on all counters. Structure: search card and quick-add card always visible up top; Downloads/Seeding/Completed switch below via the segmented tabs. All existing behavior is preserved — SSE with polling fallback, token gate, search with categories, one-click download, pause/resume/delete, stop-seed, history.
The web remote no longer invents its own light/dark themes, and the category filter no longer falls back to the browser's native select. Theme mirroring: /health now reports the configured TUI theme (id, name, full palette) read fresh from disk on every call, so a theme switched in the terminal reaches a running daemon without a restart. The web shell polls /health every few seconds and, on change, maps the theme's palette onto its design tokens: shade -> background, text -> foreground, rule -> borders, accent -> primary/ring, good/warn/bad -> semantic colors, sprout -> info. Derived surfaces (card, muted, glass) are computed by mixing the theme colors, so all ten TUI themes render coherently through the same shadcn-style components. The static fallback palette in the stylesheet mirrors Electric Cyan. The sun/moon toggle and its localStorage theme are removed — the terminal is the source of truth. Category dropdown: replaced the native select with a custom listbox matching the design system — bordered trigger button with rotating chevron, floating menu card with hover rows, a glowing accent dot on the selected option, outside-click and Escape to dismiss, and correct listbox/option ARIA attributes.
The shadcn re-skin had switched body text to Geist; restore JetBrains Mono as the single UI typeface (400/500/600/700), dropping the unused Geist download. Base size steps down to 12.5px to balance mono glyph width.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
vu1nz Security Review0 finding(s) in PR #? No security issues found. |
ThreatCrush Security Scan0 finding(s) No findings. |
No description provided.