import { useKeyboard } from "@opentui/solid"; import { For, createSignal, createMemo, onMount, onCleanup } from "solid-js"; import type { KeyEvent } from "@opentui/core"; import type { Quote } from "../../../src/core/types.js"; import { useKeyboardNav } from "../context/keyboard.js"; interface QuotesOverlayProps { quotes: Quote[]; messageIndex: number; onClose: () => void; onEdit: () => Promise; onDelete: (quoteId: string) => Promise; } export function QuotesOverlay(props: QuotesOverlayProps) { const { setOverlayActive } = useKeyboardNav(); onMount(() => setOverlayActive(true)); onCleanup(() => setOverlayActive(false)); const [selectedIndex, setSelectedIndex] = createSignal(0); const [confirmDelete, setConfirmDelete] = createSignal(false); createMemo(() => { if (selectedIndex() >= props.quotes.length) { setSelectedIndex(Math.max(0, props.quotes.length - 1)); } }); useKeyboard((event: KeyEvent) => { const key = event.name; const listLength = props.quotes.length; if (confirmDelete()) { event.preventDefault(); if (key === "y") { const quote = props.quotes[selectedIndex()]; if (quote) { void props.onDelete(quote.id); } setConfirmDelete(false); if (props.quotes.length <= 1) { props.onClose(); } } else if (key === "n" || key === "escape") { setConfirmDelete(false); } return; } if (key === "j" || key === "down") { event.preventDefault(); setSelectedIndex((prev) => Math.min(prev + 1, listLength - 1)); return; } if (key === "k" || key === "up") { event.preventDefault(); setSelectedIndex((prev) => Math.max(prev - 1, 0)); return; } if (key === "e") { event.preventDefault(); void props.onEdit(); return; } if (key === "d") { event.preventDefault(); if (listLength > 0) { setConfirmDelete(true); } return; } if (key === "escape") { event.preventDefault(); props.onClose(); return; } }); const truncateText = (text: string, maxLen: number = 60): string => { const singleLine = text.replace(/\n/g, " ").trim(); return singleLine.length > maxLen ? singleLine.slice(0, maxLen - 3) + "..." : singleLine; }; const formatTimestamp = (timestamp: string): string => { const date = new Date(timestamp); return date.toLocaleDateString() + " " + date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }); }; return ( Quotes from message [{props.messageIndex}] No quotes in this message 0}> {(quote, index) => { const isSelected = () => selectedIndex() === index(); const displayText = truncateText(quote.text); const speaker = quote.speaker === "human" ? "You" : quote.speaker; return ( {isSelected() ? "▶ " : " "}{speaker} ({formatTimestamp(quote.timestamp)}) "{displayText}" ); }} Delete this quote? (y/N) j/k: navigate | e: edit in $EDITOR | d: delete | Esc: close ); }