feat: add Tab, Esc, ⌥Enter buttons to mobile keyboard accessory bar

- Add Tab (forward), Esc, and Option+Enter (newline) buttons
- Reorder buttons: ↑ ↓ 📋 Tab ⇧Tab ⌥Enter Esc /init /clear /compact dismiss
- Unify dismiss button style with arrow buttons (was oversized with custom class)
- Remove unused .accessory-btn-dismiss CSS rules
This commit is contained in:
Teigen
2026-04-02 14:32:54 +08:00
parent 2c7557d002
commit 13d41cf7c7
2 changed files with 20 additions and 44 deletions
+20 -8
View File
@@ -4,7 +4,7 @@
* Defines two exports:
*
* - KeyboardAccessoryBar (singleton object) — Quick action buttons shown above the virtual
* keyboard on mobile: arrow up/down, Shift+Tab, /init, /clear, /compact, paste, and dismiss.
* keyboard on mobile: Esc, arrow up/down, Tab, Shift+Tab, /init, /clear, /compact, paste, and dismiss.
* Destructive actions (/clear, /compact) require double-tap confirmation (2s amber state).
* Commands are sent as text + Enter separately for Ink compatibility.
* Only initializes on touch devices (MobileDetection.isTouchDevice guard).
@@ -53,18 +53,21 @@ const KeyboardAccessoryBar = {
<path d="M19 9l-7 7-7-7"/>
</svg>
</button>
<button class="accessory-btn" data-action="shift-tab" title="Shift+Tab">⇧Tab</button>
<button class="accessory-btn" data-action="init" title="/init">/init</button>
<button class="accessory-btn" data-action="clear" title="/clear">/clear</button>
<button class="accessory-btn" data-action="compact" title="/compact">/compact</button>
<button class="accessory-btn" data-action="paste" title="Paste from clipboard">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"/>
</svg>
</button>
<button class="accessory-btn accessory-btn-dismiss" data-action="dismiss" title="Dismiss keyboard">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
<button class="accessory-btn" data-action="tab" title="Tab">Tab</button>
<button class="accessory-btn" data-action="shift-tab" title="Shift+Tab">⇧Tab</button>
<button class="accessory-btn" data-action="opt-enter" title="Option+Enter (newline)">⌥Enter</button>
<button class="accessory-btn" data-action="esc" title="Escape">Esc</button>
<button class="accessory-btn" data-action="init" title="/init">/init</button>
<button class="accessory-btn" data-action="clear" title="/clear">/clear</button>
<button class="accessory-btn" data-action="compact" title="/compact">/compact</button>
<button class="accessory-btn accessory-btn-arrow" data-action="dismiss" title="Dismiss keyboard">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<path d="M19 9l-7 7-7-7"/>
</svg>
</button>
@@ -81,7 +84,7 @@ const KeyboardAccessoryBar = {
this.handleAction(action, btn);
// Refocus terminal so keyboard stays open (tap blurs terminal → keyboard dismisses → toolbar shifts)
if ((action === 'scroll-up' || action === 'scroll-down' || action === 'shift-tab') ||
if ((action === 'scroll-up' || action === 'scroll-down' || action === 'tab' || action === 'shift-tab' || action === 'opt-enter' || action === 'esc') ||
((action === 'clear' || action === 'compact') && this._confirmAction)) {
if (typeof app !== 'undefined' && app.terminal) {
app.terminal.focus();
@@ -110,6 +113,15 @@ const KeyboardAccessoryBar = {
case 'scroll-down':
this.sendKey('\x1b[B');
break;
case 'esc':
this.sendKey('\x1b');
break;
case 'opt-enter':
this.sendKey('\x1b\r');
break;
case 'tab':
this.sendKey('\t');
break;
case 'shift-tab':
this.sendKey('\x1b[Z');
break;
-36
View File
@@ -946,24 +946,6 @@ html.mobile-init .file-browser-panel {
background: #2563eb;
}
.accessory-btn-dismiss {
padding: 8px 14px;
background: #2a2a2a;
border: 1.5px solid rgba(255, 255, 255, 0.25);
border-radius: 6px;
color: #e5e5e5;
}
.accessory-btn-dismiss svg {
width: 22px;
height: 22px;
stroke-width: 3;
}
.accessory-btn-dismiss:active {
background: #3a3a3a;
}
/* Voice preview — positioned above accessory bar on mobile */
.voice-preview {
bottom: calc(var(--safe-area-bottom) + 94px);
@@ -2131,24 +2113,6 @@ html.mobile-init .file-browser-panel {
background: #2563eb;
}
.accessory-btn-dismiss {
padding: 8px 14px;
background: #2a2a2a;
border: 1.5px solid rgba(255, 255, 255, 0.25);
border-radius: 6px;
color: #e5e5e5;
}
.accessory-btn-dismiss svg {
width: 22px;
height: 22px;
stroke-width: 3;
}
.accessory-btn-dismiss:active {
background: #3a3a3a;
}
/* ============================================================================
iOS Safari Specific Fixes
============================================================================ */