feat(frontend): redesign Electron app UI with a clean Lucide-icon system#156
feat(frontend): redesign Electron app UI with a clean Lucide-icon system#156ashish921998 wants to merge 1 commit into
Conversation
Rework the placeholder Electron shell into a clean, minimal Codex-style desktop UI. The single-file renderer (src/main.ts) builds the whole HTML/CSS/JS, so this rewrites only the three render functions; the data model and Electron lifecycle are untouched. - Replace every placeholder glyph (folder, sidebar toggle, search, the literal "S" settings icon, stop, close, chevron) with real inlined Lucide SVGs via a small icon registry + icon() helper at a uniform 1.75 stroke. No more programmer-art glyphs. - Lock a cool-neutral zinc palette, semantic green/amber/red status, a near-black primary button, and one documented radius scale. - Add per-worker status dots; long titles now ellipsize cleanly. - Drop dead cruft (invisible window-dot buttons) and dev-jargon copy leaking into the terminal placeholder text. - Drop Inter from the font stack in favor of the native SF Pro system. Fixes two layout bugs found while verifying the running app: - Sidebar worker labels were clipped (CSS grid min-width:auto); list tracks now use minmax(0, 1fr) so titles truncate and trailing status labels stay visible. - Settings modal overflowed its fixed-width <dialog>; the dialog now sizes to its content and width lives on each panel. Also exclude src/landing from the frontend tsconfig so the Electron shell typecheck/build do not pull in the separate Next.js landing app. Verified in the running app across the orchestrator, worker, new-task, and settings surfaces; npm run typecheck and npm run build pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR rewrites the Electron shell's three render functions (
Confidence Score: 3/5The UI and CSS changes are clean, but the new before-quit lifecycle handler can permanently trap the app if the native dialog ever rejects. The async before-quit handler calls event.preventDefault() synchronously then awaits confirmStopSessions() with no error handling. A dialog failure leaves the app stuck in an un-quittable state requiring a force-kill. The dead ipcMain registration and cycling worker-ID scheme are minor but warrant cleanup. frontend/src/main.ts — specifically the before-quit event handler and the ipcMain.handle registration Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant Renderer as Renderer (data: URL)
participant Main as main.ts (Main Process)
participant Electron as Electron / OS
User->>Renderer: Clicks New task
Renderer->>Renderer: openNewTask() modal.showModal()
User->>Renderer: Submits form
Renderer->>Renderer: createWorker() workspace.workers.unshift()
Renderer->>Renderer: renderWorkspaceList() + showWorker()
User->>Electron: Cmd+Q or window close
Electron->>Main: before-quit event
Main->>Main: event.preventDefault()
Main->>Electron: dialog.showMessageBox()
Electron-->>Main: response 0 or 1
alt User confirms
Main->>Main: "quitting = true"
Main->>Electron: app.quit()
else User cancels or dialog throws
Main-->>Electron: app stays open
end
Note over Main: ipcMain.handle registered but unreachable, no preload script
Reviews (1): Last reviewed commit: "feat(frontend): redesign Electron app UI..." | Re-trigger Greptile |
| app.on("before-quit", async (event) => { | ||
| if (quitting) return; | ||
| event.preventDefault(); | ||
| if (await confirmStopSessions()) { | ||
| quitting = true; | ||
| app.quit(); | ||
| } |
There was a problem hiding this comment.
Unhandled rejection in
before-quit leaves app permanently unquittable
event.preventDefault() fires synchronously, then confirmStopSessions() is awaited — but there is no try/catch. If dialog.showMessageBox ever rejects (e.g., dialog is destroyed mid-show, Electron internal error), the async handler silently swallows the rejection, app.quit() is never called, and quitting stays false. Every subsequent quit attempt hits the same path and fails identically, leaving the user unable to close the app without force-killing it.
| ipcMain.handle("app:confirm-stop-sessions", confirmStopSessions); | ||
| createWindow(); |
There was a problem hiding this comment.
The
"app:confirm-stop-sessions" IPC channel is registered but can never be invoked: contextIsolation: true is set and no preload script is configured, so the renderer has no access to ipcRenderer. The handler is dead code; confirmStopSessions is only actually exercised via the before-quit event handler.
| ipcMain.handle("app:confirm-stop-sessions", confirmStopSessions); | |
| createWindow(); | |
| createWindow(); |
| const agent = document.getElementById("task-agent").value; | ||
| const branch = document.getElementById("task-branch").value; | ||
| const prompt = promptBox.value.trim(); | ||
| const id = workspace.id.slice(0, 4) + "-" + agent.replace("-", "").slice(0, 5) + "-" + String(Date.now()).slice(-4); |
There was a problem hiding this comment.
Using
String(Date.now()).slice(-4) for ID uniqueness recycles every ~10 seconds (the last four decimal digits of the millisecond epoch roll over every 10,000 ms). Two workers created for the same workspace 10 seconds apart will get identical IDs, causing showWorker to silently select the wrong session after renderWorkspaceList re-renders.
| const id = workspace.id.slice(0, 4) + "-" + agent.replace("-", "").slice(0, 5) + "-" + String(Date.now()).slice(-4); | |
| const id = workspace.id.slice(0, 4) + "-" + agent.replace("-", "").slice(0, 5) + "-" + Math.random().toString(36).slice(2, 6); |
What
Redesigns the placeholder Electron desktop shell into a clean, minimal, Codex-style UI. All changes are in
frontend/src/main.ts— the single-file renderer that generates the entire HTML/CSS/JS. This rewrites only the three render functions (buildAppHTML,appCSS,appJS); the data model and Electron lifecycle are untouched (redesign → preserve).Why
The shell looked unfinished, primarily because every icon was a placeholder Unicode glyph (
▣folder,▥sidebar toggle,⌕search, a literalSfor settings,□stop,×close,›chevron). The goal was a clean, minimal desktop UI with real icons, matching the project's stated frontend direction.Changes
icon()helper at a uniform 1.75 stroke. Inlined as raw markup because the renderer runs from adata:URL with no bundler.--r-sm/md/lg).window-dotbuttons) and dev-jargon copy that was leaking into the terminal placeholder; droppedInterfrom the font stack in favor of native SF Pro.Bugs fixed (found while verifying the running app)
min-width: autoissue meant long worker titles never truncated, cutting off trailing labels like "Needs input" / "18m". Tracks now usegrid-template-columns: minmax(0, 1fr).<dialog>(latent in the original). The dialog now sizes to its content and width lives on each panel.Reviewer notes
frontend/tsconfig.jsonis included: it excludessrc/landingfrom the frontend TypeScript program so the Electron shell typecheck/build don't pull in the separate Next.js landing app. (This change predated the redesign in the working tree but is required fornpm run typecheck/buildto pass for the shell.)Verification
npm run typecheckandnpm run buildpass. Source audit confirms zero em-dashes and zero remaining glyph icons.🤖 Generated with Claude Code