Skip to content

feat: Normal App mode, Settings UI tabs, Dev Hub sub-title#112

Merged
grimmerk merged 20 commits intomainfrom
feat/normal-app-mode
Apr 6, 2026
Merged

feat: Normal App mode, Settings UI tabs, Dev Hub sub-title#112
grimmerk merged 20 commits intomainfrom
feat/normal-app-mode

Conversation

@grimmerk
Copy link
Copy Markdown
Owner

@grimmerk grimmerk commented Apr 6, 2026

Summary

Add Normal App mode as an alternative to the current Menu Bar mode. New users default to Normal App mode for better discoverability.

Normal App mode

  • Window shows in Dock
  • No auto-hide on blur (stays visible)
  • Draggable via title bar
  • Cmd+Ctrl+R toggles show/hide (no minimize animation)
  • Window remembers position (not re-centered)
  • Shows immediately on app startup

Menu Bar mode (existing behavior)

  • Hidden from Dock
  • Auto-hide on blur
  • Centers on screen each time
  • Cmd+Ctrl+R toggles show/hide

Settings

  • App Mode: Normal App / Menu Bar (in General section)
  • Instant switching (no restart needed)
  • Switching to Menu Bar re-centers window

UI hints

  • Title bar: "CodeV Dev Hub" + mode indicator ("normal mode" / "menu bar mode") + actual shortcut key (right-aligned)
  • Banner on first launch (Normal mode) and on mode switch (auto-dismiss 5-6s)
  • Shortcut display syncs in real-time when changed in Settings
  • Clicking Dock icon shows hidden window in Normal mode

Settings UI redesign

  • 3 tabs: General / Sessions / Shortcuts (replaces single scrollable panel)
  • General: Launch at Login, App Mode, Left-Click (tray), Default Tab, Working Dir (projects/term), Launch Terminal (sessions), Launch Mode (tab/window), IDE (projects)
  • Sessions: Session Preview, Session Status (hooks)
  • Shortcuts: Global shortcuts (editable) + Tab Switching + Claude Session Launch (in Projects)
  • Context hints on settings that only affect specific tabs
  • Terminal renamed to Terminal.app in dropdown

Test plan

  • Normal mode: shows in Dock
  • Normal mode: no auto-hide on blur
  • Normal mode: draggable title bar
  • Normal mode: Cmd+Ctrl+R toggles hide/show (no animation)
  • Normal mode: window shows on startup
  • Normal mode: clicking Dock icon shows hidden window
  • Menu Bar mode: all existing behavior preserved
  • Switch Normal → Menu Bar: re-centers, drag disabled
  • Switch Menu Bar → Normal: drag enabled
  • Setting persists across restart
  • Title bar: Dev Hub + mode indicator + shortcut
  • Banner on mode switch (auto-dismiss)
  • Shortcut display syncs on save/reset
  • Settings tabs: General / Sessions / Shortcuts
  • No scrolling needed in any settings tab
  • Terminal.app in dropdown

Normal mode: what updates when unfocused (visible but not active)

Updates in real-time? Mechanism
Status dots (working/idle/needs-attention) Yes fs.watch on codev-status/
Final assistant message (blue text) Yes refreshSessionPreview() on idle
Final user message (amber text) Yes refreshSessionPreview() on idle
Session order (re-sort) Yes (idle-triggered only) refreshSessionPreview() updates lastTimestamp
New session appearing No Requires fetchClaudeSessions() (focus-triggered)
Session disappearing No Same
Full list re-fetch No Only on window re-focus

Known limitation: New sessions won't appear until the window is re-focused. This is a trade-off — continuous full refresh would cause visual noise (sessions jumping around). Could be improved by detecting new sessions via fs.watch without full refresh (follow-up).

🤖 On behalf of @grimmerk — generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Configurable App Mode (Normal/Menu Bar) with persistent selection, Dock visibility, mode banners, draggable title bar in Normal mode, and Cmd+Ctrl+R toggle
    • Redesigned Settings with tabs (General, Sessions, Shortcuts), reduced context switching, added hints, and reorganized shortcuts UI (includes quick-launch shortcut display and resume-on-tab-switch)
    • Minor UI tweaks: reduced title bar padding and renamed Terminal entry to “Terminal.app”
  • Documentation

    • README updated to document App Mode behavior and updated settings paths

