"use client"; // The grounding palette — the connective tissue between the search results and // the chat. It always states WHAT the AI is looking at and turns that target // into an action. This is the one deliberately-bold control in the workspace: // // • a first-class segmented MODE TOGGLE (Whole search ⇄ Selection), and // • a cluster of ACTION buttons operating on the active target — Ask, Sweep, // and a couple of preset directives that pre-fill the composer/sweep box. // // Everything else stays quiet (semantic theme tokens, lucide icons); the palette // carries the emphasis. import { GlobeIcon, ListChecksIcon, SendIcon, TelescopeIcon, XIcon, } from "lucide-react"; import type { SearchHandoff } from "yt-dlp-transcript-common/lib/aiHandoff"; import type { GroundingMode } from "yt-dlp-transcript-common/components/SearchSessionContext"; // Preset directives — one click pre-fills the composer (which is also the sweep // directive), so a common report focus is a keystroke away. const PRESETS: { label: string; directive: string }[] = [ { label: "Summary", directive: "a concise summary of the key points" }, { label: "Contradictions", directive: "the major contradictions between these" }, { label: "Timeline", directive: "a chronological timeline of what happened" }, ]; export function GroundingPalette({ pinned, effectiveMode, setMode, selectedCount, onDeselect, onClearSelection, canSweep, sweeping, hasReport, busy, hasKey, onAsk, onSweep, onPreset, }: { // The active grounding (for the selection chips + counts). Never null here — // AskChat only renders the palette when there's a grounding to act on. pinned: SearchHandoff; // The mode after the empty-selection guard (what's actually in effect). effectiveMode: GroundingMode; setMode: (m: GroundingMode) => void; selectedCount: number; onDeselect: (key: string) => void; onClearSelection: () => void; canSweep: boolean; sweeping: boolean; hasReport: boolean; busy: boolean; hasKey: boolean; // Submit the composer as a normal grounded question. onAsk: () => void; // Start (or extend) a whole-target sweep. onSweep: (mode: "fresh" | "extend") => void; // Pre-fill the composer / sweep directive. onPreset: (directive: string) => void; }) { const hasSelection = selectedCount > 0; const n = pinned.videos.length; return (
{/* ── Mode toggle: the signature segmented switch ── */}
{effectiveMode === "selection" ? `Grounded in ${n} selected video${n === 1 ? "" : "s"}` : "Grounded in the whole search"}
{/* ── Selection chips (dismissible → deselect) ── */} {effectiveMode === "selection" && (
{pinned.videos.map((v) => ( {v.title} ))}
)} {/* ── Action cluster: Ask · Sweep · presets ── */}
); }