8.0 KiB
Settings Panel & New Session Design
Goal
Add a Settings panel and New Session feature to muxplex, removing the command palette (now redundant with the sidebar).
Background
The command palette was the original mechanism for session switching, but the sidebar + hover preview + click-to-navigate flow now covers the same functionality. The header space freed by removing the palette is better used for settings access and session creation — two features muxplex currently lacks.
Settings need to live in two places: per-device preferences (font size, notifications) in localStorage, and per-user configuration (session defaults, templates) in a server-side file that persists across devices.
Approach
- Settings as a modal dialog (desktop) / bottom sheet (mobile), triggered by a gear icon in the header. Controls apply immediately with debounced persistence — no Save button.
- New Session as an inline name input that replaces the
+button on click. A configurable command template in settings controls what actually runs on the server. - Command palette removal — delete all palette HTML, CSS, and JS.
Architecture
Settings Access
Gear icon (⚙) in the header, right side, next to a + (new session) button and connection status indicator. Same position in both dashboard and expanded terminal views.
Keyboard shortcut: , (comma, VS Code convention).
Desktop Layout (≥600px)
Centered modal dialog — same pattern as the now-removed command palette (backdrop, escape-to-close, centered panel):
- Width:
min(600px, 90vw) - Height:
min(480px, 80vh) - Left tab list: 140px fixed width
- Active tab:
color: var(--accent)with 2px left border invar(--accent)
Tabs: Display, Sessions, Notifications, New Session.
Mobile Layout (<600px)
Bottom half-sheet (slides up from bottom, drag-to-dismiss downward):
- Same gear icon trigger
- 48px minimum touch targets for all controls
- Dim overlay behind
- Max height ~85vh
Storage Split
localStorage (per-device): Font size, grid columns, hover preview delay, bell sound, desktop notification permission.
Server (~/.config/muxplex/settings.json): Default session, sort order, hidden sessions, window-size largest, auto-open created sessions, new session command template.
No sync between the two. If localStorage is cleared, the user gets defaults. Server settings persist across devices via the API.
Controls Behavior
All controls apply immediately — no Save button. Each change debounces 500ms then persists (PATCH to server or localStorage write). A subtle toast confirms the save. This matches developer tool conventions (VS Code, terminal settings).
Components
API Endpoints
| Method | Path | Description |
|---|---|---|
GET |
/api/settings |
Returns server-side settings.json contents |
PATCH |
/api/settings |
Partial update — merges single-field saves |
POST |
/api/sessions |
Creates a new session ({"name": "my-project"}) |
Server-Side Settings File
~/.config/muxplex/settings.json:
{
"default_session": null,
"sort_order": "manual",
"hidden_sessions": [],
"window_size_largest": false,
"auto_open_created": true,
"new_session_template": "tmux new-session -d -s {name}"
}
localStorage Key
muxplex.display — single JSON blob:
{
"fontSize": 14,
"hoverPreviewDelay": 1500,
"gridColumns": "auto",
"bellSound": false,
"notificationPermission": "default"
}
Settings Categories & Fields
Display Tab (localStorage)
| Field | Control | Default |
|---|---|---|
| Font size | <select> (11, 12, 13, 14, 16px) |
14 |
| Hover preview delay | <select> (Off, 1s, 1.5s, 2s, 3s) |
1.5s |
| Grid columns | <select> (Auto, 2, 3, 4) |
Auto |
Sessions Tab (server)
| Field | Control | Default |
|---|---|---|
| Default session | <select> (None + current session list) |
None |
| Sort order | <select> (Manual, Alphabetical, Recent activity) |
Manual |
| Hidden sessions | Checkbox list of session names | None hidden |
| Auto-set window-size largest | Checkbox | Off |
| Auto-open created sessions | Checkbox | On |
Notifications Tab (localStorage)
| Field | Control | Default |
|---|---|---|
| Bell sound | Checkbox | Off |
| Desktop notifications | Button: "Request permission" / status text | Not requested |
New Session Tab (server)
| Field | Control | Default |
|---|---|---|
| Command template | <textarea> monospace, 3 rows |
tmux new-session -d -s {name} |
Helper text: {name} is replaced with the session name |
||
[ Reset to default ] button |
New Session Feature
Button Placement
- Dashboard header:
[+]button, right side, between wordmark and gear icon. Styled same as gear —border: 1px solid var(--border),color: var(--text-dim). - Expanded view sidebar:
+ Newsticky footer below session list. - Mobile (<960px): 56px FAB, bottom-right, 16px from edges.
+icon. Replaces header button on mobile.
Creation Flow — Inline Name Input
Click + → button transforms into a text input inline in the header. Auto-focus, placeholder "Session name…", Enter to create, Escape to cancel. One field only — everything else comes from the template.
Sidebar footer: same pattern — button becomes input field inline.
Template Execution
Configured in Settings → New Session tab. Default: tmux new-session -d -s {name}. The {name} variable is the only substitution — replaced at creation time.
Backend
POST /api/sessions with {"name": "my-project"}.
Server reads template from settings.json, substitutes {name}, executes via subprocess. Returns 200 with {"name": "..."}.
No existence check — this deliberately handles create-or-reattach patterns (e.g., amplifier-dev ~/dev/{name} creates new or reattaches to existing). If the command fails, the session won't appear and the user sees the dashboard unchanged.
Post-Creation Behavior
- Show toast: "Session '{name}' created"
- Trigger immediate
pollSessions()refresh - Auto-open the session if "auto-open created sessions" is enabled in settings
Command Palette Removal
Remove the entire command palette:
- HTML:
#command-palettediv +#palette-triggerbutton - CSS:
.command-palette*,.palette-* - JS: palette state variables,
openPalette,closePalette,renderPaletteList,highlightPaletteItem, palette keyboard handler, palette event bindings
The sidebar + hover preview + click-to-navigate already provides the same session switching functionality. The header space freed by removing the ⌘K button is where the + and ⚙ buttons go.
Security
The new session template is a shell command the user writes and the server executes. PAM auth already proves they own the machine — this is equivalent to typing in their own terminal. No command sanitization needed.
Implementation Notes
Files to Create
muxplex/frontend/settings.js— settings modal/sheet logic, tab switching, field rendering, localStorage + API integrationmuxplex/frontend/settings.html(or inline inindex.html) — settings dialog markup
Files to Modify
muxplex/frontend/index.html— remove command palette HTML, add settings dialog HTML, add+and⚙header buttonsmuxplex/frontend/style.css— remove palette CSS, add settings modal/sheet CSS, add FAB CSS, add inline input CSSmuxplex/frontend/app.js— remove all palette JS, add settings open/close, add new session creation flow, wire up+button and FABmuxplex/main.py— addGET/PATCH /api/settingsendpoints, addPOST /api/sessionsendpointmuxplex/cli.py— loadsettings.jsonat startup for template default
Open Questions
- Should hidden sessions still be visible with a "hidden" badge, or completely removed from the grid?
- Should the new session input validate the name (alphanumeric + dash only) or accept anything tmux accepts?
- Should the gear/settings be accessible from the login page (pre-auth) for display preferences? Probably not for v1.