grimmerk and others added 3 commits April 6, 2026 22:22
- App Mode setting: Normal App (default) / Menu Bar
- Normal mode: shows in Dock, no auto-hide on blur, window
  stays in place (draggable via title bar), minimize on hide
- Menu Bar mode: current behavior (hidden dock, auto-hide,
  center on show)
- Instant switching via IPC (no restart needed)
- Title bar uses -webkit-app-region: drag for frameless window

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Normal mode: show window immediately on app start
- Cmd+Ctrl+R in normal mode: only show+focus (no hide/minimize)
- Drag region only active in normal mode (fixes menu bar mode
  being draggable then snapping back)
- Send app-mode-changed IPC to renderer for dynamic drag toggle

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Switching to menu bar mode immediately re-centers window
- Normal mode shortcut uses hide() not minimize() (no animation)
- Shortcut toggles hide/show in both modes (restored from
  focus-only to full toggle)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e5db861e-eb61-4116-aa15-a4863547bd30

📥 Commits

Reviewing files that changed from the base of the PR and between 50d4bf0 and 5a16167.

📒 Files selected for processing (1)
  • README.md

📝 Walkthrough

Walkthrough

Adds a persisted App Mode (normal | menubar) with IPC get/set and notifications, moves Dock/show/hide logic into init and mode switch handlers, redesigns Settings into General/Sessions/Shortcuts tabs (adds App Mode control), and surfaces mode banners and shortcut display in the switcher UI.

Changes

Cohort / File(s) Summary
Version & Changelog
CHANGELOG.md, package.json
Bumped version to 1.0.70 and added ## 1.0.70 entries describing Normal App mode behaviors, Settings UI redesign, and styling/title tweaks.
IPC Surface & Preload
src/electron-api.d.ts, src/preload.ts
Extended electron API with getAppMode(), setAppMode(mode), onAppModeChanged(), and onShortcutsUpdated(); exposed corresponding ipcRenderer handlers in preload.
Main Process / App State
src/main.ts
Introduced persisted appMode state; added ipcMain.handle('get-app-mode') and ipcMain.on('set-app-mode'); moved Dock hide/show into async init and mode switch handling; adjusted switcher show/blur/minimize logic and emits app-mode-changed / shortcuts-updated.
Settings UI (popup)
src/popup.tsx
Reworked settings into tabbed panels (General/Sessions/Shortcuts); added appModeState bound to getAppMode/setAppMode; changed session and shortcut controls and resume-on-tab-change shortcut behavior.
Switcher UI & Header
src/switcher-ui.tsx
Added currentAppMode, dismissible mode banners, quick-switcher shortcut display, and subscriptions to app-mode/shortcut events; conditional header drag region and padding adjustments.
Docs
README.md
Documented new App Mode behaviors, Normal vs Menu Bar differences, and updated setting path references and refresh behavior notes.

Sequence Diagram

sequenceDiagram
    actor User
    participant Renderer as Renderer (popup.tsx / switcher-ui.tsx)
    participant Preload as Preload (electronAPI)
    participant Main as Main Process (main.ts)
    participant Store as Settings Store

    User->>Renderer: Open Settings / Toggle Mode
    Renderer->>Preload: invoke getAppMode()
    Preload->>Main: invoke('get-app-mode')
    Main->>Store: read app-mode
    Main-->>Preload: return appMode
    Preload-->>Renderer: appMode
    Renderer->>Renderer: update local state

    User->>Renderer: setAppMode('menubar')
    Renderer->>Preload: send setAppMode('menubar')
    Preload->>Main: send('set-app-mode','menubar')
    Main->>Store: write app-mode
    Main->>Main: update appMode, adjust Dock, window behavior
    Main->>Preload: emit 'app-mode-changed'
    Preload-->>Renderer: onAppModeChanged callback
    Renderer->>Renderer: show mode banner / update header
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I hopped between Dock and menu with glee,
Tabs for my settings, banners for me.
Shortcuts displayed, modes switched with a click,
A centered menubar, a docked view so slick.
Rabbit-approved changes—quick, tidy, and spry!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Normal App mode, Settings UI tabs, Dev Hub sub-title' accurately captures the three main changes in the pull request: introduction of Normal App mode, redesigned Settings UI with tabs, and title bar updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/normal-app-mode

Comment @coderabbitai help to get the list of available commands and usage tips.

