Files
web-terminal/public/search.ts
Yaojia Wang eaeacf3a78 feat(v0.3): keybar Claude shortcuts + scrollback search + clickable links
- keybar: add Esc·Esc / ^O / ^T / ^B + per-button tooltips (KEY_MAP 14 keys)
- M1 search: @xterm/addon-search per terminal; 🔍 toolbar button + search box
  (Enter=next, Shift+Enter=prev, Esc=close)
- M2 links: @xterm/addon-web-links per terminal (tap URLs Claude prints)
- tab bar split into #tabs (scrollable) + #toolbar (utility cluster) for future
  utilities (QR/settings/dashboard)
- Browser-verified: 14 keybar buttons, search highlights matches, no console errors.
  199 tests green, typechecks + build ok.
2026-06-17 18:28:40 +02:00

66 lines
1.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* public/search.ts — scrollback search box for the active terminal (M1).
*
* Adds a 🔍 button to the toolbar that toggles a small search overlay.
* Enter = next, Shift+Enter = previous, Esc = close.
*/
export interface SearchHooks {
find: (query: string, dir: 'next' | 'prev') => void
clear: () => void
}
function makeBtn(label: string, title: string): HTMLButtonElement {
const b = document.createElement('button')
b.textContent = label
b.title = title
b.setAttribute('aria-label', title)
return b
}
export function mountSearch(toolbar: HTMLElement, hooks: SearchHooks): void {
const box = document.createElement('div')
box.id = 'searchbox'
box.style.display = 'none'
const input = document.createElement('input')
input.type = 'text'
input.className = 'search-input'
input.placeholder = 'Search scrollback…'
const prev = makeBtn('↑', 'Previous match (Shift+Enter)')
const next = makeBtn('↓', 'Next match (Enter)')
const close = makeBtn('×', 'Close (Esc)')
box.append(input, prev, next, close)
document.body.appendChild(box)
const open = (): void => {
box.style.display = 'flex'
input.focus()
input.select()
}
const hide = (): void => {
box.style.display = 'none'
hooks.clear()
}
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
e.preventDefault()
hooks.find(input.value, e.shiftKey ? 'prev' : 'next')
} else if (e.key === 'Escape') {
e.preventDefault()
hide()
}
e.stopPropagation()
})
prev.addEventListener('click', () => hooks.find(input.value, 'prev'))
next.addEventListener('click', () => hooks.find(input.value, 'next'))
close.addEventListener('click', hide)
const toggle = makeBtn('🔍', 'Search scrollback')
toggle.className = 'toolbtn'
toggle.addEventListener('click', () => (box.style.display === 'none' ? open() : hide()))
toolbar.appendChild(toggle)
}