Ports catalog.ts's tree renderer to components under src/components/sidebar/, following docs/SIDEBAR.md: two-line cards behind a 5px activity rail, adaptive meta line (duration, detail, program, diff stat), collapsible folders, j/k walk, inline rename and a right-click menu. The nav walk reads a pure model (model.ts) rather than the DOM, so the rule that an expanded folder header is skipped and a collapsed one is not is testable without a render. Rail motion needs @keyframes, so it stays in sidebar.css rather than the Tailwind config. Closes #244
35 lines
1.1 KiB
TypeScript
35 lines
1.1 KiB
TypeScript
// The sidebar's search field: a substring filter over the tree (name, command
|
|
// and cwd). Escape clears it and hands the keyboard back to the list.
|
|
|
|
export interface SidebarSearchProps {
|
|
value: string;
|
|
onChange(value: string): void;
|
|
/** Escape on an already-empty field — the list wants the keyboard back. */
|
|
onDismiss?(): void;
|
|
}
|
|
|
|
export function SidebarSearch({ value, onChange, onDismiss }: SidebarSearchProps) {
|
|
return (
|
|
<header className="sidebar-search p-sp-2">
|
|
<input
|
|
type="search"
|
|
className="search w-full rounded-r-1 border border-border bg-surface-2 px-sp-2 py-sp-1 text-fs-12 text-ink"
|
|
placeholder="Search sessions…"
|
|
aria-label="Search sessions"
|
|
autoComplete="off"
|
|
autoCorrect="off"
|
|
autoCapitalize="off"
|
|
spellCheck={false}
|
|
value={value}
|
|
onChange={(e) => onChange(e.currentTarget.value)}
|
|
onKeyDown={(e) => {
|
|
if (e.key !== "Escape") return;
|
|
e.preventDefault();
|
|
if (value) onChange("");
|
|
else onDismiss?.();
|
|
}}
|
|
/>
|
|
</header>
|
|
);
|
|
}
|