From b8a7810bfd421e3dbd9cd11f1478ee06eb735b0f Mon Sep 17 00:00:00 2001 From: Mortdecai Date: Fri, 24 Apr 2026 19:51:48 -0400 Subject: [PATCH] chore: archive design handoff bundle for toolbar refresh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stores SethMux_4-24-26.zip + extracted design_handoff_sethmux_toolbar/ so the spec, mockups, and reference jsx components stay in-repo for future reference. Not served in production — the only file that ships is static/toolbar.js, which already matches the design's toolbar.js byte-for-byte. --- claude-design/SethMux_4-24-26.zip | Bin 0 -> 20078 bytes .../design_handoff_sethmux_toolbar/README.md | 145 +++++++++ .../android-frame.jsx | 214 ++++++++++++ .../browser-window.jsx | 114 +++++++ .../preview-desktop.html | 197 +++++++++++ .../preview-mobile.html | 269 +++++++++++++++ .../preview.html | 96 ++++++ .../design_handoff_sethmux_toolbar/toolbar.js | 305 ++++++++++++++++++ 8 files changed, 1340 insertions(+) create mode 100644 claude-design/SethMux_4-24-26.zip create mode 100644 claude-design/design_handoff_sethmux_toolbar/README.md create mode 100644 claude-design/design_handoff_sethmux_toolbar/android-frame.jsx create mode 100644 claude-design/design_handoff_sethmux_toolbar/browser-window.jsx create mode 100644 claude-design/design_handoff_sethmux_toolbar/preview-desktop.html create mode 100644 claude-design/design_handoff_sethmux_toolbar/preview-mobile.html create mode 100644 claude-design/design_handoff_sethmux_toolbar/preview.html create mode 100644 claude-design/design_handoff_sethmux_toolbar/toolbar.js diff --git a/claude-design/SethMux_4-24-26.zip b/claude-design/SethMux_4-24-26.zip new file mode 100644 index 0000000000000000000000000000000000000000..1e3b7855b9da0bbddd385c051357b688007abeb8 GIT binary patch literal 20078 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 L#bctCj^F+RoGa)a literal 0 HcmV?d00001 diff --git a/claude-design/design_handoff_sethmux_toolbar/README.md b/claude-design/design_handoff_sethmux_toolbar/README.md new file mode 100644 index 0000000..ab5d02b --- /dev/null +++ b/claude-design/design_handoff_sethmux_toolbar/README.md @@ -0,0 +1,145 @@ +# Handoff: sethmux mobile toolbar — Google Workspace dark refresh + compose bar + +## Overview + +This handoff covers two related changes to the sethmux web terminal's mobile UI (`static/toolbar.js`): + +1. **Theme refresh** — re-skin the existing 2-row mobile button bar to match the Google Workspace dark vocabulary (palette, typography, hairline borders, hover behavior) while keeping sethmux's orange `#D35400` as the accent identity. +2. **Mobile autocorrect workaround** — add an opt-in compose bar (third row, toggled by a "Type" button) that gives Gboard / iOS keyboards a real `` to operate on. Typed text is flushed to the terminal stdin on Enter / Send so swipe, autocorrect, and predictions all work despite xterm.js's per-keystroke input model. + +## About the Design Files + +The files in this bundle are **design references** — `toolbar.js` is the single source file to ship; the `preview*.html` files are visual mockups demonstrating intended look and behavior in a Chrome window and an Android phone frame, and the `*.jsx` files are throwaway frame components used only by the previews. + +The task is to drop the new `toolbar.js` into the existing sethmux project at `static/toolbar.js`, replacing the current file. No build step required; no other static files change. The previews are not meant to be served in production. + +## Fidelity + +**High-fidelity.** All colors, type sizes, spacings, radii, and behaviors are final. Implement to spec. + +## What changed in toolbar.js + +### Visual system (Google Workspace dark) + +| Token | Hex | Usage | +|------------------|-----------|-----------------------------------------------| +| toolbar bg | `#202124` | bar background | +| button surface | `#303134` | button face at rest | +| border | `#3c4043` | 1px hairlines, group dividers | +| primary text | `#e8eaed` | button labels | +| secondary text | `#9aa0a6` | mono-class buttons at rest | +| tertiary text | `#5f6368` | placeholder, disabled | +| accent (sethmux) | `#D35400` | active/toggled fill, send button, focus ring | +| accent at rest | `#f0a36b` | text color of `.hi` (orange-tinted) buttons | +| accent bg-1 | `#2a1f15` | `.hi` button background at rest | +| accent bg-2 | `#3a2a1a` | hover wash (subtle orange tint) | +| accent border | `#5a3a22` | `.hi` border at rest | +| success at rest | `#81c995` | Save button text | +| success filled | `#1e8e3e` | Save button after confirm | + +### Typography + +- Primary: `Roboto, 'Helvetica Neue', Arial, sans-serif`, 12px / 500, letter-spacing 0.1px +- Mono (chord and arrow keys, terminal input): `'Roboto Mono', 'SF Mono', ui-monospace, Menlo, Consolas, monospace`, 14px / 400 in the compose input, 12px / 400 on `.mono` buttons + +### Geometry + +- Bar padding: `6px 8px 7px` +- Button: `height: 32px`, `min-width: 40px`, `padding: 0 10px`, `border-radius: 4px`, `border: 1px solid #3c4043` +- Narrow-phone breakpoint at `max-width: 380px`: button `height: 30px`, `min-width: 34px`, `padding: 0 7px`, `font-size: 11.5px` +- Compose input: `height: 36px`, `padding: 0 10px`, `border-radius: 4px`, orange caret + orange focus border `#D35400` +- Send button: `height: 36px`, `min-width: 54px`, filled `#D35400` on text `#0a0a0a` +- Newline button (`↵`): same height as Send, `min-width: 38px`, neutral surface (`#303134` / `#3c4043`) +- Group dividers (`.sep`): 1px wide × 20px tall, `#3c4043`, 4px horizontal margin (2px on narrow phones) +- Bar shadow: `0 -1px 0 rgba(0,0,0,.4), 0 -8px 24px rgba(0,0,0,.35)` +- Transitions: `background .15s ease, border-color .15s ease, color .15s ease` (no bounces) + +### Button states + +- Default: `#303134` bg, `#3c4043` border, `#e8eaed` text +- Hover: `#3a2a1a` bg, `#fff` text +- Active (mouse-down): full orange fill `#D35400` on `#0a0a0a` +- `.hi` (accent at rest): orange-tinted bg `#2a1f15`, border `#5a3a22`, text `#f0a36b`. Hover deepens both +- `.on` (toggled, e.g. selection mode active, Type active): full `#D35400` fill, hover lightens to `#e26416` +- `.mono` (chord keys): mono font, `#9aa0a6` text → `#e8eaed` on hover +- `.grn` (Save): `#81c995` text at rest; `.grn.on` (post-confirm) fills `#1e8e3e` and shows "✓ Saved" for 1500ms + +### Layout / structure + +The bar is a single `position: fixed; bottom: 0` element with `flex-direction: column`. + +**Row 1** (always visible): +``` +[+ Tab] [Next] [Prev] | [^C] [^D] [Clr] | [Esc] [Tab] [▲] [▼] +``` +- `+ Tab` is `.hi`, the rest neutral, `^C ^D Esc Tab ▲ ▼` are `.mono`. + +**Row 2** (always visible): +``` +[Sel] [Paste] [Zoom] [Save] | [V.Spl] [H.Spl] [Pane] [Kill] | [Type] +``` +- `Sel`, `Paste`, `Type` are `.hi`. `Save` is `.grn`. The `Type` button is the new entry point for the compose bar. + +**Row 3 — compose** (only visible when `#mb` has class `composing`): +``` +[ input field ] [↵] [Send] +``` +- The input is full-width-flex, monospace, autocorrect on. `↵` and `Send` both flush. + +### Interactions / behavior + +**Send to stdin (`send(k)`):** unchanged. Tries `term._core.coreService.triggerDataEvent(k)` first, falls back to `term._core._onData.fire(k)`, then `term.input(k)`. Always re-focuses the terminal afterward. + +**Selection mode (`Sel`):** unchanged. Toggles `body.selmode` which adds `pointer-events: none` to `.xterm-screen` and forces text selection. While in selmode the body also gets `filter: brightness(.92)` for a subtle visual cue. Sending any key auto-exits selmode. + +**Paste:** unchanged. Reads `navigator.clipboard.readText()` and feeds the result through `send()`. Alerts if HTTPS clipboard is unavailable. + +**Save:** unchanged behavior — sends `\x01S` (`Ctrl-A S`, the tmux capture binding). Adds the `.on` class and label `✓ Saved` for 1500ms, then reverts. + +**Compose / Type (new):** +- Tapping `Type` toggles the `composing` class on `#mb`. +- On open, `#mb-compose` gets focused via `setTimeout(...,0)` so iOS/Android keyboards open reliably. +- Input attributes: `autocomplete="on" autocorrect="on" autocapitalize="sentences" spellcheck="true" enterkeyhint="send" inputmode="text"`. These are required — the whole point is to let the OS keyboard's correction layer mutate the input value, which xterm.js's hidden textarea cannot do. +- Pressing `Enter` (or tapping `Send` or `↵`) calls `flushCompose(true)`: reads the input value, clears it, sends the value as a string to stdin, then sends `\r`. Re-focuses the input so the user can keep typing. +- Other toolbar buttons remain active while composing. If a chord/arrow/etc. button is tapped with non-empty input text, the typed text is flushed first (preserving order), then the chord is sent. **The compose bar stays open**; the user is mid-thought. + +**Layout reflow (`relayout()`):** The terminal pane (`.xterm`) is sized via `height: calc(100vh - {barHeight + 4}px)` whenever the bar's height changes. This runs on: +- DOM mutations (existing `MutationObserver`) +- Window resize +- Toggling the `composing` class (called from `toggleType()`) + +The previous implementation hard-coded `calc(100vh - 92px)`; the new code measures `bar.offsetHeight` so opening the third row reflows correctly without overlap. + +**Helper textarea hardening:** unchanged. Still sets `autocomplete=off`, `autocorrect=off`, `autocapitalize=off`, `spellcheck=false` on `.xterm-helper-textarea` once it appears. This is the standard xterm.js mitigation and is still useful — it prevents Gboard from trying to munge the per-keystroke stream when the user happens to type *outside* the compose bar. + +### Mobile breakpoint + +The toolbar shows at `@media (max-width: 900px)`. Unchanged. Above that, sethmux assumes a real keyboard and the bar stays hidden. + +## Why the compose bar is necessary + +xterm.js reads from a hidden `