feat(terminal): mobile virtual key bar
Add an on-screen virtual key bar for the terminal panel so mobile users
can send escape / tab / control / arrow / page keys without a hardware
keyboard. The bar mirrors the pios implementation: two rows of 14 buttons
(ESC / / — HOME ↑ END PGUP | TAB CTRL ALT ← ↓ → PGDN) with a CTRL/ALT
latch that wraps the next soft-keyboard input as a control byte or ESC
prefix respectively.
Pure encoding lives in lib/terminal/keybar.ts — 12 keys + termKeySeq +
applyTermMods + kbdLiftPx — covered by 18 unit tests. The new
<TermKeybar /> component is purely presentational and uses shadcn Button
+ Tailwind utilities, so there is no raw CSS.
Wiring:
- terminal-panel.tsx adds useMediaQuery('(max-width: 768px)') and a
localStorage-backed collapse flag (codeg:term-keybar) shared across
all tabs, then forwards keybarVisible down.
- terminal-tab-bar.tsx gains a ⌨ toggle button (mobile-only, with
tooltip + active highlight) that flips the flag.
- terminal-view.tsx exposes writeQueueRef so the key bar's bytes feed
the existing ordered single-flight write pump (without this the key
bar would bypass the queue and scramble with onData on slow transport).
onData is wrapped with applyTermMods to honor the latch. The
visualViewport observer drives a kbdLift max-height on the outer flex
column so the bar lifts above the soft keyboard and xterm auto-refits
via the existing ResizeObserver.
- workspace/layout.tsx bumps the mobile Drawer from 70vh to 95vh to
give the new bar enough room when folded in.
i18n: 16 new keys under Folder.terminal.keybar across all 10 locales
(symbols are language-neutral; show/hide/label are translated for
zh-CN/zh-TW/ja/ko/es/de/fr/pt/ar). English fallbacks keep the type
contract aligned.
Desktop path is untouched: useMediaQuery stays false, the toggle and
the bar never render, and the writeQueueRef sits at null. Y
Your Name committed
bde2aecbe8089a453d73999dfea753263cca3935
Parent: 938b235