Skip to content

Commit 0682e32

Browse files
feat(frontend): redesign Tools menu and unify user preferences (#225)
Closes #224. Reworks the Tools side menu into clear sections (SESSION / FILES / VIEW / SHARE / AGENTS / SETTINGS / SYSTEM), renames CommandPalette to ToolsPanel, and adds a non-blocking SettingsPanel that keeps the terminal and TouchBar visible so theme/font/custom-keys changes are observable in real time. Backs the UI with a unified `usePreferencesStore` synced through new `GET`/`PUT /api/preferences` endpoints (file: `~/.termbeam/prefs.json`, 0o600), with a one-time migration from the old localStorage keys. Adds TouchBar collapse, user-defined custom keys (capped at 7), optional haptics, and a startup workspace boot that auto-launches configured sessions on first connect. The PR is structured as 9 reviewable commits — each compiles and tests green on its own. Reviewing commit-by-commit is recommended. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8829e0c commit 0682e32

49 files changed

Lines changed: 7826 additions & 926 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/copilot-instructions.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,13 @@ TermBeam is a Node.js CLI tool that exposes a local PTY (pseudo-terminal) over H
8383
- `version.js` — detects version from package.json
8484
- `update-check.js` — npm update checking
8585

86-
**Frontend:** React SPA in `src/frontend/` built with Vite + TypeScript. Builds to `public/` (gitignored build artifact). Uses xterm.js, Zustand for state, and Radix UI for accessible components. Components organized into: CommandPalette, FolderBrowser, LoginPage, Modals, Overlays, SearchBar, SessionsHub, SidePanel, TabBar, TerminalApp, TerminalPane, TouchBar, and common reusable components (TopBar, ThemePicker, UpdateBanner).
86+
**Frontend:** React SPA in `src/frontend/` built with Vite + TypeScript. Builds to `public/` (gitignored build artifact). Uses xterm.js, Zustand for state, and Radix UI for accessible components. Components organized into: ToolsPanel (right slide-in, formerly CommandPalette), Settings (preferences drawer/sheet), FolderBrowser, LoginPage, Modals, Overlays, SearchBar, SessionsHub, SidePanel (left slide-in), TabBar, TerminalApp, TerminalPane, TouchBar, and common reusable components (TopBar, ThemePicker, UpdateBanner).
87+
88+
**UI surfaces (terminology — use these names consistently):**
89+
90+
- **SidePanel** (`src/frontend/src/components/SidePanel/`) — left slide-in containing the sessions picker. Triggered by the ☰ menu button.
91+
- **ToolsPanel** (`src/frontend/src/components/ToolsPanel/`, formerly `CommandPalette`) — right slide-in titled "Tools". Triggered by the ▦ button or `Cmd/Ctrl+K`. Sections: SESSION · FILES · VIEW · SHARE · AGENTS · SETTINGS · SYSTEM. The SETTINGS section contains a single "Settings…" row that opens the SettingsPanel.
92+
- **SettingsPanel** (`src/frontend/src/components/Settings/`) — non-blocking preferences surface. **Top sheet** on mobile (slides down from top so terminal + TouchBar stay visible below — toggles like "Start collapsed" and "Haptic feedback" can be observed live). **Right-side drawer (420 px)** on desktop with no backdrop dim. Reached from the ToolsPanel "Settings…" row or `Cmd/Ctrl+,`. Holds Appearance, Startup, TouchBar, Terminal, and Startup Workspace sections. Backed by `usePreferencesStore`, which syncs to the server via `GET`/`PUT /api/preferences`.
8793

8894
**WebSocket protocol:** JSON messages over `/ws`. Client sends `attach`, `input`, `resize`; server sends `output`, `attached`, `exit`, `error`. Auth is validated at WebSocket upgrade or first message.
8995

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ https://github.com/user-attachments/assets/9dd4f3d7-f017-4314-9b3a-f6a5688e3671
2727
<td align="center"><img src="packages/site/public/mobile-session-hub.jpeg" alt="Session hub on mobile" width="250" /></td>
2828
<td align="center"><img src="packages/site/public/mobile-terminal.jpeg" alt="Terminal with touch bar on mobile" width="250" /></td>
2929
<td align="center"><img src="packages/site/public/mobile-session-preview.jpeg" alt="File browser on mobile" width="250" /></td>
30-
<td align="center"><img src="packages/site/public/mobile-command-palette.jpeg" alt="Command palette on mobile" width="250" /></td>
30+
<td align="center"><img src="packages/site/public/mobile-command-palette.jpeg" alt="Tools panel on mobile" width="250" /></td>
3131
</tr>
3232
</table>
3333

@@ -72,7 +72,9 @@ termbeam -i # interactive setup wizard
7272
### Productivity
7373

7474
- **Terminal search** with regex, match count, and prev/next navigation
75-
- **Command palette** (Ctrl+K / Cmd+K) for quick access to all actions
75+
- **Tools panel** (Ctrl+K / Cmd+K) — slide-out sheet for quick access to all actions, organized into **Session · Files · View · Share · Agents · Settings · System**. Settings (theme, font size, defaults, haptics) are inline panels reachable from the panel; on mobile the panel slides up from the bottom, on desktop it docks to the right.
76+
- **Customizable Touch Bar** — 8-column, multi-row (up to 3) key grid with drag-to-reorder, collapsible drawer, and a dedicated key editor (label, send payload, action, modifier).
77+
- **Workspaces** — save named bundles of sessions (each with its own name, cwd, shell, color and initial command). Mark one as `default` and the **server** auto-spawns it on startup, so connecting any client lands on a ready terminal. Preferences (theme, fonts, defaults, custom keys, workspaces) are persisted server-side in `~/.termbeam/prefs.json` and sync across devices.
7678
- **File upload** — send files from your phone to the session's working directory
7779
- **File browser & download** — browse files in a session's working directory from the side panel and download them to your device
7880
- **Markdown viewer** — preview `.md` files rendered with GitHub Flavored Markdown directly in the browser

packages/site/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export default defineConfig({
7373
label: 'Guides',
7474
items: [
7575
{ label: 'Usage Guide', slug: 'usage-guide' },
76+
{ label: 'Customization', slug: 'customization' },
7677
{ label: 'AI Agents', slug: 'ai-agents' },
7778
{ label: 'Configuration', slug: 'configuration' },
7879
{ label: 'Resume & List', slug: 'resume' },

packages/site/src/content/docs/api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ Create a new session.
139139
}
140140
```
141141

142-
All fields are optional. If `initialCommand` is provided, it will be sent to the shell after startup. If `color` is omitted, a color is assigned automatically from a built-in palette. The optional `cols` and `rows` fields set the initial terminal size (defaults to 120×30 if omitted).
142+
All fields are optional. If `initialCommand` is provided, it will be sent to the shell after startup (capped at 8192 characters — longer values are rejected with `400 initialCommand too long`). If `color` is omitted, a color is assigned automatically from a built-in palette. The optional `cols` and `rows` fields set the initial terminal size (defaults to 120×30 if omitted).
143143

144144
The `shell` field is validated against the list of detected shells (see `GET /api/shells`). The `cwd` field must be an absolute path to an existing directory.
145145

packages/site/src/content/docs/architecture.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ The terminal page includes several client-side features:
169169
- **Command completion notifications** — uses the browser Notification API to alert when a command finishes in a background tab. Toggled via a bell icon; preference stored in `localStorage` (`termbeam-notifications`).
170170
- **Push notifications** — native push notifications via the Web Push API, delivered even when the browser tab is closed. The service worker (`sw.ts`) handles push events and uses the Badge API to show unread counts. Push subscription lifecycle (subscribe, unsubscribe, VAPID key mismatch detection) is managed by `services/pushSubscription.ts`.
171171
- **Git changes view**`GitChanges/`, `DiffViewer/`, and `BlameGutter/` components in the CodeViewer directory provide a full git integration UI: staged/unstaged diffs with syntax highlighting, per-line blame annotations, and commit history browsing.
172-
- **Command palette** — <kbd>Ctrl+K</kbd> / <kbd>Cmd+K</kbd> (or the floating ⚙️ button) opens a slide-out tool panel with categorized actions (Session, Search, View, Share, Notifications, System).
172+
- **Tools panel** — <kbd>Ctrl+K</kbd> / <kbd>Cmd+K</kbd> (or the floating ▦ button) opens a slide-out sheet with categorized actions (Session, Files, View, Share, Agents, Settings, System). Settings, the workspace launcher and the touch-bar key editor are inline panels reachable from this entry point.
173+
- **Workspace autoboot (server-side)** — at startup `src/server/index.js` reads `~/.termbeam/prefs.json` and, if a workspace is flagged `default: true` (or there is exactly one named workspace, or the legacy `startupWorkspace.enabled` is true), spawns each session itself. Each session's saved `shell` is validated against the host's detected shells and falls back to the runtime default if missing (covers the host-migration case where saved shells no longer exist). If every workspace session fails to spawn, the server falls back to a single default session so the user always lands on something. This replaced the previous client-side autoboot so deleting a session in the UI stays deleted until the next service restart. When no workspace is configured the server falls back to a single default session in `config.cwd`.
173174

174175
## Data Flow
175176

packages/site/src/content/docs/configuration.md

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,57 @@ TermBeam auto-detects your current shell by inspecting the parent process tree.
5050
The environment variables `PTY_PASSWORD` and `PTY_CWD` are also supported as fallbacks for `TERMBEAM_PASSWORD` and `TERMBEAM_CWD` respectively.
5151
:::
5252

53-
## Client-Side Settings (localStorage)
53+
## Settings (UI)
54+
55+
TermBeam exposes settings through the **Tools panel**, opened from the floating ▦ button or `Ctrl/Cmd+K`. From there pick **Settings…** (or use the `Cmd/Ctrl+,` shortcut). On mobile the panel slides up from the bottom; on desktop it docks to the right (~420 px wide). It is non-blocking so theme, font size, collapsed-touchbar and haptics changes can be observed live against the terminal underneath.
56+
57+
For the full UI walkthrough — Tools panel sections, Settings panels, Touch Bar key editor, Workspaces — see **[Customization](../customization/)**.
58+
59+
### Where preferences are stored
60+
61+
Preferences are persisted **server-side** in `~/.termbeam/prefs.json` (mode `0o600`) via the authenticated `GET /api/preferences` and `PUT /api/preferences` endpoints. The browser keeps a `localStorage` cache (`termbeam-prefs`) for instant first paint and offline UX, but the server file is the source of truth — opening TermBeam from a phone, tablet and laptop against the same instance gets the same settings.
62+
63+
The schema is roughly:
64+
65+
```jsonc
66+
{
67+
"themeId": "one-dark",
68+
"fontSize": 13,
69+
"notifications": false,
70+
"haptics": true,
71+
"defaultFolder": "",
72+
"defaultInitialCommand": "",
73+
"touchBarCollapsed": true,
74+
"touchBarKeys": [{ "id": "esc", "label": "Esc", "send": "\u001b", "row": 1, "col": 1 }],
75+
"workspaces": [
76+
{
77+
"name": "DevWorkspace",
78+
"default": true,
79+
"sessions": [
80+
{
81+
"name": "server",
82+
"cwd": "/path",
83+
"shell": "/bin/zsh",
84+
"color": "#4a9eff",
85+
"initialCommand": "npm run dev",
86+
},
87+
],
88+
},
89+
],
90+
"startupWorkspace": { "enabled": false, "sessions": [] }, // legacy
91+
}
92+
```
5493

55-
The browser UI stores the following preferences in `localStorage`:
94+
The legacy device-local keys below are still read once on first load after upgrade and migrated into the unified store; they remain device-only:
5695

57-
| Key | Description | Default |
58-
| ------------------------ | --------------------------------------------------------- | ------- |
59-
| `termbeam-notifications` | Command completion notifications enabled (`true`/`false`) | `true` |
60-
| `termbeam-font-size` | Terminal font size | `14` |
61-
| `termbeam-theme` | Light/dark theme preference | `dark` |
62-
| `termbeam-tab-order` | Saved tab order (JSON array of session IDs) | None |
96+
| Key | Description |
97+
| ---------------------------- | -------------------------------------------------------- |
98+
| `termbeam-tab-order` | Saved tab order (JSON array of session IDs). |
99+
| `termbeam-hub-filter` | Last-used filter on the SessionsHub page. |
100+
| `termbeam-push-subscribed` | Whether the browser is subscribed to push notifications. |
101+
| `termbeam-review-comments:*` | Per-PR review-comment state (Copilot integration). |
63102

64-
These settings are per-browser and persist across sessions. They can be cleared by the user via the browser's developer tools or the Refresh button in the toolbar.
103+
These can be cleared at any time via the browser's developer tools.
65104

66105
## Subcommands
67106

@@ -164,9 +203,10 @@ termbeam --persisted-tunnel --password mysecret
164203

165204
<!-- prettier-ignore -->
166205
:::tip[Persisted vs Ephemeral Tunnels]
206+
167207
- `--tunnel` — Creates a fresh tunnel each time, deleted on shutdown. Good for one-off use.
168208
- `--persisted-tunnel` — Saves the tunnel ID to `~/.termbeam/tunnel.json` and reuses it across restarts (30-day expiry). The URL stays the same so you can bookmark it on your phone. To get a fresh URL, just switch back to `--tunnel`.
169-
:::
209+
:::
170210

171211
<!-- prettier-ignore -->
172212
:::caution

0 commit comments

Comments
 (0)