grimmerk and others added 13 commits April 6, 2026 22:45
- Title bar shows 'Normal' or 'Menu Bar' in grey text
- Banner on first launch (Normal mode) and on mode switch
- Banner auto-dismisses after 5-6s, dismissable via x
- Clicking Dock icon shows hidden window in Normal mode

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show actual quickSwitcher shortcut (from settings) on right
  side of title bar, before tab buttons
- Fix banner flashing on every show (removed app-mode-changed
  IPC from showSwitcherWindow — only fires on actual mode change)
- Mode indicator stays on left side next to CodeV

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shortcut text in title bar now updates in real-time when
user saves or resets shortcuts in Settings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 'Dev Hub' in #888 (11px) next to CodeV
- 'normal mode' / 'menu bar mode' in #555 (9px) below Dev Hub
- Two-line layout using inline-flex column

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace single scrollable settings panel with 3 tabs:
- General: Default Tab, App Mode, Left-Click, Launch at Login,
  Launch Terminal, Launch Mode, IDE, Working Dir
- Sessions: Session Preview, Session Status (hooks)
- Shortcuts: Global shortcuts (editable), Claude Session Launch,
  Tab Switching reference

No more conditional content based on active main tab.
No more scrolling needed — each tab fits without scroll.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Order: Launch at Login > App Mode > Left-Click > Default Tab >
  Working Dir > Launch Terminal > Launch Mode > IDE
- Hints: Working Dir (projects/term), Launch Terminal (sessions),
  Launch Mode (tab/window), IDE (projects), Left-Click (tray)
- Terminal renamed to Terminal.app in dropdown
- Claude Session Launch moved below Tab Switching, noted (in Projects)
- Working Dir always visible (removed switcherMode conditional)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@grimmerk grimmerk marked this pull request as ready for review April 6, 2026 15:54
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/switcher-ui.tsx">

<violation number="1" location="src/switcher-ui.tsx:710">
P2: Banner dismiss timeouts are never cleared. If the mode changes while a previous banner's timeout is still pending, the stale timeout will prematurely dismiss the new banner. Store the timeout ID in a ref and call `clearTimeout` before scheduling a new one.</violation>
</file>

<file name="src/main.ts">

<violation number="1" location="src/main.ts:1976">
P2: `app.dock.show()` returns a `Promise<void>` in Electron but is not awaited. The renderer gets notified via `app-mode-changed` before the dock icon is guaranteed to be visible, and any rejection would be unhandled.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/electron-api.d.ts (1)

31-35: Tighten the new IPC contract before it spreads string everywhere.

Lines 32-35 model a closed set of values, but the declarations widen them to plain string and generic callback payloads. That drops exhaustiveness checks immediately in the new renderer code. Prefer a shared AppMode = 'normal' | 'menubar' union and a typed shortcut payload on this surface.

As per coding guidelines, src/**/*.{ts,tsx}: Use TypeScript for all components with strict typing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/electron-api.d.ts` around lines 31 - 35, The IPC type surface currently
uses plain string and untyped callbacks for app mode and shortcuts (getAppMode,
setAppMode, onAppModeChanged, onShortcutsUpdated), which loses exhaustiveness
checks; define a shared union type AppMode = 'normal' | 'menubar' and replace
any string usages with AppMode, and tighten IpcCallback payloads so
onAppModeChanged receives AppMode and onShortcutsUpdated receives a properly
typed ShortcutPayload interface (e.g., keys, enabled flags) to ensure strict
typing across renderer and main code; update all references to these symbols to
use the new types.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main.ts`:
- Around line 1083-1087: The switcher window is shown (showSwitcherWindow)
before the backend is ready (bootstrap), causing the renderer's initial fetch
for working-folder to hit an unavailable local server; to fix, defer the initial
call to showSwitcherWindow until after await bootstrap() completes (or expose
and await an explicit readiness signal from bootstrap) so the renderer only
mounts when the server is ready; update the startup sequence around
createSwitcherWindow/showSwitcherWindow and bootstrap to ensure
showSwitcherWindow runs after bootstrap (or after the readiness event) and add a
comment referencing the renderer's working-folder fetch to document the
dependency.

In `@src/popup.tsx`:
- Around line 325-347: The tab switch handler currently calls
setSettingsTab(tab) even when a shortcut capture is in progress
(editingShortcut), which leaves the global shortcut paused and its UI hidden;
update the onClick for the tab buttons to first detect if editingShortcut is
active and gracefully stop/cancel that capture before changing tabs — e.g., call
the existing cancel/cleanup function (or
setEditingShortcut(null)/setEditingShortcut(false) and invoke the
resumeGlobalShortcutCapture or cancelShortcutEdit helper) and only then call
setSettingsTab(tab) so the capture is resumed or cleaned up whenever the user
navigates away from the "shortcuts" tab.

