'use client'; import { Info, Lightbulb, AlertTriangle } from 'lucide-react'; import { useLayoutEffect, useRef } from 'react'; import type { EditorHint } from '@/lib/edit/scene-editor-surface'; interface HintRailProps { readonly hints?: readonly EditorHint[]; readonly reserveSpace?: boolean; } /** * Reserved AI inline-coach surface. Renders nothing in Phase 1 (surfaces * return [] for hints). Layout slot is wired so future phases can populate * it without restructuring the shell. */ export function HintRail({ hints, reserveSpace = false }: HintRailProps) { const railRef = useRef(null); useLayoutEffect(() => { const rail = railRef.current; const host = rail?.parentElement; if (!reserveSpace || !rail || !host) return; const updateReservedSpace = () => { host.style.setProperty( '--editor-hint-rail-height', `${rail.getBoundingClientRect().height}px`, ); }; updateReservedSpace(); const observer = new ResizeObserver(updateReservedSpace); observer.observe(rail); return () => { observer.disconnect(); host.style.removeProperty('--editor-hint-rail-height'); }; }, [hints, reserveSpace]); if (!hints || hints.length === 0) return null; return (
{hints.map((hint) => ( ))}
); } const ICONS = { info: Info, suggestion: Lightbulb, warning: AlertTriangle, } as const; const SEVERITY_STYLES = { info: 'border-zinc-200 bg-white text-zinc-700 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-200', suggestion: 'border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-900/40 dark:bg-amber-950/40 dark:text-amber-100', warning: 'border-rose-200 bg-rose-50 text-rose-900 dark:border-rose-900/40 dark:bg-rose-950/40 dark:text-rose-100', } as const; function HintCard({ hint }: { readonly hint: EditorHint }) { const Icon = ICONS[hint.severity]; return (
{hint.message}
{hint.action && ( )}
); }