In `@src/switcher-ui.tsx`:
- Around line 686-710: The startup banner shown in the getAppMode() block should
only appear once per user, not every Normal-mode startup: persist a
“modeBannerSeen” flag (e.g., via localStorage or your app settings) and check it
before calling setModeBanner in the window.electronAPI.getAppMode() handler,
setting the flag after showing the banner; also remove the hardcoded
'Cmd+Ctrl+R' in the onAppModeChanged handler and instead construct the Menu Bar
mode message using the current quickSwitcherShortcut state
(quickSwitcherShortcut / setQuickSwitcherShortcut) so the copy always reflects
the user’s configured shortcut.

---

Nitpick comments:
In `@src/electron-api.d.ts`:
- Around line 31-35: The IPC type surface currently uses plain string and
untyped callbacks for app mode and shortcuts (getAppMode, setAppMode,
onAppModeChanged, onShortcutsUpdated), which loses exhaustiveness checks; define
a shared union type AppMode = 'normal' | 'menubar' and replace any string usages
with AppMode, and tighten IpcCallback payloads so onAppModeChanged receives
AppMode and onShortcutsUpdated receives a properly typed ShortcutPayload
interface (e.g., keys, enabled flags) to ensure strict typing across renderer
and main code; update all references to these symbols to use the new types.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6db25675-0447-4f41-98bd-93b6189c103f

📥 Commits

Reviewing files that changed from the base of the PR and between 4a00e9a and 36a9694.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • package.json
  • src/electron-api.d.ts
  • src/main.ts
  • src/popup.tsx
  • src/preload.ts
  • src/switcher-ui.tsx

grimmerk and others added 2 commits April 7, 2026 00:06
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rtcut resume

- Clear banner timeout before scheduling new one (cubic P2)
- Await app.dock.show() (cubic P2)
- Delay showSwitcherWindow to after bootstrap (CodeRabbit)
- Resume paused shortcut when switching settings tabs (CodeRabbit)
- Use actual shortcut key in mode switch banner (CodeRabbit)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@grimmerk grimmerk changed the title feat: Normal App mode (dock visible, draggable, no auto-hide) feat: Normal App mode, Settings UI tabs, Dev Hub sub-title Apr 6, 2026
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/popup.tsx">

<violation number="1" location="src/popup.tsx:332">
P2: The shortcut-editing cleanup fires on every tab click, including re-clicking the "shortcuts" tab itself. This cancels an in-progress shortcut edit if the user clicks the active tab. Guard with `tab !== 'shortcuts'` to match the stated intent.</violation>
</file>

<file name="src/main.ts">

<violation number="1" location="src/main.ts:1087">
P2: The 100ms `setTimeout` does not guarantee `bootstrap()` has completed — `bootstrap()` is called ~190 lines later at line 1278, not earlier as the comment states. On slower machines or if the NestJS server takes >0ms to start, the window may show before the API server is ready, causing failed API calls from the renderer.

Consider moving `showSwitcherWindow()` to after the `await bootstrap()` call, or using an event/promise to signal server readiness.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

- Skip shortcut resume when re-clicking active Shortcuts tab
- Move showSwitcherWindow() to after bootstrap() + loadUserSettings()
  (was using setTimeout(100) which didn't guarantee readiness)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Around line 57-58: Update the README text that currently reads "Settings → App
Mode" to the new tabbed-UI path "Settings → General → App Mode" so the
documentation matches the redesigned navigation; locate the string "Settings →
App Mode" in README.md and replace it with "Settings → General → App Mode".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0e7d61b1-7cac-49d1-a1e8-1f06d1410e92

📥 Commits

Reviewing files that changed from the base of the PR and between 36a9694 and 50d4bf0.

📒 Files selected for processing (4)
  • README.md
  • src/main.ts
  • src/popup.tsx
  • src/switcher-ui.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/popup.tsx
  • src/switcher-ui.tsx
  • src/main.ts

Settings → App Mode → Settings → General → App Mode
Settings → Working Directory → Settings → General → Working Dir
Settings → IDE Preference → Settings → General → IDE

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@grimmerk grimmerk merged commit 20908f9 into main Apr 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant