@tangle-network/agent-app 0.46.7 → 0.46.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/studio-react/use-studio-generations.ts","../../src/studio-react/studio-composer.tsx","../../src/studio-react/composer-option-controls.tsx","../../src/studio-react/generation-notice.tsx","../../src/studio-react/media-tile.tsx","../../src/studio-react/vault-path-popover.tsx","../../src/studio-react/download-generations.ts","../../src/studio-react/studio-playback.tsx","../../src/studio-react/media-viewer.tsx","../../src/studio-react/studio-home-screen.tsx","../../src/studio-react/studio-confirm.tsx","../../src/studio-react/studio-toasts.tsx","../../src/studio-react/use-batch-navigation.ts","../../src/studio-react/use-deferred-delete.ts","../../src/studio-react/studio-generation-screen.tsx","../../src/studio-react/studio-history-screen.tsx","../../src/studio-react/use-generation-history.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useRevalidator } from 'react-router'\nimport {\n type Generation,\n generationStatus,\n isLocalGeneration,\n latestBatchOf,\n mergeLiveGeneration,\n mergeLoaderAndLive,\n} from '../studio'\n\n/**\n * The generation orchestrator behind a studio surface: it merges the loader's\n * rows with in-flight live generations, computes the latest batch for the\n * canvas, polls running generations until they settle, and revalidates the\n * route loader when a status changes.\n *\n * The merge keeps the canvas, the library, and the polling path looking at the\n * same full list. Polling hits `generationsEndpoint` (default `/api/generations`,\n * the convention both apps already serve); pass an override if a product routes\n * it elsewhere. `onGenerated` is wired to the composer's per-result callback.\n */\nexport function useStudioGenerations(\n loaderGenerations: Generation[],\n options: { workspaceId?: string; generationsEndpoint?: string } = {},\n) {\n const { workspaceId, generationsEndpoint = '/api/generations' } = options\n const revalidator = useRevalidator()\n const [liveGenerations, setLiveGenerations] = useState<Generation[]>([])\n\n const mergedGenerations = useMemo(\n () => mergeLoaderAndLive(loaderGenerations, liveGenerations),\n [loaderGenerations, liveGenerations],\n )\n\n const latestBatch = useMemo(() => latestBatchOf(mergedGenerations), [mergedGenerations])\n\n const runningGenerationIds = useMemo(() => mergedGenerations\n .filter((gen) => {\n const status = generationStatus(gen)\n return status === 'pending' || status === 'running'\n })\n .map((gen) => gen.id)\n .filter((id) => !id.startsWith('local-')), [mergedGenerations])\n\n // The poll loop must not churn the effect. `runningGenerationIds` is a fresh\n // array every render and react-router's `revalidator` identity flips while a\n // revalidation is in flight — depending on either restarts the interval on\n // every tick, collapsing the 4s cadence into a request flood. Key the effect\n // on the STABLE join of the running ids (re-subscribe only when the set\n // actually changes) and reach the live ids / revalidate through refs.\n const runningIdsRef = useRef(runningGenerationIds)\n runningIdsRef.current = runningGenerationIds\n const revalidateRef = useRef(revalidator.revalidate)\n revalidateRef.current = revalidator.revalidate\n const runningKey = runningGenerationIds.join(',')\n\n useEffect(() => {\n if (!workspaceId || !runningKey) return\n let cancelled = false\n const poll = async () => {\n const responses = await Promise.all(runningIdsRef.current.map(async (id) => {\n const res = await fetch(`${generationsEndpoint}?workspaceId=${encodeURIComponent(workspaceId)}&id=${encodeURIComponent(id)}`)\n if (!res.ok) return null\n const data = await res.json() as { generation?: Generation }\n return data.generation ?? null\n }))\n if (cancelled) return\n const refreshed = responses.filter((gen): gen is Generation => Boolean(gen))\n if (refreshed.length > 0) {\n setLiveGenerations((current) => refreshed.reduce(mergeLiveGeneration, current))\n }\n if (refreshed.some((gen) => generationStatus(gen) !== 'running' && generationStatus(gen) !== 'pending')) {\n revalidateRef.current()\n }\n }\n const interval = window.setInterval(() => { void poll() }, 4_000)\n void poll()\n return () => {\n cancelled = true\n window.clearInterval(interval)\n }\n }, [runningKey, workspaceId, generationsEndpoint])\n\n const onGenerated = useCallback((generation: Generation) => {\n setLiveGenerations((current) => mergeLiveGeneration(current, generation))\n if (!isLocalGeneration(generation)) revalidateRef.current()\n }, [])\n\n return { mergedGenerations, latestBatch, onGenerated }\n}\n","/**\n * The studio composer: one chat-shaped card — prompt, media-type switch, and a\n * band of option pills — that replaces the stacked field panel.\n *\n * The whole point of the rework is that the CONTROLS ARE THE MODEL'S OWN. A pill\n * renders only when the selected model publishes that parameter, its choices are\n * the published enum (or the published range), and the value goes onto the wire\n * exactly as published — seedance takes the string `'5'`, veo `'8s'`, kling the\n * number `5`, and coercing any of them is a 400 from the provider. A model that\n * publishes nothing (`ltx-video`) shows the model pill and nothing else: the\n * honest reading of \"we do not know what this takes\" is an absent control, not\n * an invented one and not a disabled one.\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport {\n AudioLines,\n ArrowUp,\n Clock,\n Copy,\n Gauge,\n Image as ImageIcon,\n Mic,\n Monitor,\n Ratio,\n Scaling,\n SlidersHorizontal,\n Sparkles,\n TriangleAlert,\n Video,\n type LucideIcon,\n} from 'lucide-react'\nimport {\n type Generation,\n type MediaModelCatalogResponse,\n type MediaModelOption,\n type ModelOptionMetadata,\n type ModelOptionValue,\n type ModelOptionsMetadata,\n aspectRatioFromOptions,\n buildGenerationRequestBody,\n curateComposerModels,\n failedOptimisticGeneration,\n imageToVideoSibling,\n laneUnavailable,\n normalizeImageCount,\n optimisticGeneration,\n optionChoices,\n preferredModelId,\n reconcileOptionValues,\n resolveComposerOptions,\n supportsCustomImageSize,\n textToVideoSibling,\n userSafeGenerationMessage,\n} from '../studio'\nimport {\n AudioTogglePill,\n ComposerBand,\n CustomSizeForm,\n MediaTypeSegments,\n ModelPill,\n OptionPill,\n ReferencePill,\n type MediaTypeSegment,\n type OptionChoice,\n optionValueLabel,\n} from './composer-option-controls'\n\n/** The lanes the composer offers. Avatar and transcription stay disabled\n * (#451); \"Audio\" is the word for the `speech` lane everywhere on screen. */\nexport type ComposerType = 'image' | 'video' | 'speech'\n\nconst SEGMENTS: readonly MediaTypeSegment<ComposerType>[] = [\n { type: 'image', label: 'Image', icon: ImageIcon },\n { type: 'video', label: 'Video', icon: Video },\n { type: 'speech', label: 'Audio', icon: AudioLines },\n]\n\n/** Pill order per lane. A parameter absent from the model's metadata, or marked\n * `supported: false`, drops out of the row entirely. */\nconst PILL_ORDER: Record<ComposerType, readonly string[]> = {\n image: ['size', 'quality', 'n'],\n video: ['duration', 'resolution', 'aspect_ratio', 'mode'],\n speech: ['voice', 'speed'],\n}\n\nconst PARAM_LABELS: Record<string, string> = {\n size: 'Size',\n quality: 'Quality',\n n: 'Count',\n duration: 'Duration',\n resolution: 'Resolution',\n aspect_ratio: 'Aspect',\n mode: 'Mode',\n voice: 'Voice',\n speed: 'Speed',\n}\n\nconst PARAM_ICONS: Record<string, LucideIcon> = {\n size: Scaling,\n quality: Sparkles,\n n: Copy,\n duration: Clock,\n resolution: Monitor,\n aspect_ratio: Ratio,\n mode: SlidersHorizontal,\n voice: Mic,\n speed: Gauge,\n}\n\n/**\n * Speed is published as a continuous range (0.25–4.0 on OpenAI's endpoint), and\n * a range is not a menu: enumerating it at the step a user would actually pick\n * is 376 rows. These are the presets, filtered against whatever range the model\n * publishes, so a narrower range can never offer a speed it rejects.\n */\nconst SPEED_PRESETS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 4] as const\n\nfunction choicesFor(param: string, meta: ModelOptionMetadata): readonly ModelOptionValue[] {\n const { min, max } = meta\n if (param === 'speed' && !meta.values && min != null && max != null) {\n return SPEED_PRESETS.filter((speed) => speed >= min && speed <= max)\n }\n return optionChoices(meta)\n}\n\n/** The parameters a lane renders, in order, skipping unknown and unsupported\n * ones. `audio` and the reference image are not in here — neither is a value\n * menu. */\nfunction visibleParams(type: ComposerType, options: ModelOptionsMetadata | undefined): string[] {\n if (!options) return []\n return PILL_ORDER[type].filter((param) => {\n const meta = options[param]\n return Boolean(meta) && meta?.supported !== false\n })\n}\n\n/**\n * The lane's model. The catalog's own default wins when it survives curation;\n * otherwise the first curated model does — a default that #449 curation removed\n * (a Sora model, a non-gpt-image-2 image model) must not leave the lane with a\n * selection its own menu does not offer.\n */\nfunction defaultModelId(\n type: ComposerType,\n catalog: MediaModelCatalogResponse | null,\n curated: readonly MediaModelOption[],\n): string {\n const preferred = preferredModelId(type, catalog)\n if (preferred && curated.some((model) => model.id === preferred && model.status !== 'unavailable')) return preferred\n return curated.find((model) => model.status !== 'unavailable')?.id ?? curated[0]?.id ?? ''\n}\n\nexport interface StudioComposerProps {\n workspaceId?: string\n onGenerated: (generation: Generation) => void\n /** `home` (under a page heading) vs `docked` (pinned under a generation).\n * Presentational only — the card itself is identical either way. */\n variant?: 'home' | 'docked'\n /** Pick or upload a reference image, resolving to a URL or `null` on cancel.\n * Without it the Reference pill takes a URL instead, which is the most a host\n * with no upload endpoint can honestly offer. */\n pickReferenceImage?: () => Promise<string | null>\n className?: string\n}\n\n/**\n * The composer card. The host owns its width (the card fills its container) and\n * the heading above it; this owns the prompt, the controls, and the POST.\n */\nexport function StudioComposer({\n workspaceId,\n onGenerated,\n variant = 'home',\n pickReferenceImage,\n className,\n}: StudioComposerProps) {\n const [type, setType] = useState<ComposerType>('image')\n const [prompt, setPrompt] = useState('')\n const [catalog, setCatalog] = useState<MediaModelCatalogResponse | null>(null)\n const [catalogLoading, setCatalogLoading] = useState(false)\n const [catalogError, setCatalogError] = useState<string | null>(null)\n const [selectedModels, setSelectedModels] = useState<Partial<Record<ComposerType, string>>>({})\n const [optionValues, setOptionValues] = useState<Record<ComposerType, Record<string, ModelOptionValue>>>({\n image: {},\n video: {},\n speech: {},\n })\n const [referenceImageUrl, setReferenceImageUrl] = useState<string | null>(null)\n const [isSubmitting, setIsSubmitting] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const submitLockRef = useRef(false)\n const bandRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!workspaceId) return\n let cancelled = false\n setCatalogLoading(true)\n setCatalogError(null)\n\n fetch(`/api/media-models?workspaceId=${encodeURIComponent(workspaceId)}`)\n .then(async (res) => {\n const data = await res.json() as MediaModelCatalogResponse\n if (!res.ok) throw new Error(data.error ?? 'Could not load media models')\n return data\n })\n .then((data) => {\n if (cancelled) return\n setCatalog(data)\n })\n .catch(() => {\n if (cancelled) return\n setCatalog(null)\n // Never surface the raw fetch/parse error — a non-JSON 404 page reads\n // as `Unexpected token 'N', \"Not Found\" is not valid JSON` to users.\n setCatalogError('Could not load media models')\n })\n .finally(() => {\n if (!cancelled) setCatalogLoading(false)\n })\n\n return () => {\n cancelled = true\n }\n }, [workspaceId])\n\n const laneModels = useMemo(() => catalog?.models[type] ?? [], [catalog, type])\n const curatedModels = useMemo(() => curateComposerModels(type, laneModels), [laneModels, type])\n // A retained pick survives only while the CURRENT catalog can honour it: with\n // no catalog yet keep it; an intentionally-uncurated i2v sibling stays (it is\n // reached by attaching a reference, never listed); anything else must be\n // present in the curated list, or the lane falls back to its\n // default. The deleted ComposerHero defended this via selectedModelsWithDefaults;\n // that helper resolves over the FULL catalog and would resurrect\n // curation-removed defaults, so the guard is re-derived here over curatedModels.\n const retained = selectedModels[type]\n const retainedUsable = retained !== undefined && (\n !catalog\n || Boolean(textToVideoSibling(retained))\n || curatedModels.some((model) => model.id === retained)\n )\n const modelId = retainedUsable ? retained : defaultModelId(type, catalog, curatedModels)\n // The image-to-video sibling is deliberately absent from the curated menu (it\n // is reached by attaching a reference image), so the row backing the pill is\n // looked up in the FULL lane list and may still be missing — a sibling the\n // catalog does not carry is sent by id and displayed as its id.\n const modelOption = laneModels.find((model) => model.id === modelId)\n\n // A dead selection is honoured only while the user is looking at it: a catalog\n // (re)load or a lane switch re-resolves to the first available model, so a dead\n // default never stays selected on its own (#463). A menu pick of an unavailable\n // model after that still sticks — until the catalog or the lane changes again.\n useEffect(() => {\n setSelectedModels((current) => {\n const retainedId = current[type]\n if (!retainedId || !catalog) return current\n // Never prune the image-to-video sibling: it is reached only by attaching a\n // reference (never menu-listed), and pruning it would fall back to the t2v\n // parent with the reference still attached — a reference on a text-to-video\n // request. An unavailable sibling instead keeps the warned pill and the\n // modelReady send gate, exactly the pre-#463 behavior.\n if (textToVideoSibling(retainedId)) return current\n const row = (catalog.models[type] ?? []).find((model) => model.id === retainedId)\n if (!row || row.status !== 'unavailable') return current\n const next = { ...current }\n delete next[type]\n return next\n })\n }, [catalog, type])\n\n const options = useMemo(\n () => (modelId\n ? resolveComposerOptions({\n type,\n modelId,\n provider: modelOption?.provider,\n catalogOptions: modelOption?.options,\n })\n : undefined),\n [modelId, modelOption, type],\n )\n\n // Re-reconcile whenever the resolved options change: a selection the new model\n // still accepts survives, an illegal one resets to that model's default, and a\n // parameter it does not publish is dropped rather than carried invisibly.\n useEffect(() => {\n setOptionValues((current) => {\n const next = reconcileOptionValues(options, current[type], {\n allowCustomSize: supportsCustomImageSize(modelId),\n })\n const unchanged = Object.keys(next).length === Object.keys(current[type]).length\n && Object.entries(next).every(([key, value]) => current[type][key] === value)\n return unchanged ? current : { ...current, [type]: next }\n })\n }, [modelId, options, type])\n\n const values = optionValues[type]\n const params = visibleParams(type, options)\n const audioMeta = type === 'video' ? options?.audio : undefined\n const audioSupported = Boolean(audioMeta) && audioMeta?.supported !== false\n // A model the catalog does not list is normally \"not ready\" — except for a\n // verified image-to-video sibling, which the composer selected itself by\n // attaching a reference image and must be able to send even when the catalog\n // never listed it.\n const unlistedSibling = !modelOption && Boolean(textToVideoSibling(modelId))\n const referenceSupported = type === 'video'\n && Boolean(imageToVideoSibling(modelId) ?? textToVideoSibling(modelId))\n\n const modelReady = (Boolean(modelOption) || unlistedSibling)\n && modelOption?.status !== 'unavailable'\n && !catalogLoading\n && !catalogError\n const laneDown = Boolean(catalog) && !catalogLoading && !catalogError && laneUnavailable(curatedModels)\n const canSubmit = Boolean(workspaceId) && modelReady && Boolean(prompt.trim()) && !isSubmitting\n\n function selectModel(id: string) {\n setSelectedModels((current) => ({ ...current, [type]: id }))\n }\n\n /** The model MENU's handler. While a reference is attached the selection must\n * keep the attachment ⇒ image-to-video invariant: a reference-capable pick is\n * re-mapped to its i2v sibling, and a pick with no sibling drops the\n * attachment explicitly rather than hiding it to reappear later. */\n function chooseModel(id: string) {\n if (!referenceImageUrl || type !== 'video') return selectModel(id)\n const sibling = imageToVideoSibling(id)\n if (sibling) return selectModel(sibling)\n if (!textToVideoSibling(id)) setReferenceImageUrl(null)\n return selectModel(id)\n }\n\n function setOption(param: string, value: ModelOptionValue) {\n setOptionValues((current) => ({ ...current, [type]: { ...current[type], [param]: value } }))\n }\n\n function attachReference(url: string) {\n setReferenceImageUrl(url)\n const sibling = imageToVideoSibling(modelId)\n if (sibling) selectModel(sibling)\n }\n\n function removeReference() {\n setReferenceImageUrl(null)\n const sibling = textToVideoSibling(modelId)\n if (sibling) selectModel(sibling)\n }\n\n async function generate() {\n if (!workspaceId || submitLockRef.current || isSubmitting) return\n const promptText = prompt.trim()\n if (!promptText) return\n if (!modelReady) return\n submitLockRef.current = true\n setIsSubmitting(true)\n setError(null)\n\n const clientRequestId = crypto.randomUUID()\n const imageCount = type === 'image' ? normalizeImageCount(values.n ?? 1) : 1\n const localGenerations = Array.from({ length: imageCount }, (_, outputIndex) => optimisticGeneration(\n {\n type,\n prompt: promptText,\n model: modelId,\n clientRequestId,\n outputIndex: type === 'image' ? outputIndex : undefined,\n outputCount: type === 'image' ? imageCount : undefined,\n },\n aspectRatioFromOptions(type, {\n size: asText(values.size),\n aspectRatio: asText(values.aspect_ratio),\n }),\n ))\n localGenerations.slice().reverse().forEach(onGenerated)\n setPrompt('')\n\n let receivedServerGeneration = false\n try {\n const body = buildGenerationRequestBody({\n workspaceId,\n clientRequestId,\n type,\n model: modelId,\n prompt: promptText,\n // `duration`, `audio` and `speed` go on the wire in the TYPE the model\n // published them in — a `duration` of `'5'` that arrives as `5` is a\n // different request, and the three providers behind this lane disagree\n // about which is right. An absent value is omitted, never defaulted.\n image: {\n size: asText(values.size),\n quality: asText(values.quality),\n count: imageCount,\n },\n video: {\n duration: asWireScalar(values.duration),\n resolution: asText(values.resolution),\n aspectRatio: asText(values.aspect_ratio),\n referenceImageUrl: referenceSupported && referenceImageUrl ? referenceImageUrl : undefined,\n audio: audioSupported && typeof values.audio === 'boolean' ? values.audio : undefined,\n mode: asText(values.mode),\n },\n speech: {\n voice: asText(values.voice),\n speed: typeof values.speed === 'number' ? values.speed : undefined,\n },\n })\n\n const res = await fetch('/api/generate', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n const data = await res.json() as { generation?: Generation; generations?: Generation[]; error?: string }\n const serverGenerations = data.generations?.length ? data.generations : data.generation ? [data.generation] : []\n if (serverGenerations.length > 0) {\n receivedServerGeneration = true\n serverGenerations.slice().reverse().forEach(onGenerated)\n }\n if (!res.ok || serverGenerations.length === 0) throw new Error(data.error ?? 'Generation failed')\n } catch (err) {\n if (!receivedServerGeneration) localGenerations.map(failedOptimisticGeneration).forEach(onGenerated)\n setError(err instanceof Error ? userSafeGenerationMessage(err.message) : 'Generation failed')\n } finally {\n submitLockRef.current = false\n setIsSubmitting(false)\n }\n }\n\n const notice = catalogError ?? error\n const laneLabel = SEGMENTS.find((segment) => segment.type === type)!.label\n // An empty curated lane can reflect catalog or curation policy, not an outage.\n const laneDownMessage = curatedModels.length > 0\n ? `${laneLabel} models are temporarily unavailable`\n : `No ${laneLabel.toLowerCase()} models are available`\n\n return (\n <section\n data-variant={variant}\n className={`rounded-[14px] border border-border bg-card px-2.5 pb-[9px] pt-2 shadow-sm transition focus-within:border-primary focus-within:ring-[3px] focus-within:ring-ring/30 ${className ?? ''}`}\n >\n {laneDown ? (\n <p className=\"flex min-h-0 items-center gap-2 px-1.5 pb-3 pt-1.5 text-[13px] font-medium text-warning\">\n <TriangleAlert aria-hidden className=\"h-4 w-4 shrink-0\" strokeWidth={2} />\n <span>{laneDownMessage}</span>\n </p>\n ) : (\n <textarea\n value={prompt}\n onChange={(event) => setPrompt(event.target.value)}\n onKeyDown={(event) => {\n if (event.key !== 'Enter' || event.shiftKey) return\n event.preventDefault()\n void generate()\n }}\n rows={3}\n aria-label=\"Prompt\"\n placeholder=\"Describe what you want to generate…\"\n className=\"block min-h-[66px] w-full resize-none border-0 bg-transparent px-1.5 pb-1 pt-1.5 text-[14.5px] leading-relaxed outline-none placeholder:text-muted-foreground\"\n />\n )}\n\n <div className=\"flex items-center gap-2\">\n <MediaTypeSegments value={type} segments={SEGMENTS} onChange={setType} />\n\n <ComposerBand bandRef={bandRef} resetKey={type}>\n <ModelPill\n models={curatedModels}\n value={modelId}\n displayName={modelOption?.name || modelId || 'Select a model'}\n provider={modelOption?.provider}\n unavailable={modelOption?.status === 'unavailable'}\n onSelect={chooseModel}\n bandRef={bandRef}\n />\n\n {params.map((param) => (\n <div key={`${type}-${param}`} className=\"studio-pill-in flex-none\">\n <OptionPill\n label={PARAM_LABELS[param] ?? param}\n icon={PARAM_ICONS[param] ?? SlidersHorizontal}\n value={values[param]}\n choices={choicesForPill(param, options?.[param], values[param])}\n onSelect={(value) => setOption(param, value)}\n bandRef={bandRef}\n custom={param === 'size' && supportsCustomImageSize(modelId)\n ? {\n label: 'Custom…',\n render: ({ close }) => (\n <CustomSizeForm\n initial={asText(values.size)}\n onApply={(size) => {\n setOption('size', size)\n close()\n }}\n onCancel={close}\n />\n ),\n }\n : undefined}\n />\n </div>\n ))}\n\n {audioSupported && (\n <div key={`${type}-audio`} className=\"studio-pill-in flex-none\">\n <AudioTogglePill\n on={values.audio === true}\n onToggle={(on) => setOption('audio', on)}\n />\n </div>\n )}\n\n {referenceSupported && (\n <div key={`${type}-reference`} className=\"studio-pill-in flex-none\">\n <ReferencePill\n url={referenceImageUrl}\n onAttach={attachReference}\n onRemove={removeReference}\n pick={pickReferenceImage}\n bandRef={bandRef}\n />\n </div>\n )}\n </ComposerBand>\n\n <button\n type=\"button\"\n aria-label=\"Generate\"\n title=\"Generate\"\n disabled={!canSubmit}\n onClick={() => void generate()}\n className=\"studio-send ml-auto inline-flex h-8 w-8 flex-none items-center justify-center rounded-full text-white transition disabled:opacity-40\"\n >\n <ArrowUp className=\"h-4 w-4\" strokeWidth={2} />\n </button>\n </div>\n\n {notice && (\n <p className=\"px-1.5 pt-1.5 text-[12px] text-destructive\">\n {notice}\n </p>\n )}\n </section>\n )\n}\n\n/** A text-typed field's value, or `undefined` so the field is omitted entirely\n * — `String(undefined)` puts the literal `\"undefined\"` on the wire, which the\n * provider will try to honour. These fields are typed `string` by the\n * `/api/generate` contract, so a numeric published value is rendered as its\n * digits; the type-sensitive fields (`duration`, `audio`, `speed`) never pass\n * through here. */\nfunction asText(value: ModelOptionValue | undefined): string | undefined {\n return typeof value === 'string' ? value : typeof value === 'number' ? String(value) : undefined\n}\n\n/** A duration passes through as published: the string `'5'`, the string `'8s'`,\n * or the number `5`. Only a boolean (which no lane publishes here) is refused. */\nfunction asWireScalar(value: ModelOptionValue | undefined): string | number | undefined {\n return typeof value === 'string' || typeof value === 'number' ? value : undefined\n}\n\n/** The pill's rows: the published choices, plus the current value when it is a\n * legal off-enum one (a custom gpt-image-2 size), so the pill reports what is\n * actually selected instead of falling back to a dash. */\nfunction choicesForPill(\n param: string,\n meta: ModelOptionMetadata | undefined,\n value: ModelOptionValue | undefined,\n): OptionChoice[] {\n if (!meta) return []\n const choices = choicesFor(param, meta).map((choice) => ({\n value: choice,\n label: optionValueLabel(param, choice),\n }))\n if (value === undefined || choices.some((choice) => choice.value === value)) return choices\n return [...choices, { value, label: `${optionValueLabel(param, value)} · custom` }]\n}\n","/**\n * The studio composer's control row: the media-type segmented group, the\n * horizontally scrolling option band, and the pills that dock in it.\n *\n * Every pill that opens a panel opens it through `usePopover` + `PopoverSurface`\n * (`../web-react/controls`), never an in-place `absolute` panel: the band IS a\n * scroll container (`overflow-x-auto`), and a scroll container clips every\n * positioned descendant whose containing block sits inside it — the measured\n * failure that left the chat composer's own menus painting zero pixels. The\n * surface portals to `document.body` and re-anchors on capture-phase scroll, so\n * scrolling the band moves an open menu with its pill. The one rule the surface\n * cannot supply is when to give up: a menu whose pill has been scrolled out of\n * the band no longer points at anything, so it closes when the pill's\n * horizontal CENTRE leaves the band's box.\n */\n\nimport {\n useCallback,\n useEffect,\n useId,\n useState,\n type JSX,\n type ReactNode,\n type RefObject,\n} from 'react'\nimport { ImagePlus, TriangleAlert, Volume2, VolumeX, X, type LucideIcon } from 'lucide-react'\nimport {\n CheckGlyph,\n ChevronDown,\n OVERLAY_SHADOW,\n POPOVER_OPTION_FOCUS,\n PopoverSurface,\n usePopover,\n} from '../web-react/controls'\nimport { ProviderLogo } from '../web-react/provider-logo'\nimport { type MediaModelOption, type ModelOptionValue, validateCustomImageSize } from '../studio'\n\n/** The resting pill: one row height, never wraps, shrink-proof in the band. */\nconst PILL = 'inline-flex h-7 flex-none items-center gap-1.5 whitespace-nowrap rounded-full border border-border bg-card px-2.5 text-[12.5px] font-medium text-foreground transition hover:bg-accent'\n/**\n * Optically centers a pill label. Flex `items-center` centers the LINE BOX, but\n * where the glyphs sit inside it is font-metric-determined — with an\n * ascent-heavy font the text reads ~1.5px high. Trimming the line box to the\n * cap→baseline band makes flex centering center the visible text in every\n * font; unsupported browsers keep the untrimmed (current) behavior.\n */\nconst PILL_LABEL = '[text-box:trim-both_cap_alphabetic]'\nconst MENU_PANEL = `flex min-w-[184px] flex-col overflow-y-auto rounded-xl border border-border bg-popover p-1 text-popover-foreground ${OVERLAY_SHADOW}`\nconst MENU_HEADER = 'px-2.5 pb-1 pt-1.5 text-[10.5px] font-semibold uppercase tracking-[0.08em] text-muted-foreground'\n\nfunction menuRowClass(selected: boolean): string {\n return `flex w-full items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-[13px] transition ${POPOVER_OPTION_FOCUS} ${\n selected ? 'bg-primary/10 font-medium' : 'hover:bg-accent'\n }`\n}\n\n/** Deepest edge fade, in px. Beyond this the fade stops reading as \"there is\n * more\" and starts reading as a vignette. */\nconst MAX_FADE = 32\n\n/** One media lane's segment: the icon it shows collapsed, the word it shows\n * when active. */\nexport interface MediaTypeSegment<T extends string> {\n type: T\n label: string\n icon: LucideIcon\n}\n\n/**\n * The pinned-left media-type group: a track holding one filled pill (the active\n * lane, icon + word) and icon-only siblings. `aria-pressed` carries the state\n * and `aria-label` carries the word the collapsed items drop.\n */\nexport function MediaTypeSegments<T extends string>({\n value,\n segments,\n onChange,\n}: {\n value: T\n segments: readonly MediaTypeSegment<T>[]\n onChange: (type: T) => void\n}) {\n return (\n <div\n role=\"group\"\n aria-label=\"Media type\"\n className=\"flex flex-none items-center gap-0.5 rounded-full border border-border bg-muted p-[3px]\"\n >\n {segments.map(({ type, label, icon: Icon }) => {\n const active = type === value\n return (\n <button\n key={type}\n type=\"button\"\n aria-pressed={active}\n aria-label={label}\n title={label}\n onClick={() => onChange(type)}\n className={`inline-flex h-7 items-center gap-1.5 whitespace-nowrap rounded-full text-[12.5px] transition ${\n active\n ? 'bg-card px-2.5 font-medium text-foreground shadow-sm'\n : 'px-2 text-muted-foreground hover:text-foreground'\n }`}\n >\n <Icon className=\"h-4 w-4 shrink-0\" strokeWidth={1.5} />\n {active && <span>{label}</span>}\n </button>\n )\n })}\n </div>\n )\n}\n\n/**\n * The middle scroller. It hides its scrollbar and fades whichever edge has\n * content behind it, at the DEPTH of what is actually hidden (capped at\n * {@link MAX_FADE}) rather than a fixed gradient that claims more is off-screen\n * than there is. A media-type switch resets the scroll to the start, because\n * the control set itself changed; every other re-render leaves `scrollLeft`\n * alone, so picking a value cannot jump the band back to the beginning.\n */\nexport function ComposerBand({\n bandRef,\n resetKey,\n children,\n}: {\n bandRef: RefObject<HTMLDivElement | null>\n /** Changing this scrolls the band back to the start. */\n resetKey: string\n children: ReactNode\n}) {\n const sync = useCallback(() => {\n const band = bandRef.current\n if (!band) return\n const hiddenStart = band.scrollLeft\n const hiddenEnd = Math.max(0, band.scrollWidth - band.clientWidth - band.scrollLeft)\n const atStart = hiddenStart > 1\n const atEnd = hiddenEnd > 1\n band.dataset.overflow = atStart && atEnd ? 'both' : atStart ? 'start' : atEnd ? 'end' : 'none'\n band.style.setProperty('--fade-start', `${atStart ? Math.min(MAX_FADE, hiddenStart) : 0}px`)\n band.style.setProperty('--fade-end', `${atEnd ? Math.min(MAX_FADE, hiddenEnd) : 0}px`)\n }, [bandRef])\n\n // After every render: the pill set changes with the model and the lane, so\n // the hidden width this reads is only correct once the new pills are laid out.\n useEffect(sync)\n\n useEffect(() => {\n const band = bandRef.current\n window.addEventListener('resize', sync)\n // jsdom and older browsers have no ResizeObserver; the window listener still\n // covers the case that matters (the viewport getting narrower).\n const observer = typeof ResizeObserver === 'undefined' || !band ? null : new ResizeObserver(sync)\n if (band) observer?.observe(band)\n return () => {\n window.removeEventListener('resize', sync)\n observer?.disconnect()\n }\n }, [bandRef, sync])\n\n useEffect(() => {\n const band = bandRef.current\n if (band) band.scrollLeft = 0\n sync()\n }, [bandRef, resetKey, sync])\n\n return (\n <div\n ref={bandRef}\n data-overflow=\"none\"\n onScroll={sync}\n className=\"studio-band flex min-w-0 flex-1 flex-nowrap items-center gap-2 overflow-x-auto\"\n >\n {children}\n </div>\n )\n}\n\n/**\n * Close an open menu once its pill has been scrolled out of the band.\n *\n * `PopoverSurface` re-anchors on scroll, so a menu follows its pill for free —\n * which is right until the pill leaves the band entirely and the menu is left\n * pointing at a clipped edge. The centre is the test rather than either edge: a\n * pill half-way out is still the pill the user opened.\n */\nfunction useCloseWhenScrolledOut(\n open: boolean,\n setOpen: (open: boolean) => void,\n triggerRef: RefObject<HTMLElement | null>,\n bandRef: RefObject<HTMLDivElement | null>,\n) {\n useEffect(() => {\n const band = bandRef.current\n if (!open || !band) return\n const onScroll = () => {\n const trigger = triggerRef.current\n if (!trigger) return\n const anchor = trigger.getBoundingClientRect()\n const box = band.getBoundingClientRect()\n const centre = anchor.left + anchor.width / 2\n if (centre < box.left || centre > box.right) setOpen(false)\n }\n band.addEventListener('scroll', onScroll)\n return () => band.removeEventListener('scroll', onScroll)\n }, [bandRef, open, setOpen, triggerRef])\n}\n\n/** One renderable value: the wire value, untouched, and how it reads. */\nexport interface OptionChoice {\n value: ModelOptionValue\n label: string\n icon?: LucideIcon\n}\n\nfunction MenuRows<T extends ModelOptionValue>({\n value,\n choices,\n onSelect,\n}: {\n value: T | undefined\n choices: readonly { value: T; label: string; icon?: LucideIcon }[]\n onSelect: (value: T) => void\n}) {\n return choices.map((choice) => {\n const Icon = choice.icon\n return (\n <button\n key={String(choice.value)}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={choice.value === value}\n onClick={() => onSelect(choice.value)}\n className={menuRowClass(choice.value === value)}\n >\n {Icon && <Icon aria-hidden className=\"h-3.5 w-3.5 shrink-0\" strokeWidth={1.5} />}\n <span className=\"truncate\">{choice.label}</span>\n {choice.value === value && (\n <CheckGlyph className=\"ml-auto h-3.5 w-3.5 shrink-0 text-primary\" />\n )}\n </button>\n )\n })\n}\n\n/** A standalone enum picker using the studio composer's pill and menu grammar. */\nexport function MenuPill<T extends string>({\n label,\n value,\n choices,\n onSelect,\n className,\n icon: Icon,\n trigger = 'pill',\n}: {\n label: string\n value: T\n choices: readonly { value: T; label: string; icon?: LucideIcon }[]\n onSelect: (value: T) => void\n className?: string\n icon?: LucideIcon\n trigger?: 'pill' | 'text'\n}): JSX.Element {\n const [open, setOpen] = useState(false)\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen)\n const panelId = useId()\n const selected = choices.find((choice) => choice.value === value)\n\n return (\n <div ref={containerRef} className=\"relative inline-flex flex-none\">\n <button\n type=\"button\"\n {...triggerProps}\n aria-controls={open ? panelId : undefined}\n title={label}\n aria-label={label}\n onClick={() => setOpen(!open)}\n className={`${trigger === 'text'\n ? 'inline-flex h-7 flex-none items-center gap-1 whitespace-nowrap rounded-full px-2 text-[12.5px] font-medium text-primary transition hover:bg-accent'\n : PILL} ${className ?? ''}`}\n >\n {Icon && <Icon aria-hidden className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" strokeWidth={1.5} />}\n <span className={PILL_LABEL}>{selected?.label ?? '—'}</span>\n <ChevronDown className={`h-3 w-3 shrink-0 ${trigger === 'text' ? 'text-primary' : 'text-muted-foreground'}`} />\n </button>\n\n <PopoverSurface\n open={open}\n id={panelId}\n role=\"menu\"\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={MENU_PANEL}\n >\n <div className={MENU_HEADER}>{label}</div>\n <MenuRows\n value={value}\n choices={choices}\n onSelect={(next) => {\n onSelect(next)\n setOpen(false)\n }}\n />\n </PopoverSurface>\n </div>\n )\n}\n\n/**\n * A value pill and the menu it opens.\n *\n * The pill shows the VALUE and carries the parameter name in `title` and in its\n * accessible name — a band of eight labelled pills does not fit a chat card,\n * and \"5s\" alone tells a screen-reader user nothing about which parameter it\n * belongs to.\n */\nexport function OptionPill({\n label,\n value,\n choices,\n onSelect,\n bandRef,\n custom,\n icon: Icon,\n}: {\n label: string\n value: ModelOptionValue | undefined\n choices: readonly OptionChoice[]\n onSelect: (value: ModelOptionValue) => void\n bandRef: RefObject<HTMLDivElement | null>\n icon?: LucideIcon\n /** A trailing row that swaps the menu to a form (the gpt-image-2 custom\n * size). Absent for every parameter whose values are an enum. */\n custom?: {\n label: string\n render: (args: { close: () => void }) => ReactNode\n }\n}) {\n const [open, setOpen] = useState(false)\n const [customOpen, setCustomOpen] = useState(false)\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen)\n const panelId = useId()\n useCloseWhenScrolledOut(open, setOpen, triggerRef, bandRef)\n\n const selected = choices.find((choice) => choice.value === value)\n const close = () => {\n setOpen(false)\n setCustomOpen(false)\n }\n\n return (\n <div ref={containerRef} className=\"relative inline-flex flex-none\">\n <button\n type=\"button\"\n {...triggerProps}\n aria-controls={open ? panelId : undefined}\n title={label}\n aria-label={`${label}: ${selected?.label ?? 'not set'}`}\n onClick={() => {\n setCustomOpen(false)\n setOpen(!open)\n }}\n className={PILL}\n >\n {Icon && <Icon aria-hidden className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" strokeWidth={1.5} />}\n <span className={PILL_LABEL}>{selected?.label ?? '—'}</span>\n <ChevronDown className=\"h-3 w-3 shrink-0 text-muted-foreground\" />\n </button>\n\n <PopoverSurface\n open={open}\n id={panelId}\n role={customOpen ? undefined : 'menu'}\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={MENU_PANEL}\n >\n <div className={MENU_HEADER}>{label}</div>\n {customOpen && custom\n ? custom.render({ close })\n : (\n <>\n <MenuRows\n value={value}\n choices={choices}\n onSelect={(next) => {\n onSelect(next)\n close()\n }}\n />\n {custom && (\n <button\n type=\"button\"\n onClick={() => setCustomOpen(true)}\n className={`${menuRowClass(false)} text-muted-foreground`}\n >\n {custom.label}\n </button>\n )}\n </>\n )}\n </PopoverSurface>\n </div>\n )\n}\n\n/**\n * The custom-size form the Size menu swaps to.\n *\n * The reason a size is refused renders next to the fields that are wrong — a\n * toast would be gone by the time the user looks back at the inputs — and Apply\n * refuses rather than disables, so the reason is always reachable.\n */\nexport function CustomSizeForm({\n initial,\n onApply,\n onCancel,\n}: {\n initial?: string\n onApply: (size: string) => void\n onCancel: () => void\n}) {\n const parsed = /^(\\d+)x(\\d+)$/.exec(initial ?? '')\n const [width, setWidth] = useState(parsed?.[1] ?? '')\n const [height, setHeight] = useState(parsed?.[2] ?? '')\n const [error, setError] = useState<string | null>(null)\n const fieldClass = 'h-8 w-[74px] rounded-md border border-input bg-background px-2 text-[13px] tabular-nums'\n\n function apply() {\n const verdict = validateCustomImageSize(Number(width), Number(height))\n if (!verdict.ok) {\n setError(verdict.reason)\n return\n }\n onApply(`${Number(width)}x${Number(height)}`)\n }\n\n return (\n <div className=\"flex w-[228px] flex-col gap-2 p-1.5\">\n <div className=\"flex items-center gap-2\">\n <input\n type=\"number\"\n value={width}\n aria-label=\"Custom width\"\n onChange={(event) => {\n setWidth(event.target.value)\n setError(null)\n }}\n className={fieldClass}\n />\n <span aria-hidden className=\"text-muted-foreground\">×</span>\n <input\n type=\"number\"\n value={height}\n aria-label=\"Custom height\"\n onChange={(event) => {\n setHeight(event.target.value)\n setError(null)\n }}\n className={fieldClass}\n />\n </div>\n {error\n ? <p className=\"text-[12px] text-destructive\">{error}</p>\n : <p className=\"text-[12px] text-muted-foreground\">Multiples of 16, long edge up to 3840, ratio between 1:3 and 3:1.</p>}\n <div className=\"flex items-center justify-end gap-1.5\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"rounded-md px-2.5 py-1 text-[12.5px] font-medium text-muted-foreground transition hover:bg-accent hover:text-foreground\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={apply}\n className=\"rounded-md bg-primary px-2.5 py-1 text-[12.5px] font-medium text-primary-foreground transition hover:opacity-90\"\n >\n Apply\n </button>\n </div>\n </div>\n )\n}\n\n/**\n * The audio switch. It is a toggle rather than a menu because the parameter has\n * exactly two states, and a two-row menu to say \"on\" is a menu that costs a\n * click for nothing.\n */\nexport function AudioTogglePill({ on, onToggle }: { on: boolean; onToggle: (on: boolean) => void }) {\n return (\n <button\n type=\"button\"\n aria-pressed={on}\n title=\"Audio\"\n onClick={() => onToggle(!on)}\n className={`${PILL} ${on ? '' : 'text-muted-foreground'}`}\n >\n {on\n ? <Volume2 className=\"h-4 w-4 shrink-0\" strokeWidth={1.5} />\n : <VolumeX className=\"h-4 w-4 shrink-0\" strokeWidth={1.5} />}\n <span className={PILL_LABEL}>{on ? 'Audio on' : 'Audio off'}</span>\n </button>\n )\n}\n\n/**\n * The reference-image pill: the only control that changes which MODEL runs, so\n * the swap to the image-to-video sibling is the caller's (`onAttach`/`onRemove`)\n * and the pill only reports what is attached.\n *\n * With no `pick` seam it opens a URL form instead of a file dialog — a URL is\n * something a host with no upload endpoint can still supply, and refusing\n * anything that is not `http(s)` keeps a pasted local path from reaching the\n * provider as an unfetchable reference.\n */\nexport function ReferencePill({\n url,\n onAttach,\n onRemove,\n pick,\n bandRef,\n}: {\n url: string | null\n onAttach: (url: string) => void\n onRemove: () => void\n pick?: () => Promise<string | null>\n bandRef: RefObject<HTMLDivElement | null>\n}) {\n const [open, setOpen] = useState(false)\n const [draft, setDraft] = useState('')\n const [error, setError] = useState<string | null>(null)\n const { containerRef, triggerRef, panelRef } = usePopover(open, setOpen)\n const panelId = useId()\n useCloseWhenScrolledOut(open, setOpen, triggerRef, bandRef)\n\n if (url) {\n return (\n <div className={`${PILL} border-primary bg-primary/10 pr-1.5 text-primary hover:bg-primary/10`}>\n <img src={url} alt=\"\" className=\"h-[18px] w-[18px] shrink-0 rounded-[5px] object-cover\" />\n <span className={PILL_LABEL}>Reference</span>\n <button\n type=\"button\"\n aria-label=\"Remove reference image\"\n onClick={onRemove}\n className=\"ml-0.5 inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full transition hover:bg-primary/20\"\n >\n <X className=\"h-3 w-3\" strokeWidth={2} />\n </button>\n </div>\n )\n }\n\n function attach() {\n const value = draft.trim()\n if (!/^https?:\\/\\//i.test(value)) {\n setError('Enter a URL starting with http:// or https://')\n return\n }\n onAttach(value)\n setDraft('')\n setError(null)\n setOpen(false)\n }\n\n return (\n <div ref={containerRef} className=\"relative inline-flex flex-none\">\n <button\n type=\"button\"\n ref={triggerRef}\n // With a `pick` seam the button opens the host's own picker, not a\n // popover — claiming `aria-haspopup` there announces a menu that never\n // appears.\n {...(pick ? {} : { 'aria-haspopup': true as const, 'aria-expanded': open, 'aria-controls': open ? panelId : undefined })}\n title=\"Reference image\"\n onClick={() => {\n if (!pick) {\n setOpen(!open)\n return\n }\n void pick().then((picked) => {\n if (picked) onAttach(picked)\n })\n }}\n className={PILL}\n >\n <ImagePlus className=\"h-4 w-4 shrink-0 text-muted-foreground\" strokeWidth={1.5} />\n <span className={PILL_LABEL}>Reference image</span>\n </button>\n\n {!pick && (\n <PopoverSurface\n open={open}\n id={panelId}\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={MENU_PANEL}\n >\n <div className={MENU_HEADER}>Reference image</div>\n <div className=\"flex w-[260px] flex-col gap-2 p-1.5\">\n <input\n type=\"url\"\n value={draft}\n aria-label=\"Reference image URL\"\n placeholder=\"https://…\"\n onChange={(event) => {\n setDraft(event.target.value)\n setError(null)\n }}\n className=\"h-8 w-full rounded-md border border-input bg-background px-2 text-[13px]\"\n />\n {error && <p className=\"text-[12px] text-destructive\">{error}</p>}\n <div className=\"flex items-center justify-end gap-1.5\">\n <button\n type=\"button\"\n onClick={() => setOpen(false)}\n className=\"rounded-md px-2.5 py-1 text-[12.5px] font-medium text-muted-foreground transition hover:bg-accent hover:text-foreground\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={attach}\n className=\"rounded-md bg-primary px-2.5 py-1 text-[12.5px] font-medium text-primary-foreground transition hover:opacity-90\"\n >\n Attach\n </button>\n </div>\n </div>\n </PopoverSurface>\n )}\n </div>\n )\n}\n\n/**\n * The model pill — first in the band on every lane, and the only pill that is\n * always there. A model with no published option metadata renders this and\n * nothing else, which is the honest reading of \"we do not know what this model\n * takes\".\n */\nexport function ModelPill({\n models,\n value,\n displayName,\n provider,\n unavailable,\n onSelect,\n bandRef,\n}: {\n models: readonly MediaModelOption[]\n value: string\n /** What the pill reads. Falls back to the id — including for a model the\n * catalog does not list, such as an image-to-video sibling. */\n displayName: string\n provider?: string\n /** The selected model is listed but not routable — the pill carries the warning instead of any status line. */\n unavailable?: boolean\n onSelect: (id: string) => void\n bandRef: RefObject<HTMLDivElement | null>\n}) {\n const [open, setOpen] = useState(false)\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen)\n const panelId = useId()\n useCloseWhenScrolledOut(open, setOpen, triggerRef, bandRef)\n\n return (\n <div ref={containerRef} className=\"relative inline-flex flex-none\">\n <button\n type=\"button\"\n {...triggerProps}\n aria-controls={open ? panelId : undefined}\n title=\"Model\"\n aria-label={`Model: ${displayName}${unavailable ? ' (unavailable)' : ''}`}\n onClick={() => setOpen(!open)}\n className={`${PILL}${unavailable ? ' border-warning/50' : ''}`}\n >\n {unavailable && <TriangleAlert aria-hidden className=\"h-3.5 w-3.5 shrink-0 text-warning\" strokeWidth={2} />}\n {provider && <ProviderLogo provider={provider} size={14} />}\n <span className={`max-w-[168px] truncate ${PILL_LABEL}`}>{displayName}</span>\n <ChevronDown className=\"h-3 w-3 shrink-0 text-muted-foreground\" />\n </button>\n\n <PopoverSurface\n open={open}\n id={panelId}\n role=\"menu\"\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={`${MENU_PANEL} max-w-[320px]`}\n >\n <div className={MENU_HEADER}>Model</div>\n {models.length === 0 && (\n <p className=\"px-2.5 py-2 text-[13px] text-muted-foreground\">No models are available for this media type.</p>\n )}\n {models.map((model) => (\n <button\n key={model.id}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={model.id === value}\n onClick={() => {\n onSelect(model.id)\n setOpen(false)\n }}\n className={menuRowClass(model.id === value)}\n >\n {model.provider && (\n <span className={model.status === 'unavailable' ? 'opacity-45' : undefined}>\n <ProviderLogo provider={model.provider} size={14} />\n </span>\n )}\n <span className={`truncate${model.status === 'unavailable' ? ' opacity-45' : ''}`}>\n {model.name || model.id}\n </span>\n {model.status === 'unavailable' ? (\n <>\n <span className=\"ml-auto shrink-0 text-[11px] text-warning\">Unavailable</span>\n <TriangleAlert aria-hidden className=\"h-3.5 w-3.5 shrink-0 text-warning\" strokeWidth={2} />\n </>\n ) : model.status === 'limited' && (\n <span className=\"ml-auto shrink-0 text-[11px] capitalize text-muted-foreground\">{model.status}</span>\n )}\n {model.id === value && (\n <CheckGlyph className={`${model.status === 'available' ? 'ml-auto ' : ''}h-3.5 w-3.5 shrink-0 text-primary`} />\n )}\n </button>\n ))}\n </PopoverSurface>\n </div>\n )\n}\n\n/**\n * How a wire value reads, with the wire value itself untouched underneath.\n *\n * Keyed on the PARAMETER because the same scalar means different things across\n * them: `5` is \"5s\" of video and `2` is \"×2\" images. Anything this table has no\n * rule for reads as itself with a capital letter — never as an invented word,\n * so `std` renders \"Std\" and not a \"Standard\" nobody published.\n */\nexport function optionValueLabel(param: string, value: ModelOptionValue): string {\n if (typeof value === 'boolean') return value ? 'On' : 'Off'\n const text = String(value)\n if (param === 'n') return `×${text}`\n if (param === 'speed') return `${text}×`\n if (text === 'auto') return 'Auto'\n if (param === 'duration') return /^\\d+(\\.\\d+)?$/.test(text) ? `${text}s` : text\n if (param === 'size') {\n const size = /^(\\d+)x(\\d+)$/.exec(text)\n return size ? `${size[1]}×${size[2]}` : text\n }\n if (param === 'resolution' || param === 'aspect_ratio') return text\n return text.charAt(0).toUpperCase() + text.slice(1)\n}\n","import { Info } from 'lucide-react'\n\n/**\n * The one thing a chat-shaped generator has to say about itself: each prompt is\n * a fresh generation, and nothing carries over from the last one.\n *\n * A chat card sets the expectation that the thing on the other side remembers\n * the conversation. This one does not, and the cost of learning that by\n * experiment is a wasted generation. The chip is a soft brand-tinted hint: its\n * primary-tinted surface and primary icon keep it noticeable, while the hard\n * border and shadow read as an alert and were cut after gtm QA (issue #465).\n *\n * The icon is INLINE in the text flow rather than a flex sibling, so a narrow\n * viewport wraps it with the sentence instead of stranding a lone glyph beside\n * a two-line block.\n */\nexport function GenerationNoticeChip({ className }: { className?: string }) {\n return (\n <p\n className={`inline-block rounded-full px-3.5 py-1.5 text-center text-[12px] leading-relaxed text-muted-foreground ${className ?? ''}`}\n style={{ background: 'var(--studio-notice-bg)' }}\n >\n <Info className=\"mr-1.5 inline-block h-[14px] w-[14px] align-[-2px] text-primary\" strokeWidth={1.5} aria-hidden />\n Each prompt starts a new generation — this chat does not remember the last one.\n </p>\n )\n}\n","import {\n Check,\n Download,\n FileText,\n FolderOpen,\n FolderPlus,\n Pause,\n Play,\n Trash2,\n} from 'lucide-react'\nimport {\n type CSSProperties,\n type JSX,\n type KeyboardEvent,\n type MouseEvent,\n useEffect,\n useState,\n} from 'react'\n\nimport { hashSeed, previewWaveformBars } from '../studio/audio-preview'\nimport {\n generationError,\n generationStatus,\n generationVaultPath,\n type Generation,\n} from '../studio/generation'\nimport type { StudioMediaActions, VaultSaveResult } from '../studio/ports'\nimport { usePopover } from '../web-react/controls'\nimport { VaultPathPopover } from './vault-path-popover'\nimport { downloadGenerationsViaAnchor } from './download-generations'\nimport { useStudioPlayback } from './studio-playback'\n\nexport interface MediaTileProps {\n generation: Generation\n context: 'home' | 'generation' | 'history'\n onOpen: (generation: Generation) => void\n actions?: StudioMediaActions\n /** Generation screen passes the batch aspect; omitted → square. */\n aspectRatio?: number\n /** 26 for grids (default), 72 for wide generation/viewer tiles. */\n waveformBars?: number\n selectMode?: boolean\n selected?: boolean\n onToggleSelect?: (id: string) => void\n onRequestDelete?: (generation: Generation) => void\n onSaved?: (results: readonly VaultSaveResult[]) => void\n className?: string\n style?: CSSProperties\n}\n\ntype TileStyle = CSSProperties & { '--r'?: number }\n\nfunction stop(event: MouseEvent<HTMLElement>): void {\n event.stopPropagation()\n}\n\nexport function MediaTile({\n generation,\n context,\n onOpen,\n actions,\n aspectRatio,\n waveformBars = 26,\n selectMode = false,\n selected = false,\n onToggleSelect,\n onRequestDelete,\n onSaved,\n className,\n style,\n}: MediaTileProps): JSX.Element {\n const playback = useStudioPlayback()\n const [waveNode, setWaveNode] = useState<HTMLDivElement | null>(null)\n const [saveOpen, setSaveOpen] = useState(false)\n const [saving, setSaving] = useState(false)\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(saveOpen, setSaveOpen)\n const vaultPath = generationVaultPath(generation)\n const status = generationStatus(generation)\n const isSpeech = generation.type === 'speech'\n const isPlaying = isSpeech && playback.activeId === generation.id && playback.playing\n\n useEffect(() => playback.registerPositionNode(generation.id, waveNode), [\n generation.id,\n playback.registerPositionNode,\n waveNode,\n ])\n\n const classes = [\n 'studio-tile relative isolate m-0 cursor-pointer overflow-hidden rounded-none border-0 bg-accent',\n aspectRatio === undefined ? 'aspect-square' : '',\n 'focus-visible:[outline-offset:-2px]',\n isSpeech ? 'studio-has-player' : '',\n selectMode ? 'studio-selectmode' : '',\n selected ? 'outline outline-2 -outline-offset-2 outline-primary' : '',\n className ?? '',\n ].filter(Boolean).join(' ')\n const tileStyle: TileStyle = aspectRatio === undefined\n ? { ...style }\n : { ...style, aspectRatio, '--r': aspectRatio }\n\n function activate(): void {\n if (selectMode) onToggleSelect?.(generation.id)\n else onOpen(generation)\n }\n\n function onKeyDown(event: KeyboardEvent<HTMLElement>): void {\n if (event.target !== event.currentTarget || (event.key !== 'Enter' && event.key !== ' ')) return\n event.preventDefault()\n activate()\n }\n\n async function save(path: string): Promise<void> {\n if (!actions?.save) return\n setSaving(true)\n try {\n const results = await actions.save({ generations: [generation], path })\n setSaveOpen(false)\n onSaved?.(results)\n } finally {\n setSaving(false)\n }\n }\n\n const bars = isSpeech ? previewWaveformBars(generation.id, waveformBars) : []\n const hue = hashSeed(generation.id) % 360\n const secondHue = (hue + 34) % 360\n\n return (\n <figure\n role=\"button\"\n tabIndex={0}\n aria-label={`${generation.prompt} — open`}\n className={classes}\n style={tileStyle}\n data-selectable={context === 'history'}\n data-selected={selected}\n onClick={activate}\n onKeyDown={onKeyDown}\n >\n <div className=\"absolute inset-0\">\n {status === 'pending' || status === 'running' ? (\n <div className=\"studio-skeleton absolute inset-0\" />\n ) : status === 'failed' ? (\n <div className=\"grid h-full w-full place-items-center bg-accent p-3 text-center text-[12px] text-destructive\">\n {generationError(generation) ?? 'Generation failed'}\n </div>\n ) : generation.result === null ? (\n <div className=\"studio-skeleton absolute inset-0\" />\n ) : generation.type === 'image' ? (\n <img\n src={generation.result}\n alt=\"\"\n className=\"h-full w-full object-cover\"\n loading=\"lazy\"\n draggable={false}\n />\n ) : generation.type === 'video' || generation.type === 'avatar' ? (\n <video\n src={generation.result}\n muted\n playsInline\n preload=\"metadata\"\n className=\"h-full w-full object-cover\"\n />\n ) : generation.type === 'transcription' ? (\n <div className=\"grid h-full w-full place-items-center bg-muted text-muted-foreground\">\n <FileText size={20} strokeWidth={1.5} />\n </div>\n ) : isSpeech ? (\n <div\n className=\"absolute inset-0\"\n style={{ background: `linear-gradient(158deg, hsl(${hue} 38% 24%), hsl(${secondHue} 46% 13%))` }}\n >\n <div\n className=\"studio-wave-layers\"\n ref={setWaveNode}\n style={{ color: `hsl(${hue} 92% 74%)` }}\n >\n <div className=\"studio-wave studio-wave-base\">\n {bars.map((bar, index) => (\n <i key={index} style={{ height: `${bar.heightPct}%`, opacity: bar.opacity }} />\n ))}\n </div>\n <div className=\"studio-wave studio-wave-play\">\n {bars.map((bar, index) => (\n <i key={index} style={{ height: `${bar.heightPct}%`, opacity: bar.opacity }} />\n ))}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n\n <div className=\"studio-tile-scrim absolute inset-0\" />\n\n <div className=\"studio-tile-actions absolute right-2 top-2 flex gap-[5px]\">\n <button\n type=\"button\"\n className=\"studio-ibtn relative grid h-[30px] w-[30px] place-items-center rounded-full\"\n data-tip=\"Download\"\n aria-label=\"Download\"\n onClick={(event) => {\n stop(event)\n void (actions?.download ?? downloadGenerationsViaAnchor)([generation])\n }}\n >\n <Download size={15} strokeWidth={1.5} />\n </button>\n\n {!vaultPath && actions?.save && (\n <div ref={containerRef}>\n <button\n {...triggerProps}\n type=\"button\"\n className=\"studio-ibtn relative grid h-[30px] w-[30px] place-items-center rounded-full\"\n data-tip=\"Save to vault\"\n aria-label=\"Save to vault\"\n onClick={(event) => {\n stop(event)\n setSaveOpen((open) => !open)\n }}\n >\n <FolderPlus size={15} strokeWidth={1.5} />\n </button>\n <VaultPathPopover\n open={saveOpen}\n triggerRef={triggerRef}\n panelRef={panelRef}\n generations={[generation]}\n onSubmit={save}\n onCancel={() => setSaveOpen(false)}\n pending={saving}\n />\n </div>\n )}\n\n {vaultPath && actions?.vaultHref && (\n <a\n href={actions.vaultHref(vaultPath)}\n className=\"studio-ibtn relative grid h-[30px] w-[30px] place-items-center rounded-full\"\n data-tip=\"View in vault\"\n aria-label=\"View in vault\"\n onClick={(event) => {\n stop(event)\n if (actions.onOpenVault) {\n event.preventDefault()\n actions.onOpenVault(generation)\n }\n }}\n >\n <FolderOpen size={15} strokeWidth={1.5} />\n </a>\n )}\n {vaultPath && !actions?.vaultHref && actions?.onOpenVault && (\n <button\n type=\"button\"\n className=\"studio-ibtn relative grid h-[30px] w-[30px] place-items-center rounded-full\"\n data-tip=\"View in vault\"\n aria-label=\"View in vault\"\n onClick={(event) => {\n stop(event)\n actions.onOpenVault?.(generation)\n }}\n >\n <FolderOpen size={15} strokeWidth={1.5} />\n </button>\n )}\n\n {actions?.remove && onRequestDelete && (\n <button\n type=\"button\"\n className=\"studio-ibtn studio-ibtn-danger relative grid h-[30px] w-[30px] place-items-center rounded-full\"\n data-tip=\"Delete\"\n aria-label=\"Delete\"\n onClick={(event) => {\n stop(event)\n onRequestDelete(generation)\n }}\n >\n <Trash2 size={15} strokeWidth={1.5} />\n </button>\n )}\n </div>\n\n <div className=\"studio-tile-badges absolute bottom-2 left-2 flex items-center gap-1.5\">\n {(generation.type === 'video' || generation.type === 'avatar') && (\n <span className=\"studio-chip-dark grid h-[22px] w-[22px] place-items-center rounded-full\" aria-hidden=\"true\">\n <Play size={11} strokeWidth={1.5} fill=\"currentColor\" />\n </span>\n )}\n {isSpeech && (\n <button\n type=\"button\"\n className=\"studio-play-btn studio-chip-dark grid h-[22px] w-[22px] place-items-center rounded-full\"\n aria-label={isPlaying ? `Pause ${generation.prompt}` : `Play ${generation.prompt}`}\n onClick={(event) => {\n stop(event)\n playback.toggle(generation)\n }}\n >\n {isPlaying\n ? <Pause size={11} strokeWidth={1.5} fill=\"currentColor\" />\n : <Play size={11} strokeWidth={1.5} fill=\"currentColor\" />}\n </button>\n )}\n {vaultPath && (\n <span className=\"studio-chip-dark inline-flex h-5 items-center gap-1 rounded-full pl-1.5 pr-2 text-[11px]\">\n <FolderOpen size={12} strokeWidth={1.5} />\n In vault\n </span>\n )}\n </div>\n\n {context === 'history' && (\n <button\n type=\"button\"\n className={`studio-tile-sel studio-chip-dark absolute left-2 top-2 h-6 w-6 place-items-center rounded-full ${selected ? '!bg-primary border-primary' : ''}`}\n aria-pressed={selected}\n aria-label=\"Select this item\"\n onClick={(event) => {\n stop(event)\n onToggleSelect?.(generation.id)\n }}\n >\n <Check\n size={13}\n strokeWidth={1.5}\n className={selected ? 'opacity-100' : 'opacity-0'}\n />\n </button>\n )}\n\n <figcaption className=\"studio-tile-prompt absolute inset-x-[11px] bottom-[9px] m-0 truncate text-[12px] text-white\">\n {generation.prompt}\n </figcaption>\n </figure>\n )\n}\n","import { useEffect, useId, useRef, useState, type FormEvent, type JSX, type RefObject } from 'react'\nimport { defaultVaultPathFor, normalizeVaultPath, type Generation } from '../studio'\nimport { OVERLAY_SHADOW, PopoverSurface } from '../web-react/controls'\n\nexport interface VaultPathPopoverProps {\n open: boolean\n triggerRef: RefObject<HTMLElement | null>\n panelRef: RefObject<HTMLDivElement | null>\n generations: readonly Generation[]\n onSubmit: (path: string) => void | Promise<void>\n onCancel: () => void\n pending?: boolean\n}\n\nexport function VaultPathPopover({\n open,\n triggerRef,\n panelRef,\n generations,\n onSubmit,\n onCancel,\n pending = false,\n}: VaultPathPopoverProps): JSX.Element | null {\n const inputRef = useRef<HTMLInputElement>(null)\n const inputId = useId()\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n if (!open) return\n setError(null)\n inputRef.current?.focus()\n inputRef.current?.select()\n }, [open])\n\n if (!open) return null\n\n async function submit(event: FormEvent) {\n event.preventDefault()\n const normalized = normalizeVaultPath(inputRef.current?.value ?? '')\n if (!normalized) {\n setError('Enter a folder path inside the vault.')\n return\n }\n setError(null)\n try {\n await onSubmit(normalized)\n } catch {\n setError('Could not save to vault. Try again.')\n }\n }\n\n const count = generations.length\n const defaultPath = defaultVaultPathFor(generations)\n return (\n <PopoverSurface\n open={open}\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={`flex w-[262px] flex-col overflow-y-auto rounded-xl border border-border bg-popover p-1.5 text-popover-foreground ${OVERLAY_SHADOW}`}\n >\n <form onSubmit={submit}>\n <label htmlFor={inputId} className=\"block px-0.5 pb-[7px] pt-0.5 text-[12px] text-muted-foreground\">\n Save {count} item{count > 1 ? 's' : ''} to\n </label>\n <input\n key={defaultPath}\n ref={inputRef}\n id={inputId}\n defaultValue={defaultPath}\n spellCheck={false}\n autoComplete=\"off\"\n className=\"h-8 w-full rounded-lg border border-input bg-muted px-2.5 text-[13px] outline-none focus:border-primary focus:ring-[3px] focus:ring-ring/30\"\n />\n {error && <p className=\"pt-1.5 text-[12px] text-destructive\">{error}</p>}\n <p className=\"pt-2 text-[11.5px] text-muted-foreground\">Media stays in Studio until you save it into the vault.</p>\n <div className=\"flex justify-end gap-2 pt-2.5\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"h-[30px] rounded-full border border-border px-3.5 text-[13px] hover:bg-accent\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={pending}\n className=\"h-[30px] rounded-full bg-primary px-3.5 text-[13px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n Save\n </button>\n </div>\n </form>\n </PopoverSurface>\n )\n}\n","import type { DownloadGenerations } from '../studio/ports'\n\n/** Same-origin anchor download, staggered so the browser does not swallow\n * every request after the first. Default when no `download` port is given. */\nexport const downloadGenerationsViaAnchor: DownloadGenerations = (generations) => {\n if (typeof document === 'undefined') return\n\n const downloadable = generations.filter((generation) => generation.result !== null)\n downloadable.forEach((generation, index) => {\n setTimeout(() => {\n if (generation.result === null) return\n const vaultPath = generation.metadata?.vaultPath\n const filename = typeof vaultPath === 'string' && vaultPath.trim()\n ? vaultPath.trim().split('/').filter(Boolean).at(-1) ?? `${generation.type}-${generation.id}`\n : `${generation.type}-${generation.id}`\n const anchor = document.createElement('a')\n anchor.href = generation.result\n anchor.download = filename\n document.body.appendChild(anchor)\n anchor.click()\n anchor.remove()\n }, index * 150)\n })\n}\n","import {\n createContext,\n type JSX,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\n\nimport type { Generation } from '../studio/generation'\n\nexport interface StudioAudioElementLike {\n src: string\n currentTime: number\n readonly duration: number\n play(): Promise<void> | void\n pause(): void\n addEventListener(type: string, listener: () => void): void\n removeEventListener(type: string, listener: () => void): void\n}\n\nexport interface StudioPlayback {\n activeId: string | null\n playing: boolean\n durationSeconds: number\n play(generation: Generation): void\n pause(): void\n toggle(generation: Generation): void\n stop(): void\n seekTo(generation: Generation, seconds: number): void\n seekBy(seconds: number): void\n getPositionSeconds(): number\n registerPositionNode(id: string, node: HTMLElement | null): () => void\n registerTimeNode(node: HTMLElement | null): () => void\n}\n\nconst StudioPlaybackContext = createContext<StudioPlayback | null>(null)\n\nconst createBrowserAudioElement = (): StudioAudioElementLike => new Audio()\n\nexport function formatClock(seconds: number): string {\n const wholeSeconds = Math.max(0, Math.floor(Number.isFinite(seconds) ? seconds : 0))\n return `${Math.floor(wholeSeconds / 60)}:${String(wholeSeconds % 60).padStart(2, '0')}`\n}\n\nfunction metadataDuration(generation: Generation): number {\n const duration = generation.metadata?.durationSeconds\n return typeof duration === 'number' && Number.isFinite(duration) ? Math.max(0, duration) : 0\n}\n\nfunction clampPosition(seconds: number, duration: number): number {\n const finiteSeconds = Number.isFinite(seconds) ? seconds : 0\n return Math.max(0, duration > 0 ? Math.min(finiteSeconds, duration) : finiteSeconds)\n}\n\nexport function StudioPlaybackProvider(props: {\n children: ReactNode\n createAudioElement?: () => StudioAudioElementLike\n}): JSX.Element {\n const [activeId, setActiveId] = useState<string | null>(null)\n const [playing, setPlaying] = useState(false)\n const [durationSeconds, setDurationSeconds] = useState(0)\n\n const activeIdRef = useRef<string | null>(null)\n const playingRef = useRef(false)\n const durationRef = useRef(0)\n const createAudioElementRef = useRef(props.createAudioElement ?? createBrowserAudioElement)\n createAudioElementRef.current = props.createAudioElement ?? createBrowserAudioElement\n const audioRef = useRef<StudioAudioElementLike | null>(null)\n const audioListenersRef = useRef<{\n loadedmetadata: () => void\n ended: () => void\n } | null>(null)\n const positionNodesRef = useRef(new Map<string, Set<HTMLElement>>())\n const timeNodeRef = useRef<HTMLElement | null>(null)\n const animationFrameRef = useRef<number | null>(null)\n const playAttemptRef = useRef(0)\n\n const setActive = useCallback((id: string | null) => {\n activeIdRef.current = id\n setActiveId(id)\n }, [])\n\n const setIsPlaying = useCallback((value: boolean) => {\n playingRef.current = value\n setPlaying(value)\n }, [])\n\n const setDuration = useCallback((value: number) => {\n const normalized = Number.isFinite(value) ? Math.max(0, value) : 0\n durationRef.current = normalized\n setDurationSeconds(normalized)\n }, [])\n\n const paintAll = useCallback(() => {\n const currentId = activeIdRef.current\n const position = currentId ? Math.max(0, audioRef.current?.currentTime ?? 0) : 0\n const duration = durationRef.current\n const fraction = duration > 0 ? Math.min(1, position / duration) : 0\n\n for (const [id, nodes] of positionNodesRef.current) {\n const isActive = id === currentId && (playingRef.current || position > 0)\n for (const node of nodes) {\n node.style.setProperty('--pos', isActive ? fraction.toFixed(4) : '0')\n if (isActive) node.dataset.active = 'true'\n else delete node.dataset.active\n }\n }\n if (timeNodeRef.current) timeNodeRef.current.textContent = formatClock(position)\n }, [])\n\n const cancelAnimation = useCallback(() => {\n if (animationFrameRef.current !== null && typeof cancelAnimationFrame === 'function') {\n cancelAnimationFrame(animationFrameRef.current)\n }\n animationFrameRef.current = null\n }, [])\n\n const startAnimation = useCallback(() => {\n if (animationFrameRef.current !== null || typeof requestAnimationFrame !== 'function') return\n const frame = () => {\n animationFrameRef.current = null\n paintAll()\n if (playingRef.current) animationFrameRef.current = requestAnimationFrame(frame)\n }\n animationFrameRef.current = requestAnimationFrame(frame)\n }, [paintAll])\n\n const ensureAudio = useCallback(() => {\n if (audioRef.current) return audioRef.current\n const audio = createAudioElementRef.current()\n const onLoadedMetadata = () => {\n if (Number.isFinite(audio.duration)) setDuration(audio.duration)\n paintAll()\n }\n const onEnded = () => {\n playAttemptRef.current += 1\n audio.currentTime = 0\n setIsPlaying(false)\n cancelAnimation()\n paintAll()\n }\n audio.addEventListener('loadedmetadata', onLoadedMetadata)\n audio.addEventListener('ended', onEnded)\n audioListenersRef.current = { loadedmetadata: onLoadedMetadata, ended: onEnded }\n audioRef.current = audio\n return audio\n }, [cancelAnimation, paintAll, setDuration, setIsPlaying])\n\n const adopt = useCallback((generation: Generation) => {\n const audio = ensureAudio()\n if (activeIdRef.current !== generation.id) {\n audio.src = generation.result ?? ''\n audio.currentTime = 0\n setDuration(metadataDuration(generation))\n setActive(generation.id)\n }\n return audio\n }, [ensureAudio, setActive, setDuration])\n\n const play = useCallback((generation: Generation) => {\n if (!generation.result) return\n const audio = adopt(generation)\n const attempt = ++playAttemptRef.current\n setIsPlaying(false)\n cancelAnimation()\n paintAll()\n\n try {\n const result = audio.play()\n if (result && typeof result.then === 'function') {\n void result.then(() => {\n if (playAttemptRef.current !== attempt || activeIdRef.current !== generation.id) return\n setIsPlaying(true)\n paintAll()\n startAnimation()\n }, () => {\n if (playAttemptRef.current !== attempt) return\n setIsPlaying(false)\n cancelAnimation()\n paintAll()\n })\n } else {\n setIsPlaying(true)\n paintAll()\n startAnimation()\n }\n } catch {\n if (playAttemptRef.current === attempt) {\n setIsPlaying(false)\n cancelAnimation()\n paintAll()\n }\n }\n }, [adopt, cancelAnimation, paintAll, setIsPlaying, startAnimation])\n\n const pause = useCallback(() => {\n playAttemptRef.current += 1\n audioRef.current?.pause()\n setIsPlaying(false)\n cancelAnimation()\n paintAll()\n }, [cancelAnimation, paintAll, setIsPlaying])\n\n const stop = useCallback(() => {\n playAttemptRef.current += 1\n audioRef.current?.pause()\n if (audioRef.current) audioRef.current.currentTime = 0\n setIsPlaying(false)\n setActive(null)\n cancelAnimation()\n paintAll()\n }, [cancelAnimation, paintAll, setActive, setIsPlaying])\n\n const toggle = useCallback((generation: Generation) => {\n if (activeIdRef.current === generation.id && playingRef.current) pause()\n else play(generation)\n }, [pause, play])\n\n const seekTo = useCallback((generation: Generation, seconds: number) => {\n if (!generation.result) return\n const changedTrack = activeIdRef.current !== generation.id\n const audio = adopt(generation)\n if (changedTrack) {\n playAttemptRef.current += 1\n setIsPlaying(false)\n cancelAnimation()\n }\n audio.currentTime = clampPosition(seconds, durationRef.current)\n paintAll()\n }, [adopt, cancelAnimation, paintAll, setIsPlaying])\n\n const seekBy = useCallback((seconds: number) => {\n if (!activeIdRef.current || !audioRef.current) return\n audioRef.current.currentTime = clampPosition(audioRef.current.currentTime + seconds, durationRef.current)\n paintAll()\n }, [paintAll])\n\n const getPositionSeconds = useCallback(() => audioRef.current?.currentTime ?? 0, [])\n\n const registerPositionNode = useCallback((id: string, node: HTMLElement | null) => {\n if (!node) {\n const nodes = positionNodesRef.current.get(id)\n if (nodes) {\n for (const registered of nodes) {\n registered.style.setProperty('--pos', '0')\n delete registered.dataset.active\n }\n }\n positionNodesRef.current.delete(id)\n return () => {}\n }\n const nodes = positionNodesRef.current.get(id) ?? new Set<HTMLElement>()\n nodes.add(node)\n positionNodesRef.current.set(id, nodes)\n paintAll()\n return () => {\n nodes.delete(node)\n if (nodes.size === 0) positionNodesRef.current.delete(id)\n }\n }, [paintAll])\n\n const registerTimeNode = useCallback((node: HTMLElement | null) => {\n timeNodeRef.current = node\n paintAll()\n return () => {\n if (timeNodeRef.current === node) timeNodeRef.current = null\n }\n }, [paintAll])\n\n useEffect(() => {\n paintAll()\n }, [activeId, durationSeconds, paintAll, playing])\n\n useEffect(() => () => {\n playAttemptRef.current += 1\n cancelAnimation()\n const audio = audioRef.current\n if (!audio) return\n audio.pause()\n const listeners = audioListenersRef.current\n if (listeners) {\n audio.removeEventListener('loadedmetadata', listeners.loadedmetadata)\n audio.removeEventListener('ended', listeners.ended)\n }\n }, [cancelAnimation])\n\n const value = useMemo<StudioPlayback>(() => ({\n activeId,\n playing,\n durationSeconds,\n play,\n pause,\n toggle,\n stop,\n seekTo,\n seekBy,\n getPositionSeconds,\n registerPositionNode,\n registerTimeNode,\n }), [\n activeId,\n durationSeconds,\n getPositionSeconds,\n pause,\n play,\n playing,\n registerPositionNode,\n registerTimeNode,\n seekBy,\n seekTo,\n stop,\n toggle,\n ])\n\n return <StudioPlaybackContext.Provider value={value}>{props.children}</StudioPlaybackContext.Provider>\n}\n\nexport function useStudioPlayback(): StudioPlayback {\n const playback = useContext(StudioPlaybackContext)\n if (!playback) throw new Error('useStudioPlayback must be used within a StudioPlaybackProvider')\n return playback\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type JSX,\n type KeyboardEvent,\n type MouseEvent,\n type PointerEvent,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { Download, FolderOpen, FolderPlus, Pause, Play, Trash2, X } from 'lucide-react'\n\nimport {\n generationAspectRatio,\n generationError,\n generationSpecSegments,\n generationStatus,\n generationVaultPath,\n hashSeed,\n previewWaveformBars,\n relativeTime,\n WIDE_WAVEFORM_BARS,\n type Generation,\n type StudioMediaActions,\n type VaultSaveResult,\n} from '../studio'\nimport { OVERLAY_SHADOW, POPOVER_SURFACE_ATTR, usePopover } from '../web-react/controls'\nimport { downloadGenerationsViaAnchor } from './download-generations'\nimport { formatClock, useStudioPlayback } from './studio-playback'\nimport { VaultPathPopover } from './vault-path-popover'\n\nexport interface MediaViewerModalProps {\n generation: Generation | null\n onClose: () => void\n actions?: StudioMediaActions\n /** Screens own the delete confirm; absent hides the Delete button. */\n onRequestDelete?: (generation: Generation) => void\n /** After a successful save from the footer popover. */\n onSaved?: (results: readonly VaultSaveResult[]) => void\n}\n\nconst TYPE_LABELS: Record<string, string> = {\n image: 'Image',\n video: 'Video',\n speech: 'Audio',\n avatar: 'Avatar',\n transcription: 'Transcript',\n}\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'textarea:not([disabled])',\n 'select:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ')\n\nconst footerButtonClass =\n 'inline-flex h-8 items-center gap-1.5 rounded-full border border-border px-3 text-[12.5px] font-medium hover:bg-accent'\n\nfunction hasOpenPopover(): boolean {\n return typeof document !== 'undefined' && document.querySelector(`[${POPOVER_SURFACE_ATTR}]`) !== null\n}\n\nfunction Waveform({ generation }: { generation: Generation }): JSX.Element {\n const { registerPositionNode } = useStudioPlayback()\n const layersRef = useRef<HTMLDivElement>(null)\n const bars = useMemo(\n () => previewWaveformBars(generation.id, WIDE_WAVEFORM_BARS),\n [generation.id],\n )\n const hue = useMemo(() => hashSeed(generation.id) % 360, [generation.id])\n\n useEffect(() => registerPositionNode(generation.id, layersRef.current), [generation.id, registerPositionNode])\n\n const renderBars = () => bars.map((bar, index) => (\n <i key={index} style={{ height: `${bar.heightPct}%`, opacity: bar.opacity }} />\n ))\n return (\n <div\n className=\"absolute inset-0\"\n style={{ background: `linear-gradient(158deg, hsl(${hue} 38% 24%), hsl(${(hue + 34) % 360} 46% 13%))` }}\n >\n <div ref={layersRef} className=\"studio-wave-layers\" style={{ color: `hsl(${hue} 92% 74%)` }}>\n <div className=\"studio-wave studio-wave-base\">{renderBars()}</div>\n <div className=\"studio-wave studio-wave-play\">{renderBars()}</div>\n </div>\n </div>\n )\n}\n\nfunction AudioTransport({ generation }: { generation: Generation }): JSX.Element {\n const playback = useStudioPlayback()\n const elapsedRef = useRef<HTMLSpanElement>(null)\n const seekRef = useRef<HTMLDivElement>(null)\n const trackRef = useRef<HTMLDivElement>(null)\n const pointerIdRef = useRef<number | null>(null)\n const [ariaPosition, setAriaPosition] = useState(0)\n const isPlaying = playback.activeId === generation.id && playback.playing\n const duration = playback.activeId === generation.id ? playback.durationSeconds : 0\n\n useEffect(() => playback.registerTimeNode(elapsedRef.current), [playback.registerTimeNode])\n useEffect(\n () => playback.registerPositionNode(generation.id, seekRef.current),\n [generation.id, playback.registerPositionNode],\n )\n useEffect(() => {\n setAriaPosition(playback.activeId === generation.id ? playback.getPositionSeconds() : 0)\n }, [generation.id, playback.activeId, playback.durationSeconds, playback.getPositionSeconds, playback.playing])\n\n const syncAriaPosition = useCallback(() => {\n setAriaPosition(playback.activeId === generation.id ? playback.getPositionSeconds() : 0)\n }, [generation.id, playback])\n\n function toggle() {\n playback.toggle(generation)\n syncAriaPosition()\n }\n\n function seekFromClientX(clientX: number) {\n const rect = trackRef.current?.getBoundingClientRect()\n if (!rect || rect.width <= 0 || duration <= 0) return\n const fraction = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width))\n playback.seekTo(generation, fraction * duration)\n setAriaPosition(fraction * duration)\n }\n\n function onPointerDown(event: PointerEvent<HTMLDivElement>) {\n event.currentTarget.focus()\n pointerIdRef.current = event.pointerId\n event.currentTarget.setPointerCapture?.(event.pointerId)\n seekFromClientX(event.clientX)\n }\n\n function onPointerMove(event: PointerEvent<HTMLDivElement>) {\n if (pointerIdRef.current !== event.pointerId) return\n seekFromClientX(event.clientX)\n }\n\n function endPointer(event: PointerEvent<HTMLDivElement>) {\n if (pointerIdRef.current !== event.pointerId) return\n event.currentTarget.releasePointerCapture?.(event.pointerId)\n pointerIdRef.current = null\n syncAriaPosition()\n }\n\n function onKeyDown(event: KeyboardEvent<HTMLDivElement>) {\n if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {\n event.preventDefault()\n playback.seekBy(event.key === 'ArrowLeft' ? -5 : 5)\n syncAriaPosition()\n } else if (event.key === ' ' || event.code === 'Space') {\n event.preventDefault()\n toggle()\n }\n }\n\n const position = Math.max(0, duration > 0 ? Math.min(ariaPosition, duration) : ariaPosition)\n return (\n <div className=\"mt-3.5 flex items-center gap-3 px-0.5\">\n <button\n type=\"button\"\n aria-label={isPlaying ? 'Pause' : 'Play'}\n onClick={toggle}\n className=\"grid h-[38px] w-[38px] shrink-0 place-items-center rounded-full bg-primary text-primary-foreground shadow-raised hover:brightness-110\"\n >\n {isPlaying\n ? <Pause size={15} strokeWidth={1.5} fill=\"currentColor\" />\n : <Play size={15} strokeWidth={1.5} fill=\"currentColor\" />}\n </button>\n <span ref={elapsedRef} className=\"min-w-8 text-[12px] text-muted-foreground tabular-nums\">\n {duration > 0 ? '0:00' : '--:--'}\n </span>\n <div\n ref={seekRef}\n className=\"studio-seek relative flex h-5 min-w-0 flex-1 cursor-pointer items-center\"\n role=\"slider\"\n tabIndex={0}\n aria-label=\"Seek\"\n aria-valuemin={0}\n aria-valuemax={duration}\n aria-valuenow={position}\n aria-valuetext={duration > 0 ? formatClock(position) : '--:--'}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endPointer}\n onPointerCancel={endPointer}\n onKeyDown={onKeyDown}\n >\n <div ref={trackRef} className=\"relative h-1 w-full overflow-hidden rounded-full bg-accent\">\n <div className=\"studio-seek-fill absolute inset-y-0 left-0 bg-primary\" />\n </div>\n <div className=\"studio-seek-thumb absolute h-[13px] w-[13px] -translate-x-1/2 rounded-full bg-primary ring-2 ring-card\" />\n </div>\n <span className=\"text-[12px] text-muted-foreground tabular-nums\">\n {duration > 0 ? formatClock(duration) : '--:--'}\n </span>\n </div>\n )\n}\n\nexport function MediaViewerModal({\n generation,\n onClose,\n actions,\n onRequestDelete,\n onSaved,\n}: MediaViewerModalProps): JSX.Element | null {\n const playback = useStudioPlayback()\n const stopPlayback = playback.stop\n const panelRef = useRef<HTMLDivElement>(null)\n const closeRef = useRef<HTMLButtonElement>(null)\n const priorFocusRef = useRef<HTMLElement | null>(null)\n const openSessionRef = useRef(false)\n const [saveOpen, setSaveOpen] = useState(false)\n const [savePending, setSavePending] = useState(false)\n const popover = usePopover(saveOpen, setSaveOpen)\n const open = generation !== null\n\n const stopAndRestore = useCallback(() => {\n if (!openSessionRef.current) return\n openSessionRef.current = false\n stopPlayback()\n const priorFocus = priorFocusRef.current\n if (priorFocus?.isConnected) priorFocus.focus()\n }, [stopPlayback])\n\n const close = useCallback(() => {\n setSaveOpen(false)\n stopAndRestore()\n onClose()\n }, [onClose, stopAndRestore])\n\n useEffect(() => {\n if (!open) return\n priorFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null\n openSessionRef.current = true\n closeRef.current?.focus()\n return stopAndRestore\n }, [open, stopAndRestore])\n\n useEffect(() => {\n if (!open) return\n function onDocumentKeyDown(event: globalThis.KeyboardEvent) {\n if (event.key !== 'Escape' || event.defaultPrevented || hasOpenPopover()) return\n event.preventDefault()\n close()\n }\n document.addEventListener('keydown', onDocumentKeyDown)\n return () => document.removeEventListener('keydown', onDocumentKeyDown)\n }, [close, open])\n\n if (!generation || typeof document === 'undefined') return null\n\n const ratio = generationAspectRatio(generation)\n const status = generationStatus(generation)\n const vaultPath = generationVaultPath(generation)\n const metaSegments = [\n TYPE_LABELS[generation.type] ?? generation.type,\n generation.model,\n ...generationSpecSegments(generation),\n generation.createdAt ? relativeTime(generation.createdAt) : null,\n vaultPath,\n ].filter((segment): segment is string => typeof segment === 'string' && segment.length > 0)\n\n function onPanelKeyDown(event: KeyboardEvent<HTMLDivElement>) {\n if (event.key !== 'Tab' || hasOpenPopover()) return\n const focusable = panelRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)\n if (!focusable || focusable.length === 0) return\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n const active = document.activeElement\n if (event.shiftKey && active === first) {\n event.preventDefault()\n last?.focus()\n } else if (!event.shiftKey && active === last) {\n event.preventDefault()\n first?.focus()\n }\n }\n\n async function save(path: string) {\n if (!actions?.save || !generation) return\n setSavePending(true)\n try {\n const results = await actions.save({ generations: [generation], path })\n setSaveOpen(false)\n onSaved?.(results)\n } finally {\n setSavePending(false)\n }\n }\n\n function viewVault(event: MouseEvent<HTMLAnchorElement | HTMLButtonElement>) {\n if (!actions?.onOpenVault || !generation) return\n event.preventDefault()\n actions.onOpenVault(generation)\n }\n\n const mediaStyle: CSSProperties = generation.type === 'transcription'\n ? { width: '100%' }\n : {\n width: `min(100%, calc(70vh * ${ratio}))`,\n aspectRatio: ratio,\n }\n const vaultHref = vaultPath && actions?.vaultHref ? actions.vaultHref(vaultPath) : null\n const viewControl = vaultPath && (vaultHref || actions?.onOpenVault)\n const modal = (\n <div\n className=\"studio-layer-viewer studio-backdrop fixed inset-0 grid place-items-center p-6\"\n onMouseDown={(event) => { if (event.target === event.currentTarget) close() }}\n >\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Media detail\"\n onKeyDown={onPanelKeyDown}\n className={`studio-rise relative max-h-[92vh] w-[min(780px,100%)] overflow-auto rounded-[14px] border border-border bg-card p-3.5 ${OVERLAY_SHADOW}`}\n >\n <button\n ref={closeRef}\n type=\"button\"\n aria-label=\"Close\"\n onClick={close}\n className=\"absolute right-3.5 top-3.5 z-10 grid h-8 w-8 place-items-center rounded-full border border-border bg-card hover:bg-accent\"\n >\n <X size={15} strokeWidth={1.5} />\n </button>\n\n <div className=\"flex justify-center\">\n <div className=\"relative overflow-hidden rounded-xl border border-border bg-accent\" style={mediaStyle}>\n {status === 'pending' || status === 'running' ? (\n <div className=\"studio-skeleton absolute inset-0\" />\n ) : status === 'failed' ? (\n <div className=\"grid h-full w-full place-items-center bg-accent p-3 text-center text-[12px] text-destructive\">\n {generationError(generation) ?? 'Generation failed'}\n </div>\n ) : generation.result === null ? (\n <div className=\"studio-skeleton absolute inset-0\" />\n ) : generation.type === 'image' ? (\n <img src={generation.result} className=\"h-full w-full object-cover\" alt={generation.prompt} />\n ) : generation.type === 'video' || generation.type === 'avatar' ? (\n <video src={generation.result} controls playsInline className=\"h-full w-full object-cover\" />\n ) : generation.type === 'transcription' ? (\n <div className=\"max-h-[60vh] overflow-auto whitespace-pre-wrap p-4 text-[13.5px] leading-relaxed\">\n {generation.result ?? ''}\n </div>\n ) : generation.type === 'speech' ? (\n <Waveform generation={generation} />\n ) : null}\n </div>\n </div>\n\n {status !== 'failed' && generation.type === 'speech' && <AudioTransport generation={generation} />}\n\n <p className=\"mx-0.5 mb-1.5 mt-4 max-w-[62ch] text-[15px] leading-normal\">{generation.prompt}</p>\n <div className=\"mx-0.5 flex flex-wrap items-center gap-1.5 text-[12.5px] text-muted-foreground\">\n {metaSegments.join(' · ')}\n </div>\n\n <div className=\"mt-3.5 flex flex-wrap gap-2 border-t border-border pt-4\">\n <button\n type=\"button\"\n onClick={() => { void (actions?.download ?? downloadGenerationsViaAnchor)([generation]) }}\n className={footerButtonClass}\n >\n <Download size={15} strokeWidth={1.5} /> Download\n </button>\n\n {!vaultPath && actions?.save && (\n <div ref={popover.containerRef}>\n <button\n {...popover.triggerProps}\n type=\"button\"\n onClick={() => setSaveOpen((value) => !value)}\n className={footerButtonClass}\n >\n <FolderPlus size={15} strokeWidth={1.5} /> Save to vault\n </button>\n <VaultPathPopover\n open={saveOpen}\n triggerRef={popover.triggerRef}\n panelRef={popover.panelRef}\n generations={[generation]}\n onSubmit={save}\n onCancel={() => setSaveOpen(false)}\n pending={savePending}\n />\n </div>\n )}\n\n {viewControl && (vaultHref ? (\n <a href={vaultHref} onClick={viewVault} className={footerButtonClass}>\n <FolderOpen size={15} strokeWidth={1.5} /> View in vault\n </a>\n ) : (\n <button type=\"button\" onClick={viewVault} className={footerButtonClass}>\n <FolderOpen size={15} strokeWidth={1.5} /> View in vault\n </button>\n ))}\n\n {onRequestDelete && (\n <button\n type=\"button\"\n onClick={() => onRequestDelete(generation)}\n className={`${footerButtonClass} ml-auto text-destructive hover:border-destructive hover:bg-destructive/10`}\n >\n <Trash2 size={15} strokeWidth={1.5} /> Delete\n </button>\n )}\n </div>\n </div>\n </div>\n )\n\n return createPortal(modal, document.body)\n}\n","import {\n type JSX,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react'\n\nimport type { Generation } from '../studio/generation'\nimport type { StudioMediaActions, VaultSaveResult } from '../studio/ports'\nimport { MediaTile } from './media-tile'\nimport { MediaViewerModal } from './media-viewer'\nimport { StudioComposer } from './studio-composer'\nimport { StudioConfirmDialog } from './studio-confirm'\nimport { useStudioPlayback } from './studio-playback'\nimport { useStudioToast } from './studio-toasts'\nimport { useBatchNavigation } from './use-batch-navigation'\nimport { useDeferredDelete } from './use-deferred-delete'\n\nexport interface StudioHomeScreenProps {\n /** Newest first, from the host loader (host runs useStudioGenerations). */\n generations: Generation[]\n onGenerated: (generation: Generation) => void\n onOpenGeneration: (batchKey: string, first: Generation) => void\n onOpenHistory: () => void\n workspaceId?: string\n pickReferenceImage?: () => Promise<string | null>\n actions?: StudioMediaActions\n recentLimit?: number\n className?: string\n}\n\n/**\n * Studio's create-and-recent-media landing screen. The host must render this\n * inside both `StudioToastProvider` and `StudioPlaybackProvider`.\n */\nexport function StudioHomeScreen({\n generations,\n onGenerated,\n onOpenGeneration,\n onOpenHistory,\n workspaceId,\n pickReferenceImage,\n actions,\n recentLimit = 20,\n className,\n}: StudioHomeScreenProps): JSX.Element {\n const [viewer, setViewer] = useState<Generation | null>(null)\n const [confirmTargets, setConfirmTargets] = useState<Generation[] | null>(null)\n const playback = useStudioPlayback()\n const { toast } = useStudioToast()\n const deferredDelete = useDeferredDelete({\n remove: actions?.remove ?? (async () => {}),\n })\n const navigateNewBatch = useBatchNavigation({ seed: generations, onOpenGeneration })\n\n const wrappedOnGenerated = useCallback((generation: Generation) => {\n onGenerated(generation)\n navigateNewBatch(generation)\n }, [navigateNewBatch, onGenerated])\n\n const visible = useMemo(\n () => generations.filter((generation) => !deferredDelete.pendingIds.has(generation.id)),\n [deferredDelete.pendingIds, generations],\n )\n const renderedViewer = viewer\n ? generations.find((generation) => generation.id === viewer.id) ?? viewer\n : null\n const requestDelete = actions?.remove\n ? (generation: Generation) => setConfirmTargets([generation])\n : undefined\n\n const onSaved = useCallback((results: readonly VaultSaveResult[]) => {\n const first = results[0]\n if (first) toast({ message: `Saved to vault · ${first.vaultPath}` })\n }, [toast])\n\n useEffect(() => playback.stop, [playback.stop])\n\n function confirmDelete(): void {\n const targets = confirmTargets\n setConfirmTargets(null)\n if (!targets?.length) return\n if (viewer && targets.some((target) => target.id === viewer.id)) setViewer(null)\n deferredDelete.request(targets)\n }\n\n return (\n <main className={className}>\n <div className=\"studio-home-top mx-auto w-full max-w-[820px] px-6 pt-[clamp(24px,12vh,124px)] max-[900px]:px-4\">\n <h1 className=\"mb-5 text-center text-[30px] font-semibold leading-[1.2] tracking-[-0.02em] [text-wrap:balance] max-[640px]:text-[25px]\">\n What do you want to create?\n </h1>\n <StudioComposer\n variant=\"home\"\n workspaceId={workspaceId}\n pickReferenceImage={pickReferenceImage}\n onGenerated={wrappedOnGenerated}\n />\n </div>\n\n <section className=\"studio-home-recent pb-[72px]\">\n <div className=\"mb-3 mt-[34px] flex items-center justify-between gap-3 px-6 max-[900px]:px-4\">\n <h2 className=\"text-[13px] font-medium tracking-[0.02em] text-muted-foreground\">Recent media</h2>\n <button\n type=\"button\"\n onClick={onOpenHistory}\n className=\"h-[30px] whitespace-nowrap rounded-full border border-border bg-card px-3 text-[13px] shadow-sm hover:bg-accent\"\n >\n View history\n </button>\n </div>\n\n <div className=\"studio-grid studio-grid-library\">\n {visible.length === 0 ? (\n <div className=\"col-span-full flex flex-col items-center py-16 text-center\">\n <p className=\"text-[14px] text-foreground\">Nothing generated yet.</p>\n <p className=\"max-w-[380px] text-[13px] text-muted-foreground\">\n Whatever you make lands here first — it only reaches the vault when you save it.\n </p>\n </div>\n ) : visible.slice(0, recentLimit).map((generation) => (\n <MediaTile\n key={generation.id}\n generation={generation}\n context=\"home\"\n onOpen={setViewer}\n actions={actions}\n onRequestDelete={requestDelete}\n onSaved={onSaved}\n />\n ))}\n </div>\n </section>\n\n <MediaViewerModal\n generation={renderedViewer}\n onClose={() => setViewer(null)}\n actions={actions}\n onRequestDelete={requestDelete}\n onSaved={onSaved}\n />\n <StudioConfirmDialog\n open={confirmTargets !== null}\n count={confirmTargets?.length ?? 0}\n onConfirm={confirmDelete}\n onCancel={() => setConfirmTargets(null)}\n />\n </main>\n )\n}\n","import { useEffect, useId, useRef, type JSX } from 'react'\nimport { createPortal } from 'react-dom'\nimport { OVERLAY_SHADOW } from '../web-react/controls'\n\nexport interface StudioConfirmDialogProps {\n open: boolean\n count: number\n onConfirm: () => void\n onCancel: () => void\n}\n\nexport function StudioConfirmDialog({\n open,\n count,\n onConfirm,\n onCancel,\n}: StudioConfirmDialogProps): JSX.Element | null {\n const panelRef = useRef<HTMLDivElement>(null)\n const cancelRef = useRef<HTMLButtonElement>(null)\n const previousFocusRef = useRef<HTMLElement | null>(null)\n const titleId = useId()\n const descriptionId = useId()\n\n useEffect(() => {\n if (!open) return\n previousFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null\n cancelRef.current?.focus()\n return () => {\n const previous = previousFocusRef.current\n if (previous && document.contains(previous)) previous.focus()\n previousFocusRef.current = null\n }\n }, [open])\n\n if (!open || typeof document === 'undefined') return null\n\n function onKeyDown(event: React.KeyboardEvent) {\n if (event.key === 'Escape') {\n event.preventDefault()\n onCancel()\n return\n }\n if (event.key !== 'Tab') return\n const focusable = panelRef.current?.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n )\n if (!focusable || focusable.length === 0) return\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n const active = document.activeElement as HTMLElement | null\n if (event.shiftKey && active === first) {\n event.preventDefault()\n last?.focus()\n } else if (!event.shiftKey && active === last) {\n event.preventDefault()\n first?.focus()\n }\n }\n\n return createPortal(\n <div\n className=\"studio-layer-confirm studio-backdrop fixed inset-0 grid place-items-center p-6\"\n onMouseDown={(event) => { if (event.target === event.currentTarget) onCancel() }}\n >\n <div\n ref={panelRef}\n role=\"alertdialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={descriptionId}\n onKeyDown={onKeyDown}\n className={`w-[min(360px,100%)] rounded-[14px] border border-border bg-card px-[18px] pb-4 pt-[18px] ${OVERLAY_SHADOW}`}\n >\n <h2 id={titleId} className=\"text-[15.5px] font-semibold tracking-[-0.01em]\">\n Delete {count} item{count > 1 ? 's' : ''}?\n </h2>\n <p id={descriptionId} className=\"mt-[7px] text-[13px] text-muted-foreground\">This cannot be undone.</p>\n <div className=\"flex justify-end gap-2 pt-[18px]\">\n <button\n ref={cancelRef}\n type=\"button\"\n onClick={onCancel}\n className=\"h-[30px] rounded-full border border-border px-3.5 text-[13px] hover:bg-accent\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n className=\"h-[30px] rounded-full bg-destructive px-3.5 text-[13px] font-medium text-destructive-foreground hover:brightness-110\"\n >\n Delete\n </button>\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type JSX,\n type ReactNode,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { X } from 'lucide-react'\nimport { OVERLAY_SHADOW } from '../web-react/controls'\n\nexport interface StudioToastInput {\n message: string\n action?: { label: string; run: () => void }\n durationMs?: number\n /** Fires exactly once when the toast leaves for ANY reason. */\n onDismiss?: (reason: 'timeout' | 'dismissed' | 'action') => void\n}\n\ntype DismissReason = 'timeout' | 'dismissed' | 'action'\ntype ToastRecord = StudioToastInput & { id: string; leaving: boolean }\n\ninterface StudioToastContextValue {\n toast: (input: StudioToastInput) => string\n dismiss: (id: string) => void\n setDockLift: (px: number | null) => void\n}\n\nconst StudioToastContext = createContext<StudioToastContextValue | null>(null)\n\nfunction StudioToast({ record, leave }: { record: ToastRecord; leave: (id: string, reason: DismissReason) => void }) {\n useEffect(() => {\n if (record.leaving) return\n const duration = record.durationMs ?? 3500\n if (duration === 0) return\n const timer = window.setTimeout(() => leave(record.id, 'timeout'), duration)\n return () => window.clearTimeout(timer)\n }, [leave, record.durationMs, record.id, record.leaving])\n\n return (\n <div\n role=\"status\"\n className={`pointer-events-auto flex max-w-[min(94vw,480px)] items-center gap-2.5 rounded-[10px] border border-border bg-card py-2 pl-[13px] pr-2 text-[13px] ${OVERLAY_SHADOW} ${record.leaving ? 'studio-toast-out' : 'studio-toast-in'}`}\n >\n <span className=\"min-w-0 truncate\">{record.message}</span>\n {record.action && (\n <button\n type=\"button\"\n onClick={() => {\n record.action?.run()\n leave(record.id, 'action')\n }}\n className=\"rounded-lg border-0 px-2 py-1 text-[13px] font-semibold text-primary hover:bg-primary/10\"\n >\n {record.action.label}\n </button>\n )}\n <button\n type=\"button\"\n aria-label=\"Dismiss\"\n onClick={() => leave(record.id, 'dismissed')}\n className=\"inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-muted-foreground hover:bg-accent hover:text-foreground\"\n >\n <X className=\"h-3.5 w-3.5\" aria-hidden />\n </button>\n </div>\n )\n}\n\nexport function StudioToastProvider({ children }: { children: ReactNode }): JSX.Element {\n const [toasts, setToasts] = useState<ToastRecord[]>([])\n const [dockLift, setDockLift] = useState<number | null>(null)\n const [mounted, setMounted] = useState(false)\n const sequence = useRef(0)\n const dismissed = useRef(new Set<string>())\n const records = useRef(new Map<string, ToastRecord>())\n\n const leave = useCallback((id: string, reason: DismissReason) => {\n if (dismissed.current.has(id)) return\n const record = records.current.get(id)\n if (!record) return\n dismissed.current.add(id)\n record.onDismiss?.(reason)\n setToasts((current) => current.map((toast) => toast.id === id ? { ...toast, leaving: true } : toast))\n window.setTimeout(() => {\n records.current.delete(id)\n setToasts((current) => current.filter((toast) => toast.id !== id))\n }, 180)\n }, [])\n\n const toast = useCallback((input: StudioToastInput) => {\n const id = `studio-toast-${++sequence.current}`\n const record: ToastRecord = { ...input, id, leaving: false }\n records.current.set(id, record)\n setToasts((current) => [...current, record])\n return id\n }, [])\n\n const dismiss = useCallback((id: string) => leave(id, 'dismissed'), [leave])\n const value = useMemo(() => ({ toast, dismiss, setDockLift }), [dismiss, toast])\n\n // Match the server and first client render to avoid an SSR hydration mismatch (#465).\n useEffect(() => setMounted(true), [])\n\n return (\n <StudioToastContext.Provider value={value}>\n {children}\n {mounted && createPortal(\n <div\n role=\"region\"\n aria-label=\"Notifications\"\n style={{ bottom: dockLift ? dockLift + 10 : 22 }}\n className=\"studio-layer-toasts pointer-events-none fixed left-1/2 flex -translate-x-1/2 flex-col items-center gap-2\"\n >\n {toasts.map((record) => <StudioToast key={record.id} record={record} leave={leave} />)}\n </div>,\n document.body,\n )}\n </StudioToastContext.Provider>\n )\n}\n\nexport function useStudioToast(): StudioToastContextValue {\n const context = useContext(StudioToastContext)\n if (!context) throw new Error('useStudioToast must be used within a StudioToastProvider')\n return context\n}\n","import { useCallback, useRef } from 'react'\nimport { generationBatchKey, type Generation } from '../studio/generation'\n\nexport interface UseBatchNavigationOptions {\n /** Rows whose batch keys are treated as already seen. Read once, at mount. */\n seed: readonly Generation[]\n /**\n * A batch key that never navigates, read on every call — the generation\n * screen passes its own batch so rows landing for the batch already on\n * screen stay put while a NEW dock submit navigates.\n */\n currentBatchKey?: string\n onOpenGeneration: (batchKey: string, first: Generation) => void\n}\n\n/**\n * Returns a callback the screens wrap around `onGenerated`: the first row of a\n * batch not seen before navigates via `onOpenGeneration`, exactly once per\n * batch — a four-image batch arrives as four rows sharing one batch key and\n * must produce one navigation, and rows merely refreshed from the loader\n * (seeded at mount) must produce none.\n */\nexport function useBatchNavigation({\n seed,\n currentBatchKey,\n onOpenGeneration,\n}: UseBatchNavigationOptions): (generation: Generation) => void {\n const seenKeys = useRef<Set<string> | null>(null)\n seenKeys.current ??= new Set(seed.map(generationBatchKey))\n const currentRef = useRef(currentBatchKey)\n currentRef.current = currentBatchKey\n\n return useCallback((generation: Generation) => {\n const key = generationBatchKey(generation)\n const seen = seenKeys.current\n if (key === currentRef.current || !seen || seen.has(key)) return\n seen.add(key)\n onOpenGeneration(key, generation)\n }, [onOpenGeneration])\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type { Generation } from '../studio/generation'\nimport type { DeleteGenerations } from '../studio/ports'\nimport { useStudioPlayback } from './studio-playback'\nimport { useStudioToast } from './studio-toasts'\n\nexport interface UseDeferredDeleteOptions {\n remove: DeleteGenerations\n /** Undo window AND toast lifetime. Default 3500. */\n undoWindowMs?: number\n /** After the server call succeeds for a batch. */\n onCommitted?: (ids: readonly string[]) => void\n /** After a failed server call restored the rows (screens may refetch). */\n onRestoreFailed?: (ids: readonly string[]) => void\n}\n\nexport interface DeferredDelete {\n /** Rows the screens must filter OUT of every render. Survives refetches. */\n pendingIds: ReadonlySet<string>\n request: (generations: readonly Generation[]) => void\n /** Commit every outstanding batch NOW (unmount/navigation). */\n flush: () => void\n}\n\ninterface DeleteBatch {\n ids: readonly string[]\n toastId: string\n status: 'pending' | 'committing'\n}\n\nconst itemLabel = (count: number) => `item${count === 1 ? '' : 's'}`\n\nexport function useDeferredDelete(options: UseDeferredDeleteOptions): DeferredDelete {\n const { activeId, stop } = useStudioPlayback()\n const { dismiss, toast } = useStudioToast()\n const [pendingIds, setPendingIds] = useState<ReadonlySet<string>>(() => new Set())\n const batchesRef = useRef(new Map<string, DeleteBatch>())\n const committedIdsRef = useRef(new Set<string>())\n const sequenceRef = useRef(0)\n const optionsRef = useRef(options)\n const dismissRef = useRef(dismiss)\n optionsRef.current = options\n dismissRef.current = dismiss\n\n const visiblePendingIds = useCallback(() => {\n const ids = new Set(committedIdsRef.current)\n for (const batch of batchesRef.current.values()) {\n for (const id of batch.ids) ids.add(id)\n }\n return ids\n }, [])\n\n const commit = useCallback((batchKey: string) => {\n const batch = batchesRef.current.get(batchKey)\n if (!batch || batch.status !== 'pending') return\n batch.status = 'committing'\n\n void optionsRef.current.remove(batch.ids).then(() => {\n if (batchesRef.current.get(batchKey) !== batch) return\n batchesRef.current.delete(batchKey)\n for (const id of batch.ids) committedIdsRef.current.add(id)\n optionsRef.current.onCommitted?.(batch.ids)\n }, () => {\n if (batchesRef.current.get(batchKey) !== batch) return\n batchesRef.current.delete(batchKey)\n setPendingIds(visiblePendingIds())\n toast({ message: `Could not delete ${batch.ids.length} ${itemLabel(batch.ids.length)}` })\n optionsRef.current.onRestoreFailed?.(batch.ids)\n })\n }, [toast, visiblePendingIds])\n\n const request = useCallback((generations: readonly Generation[]) => {\n if (generations.length === 0) return\n const ids = [...new Set(generations.map((generation) => generation.id))]\n const batchKey = `deferred-delete-${++sequenceRef.current}`\n\n setPendingIds((current) => {\n const next = new Set(current)\n for (const id of ids) next.add(id)\n return next\n })\n if (activeId && ids.includes(activeId)) stop()\n\n const undo = () => {\n const batch = batchesRef.current.get(batchKey)\n if (!batch || batch.status !== 'pending') return\n batchesRef.current.delete(batchKey)\n setPendingIds(visiblePendingIds())\n toast({ message: `Restored ${ids.length} ${itemLabel(ids.length)}` })\n }\n\n const toastId = toast({\n message: `Deleted ${ids.length} ${itemLabel(ids.length)}`,\n action: { label: 'Undo', run: undo },\n durationMs: options.undoWindowMs ?? 3500,\n onDismiss: (reason) => {\n if (reason !== 'action') commit(batchKey)\n },\n })\n batchesRef.current.set(batchKey, { ids, toastId, status: 'pending' })\n }, [activeId, commit, options.undoWindowMs, stop, toast, visiblePendingIds])\n\n const flush = useCallback(() => {\n for (const [batchKey, batch] of batchesRef.current) {\n if (batch.status !== 'pending') continue\n batch.status = 'committing'\n batchesRef.current.delete(batchKey)\n dismissRef.current(batch.toastId)\n void optionsRef.current.remove(batch.ids).catch(() => {})\n }\n }, [])\n\n useEffect(() => {\n window.addEventListener('pagehide', flush)\n return () => {\n window.removeEventListener('pagehide', flush)\n flush()\n }\n }, [flush])\n\n return { pendingIds, request, flush }\n}\n","/**\n * The generation screen: ONE batch's results, with the composer docked under\n * them.\n *\n * The screen is a flex column that fills its host — results scroll, the dock\n * does not. The dock band is deliberately OPAQUE (`bg-background`): it sits\n * above the scrolling results and a translucent band would let a tile read\n * through the composer's own card. The 28px fade above it comes from\n * `.studio-dock::before` in `./studio.css`.\n *\n * The dock's measured height is published two ways, because two different\n * consumers need it: as the `--studio-dock-h` custom property on the screen\n * root (host CSS, and anything nested that must clear the band) and through\n * `useStudioToast().setDockLift`, which lifts the toast stack off the composer.\n * The body's own bottom padding is applied from the measured value directly\n * rather than read back through that property — a CSS custom property a\n * component READS must be one `tokens.css` defines (the theme contract), and a\n * dock height is a layout measurement, not a theme token.\n *\n * A prompt sent from the DOCK starts a NEW batch, which is a different screen.\n * This one reports it (`onOpenGeneration`) exactly once per new batch key and\n * lets the host navigate; every row of that batch still flows through\n * `onGenerated` so the host's list stays whole.\n *\n * The root bakes in `min-h-full` so the sticky composer dock sits at the bottom\n * of the nearest scroll container. A `min-h-*` utility passed through\n * `className` will not reliably win: equal specificity lets the later-in-sheet\n * `.min-h-full` rule take precedence. Do not make this root its own scroll\n * container through `className`; wrap the screen in a\n * `min-h-0 flex-1 overflow-y-auto` container and let the root fill it instead\n * (issue #465, item 5).\n *\n * Assumes a `StudioToastProvider` and a `StudioPlaybackProvider` above it.\n */\n\nimport { ArrowLeft } from 'lucide-react'\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type JSX,\n} from 'react'\n\nimport {\n generationAspectRatio,\n generationError,\n generationStatus,\n generationsInBatch,\n WIDE_WAVEFORM_BARS,\n type DeleteGenerations,\n type Generation,\n type StudioMediaActions,\n type VaultSaveResult,\n} from '../studio'\nimport { GenerationNoticeChip } from './generation-notice'\nimport { MediaTile } from './media-tile'\nimport { MediaViewerModal } from './media-viewer'\nimport { StudioComposer } from './studio-composer'\nimport { StudioConfirmDialog } from './studio-confirm'\nimport { useStudioPlayback } from './studio-playback'\nimport { useStudioToast } from './studio-toasts'\nimport { useBatchNavigation } from './use-batch-navigation'\nimport { useDeferredDelete } from './use-deferred-delete'\n\nexport interface StudioGenerationScreenProps {\n /** Full merged list from the host (`useStudioGenerations`). */\n generations: Generation[]\n batchKey: string\n onGenerated: (generation: Generation) => void\n /** A dock submit that starts a NEW batch navigates via the host. */\n onOpenGeneration: (batchKey: string, first: Generation) => void\n onBack: () => void\n workspaceId?: string\n pickReferenceImage?: () => Promise<string | null>\n actions?: StudioMediaActions\n className?: string\n}\n\ntype SkeletonStyle = CSSProperties & { '--r'?: number }\n\n/** What the body clears before the dock has ever been measured. */\nconst FALLBACK_DOCK_HEIGHT = 190\n\n/** `useDeferredDelete` needs a remover unconditionally; with no `remove` seam\n * no delete control is rendered, so this is never reached. */\nconst noRemove: DeleteGenerations = async () => {}\n\nfunction isRunning(generation: Generation): boolean {\n const status = generationStatus(generation)\n return status === 'pending' || status === 'running'\n}\n\nexport function StudioGenerationScreen({\n generations,\n batchKey,\n onGenerated,\n onOpenGeneration,\n onBack,\n workspaceId,\n pickReferenceImage,\n actions,\n className,\n}: StudioGenerationScreenProps): JSX.Element {\n const rootRef = useRef<HTMLDivElement>(null)\n const dockRef = useRef<HTMLDivElement>(null)\n const { setDockLift, toast } = useStudioToast()\n const { stop } = useStudioPlayback()\n const stopRef = useRef(stop)\n stopRef.current = stop\n\n const [dockHeight, setDockHeight] = useState(FALLBACK_DOCK_HEIGHT)\n const [viewerId, setViewerId] = useState<string | null>(null)\n const [deleteTarget, setDeleteTarget] = useState<Generation | null>(null)\n\n const remove = actions?.remove\n const { pendingIds, request } = useDeferredDelete({ remove: remove ?? noRemove })\n\n const rows = useMemo(\n () => generationsInBatch(generations, batchKey).filter((row) => !pendingIds.has(row.id)),\n [batchKey, generations, pendingIds],\n )\n const first = rows[0]\n const prompt = first?.prompt ?? ''\n const ratio = first ? generationAspectRatio(first) : 1.5\n const runningCount = rows.filter(isRunning).length\n\n // The rise stagger counts SETTLED rows only, so a batch whose slots finish out\n // of order still lands 60ms apart instead of inheriting a skeleton's slot.\n const settledOrder = new Map<string, number>()\n for (const row of rows) if (!isRunning(row)) settledOrder.set(row.id, settledOrder.size)\n\n const columns = rows.length === 4 ? 2 : Math.min(rows.length, 4) || 1\n const maxWidth = rows.length > 1 || first?.type === 'speech'\n ? 820\n : ratio < 1 ? 380 : 640\n\n const viewerGeneration = viewerId ? rows.find((row) => row.id === viewerId) ?? null : null\n\n const onSaved = useCallback((results: readonly VaultSaveResult[]) => {\n const saved = results[0]\n if (saved) toast({ message: `Saved to vault · ${saved.vaultPath}` })\n }, [toast])\n\n const navigateNewBatch = useBatchNavigation({ seed: [], currentBatchKey: batchKey, onOpenGeneration })\n const handleGenerated = useCallback((generation: Generation) => {\n onGenerated(generation)\n navigateNewBatch(generation)\n }, [navigateNewBatch, onGenerated])\n\n useEffect(() => {\n const dock = dockRef.current\n if (!dock) return\n const apply = (height: number) => {\n // A zero reading means \"not laid out yet\" (jsdom, a hidden host); publishing\n // it would collapse the body's clearance onto a dock that is really there.\n if (height <= 0) return\n rootRef.current?.style.setProperty('--studio-dock-h', `${height}px`)\n setDockHeight(height)\n setDockLift(height)\n }\n const measure = () => apply(dock.getBoundingClientRect().height)\n measure()\n // jsdom and older browsers have no ResizeObserver; the window listener still\n // covers the case that matters (the viewport getting narrower).\n const observer = typeof ResizeObserver === 'undefined'\n ? null\n : new ResizeObserver((entries) => apply(entries[0]?.contentRect.height ?? dock.getBoundingClientRect().height))\n observer?.observe(dock)\n window.addEventListener('resize', measure)\n return () => {\n observer?.disconnect()\n window.removeEventListener('resize', measure)\n setDockLift(null)\n }\n }, [setDockLift])\n\n // Leaving the screen stops whatever it was playing — the audio element lives\n // in the provider ABOVE this component and would otherwise keep going.\n useEffect(() => () => stopRef.current(), [])\n\n function confirmDelete(): void {\n if (!deleteTarget) return\n request([deleteTarget])\n if (viewerId === deleteTarget.id) setViewerId(null)\n setDeleteTarget(null)\n }\n\n return (\n <div ref={rootRef} className={`flex min-h-full flex-col ${className ?? ''}`}>\n <header className=\"studio-gen-head mx-auto flex w-full max-w-[868px] items-center gap-2.5 px-6 pb-4 pt-1 max-[900px]:px-4\">\n <button\n type=\"button\"\n aria-label=\"Back to Studio\"\n onClick={onBack}\n className=\"grid h-8 w-8 flex-none place-items-center rounded-full border border-border bg-card shadow-sm hover:bg-accent\"\n >\n <ArrowLeft size={16} strokeWidth={1.5} />\n </button>\n <p\n title={prompt}\n className=\"min-w-0 max-w-full truncate rounded-full border border-border bg-card px-4 py-2 text-[14px] shadow-sm\"\n >\n {prompt}\n </p>\n </header>\n\n <div\n className=\"studio-gen-body flex-1 px-6 max-[900px]:px-4\"\n style={{ paddingBottom: `${dockHeight + 16}px` }}\n >\n {rows.length === 0 ? (\n <div className=\"mx-auto flex max-w-[520px] flex-col items-center gap-1 py-16 text-center\">\n <p className=\"text-[14px]\">Nothing left from this generation.</p>\n <p className=\"text-[13px] text-muted-foreground\">Send another prompt below to start a new one.</p>\n </div>\n ) : (\n <>\n <div\n className=\"mx-auto grid gap-[3px]\"\n aria-busy={runningCount > 0}\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`, maxWidth }}\n >\n {rows.map((row) => {\n if (isRunning(row)) {\n return <div key={row.id} className=\"studio-skeleton\" style={{ '--r': ratio } as SkeletonStyle} />\n }\n // A failed row is NOT a tile: `MediaTile` reads a null result as\n // \"still running\" and draws a skeleton, which would leave a dead\n // slot sweeping for ever. The cell states the reason instead.\n if (generationStatus(row) === 'failed') {\n return (\n <div\n key={row.id}\n className=\"grid place-items-center bg-accent p-3 text-center text-[12px] text-destructive\"\n style={{ aspectRatio: ratio }}\n >\n {generationError(row) ?? 'Generation failed'}\n </div>\n )\n }\n return (\n <div\n key={row.id}\n className=\"studio-rise\"\n style={{ animationDelay: `${(settledOrder.get(row.id) ?? 0) * 60}ms` }}\n >\n <MediaTile\n generation={row}\n context=\"generation\"\n aspectRatio={ratio}\n waveformBars={WIDE_WAVEFORM_BARS}\n actions={actions}\n onOpen={(generation) => setViewerId(generation.id)}\n onRequestDelete={remove ? setDeleteTarget : undefined}\n onSaved={onSaved}\n />\n </div>\n )\n })}\n </div>\n {runningCount > 0 && (\n <p className=\"sr-only\" aria-live=\"polite\">\n Generating {runningCount} result{runningCount > 1 ? 's' : ''}…\n </p>\n )}\n </>\n )}\n </div>\n\n <div\n ref={dockRef}\n className=\"studio-dock sticky bottom-0 z-[5] bg-background px-6 pb-[18px] pt-4 max-[900px]:px-4\"\n >\n <div className=\"mx-auto w-full max-w-[820px]\">\n <div className=\"mb-2.5 flex justify-center\">\n <GenerationNoticeChip />\n </div>\n <StudioComposer\n variant=\"docked\"\n workspaceId={workspaceId}\n pickReferenceImage={pickReferenceImage}\n onGenerated={handleGenerated}\n />\n </div>\n </div>\n\n <MediaViewerModal\n generation={viewerGeneration}\n onClose={() => setViewerId(null)}\n actions={actions}\n onRequestDelete={remove ? setDeleteTarget : undefined}\n onSaved={onSaved}\n />\n <StudioConfirmDialog\n open={deleteTarget !== null}\n count={1}\n onConfirm={confirmDelete}\n onCancel={() => setDeleteTarget(null)}\n />\n </div>\n )\n}\n","/**\n * The studio history screen — the full media library behind the home screen's\n * \"View history\" button: search, a media-type filter, cursor-paged infinite\n * scroll, and the multi-select bar that runs download / save-to-vault / delete\n * over a whole selection at once.\n *\n * It ASSUMES a `StudioToastProvider` and a `StudioPlaybackProvider` above it —\n * the deferred delete it drives lives in both (undo toast, stopping audio for a\n * row that is going away), and every screen in this surface makes the same\n * assumption so a route layout can mount the two providers once.\n *\n * The screen never fetches: `fetchPage` is the product's own paged endpoint and\n * `actions` are its media seams. An ABSENT action hides its control rather than\n * rendering a batch button that does nothing.\n */\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n type CSSProperties,\n type JSX,\n} from 'react'\nimport {\n ArrowLeft,\n AudioLines,\n Download,\n FolderPlus,\n Image,\n LayoutGrid,\n Search,\n Trash2,\n Video,\n X,\n type LucideIcon,\n} from 'lucide-react'\n\nimport type { Generation } from '../studio/generation'\nimport {\n MEDIA_TYPE_FILTERS,\n type FetchGenerationsPage,\n type GenerationPage,\n type MediaTypeFilter,\n type StudioMediaActions,\n type VaultSaveResult,\n} from '../studio/ports'\nimport { POPOVER_SURFACE_ATTR, usePopover } from '../web-react/controls'\nimport { useInfiniteScroll } from '../web-react/session-history'\nimport { MenuPill } from './composer-option-controls'\nimport { downloadGenerationsViaAnchor } from './download-generations'\nimport { MediaTile } from './media-tile'\nimport { MediaViewerModal } from './media-viewer'\nimport { StudioConfirmDialog } from './studio-confirm'\nimport { useStudioPlayback } from './studio-playback'\nimport { useStudioToast } from './studio-toasts'\nimport { useDeferredDelete } from './use-deferred-delete'\nimport { useGenerationHistory } from './use-generation-history'\nimport { VaultPathPopover } from './vault-path-popover'\n\nexport interface StudioHistoryScreenProps {\n fetchPage: FetchGenerationsPage\n /** SSR/loader page 1 for the DEFAULT view (no search, no type filter). */\n initialPage?: GenerationPage\n onBack: () => void\n actions?: StudioMediaActions\n /** Trailing debounce before a keystroke becomes a fetch. */\n searchDebounceMs?: number\n className?: string\n}\n\n/** How many cells the first load and each subsequent page stand in for. */\nconst FIRST_LOAD_SKELETONS = 8\nconst MORE_SKELETONS = 4\n\nconst BAR = 'flex min-h-[44px] flex-wrap items-center justify-between gap-3 px-6 pb-[18px] pt-0.5 max-[900px]:px-4'\nconst SEARCH_INPUT = 'h-8 w-[260px] max-w-[52vw] rounded-full border border-border bg-card pl-8 pr-3 text-[13px] text-foreground outline-none placeholder:text-muted-foreground focus:border-primary focus:ring-[3px] focus:ring-ring/30 max-[640px]:w-full max-[640px]:max-w-none'\nconst OUTLINE_PILL = 'inline-flex h-8 items-center gap-1.5 rounded-full border border-border px-3 text-[12.5px] font-medium hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40'\n\nconst FILTER_ICONS: Record<MediaTypeFilter, LucideIcon> = {\n all: LayoutGrid,\n image: Image,\n video: Video,\n speech: AudioLines,\n}\nconst FILTER_CHOICES = MEDIA_TYPE_FILTERS.map((choice) => ({\n ...choice,\n icon: FILTER_ICONS[choice.value],\n}))\n\n/** The empty-state plural for a type filter, in the filter's own words. */\nconst TYPE_NOUNS: Record<Exclude<MediaTypeFilter, 'all'>, string> = {\n image: 'images',\n video: 'videos',\n speech: 'audio',\n}\n\ntype SkeletonStyle = CSSProperties & { '--r'?: number }\n/** `.studio-skeleton` defaults to the 3:2 generation ratio; the library grid is\n * square, and the ratio is a custom property rather than a utility because a\n * Tailwind `aspect-*` class ties with the stylesheet rule on specificity. */\nconst SQUARE_CELL: SkeletonStyle = { '--r': 1 }\n\nfunction skeletonCells(count: number, keyPrefix: string) {\n return Array.from({ length: count }, (_, index) => (\n <div key={`${keyPrefix}-${index}`} className=\"studio-skeleton\" style={SQUARE_CELL} aria-hidden />\n ))\n}\n\nfunction hasOpenPopover(): boolean {\n return typeof document !== 'undefined' && document.querySelector(`[${POPOVER_SURFACE_ATTR}]`) !== null\n}\n\nexport function StudioHistoryScreen({\n fetchPage,\n initialPage,\n onBack,\n actions,\n searchDebounceMs = 250,\n className,\n}: StudioHistoryScreenProps): JSX.Element {\n const playback = useStudioPlayback()\n const { stop } = playback\n const { toast } = useStudioToast()\n\n const [query, setQuery] = useState('')\n const [debouncedQuery, setDebouncedQuery] = useState('')\n const [type, setType] = useState<MediaTypeFilter>('all')\n const [selectMode, setSelectMode] = useState(false)\n const [selected, setSelected] = useState<ReadonlySet<string>>(() => new Set())\n const [viewer, setViewer] = useState<Generation | null>(null)\n const [confirmTargets, setConfirmTargets] = useState<Generation[] | null>(null)\n const [saveOpen, setSaveOpen] = useState(false)\n const [savePending, setSavePending] = useState(false)\n const savePopover = usePopover(saveOpen, setSaveOpen)\n\n // Trailing debounce. Clearing the search sets both halves at once, and the\n // equality guard is what keeps that from scheduling a redundant timer.\n useEffect(() => {\n if (query === debouncedQuery) return\n const timer = window.setTimeout(() => setDebouncedQuery(query), searchDebounceMs)\n return () => window.clearTimeout(timer)\n }, [debouncedQuery, query, searchDebounceMs])\n\n const history = useGenerationHistory({ fetchPage, q: debouncedQuery, type, initialPage })\n const deferredDelete = useDeferredDelete({\n remove: actions?.remove ?? (async () => {}),\n // Nothing to reload: `pendingIds` already hides the rows and the server has\n // dropped them. A refetch here would only re-request the page we can see.\n })\n const { pendingIds } = deferredDelete\n const rows = useMemo(\n () => history.items.filter((item) => !pendingIds.has(item.id)),\n [history.items, pendingIds],\n )\n const selectedRows = useMemo(() => rows.filter((row) => selected.has(row.id)), [rows, selected])\n\n useEffect(() => {\n if (history.isLoadingFirst || history.isLoadingMore || !playback.activeId) return\n if (rows.some((row) => row.id === playback.activeId) || viewer?.id === playback.activeId) return\n playback.stop()\n }, [history.isLoadingFirst, history.isLoadingMore, playback, rows, viewer])\n\n const sentinelRef = useInfiniteScroll(history.loadMore, {\n enabled: history.hasMore && !history.isLoadingMore && !history.isLoadingFirst && !history.isError,\n })\n\n const exitSelectMode = useCallback(() => {\n setSelectMode(false)\n setSelected(new Set())\n setSaveOpen(false)\n }, [])\n\n const toggleSelect = useCallback((id: string) => {\n if (!selectMode) {\n // Entering select mode hides every tile's play button, so a clip playing\n // underneath would have no control left to stop it.\n stop()\n setSelectMode(true)\n setSelected(new Set([id]))\n return\n }\n setSelected((current) => {\n const next = new Set(current)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n return next\n })\n }, [selectMode, stop])\n\n // The residual Escape: the confirm dialog, the viewer and every popover close\n // themselves, so this handler exists only for the case none of them owns —\n // leaving select mode. It checks for those overlays rather than assuming an\n // order, because two document listeners see the same keydown.\n useEffect(() => {\n if (!selectMode) return\n function onKeyDown(event: globalThis.KeyboardEvent) {\n if (event.key !== 'Escape') return\n if (confirmTargets || viewer || hasOpenPopover()) return\n event.preventDefault()\n exitSelectMode()\n }\n document.addEventListener('keydown', onKeyDown)\n return () => document.removeEventListener('keydown', onKeyDown)\n }, [confirmTargets, exitSelectMode, selectMode, viewer])\n\n useEffect(() => () => stop(), [stop])\n\n const clearFilters = useCallback(() => {\n setQuery('')\n setDebouncedQuery('')\n setType('all')\n }, [])\n\n const onSaved = useCallback((results: readonly VaultSaveResult[]) => {\n const path = results[0]?.vaultPath\n if (!path) return\n toast({\n message: results.length > 1\n ? `Saved ${results.length} items to vault · ${path}`\n : `Saved to vault · ${path}`,\n })\n }, [toast])\n\n function batchDownload() {\n void (actions?.download ?? downloadGenerationsViaAnchor)(selectedRows)\n exitSelectMode()\n }\n\n async function batchSave(path: string) {\n if (!actions?.save) return\n setSavePending(true)\n try {\n const results = await actions.save({ generations: selectedRows, path })\n setSaveOpen(false)\n onSaved(results)\n exitSelectMode()\n } finally {\n setSavePending(false)\n }\n }\n\n function confirmDelete() {\n const targets = confirmTargets ?? []\n setConfirmTargets(null)\n if (targets.length === 0) return\n if (viewer && targets.some((target) => target.id === viewer.id)) setViewer(null)\n deferredDelete.request(targets)\n exitSelectMode()\n }\n\n const viewerRow = viewer ? rows.find((row) => row.id === viewer.id) ?? viewer : null\n const searchTerm = debouncedQuery.trim()\n const isFiltered = query !== '' || debouncedQuery !== '' || type !== 'all'\n const emptyCopy = searchTerm\n ? {\n title: `No media matches “${searchTerm}”.`,\n body: 'Try a shorter word, or drop the type filter.',\n }\n : type !== 'all'\n ? {\n title: `No ${TYPE_NOUNS[type]} yet.`,\n body: 'Generate one from the Studio composer and it will show up here.',\n }\n : {\n title: 'Your history is empty.',\n body: 'Everything you generate is kept here until you delete it.',\n }\n\n return (\n <div className={`studio-hist-wrap pb-[72px] ${className ?? ''}`}>\n {selectMode ? (\n <div className={BAR}>\n <div className=\"flex items-center gap-2 text-[13.5px] font-medium\">\n <button\n type=\"button\"\n aria-label=\"Exit select mode\"\n onClick={exitSelectMode}\n className=\"grid h-[26px] w-[26px] place-items-center rounded-full hover:bg-accent\"\n >\n <X size={15} strokeWidth={1.5} />\n </button>\n {selected.size} selected\n </div>\n\n <div role=\"toolbar\" aria-label=\"Selection actions\" className=\"ml-auto flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n disabled={selected.size === 0}\n onClick={batchDownload}\n className={OUTLINE_PILL}\n >\n <Download size={16} strokeWidth={1.5} /> Download\n </button>\n\n {actions?.save && (\n <div ref={savePopover.containerRef} className=\"inline-flex\">\n <button\n {...savePopover.triggerProps}\n type=\"button\"\n disabled={selected.size === 0}\n onClick={() => setSaveOpen(!saveOpen)}\n className={OUTLINE_PILL}\n >\n <FolderPlus size={16} strokeWidth={1.5} /> Save to vault\n </button>\n <VaultPathPopover\n open={saveOpen}\n triggerRef={savePopover.triggerRef}\n panelRef={savePopover.panelRef}\n generations={selectedRows}\n onSubmit={batchSave}\n onCancel={() => setSaveOpen(false)}\n pending={savePending}\n />\n </div>\n )}\n\n {actions?.remove && (\n <button\n type=\"button\"\n disabled={selected.size === 0}\n onClick={() => setConfirmTargets(selectedRows)}\n className={`${OUTLINE_PILL} text-destructive hover:border-destructive hover:bg-destructive/10`}\n >\n <Trash2 size={16} strokeWidth={1.5} /> Delete\n </button>\n )}\n </div>\n </div>\n ) : (\n <div className={BAR}>\n <button\n type=\"button\"\n aria-label=\"Back to Studio\"\n onClick={onBack}\n className=\"grid h-8 w-8 flex-none place-items-center rounded-full border border-border bg-card shadow-sm hover:bg-accent\"\n >\n <ArrowLeft size={16} strokeWidth={1.5} />\n </button>\n\n <div className=\"ml-auto flex flex-wrap items-center gap-2 max-[640px]:w-full\">\n <div className=\"relative inline-flex items-center max-[640px]:flex-1 max-[640px]:basis-[160px]\">\n <Search\n size={15}\n strokeWidth={1.5}\n aria-hidden\n className=\"pointer-events-none absolute left-[11px] text-muted-foreground\"\n />\n <input\n type=\"text\"\n value={query}\n placeholder=\"Search\"\n aria-label=\"Search prompts\"\n onChange={(event) => setQuery(event.target.value)}\n className={SEARCH_INPUT}\n />\n </div>\n\n <MenuPill\n label=\"Filter by media type\"\n value={type}\n choices={FILTER_CHOICES}\n onSelect={setType}\n trigger=\"text\"\n />\n </div>\n </div>\n )}\n\n {history.isError && rows.length === 0 ? (\n <div className=\"flex flex-col items-center gap-3 px-6 py-16 text-center max-[900px]:px-4\">\n <p className=\"text-[14px] text-foreground\">Could not load media.</p>\n <button type=\"button\" onClick={history.retry} className={OUTLINE_PILL}>Retry</button>\n </div>\n ) : history.isLoadingFirst && rows.length === 0 ? (\n <div className=\"studio-grid studio-grid-library\">\n {skeletonCells(FIRST_LOAD_SKELETONS, 'first')}\n </div>\n ) : rows.length === 0 ? (\n <div className=\"flex flex-col items-center gap-1.5 px-6 py-16 text-center max-[900px]:px-4\">\n <p className=\"text-[14px] text-foreground\">{emptyCopy.title}</p>\n <p className=\"max-w-[380px] text-[13px] text-muted-foreground\">{emptyCopy.body}</p>\n {isFiltered && (\n <button type=\"button\" onClick={clearFilters} className={`${OUTLINE_PILL} mt-2`}>Clear</button>\n )}\n </div>\n ) : (\n <div className={selectMode ? 'studio-selectmode' : undefined}>\n <div className=\"studio-grid studio-grid-library\">\n {rows.map((row) => (\n <MediaTile\n key={row.id}\n generation={row}\n context=\"history\"\n onOpen={setViewer}\n actions={actions}\n selectMode={selectMode}\n selected={selected.has(row.id)}\n onToggleSelect={toggleSelect}\n onRequestDelete={actions?.remove ? (generation) => setConfirmTargets([generation]) : undefined}\n onSaved={onSaved}\n />\n ))}\n {history.isLoadingMore && skeletonCells(MORE_SKELETONS, 'more')}\n </div>\n </div>\n )}\n\n {history.isError && rows.length > 0 && (\n <div className=\"flex items-center justify-center gap-3 px-6 py-4 text-[13px] text-muted-foreground max-[900px]:px-4\">\n <span>Could not load more media.</span>\n <button type=\"button\" onClick={history.retry} className={OUTLINE_PILL}>Retry</button>\n </div>\n )}\n\n <div ref={sentinelRef} aria-hidden />\n\n <MediaViewerModal\n generation={viewerRow}\n onClose={() => setViewer(null)}\n actions={actions}\n onRequestDelete={actions?.remove ? (generation) => setConfirmTargets([generation]) : undefined}\n onSaved={onSaved}\n />\n\n <StudioConfirmDialog\n open={confirmTargets !== null}\n count={confirmTargets?.length ?? 0}\n onConfirm={confirmDelete}\n onCancel={() => setConfirmTargets(null)}\n />\n </div>\n )\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport type { FetchGenerationsPage, GenerationPage, MediaTypeFilter } from '../studio/ports'\nimport { mergeGenerationPages, type Generation } from '../studio/generation'\n\nexport interface UseGenerationHistoryOptions {\n fetchPage: FetchGenerationsPage\n /** ALREADY debounced by the caller. */\n q: string\n type: MediaTypeFilter\n /** SSR/loader page 1 for the DEFAULT view only (q === '' && type === 'all'). */\n initialPage?: GenerationPage\n}\n\nexport interface GenerationHistoryState {\n items: Generation[]\n hasMore: boolean\n isLoadingFirst: boolean\n isLoadingMore: boolean\n isError: boolean\n loadMore: () => void\n retry: () => void\n reload: () => void\n}\n\n/** Content identity keeps inline-equivalent loader pages from reseeding. */\nfunction seedSignature(page: GenerationPage | undefined): string {\n if (!page) return ''\n return `${page.nextCursor ?? ''}|${page.items.map((item) => item.id).join(',')}`\n}\n\n/** Cursor-paged generation history over the product-supplied data port. */\nexport function useGenerationHistory({\n fetchPage,\n q,\n type,\n initialPage,\n}: UseGenerationHistoryOptions): GenerationHistoryState {\n const startsFromSeed = q === '' && type === 'all' && initialPage !== undefined\n const [items, setItems] = useState<Generation[]>(startsFromSeed ? initialPage.items : [])\n const [nextCursor, setNextCursor] = useState<string | null>(\n startsFromSeed ? initialPage.nextCursor ?? null : null,\n )\n const [phase, setPhase] = useState<'idle' | 'loadingFirst' | 'loadingMore' | 'error'>(\n startsFromSeed ? 'idle' : 'loadingFirst',\n )\n const [reloadKey, setReloadKey] = useState(0)\n\n const seqRef = useRef(0)\n const resetAbortRef = useRef<AbortController | null>(null)\n const loadMoreAbortRef = useRef<AbortController | null>(null)\n const loadingFirstRef = useRef(!startsFromSeed)\n const loadingMoreRef = useRef(false)\n const lastOpRef = useRef<'first' | 'more'>('first')\n const seedEligibleRef = useRef(true)\n\n const nextCursorRef = useRef(nextCursor)\n nextCursorRef.current = nextCursor\n const viewRef = useRef({ q, type, fetchPage })\n viewRef.current = { q, type, fetchPage }\n const seedRef = useRef(initialPage)\n seedRef.current = initialPage\n\n const isDefaultView = q === '' && type === 'all'\n const seedKey = useMemo(() => seedSignature(initialPage), [initialPage])\n\n useEffect(() => {\n resetAbortRef.current?.abort()\n loadMoreAbortRef.current?.abort()\n loadingFirstRef.current = false\n loadingMoreRef.current = false\n const seq = ++seqRef.current\n\n if (!isDefaultView) seedEligibleRef.current = false\n const seed = seedRef.current\n if (isDefaultView && seedEligibleRef.current && reloadKey === 0 && seed) {\n setItems(seed.items)\n setNextCursor(seed.nextCursor ?? null)\n setPhase('idle')\n return\n }\n\n const controller = new AbortController()\n resetAbortRef.current = controller\n loadingFirstRef.current = true\n lastOpRef.current = 'first'\n setItems([])\n setNextCursor(null)\n setPhase('loadingFirst')\n\n void (async () => {\n try {\n const current = viewRef.current\n const page = await current.fetchPage({\n q: current.q.trim(),\n type: current.type,\n cursor: null,\n signal: controller.signal,\n })\n if (seq !== seqRef.current) return\n setItems(page.items)\n setNextCursor(page.nextCursor ?? null)\n setPhase('idle')\n } catch {\n if (controller.signal.aborted || seq !== seqRef.current) return\n setPhase('error')\n } finally {\n if (seq === seqRef.current) loadingFirstRef.current = false\n }\n })()\n\n return () => controller.abort()\n }, [q, type, seedKey, isDefaultView, reloadKey])\n\n const loadMore = useCallback(() => {\n const cursor = nextCursorRef.current\n if (!cursor || loadingFirstRef.current || loadingMoreRef.current) return\n\n const current = viewRef.current\n const seq = seqRef.current\n loadMoreAbortRef.current?.abort()\n const controller = new AbortController()\n loadMoreAbortRef.current = controller\n loadingMoreRef.current = true\n lastOpRef.current = 'more'\n setPhase('loadingMore')\n\n void (async () => {\n try {\n const page = await current.fetchPage({\n q: current.q.trim(),\n type: current.type,\n cursor,\n signal: controller.signal,\n })\n if (seq !== seqRef.current) return\n setItems((previous) => mergeGenerationPages(previous, page.items))\n setNextCursor(page.nextCursor ?? null)\n setPhase('idle')\n } catch {\n if (controller.signal.aborted || seq !== seqRef.current) return\n setPhase('error')\n } finally {\n if (seq === seqRef.current) loadingMoreRef.current = false\n }\n })()\n }, [])\n\n const retry = useCallback(() => {\n if (lastOpRef.current === 'more') loadMore()\n else setReloadKey((key) => key + 1)\n }, [loadMore])\n\n const reload = useCallback(() => {\n setReloadKey((key) => key + 1)\n }, [])\n\n useEffect(\n () => () => {\n resetAbortRef.current?.abort()\n loadMoreAbortRef.current?.abort()\n },\n [],\n )\n\n return {\n items,\n hasMore: nextCursor !== null,\n isLoadingFirst: phase === 'loadingFirst',\n isLoadingMore: phase === 'loadingMore',\n isError: phase === 'error',\n loadMore,\n retry,\n reload,\n }\n}\n"],"mappings":"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","names":["useEffect","useMemo","useRef","useState","TriangleAlert","useCallback","useEffect","useState","useCallback","useEffect","useState","jsx","jsxs","useState","useRef","useEffect","useMemo","TriangleAlert","jsx","jsxs","useEffect","useState","useEffect","useId","useRef","useState","jsx","jsxs","useRef","useId","useState","useEffect","useCallback","useEffect","useMemo","useRef","useState","jsx","value","stop","nodes","jsx","jsxs","useState","useEffect","useCallback","useEffect","useMemo","useRef","useState","Download","FolderOpen","FolderPlus","Pause","Play","Trash2","X","jsx","jsxs","useRef","useMemo","useEffect","useState","useCallback","Pause","Play","X","Download","FolderPlus","FolderOpen","Trash2","useCallback","useEffect","useMemo","useState","useEffect","useId","useRef","createPortal","jsx","jsxs","useRef","useId","useEffect","createPortal","createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","createPortal","X","jsx","jsxs","createContext","useEffect","X","useState","useRef","useCallback","toast","useMemo","createPortal","useContext","useCallback","useRef","useRef","useCallback","useCallback","useEffect","useRef","useState","stop","useState","useRef","useCallback","useEffect","jsx","jsxs","useState","useCallback","useMemo","useEffect","useCallback","useEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","useRef","stop","useState","useMemo","useCallback","useEffect","useCallback","useEffect","useMemo","useState","ArrowLeft","AudioLines","Download","FolderPlus","Trash2","Video","X","useCallback","useEffect","useMemo","useRef","useState","useState","useRef","useMemo","useEffect","useCallback","jsx","jsxs","Video","AudioLines","hasOpenPopover","stop","useState","useEffect","useMemo","useCallback","X","Download","FolderPlus","Trash2","ArrowLeft"]}
1
+ {"version":3,"sources":["../../src/studio-react/use-studio-generations.ts","../../src/studio-react/studio-composer.tsx","../../src/studio-react/composer-option-controls.tsx","../../src/studio-react/composer-persistence.ts","../../src/studio-react/generation-notice.tsx","../../src/studio-react/media-tile.tsx","../../src/studio-react/vault-path-popover.tsx","../../src/studio-react/download-generations.ts","../../src/studio-react/studio-playback.tsx","../../src/studio-react/media-viewer.tsx","../../src/studio-react/studio-home-screen.tsx","../../src/studio-react/studio-confirm.tsx","../../src/studio-react/studio-toasts.tsx","../../src/studio-react/use-batch-navigation.ts","../../src/studio-react/use-deferred-delete.ts","../../src/studio-react/studio-generation-screen.tsx","../../src/studio-react/studio-history-screen.tsx","../../src/studio-react/use-generation-history.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useRevalidator } from 'react-router'\nimport {\n type Generation,\n generationStatus,\n isLocalGeneration,\n latestBatchOf,\n mergeLiveGeneration,\n mergeLoaderAndLive,\n} from '../studio'\n\n/**\n * The generation orchestrator behind a studio surface: it merges the loader's\n * rows with in-flight live generations, computes the latest batch for the\n * canvas, polls running generations until they settle, and revalidates the\n * route loader when a status changes.\n *\n * The merge keeps the canvas, the library, and the polling path looking at the\n * same full list. Polling hits `generationsEndpoint` (default `/api/generations`,\n * the convention both apps already serve); pass an override if a product routes\n * it elsewhere. `onGenerated` is wired to the composer's per-result callback.\n */\nexport function useStudioGenerations(\n loaderGenerations: Generation[],\n options: { workspaceId?: string; generationsEndpoint?: string } = {},\n) {\n const { workspaceId, generationsEndpoint = '/api/generations' } = options\n const revalidator = useRevalidator()\n const [liveGenerations, setLiveGenerations] = useState<Generation[]>([])\n\n const mergedGenerations = useMemo(\n () => mergeLoaderAndLive(loaderGenerations, liveGenerations),\n [loaderGenerations, liveGenerations],\n )\n\n const latestBatch = useMemo(() => latestBatchOf(mergedGenerations), [mergedGenerations])\n\n const runningGenerationIds = useMemo(() => mergedGenerations\n .filter((gen) => {\n const status = generationStatus(gen)\n return status === 'pending' || status === 'running'\n })\n .map((gen) => gen.id)\n .filter((id) => !id.startsWith('local-')), [mergedGenerations])\n\n // The poll loop must not churn the effect. `runningGenerationIds` is a fresh\n // array every render and react-router's `revalidator` identity flips while a\n // revalidation is in flight — depending on either restarts the interval on\n // every tick, collapsing the 4s cadence into a request flood. Key the effect\n // on the STABLE join of the running ids (re-subscribe only when the set\n // actually changes) and reach the live ids / revalidate through refs.\n const runningIdsRef = useRef(runningGenerationIds)\n runningIdsRef.current = runningGenerationIds\n const revalidateRef = useRef(revalidator.revalidate)\n revalidateRef.current = revalidator.revalidate\n const runningKey = runningGenerationIds.join(',')\n\n useEffect(() => {\n if (!workspaceId || !runningKey) return\n let cancelled = false\n const poll = async () => {\n const responses = await Promise.all(runningIdsRef.current.map(async (id) => {\n const res = await fetch(`${generationsEndpoint}?workspaceId=${encodeURIComponent(workspaceId)}&id=${encodeURIComponent(id)}`)\n if (!res.ok) return null\n const data = await res.json() as { generation?: Generation }\n return data.generation ?? null\n }))\n if (cancelled) return\n const refreshed = responses.filter((gen): gen is Generation => Boolean(gen))\n if (refreshed.length > 0) {\n setLiveGenerations((current) => refreshed.reduce(mergeLiveGeneration, current))\n }\n if (refreshed.some((gen) => generationStatus(gen) !== 'running' && generationStatus(gen) !== 'pending')) {\n revalidateRef.current()\n }\n }\n const interval = window.setInterval(() => { void poll() }, 4_000)\n void poll()\n return () => {\n cancelled = true\n window.clearInterval(interval)\n }\n }, [runningKey, workspaceId, generationsEndpoint])\n\n const onGenerated = useCallback((generation: Generation) => {\n setLiveGenerations((current) => mergeLiveGeneration(current, generation))\n if (!isLocalGeneration(generation)) revalidateRef.current()\n }, [])\n\n return { mergedGenerations, latestBatch, onGenerated }\n}\n","/**\n * The studio composer: one chat-shaped card — prompt, media-type switch, and a\n * band of option pills — that replaces the stacked field panel.\n *\n * The whole point of the rework is that the CONTROLS ARE THE MODEL'S OWN. A pill\n * renders only when the selected model publishes that parameter, its choices are\n * the published enum (or the published range), and the value goes onto the wire\n * exactly as published — seedance takes the string `'5'`, veo `'8s'`, kling the\n * number `5`, and coercing any of them is a 400 from the provider. A model that\n * publishes nothing (`ltx-video`) shows the model pill and nothing else: the\n * honest reading of \"we do not know what this takes\" is an absent control, not\n * an invented one and not a disabled one.\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport {\n AudioLines,\n ArrowUp,\n Clock,\n Copy,\n Gauge,\n Image as ImageIcon,\n Mic,\n Monitor,\n Ratio,\n Scaling,\n SlidersHorizontal,\n Sparkles,\n TriangleAlert,\n Video,\n type LucideIcon,\n} from 'lucide-react'\nimport {\n type Generation,\n type MediaModelCatalogResponse,\n type MediaModelOption,\n type ModelOptionMetadata,\n type ModelOptionValue,\n type ModelOptionsMetadata,\n aspectRatioFromOptions,\n buildGenerationRequestBody,\n curateComposerModels,\n failedOptimisticGeneration,\n imageToVideoSibling,\n laneUnavailable,\n normalizeImageCount,\n optimisticGeneration,\n optionChoices,\n preferredModelId,\n reconcileOptionValues,\n resolveComposerOptions,\n supportsCustomImageSize,\n textToVideoSibling,\n userSafeGenerationMessage,\n} from '../studio'\nimport {\n AudioTogglePill,\n ComposerBand,\n CustomSizeForm,\n MediaTypeSegments,\n ModelPill,\n OptionPill,\n ReferencePill,\n type MediaTypeSegment,\n type OptionChoice,\n optionValueLabel,\n} from './composer-option-controls'\nimport {\n loadComposerSelections,\n saveComposerSelections,\n type PersistedComposerSelections,\n} from './composer-persistence'\n\n/** The lanes the composer offers. Avatar and transcription stay disabled\n * (#451); \"Audio\" is the word for the `speech` lane everywhere on screen. */\nexport type ComposerType = 'image' | 'video' | 'speech'\n\nconst SEGMENTS: readonly MediaTypeSegment<ComposerType>[] = [\n { type: 'image', label: 'Image', icon: ImageIcon },\n { type: 'video', label: 'Video', icon: Video },\n { type: 'speech', label: 'Audio', icon: AudioLines },\n]\n\n/** Pill order per lane. A parameter absent from the model's metadata, or marked\n * `supported: false`, drops out of the row entirely. */\nconst PILL_ORDER: Record<ComposerType, readonly string[]> = {\n image: ['size', 'quality', 'n'],\n video: ['duration', 'resolution', 'aspect_ratio', 'mode'],\n speech: ['voice', 'speed'],\n}\n\nconst PARAM_LABELS: Record<string, string> = {\n size: 'Size',\n quality: 'Quality',\n n: 'Count',\n duration: 'Duration',\n resolution: 'Resolution',\n aspect_ratio: 'Aspect',\n mode: 'Mode',\n voice: 'Voice',\n speed: 'Speed',\n}\n\nconst PARAM_ICONS: Record<string, LucideIcon> = {\n size: Scaling,\n quality: Sparkles,\n n: Copy,\n duration: Clock,\n resolution: Monitor,\n aspect_ratio: Ratio,\n mode: SlidersHorizontal,\n voice: Mic,\n speed: Gauge,\n}\n\n/**\n * Speed is published as a continuous range (0.25–4.0 on OpenAI's endpoint), and\n * a range is not a menu: enumerating it at the step a user would actually pick\n * is 376 rows. These are the presets, filtered against whatever range the model\n * publishes, so a narrower range can never offer a speed it rejects.\n */\nconst SPEED_PRESETS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 4] as const\n\nfunction choicesFor(param: string, meta: ModelOptionMetadata): readonly ModelOptionValue[] {\n const { min, max } = meta\n if (param === 'speed' && !meta.values && min != null && max != null) {\n return SPEED_PRESETS.filter((speed) => speed >= min && speed <= max)\n }\n return optionChoices(meta)\n}\n\n/** The parameters a lane renders, in order, skipping unknown and unsupported\n * ones. `audio` and the reference image are not in here — neither is a value\n * menu. */\nfunction visibleParams(type: ComposerType, options: ModelOptionsMetadata | undefined): string[] {\n if (!options) return []\n return PILL_ORDER[type].filter((param) => {\n const meta = options[param]\n return Boolean(meta) && meta?.supported !== false\n })\n}\n\n/**\n * The lane's model. The catalog's own default wins when it survives curation;\n * otherwise the first curated model does — a default that #449 curation removed\n * (a Sora model, a non-gpt-image-2 image model) must not leave the lane with a\n * selection its own menu does not offer.\n */\nfunction defaultModelId(\n type: ComposerType,\n catalog: MediaModelCatalogResponse | null,\n curated: readonly MediaModelOption[],\n): string {\n const preferred = preferredModelId(type, catalog)\n if (preferred && curated.some((model) => model.id === preferred && model.status !== 'unavailable')) return preferred\n return curated.find((model) => model.status !== 'unavailable')?.id ?? curated[0]?.id ?? ''\n}\n\nexport interface StudioComposerProps {\n workspaceId?: string\n onGenerated: (generation: Generation) => void\n /** `home` (under a page heading) vs `docked` (pinned under a generation).\n * Presentational only — the card itself is identical either way. */\n variant?: 'home' | 'docked'\n /** Pick or upload a reference image, resolving to a URL or `null` on cancel.\n * Without it the Reference pill takes a URL instead, which is the most a host\n * with no upload endpoint can honestly offer. */\n pickReferenceImage?: () => Promise<string | null>\n className?: string\n}\n\n/**\n * The composer card. The host owns its width (the card fills its container) and\n * the heading above it; this owns the prompt, the controls, and the POST.\n */\nexport function StudioComposer({\n workspaceId,\n onGenerated,\n variant = 'home',\n pickReferenceImage,\n className,\n}: StudioComposerProps) {\n const [type, setType] = useState<ComposerType>('image')\n const [prompt, setPrompt] = useState('')\n const [catalog, setCatalog] = useState<MediaModelCatalogResponse | null>(null)\n const [catalogLoading, setCatalogLoading] = useState(false)\n const [catalogError, setCatalogError] = useState<string | null>(null)\n const [selectedModels, setSelectedModels] = useState<Partial<Record<ComposerType, string>>>({})\n const [optionValues, setOptionValues] = useState<Record<ComposerType, Record<string, ModelOptionValue>>>({\n image: {},\n video: {},\n speech: {},\n })\n const [referenceImageUrl, setReferenceImageUrl] = useState<string | null>(null)\n const [isSubmitting, setIsSubmitting] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [hydratedWorkspaceId, setHydratedWorkspaceId] = useState<string | null>(null)\n const submitLockRef = useRef(false)\n const bandRef = useRef<HTMLDivElement>(null)\n const hydratedRef = useRef(false)\n const persistedOptionsRef = useRef<PersistedComposerSelections['optionsByModel']>({})\n\n useEffect(() => {\n hydratedRef.current = false\n setHydratedWorkspaceId(null)\n if (!workspaceId) return\n const persisted = loadComposerSelections(workspaceId)\n if (persisted) {\n setType(persisted.type)\n setSelectedModels(persisted.selectedModels)\n persistedOptionsRef.current = persisted.optionsByModel\n } else {\n persistedOptionsRef.current = {}\n }\n hydratedRef.current = true\n setHydratedWorkspaceId(workspaceId)\n }, [workspaceId])\n\n useEffect(() => {\n if (!workspaceId) return\n let cancelled = false\n setCatalogLoading(true)\n setCatalogError(null)\n\n fetch(`/api/media-models?workspaceId=${encodeURIComponent(workspaceId)}`)\n .then(async (res) => {\n const data = await res.json() as MediaModelCatalogResponse\n if (!res.ok) throw new Error(data.error ?? 'Could not load media models')\n return data\n })\n .then((data) => {\n if (cancelled) return\n setCatalog(data)\n })\n .catch(() => {\n if (cancelled) return\n setCatalog(null)\n // Never surface the raw fetch/parse error — a non-JSON 404 page reads\n // as `Unexpected token 'N', \"Not Found\" is not valid JSON` to users.\n setCatalogError('Could not load media models')\n })\n .finally(() => {\n if (!cancelled) setCatalogLoading(false)\n })\n\n return () => {\n cancelled = true\n }\n }, [workspaceId])\n\n const laneModels = useMemo(() => catalog?.models[type] ?? [], [catalog, type])\n const curatedModels = useMemo(() => curateComposerModels(type, laneModels), [laneModels, type])\n // A retained pick survives only while the CURRENT catalog can honour it: with\n // no catalog yet keep it; an intentionally-uncurated i2v sibling stays (it is\n // reached by attaching a reference, never listed); anything else must be\n // present in the curated list, or the lane falls back to its\n // default. The deleted ComposerHero defended this via selectedModelsWithDefaults;\n // that helper resolves over the FULL catalog and would resurrect\n // curation-removed defaults, so the guard is re-derived here over curatedModels.\n const retained = selectedModels[type]\n const retainedUsable = retained !== undefined && (\n !catalog\n || Boolean(textToVideoSibling(retained))\n || curatedModels.some((model) => model.id === retained)\n )\n const modelId = retainedUsable ? retained : defaultModelId(type, catalog, curatedModels)\n // The image-to-video sibling is deliberately absent from the curated menu (it\n // is reached by attaching a reference image), so the row backing the pill is\n // looked up in the FULL lane list and may still be missing — a sibling the\n // catalog does not carry is sent by id and displayed as its id.\n const modelOption = laneModels.find((model) => model.id === modelId)\n\n // A dead selection is honoured only while the user is looking at it: a catalog\n // (re)load or a lane switch re-resolves to the first available model, so a dead\n // default never stays selected on its own (#463). A menu pick of an unavailable\n // model after that still sticks — until the catalog or the lane changes again.\n useEffect(() => {\n setSelectedModels((current) => {\n const retainedId = current[type]\n if (!retainedId || !catalog) return current\n // Never prune the image-to-video sibling: it is reached only by attaching a\n // reference (never menu-listed), and pruning it would fall back to the t2v\n // parent with the reference still attached — a reference on a text-to-video\n // request. An unavailable sibling instead keeps the warned pill and the\n // modelReady send gate, exactly the pre-#463 behavior.\n if (textToVideoSibling(retainedId)) return current\n const row = (catalog.models[type] ?? []).find((model) => model.id === retainedId)\n if (!row || row.status !== 'unavailable') return current\n const next = { ...current }\n delete next[type]\n return next\n })\n }, [catalog, type])\n\n const options = useMemo(\n () => (modelId\n ? resolveComposerOptions({\n type,\n modelId,\n provider: modelOption?.provider,\n catalogOptions: modelOption?.options,\n })\n : undefined),\n [modelId, modelOption, type],\n )\n\n // Re-reconcile whenever the resolved options change: a selection the new model\n // still accepts survives, an illegal one resets to that model's default, and a\n // parameter it does not publish is dropped rather than carried invisibly.\n useEffect(() => {\n setOptionValues((current) => {\n const seed = { ...persistedOptionsRef.current[modelId], ...current[type] }\n const next = reconcileOptionValues(options, seed, {\n allowCustomSize: supportsCustomImageSize(modelId),\n })\n const unchanged = Object.keys(next).length === Object.keys(current[type]).length\n && Object.entries(next).every(([key, value]) => current[type][key] === value)\n return unchanged ? current : { ...current, [type]: next }\n })\n }, [modelId, options, type])\n\n useEffect(() => {\n if (!workspaceId || !hydratedRef.current || hydratedWorkspaceId !== workspaceId) return\n // An unknown pre-catalog model has no vocabulary to validate against yet;\n // keep its stored options intact until the catalog resolves. Known models\n // can reconcile immediately from their built-in option metadata.\n if (!catalog && modelId && persistedOptionsRef.current[modelId] !== undefined && !options) return\n const seed = { ...persistedOptionsRef.current[modelId], ...optionValues[type] }\n const reconciled = reconcileOptionValues(options, seed, {\n allowCustomSize: supportsCustomImageSize(modelId),\n })\n const reconciledReady = Object.keys(reconciled).length === Object.keys(optionValues[type]).length\n && Object.entries(reconciled).every(([key, value]) => optionValues[type][key] === value)\n if (!reconciledReady) return\n const optionsByModel = {\n ...persistedOptionsRef.current,\n ...(modelId ? { [modelId]: optionValues[type] } : {}),\n }\n saveComposerSelections(workspaceId, {\n v: 1,\n type,\n selectedModels,\n optionsByModel,\n })\n persistedOptionsRef.current = optionsByModel\n }, [catalog, hydratedWorkspaceId, modelId, optionValues, options, selectedModels, type, workspaceId])\n\n const values = optionValues[type]\n const params = visibleParams(type, options)\n const audioMeta = type === 'video' ? options?.audio : undefined\n const audioSupported = Boolean(audioMeta) && audioMeta?.supported !== false\n // A model the catalog does not list is normally \"not ready\" — except for a\n // verified image-to-video sibling, which the composer selected itself by\n // attaching a reference image and must be able to send even when the catalog\n // never listed it.\n const unlistedSibling = !modelOption && Boolean(textToVideoSibling(modelId))\n const referenceSupported = type === 'video'\n && Boolean(imageToVideoSibling(modelId) ?? textToVideoSibling(modelId))\n\n const modelReady = (Boolean(modelOption) || unlistedSibling)\n && modelOption?.status !== 'unavailable'\n && !catalogLoading\n && !catalogError\n const laneDown = Boolean(catalog) && !catalogLoading && !catalogError && laneUnavailable(curatedModels)\n const canSubmit = Boolean(workspaceId) && modelReady && Boolean(prompt.trim()) && !isSubmitting\n\n function selectModel(id: string) {\n setSelectedModels((current) => ({ ...current, [type]: id }))\n }\n\n /** The model MENU's handler. While a reference is attached the selection must\n * keep the attachment ⇒ image-to-video invariant: a reference-capable pick is\n * re-mapped to its i2v sibling, and a pick with no sibling drops the\n * attachment explicitly rather than hiding it to reappear later. */\n function chooseModel(id: string) {\n if (!referenceImageUrl || type !== 'video') return selectModel(id)\n const sibling = imageToVideoSibling(id)\n if (sibling) return selectModel(sibling)\n if (!textToVideoSibling(id)) setReferenceImageUrl(null)\n return selectModel(id)\n }\n\n function setOption(param: string, value: ModelOptionValue) {\n setOptionValues((current) => ({ ...current, [type]: { ...current[type], [param]: value } }))\n }\n\n function attachReference(url: string) {\n setReferenceImageUrl(url)\n const sibling = imageToVideoSibling(modelId)\n if (sibling) selectModel(sibling)\n }\n\n function removeReference() {\n setReferenceImageUrl(null)\n const sibling = textToVideoSibling(modelId)\n if (sibling) selectModel(sibling)\n }\n\n async function generate() {\n if (!workspaceId || submitLockRef.current || isSubmitting) return\n const promptText = prompt.trim()\n if (!promptText) return\n if (!modelReady) return\n submitLockRef.current = true\n setIsSubmitting(true)\n setError(null)\n\n const clientRequestId = crypto.randomUUID()\n const imageCount = type === 'image' ? normalizeImageCount(values.n ?? 1) : 1\n const localGenerations = Array.from({ length: imageCount }, (_, outputIndex) => optimisticGeneration(\n {\n type,\n prompt: promptText,\n model: modelId,\n clientRequestId,\n outputIndex: type === 'image' ? outputIndex : undefined,\n outputCount: type === 'image' ? imageCount : undefined,\n },\n aspectRatioFromOptions(type, {\n size: asText(values.size),\n aspectRatio: asText(values.aspect_ratio),\n }),\n ))\n localGenerations.slice().reverse().forEach(onGenerated)\n setPrompt('')\n\n let receivedServerGeneration = false\n try {\n const body = buildGenerationRequestBody({\n workspaceId,\n clientRequestId,\n type,\n model: modelId,\n prompt: promptText,\n // `duration`, `audio` and `speed` go on the wire in the TYPE the model\n // published them in — a `duration` of `'5'` that arrives as `5` is a\n // different request, and the three providers behind this lane disagree\n // about which is right. An absent value is omitted, never defaulted.\n image: {\n size: asText(values.size),\n quality: asText(values.quality),\n count: imageCount,\n },\n video: {\n duration: asWireScalar(values.duration),\n resolution: asText(values.resolution),\n aspectRatio: asText(values.aspect_ratio),\n referenceImageUrl: referenceSupported && referenceImageUrl ? referenceImageUrl : undefined,\n audio: audioSupported && typeof values.audio === 'boolean' ? values.audio : undefined,\n mode: asText(values.mode),\n },\n speech: {\n voice: asText(values.voice),\n speed: typeof values.speed === 'number' ? values.speed : undefined,\n },\n })\n\n const res = await fetch('/api/generate', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n const data = await res.json() as { generation?: Generation; generations?: Generation[]; error?: string }\n const serverGenerations = data.generations?.length ? data.generations : data.generation ? [data.generation] : []\n if (serverGenerations.length > 0) {\n receivedServerGeneration = true\n serverGenerations.slice().reverse().forEach(onGenerated)\n }\n if (!res.ok || serverGenerations.length === 0) throw new Error(data.error ?? 'Generation failed')\n } catch (err) {\n if (!receivedServerGeneration) localGenerations.map(failedOptimisticGeneration).forEach(onGenerated)\n setError(err instanceof Error ? userSafeGenerationMessage(err.message) : 'Generation failed')\n } finally {\n submitLockRef.current = false\n setIsSubmitting(false)\n }\n }\n\n const notice = catalogError ?? error\n const laneLabel = SEGMENTS.find((segment) => segment.type === type)!.label\n // An empty curated lane can reflect catalog or curation policy, not an outage.\n const laneDownMessage = curatedModels.length > 0\n ? `${laneLabel} models are temporarily unavailable`\n : `No ${laneLabel.toLowerCase()} models are available`\n\n return (\n <section\n data-variant={variant}\n className={`rounded-[14px] border border-border bg-card px-2.5 pb-[9px] pt-2 shadow-sm transition focus-within:border-primary focus-within:ring-[3px] focus-within:ring-ring/30 ${className ?? ''}`}\n >\n {laneDown ? (\n <p className=\"flex min-h-0 items-center gap-2 px-1.5 pb-3 pt-1.5 text-[13px] font-medium text-warning\">\n <TriangleAlert aria-hidden className=\"h-4 w-4 shrink-0\" strokeWidth={2} />\n <span>{laneDownMessage}</span>\n </p>\n ) : (\n <textarea\n value={prompt}\n onChange={(event) => setPrompt(event.target.value)}\n onKeyDown={(event) => {\n if (event.key !== 'Enter' || event.shiftKey) return\n event.preventDefault()\n void generate()\n }}\n rows={3}\n aria-label=\"Prompt\"\n placeholder=\"Describe what you want to generate…\"\n className=\"block min-h-[66px] w-full resize-none border-0 bg-transparent px-1.5 pb-1 pt-1.5 text-[14.5px] leading-relaxed outline-none placeholder:text-muted-foreground\"\n />\n )}\n\n <div className=\"flex items-center gap-2\">\n <MediaTypeSegments value={type} segments={SEGMENTS} onChange={setType} />\n\n <ComposerBand bandRef={bandRef} resetKey={type}>\n <ModelPill\n models={curatedModels}\n value={modelId}\n displayName={modelOption?.name || modelId || 'Select a model'}\n provider={modelOption?.provider}\n unavailable={modelOption?.status === 'unavailable'}\n onSelect={chooseModel}\n bandRef={bandRef}\n />\n\n {params.map((param) => (\n <div key={`${type}-${param}`} className=\"studio-pill-in flex-none\">\n <OptionPill\n label={PARAM_LABELS[param] ?? param}\n icon={PARAM_ICONS[param] ?? SlidersHorizontal}\n value={values[param]}\n choices={choicesForPill(param, options?.[param], values[param])}\n onSelect={(value) => setOption(param, value)}\n bandRef={bandRef}\n custom={param === 'size' && supportsCustomImageSize(modelId)\n ? {\n label: 'Custom…',\n render: ({ close }) => (\n <CustomSizeForm\n initial={asText(values.size)}\n onApply={(size) => {\n setOption('size', size)\n close()\n }}\n onCancel={close}\n />\n ),\n }\n : undefined}\n />\n </div>\n ))}\n\n {audioSupported && (\n <div key={`${type}-audio`} className=\"studio-pill-in flex-none\">\n <AudioTogglePill\n on={values.audio === true}\n onToggle={(on) => setOption('audio', on)}\n />\n </div>\n )}\n\n {referenceSupported && (\n <div key={`${type}-reference`} className=\"studio-pill-in flex-none\">\n <ReferencePill\n url={referenceImageUrl}\n onAttach={attachReference}\n onRemove={removeReference}\n pick={pickReferenceImage}\n bandRef={bandRef}\n />\n </div>\n )}\n </ComposerBand>\n\n <button\n type=\"button\"\n aria-label=\"Generate\"\n title=\"Generate\"\n disabled={!canSubmit}\n onClick={() => void generate()}\n className=\"ml-auto inline-flex h-8 w-8 flex-none items-center justify-center rounded-full bg-foreground text-background transition hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-40 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-card\"\n >\n <ArrowUp className=\"h-4 w-4\" strokeWidth={2} />\n </button>\n </div>\n\n {notice && (\n <p className=\"px-1.5 pt-1.5 text-[12px] text-destructive\">\n {notice}\n </p>\n )}\n </section>\n )\n}\n\n/** A text-typed field's value, or `undefined` so the field is omitted entirely\n * — `String(undefined)` puts the literal `\"undefined\"` on the wire, which the\n * provider will try to honour. These fields are typed `string` by the\n * `/api/generate` contract, so a numeric published value is rendered as its\n * digits; the type-sensitive fields (`duration`, `audio`, `speed`) never pass\n * through here. */\nfunction asText(value: ModelOptionValue | undefined): string | undefined {\n return typeof value === 'string' ? value : typeof value === 'number' ? String(value) : undefined\n}\n\n/** A duration passes through as published: the string `'5'`, the string `'8s'`,\n * or the number `5`. Only a boolean (which no lane publishes here) is refused. */\nfunction asWireScalar(value: ModelOptionValue | undefined): string | number | undefined {\n return typeof value === 'string' || typeof value === 'number' ? value : undefined\n}\n\n/** The pill's rows: the published choices, plus the current value when it is a\n * legal off-enum one (a custom gpt-image-2 size), so the pill reports what is\n * actually selected instead of falling back to a dash. */\nfunction choicesForPill(\n param: string,\n meta: ModelOptionMetadata | undefined,\n value: ModelOptionValue | undefined,\n): OptionChoice[] {\n if (!meta) return []\n const choices = choicesFor(param, meta).map((choice) => ({\n value: choice,\n label: optionValueLabel(param, choice),\n }))\n if (value === undefined || choices.some((choice) => choice.value === value)) return choices\n return [...choices, { value, label: `${optionValueLabel(param, value)} · custom` }]\n}\n","/**\n * The studio composer's control row: the media-type segmented group, the\n * horizontally scrolling option band, and the pills that dock in it.\n *\n * Every pill that opens a panel opens it through `usePopover` + `PopoverSurface`\n * (`../web-react/controls`), never an in-place `absolute` panel: the band IS a\n * scroll container (`overflow-x-auto`), and a scroll container clips every\n * positioned descendant whose containing block sits inside it — the measured\n * failure that left the chat composer's own menus painting zero pixels. The\n * surface portals to `document.body` and re-anchors on capture-phase scroll, so\n * scrolling the band moves an open menu with its pill. The one rule the surface\n * cannot supply is when to give up: a menu whose pill has been scrolled out of\n * the band no longer points at anything, so it closes when the pill's\n * horizontal CENTRE leaves the band's box.\n */\n\nimport {\n useCallback,\n useEffect,\n useId,\n useState,\n type JSX,\n type ReactNode,\n type RefObject,\n} from 'react'\nimport { ImagePlus, TriangleAlert, Volume2, VolumeX, X, type LucideIcon } from 'lucide-react'\nimport {\n CheckGlyph,\n ChevronDown,\n OVERLAY_SHADOW,\n POPOVER_OPTION_FOCUS,\n PopoverSurface,\n usePopover,\n} from '../web-react/controls'\nimport { ProviderLogo } from '../web-react/provider-logo'\nimport { type MediaModelOption, type ModelOptionValue, validateCustomImageSize } from '../studio'\n\n/** The resting pill: one row height, never wraps, shrink-proof in the band. */\nconst PILL = 'inline-flex h-7 flex-none items-center gap-1.5 whitespace-nowrap rounded-full border border-border bg-card px-2.5 text-[12.5px] font-medium text-foreground transition hover:bg-accent'\n/**\n * Optically centers a pill label. Flex `items-center` centers the LINE BOX, but\n * where the glyphs sit inside it is font-metric-determined — with an\n * ascent-heavy font the text reads ~1.5px high. Trimming the line box to the\n * cap→baseline band makes flex centering center the visible text in every\n * font; unsupported browsers keep the untrimmed (current) behavior.\n */\nconst PILL_LABEL = '[text-box:trim-both_cap_alphabetic]'\nconst MENU_PANEL = `flex min-w-[184px] flex-col overflow-y-auto rounded-xl border border-border bg-popover p-1 text-popover-foreground ${OVERLAY_SHADOW}`\nconst MENU_HEADER = 'px-2.5 pb-1 pt-1.5 text-[10.5px] font-semibold uppercase tracking-[0.08em] text-muted-foreground'\n\nfunction menuRowClass(selected: boolean): string {\n return `flex w-full items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-[13px] transition ${POPOVER_OPTION_FOCUS} ${\n selected ? 'bg-primary/10 font-medium' : 'hover:bg-accent'\n }`\n}\n\n/** Deepest edge fade, in px. Beyond this the fade stops reading as \"there is\n * more\" and starts reading as a vignette. */\nconst MAX_FADE = 32\n\n/** One media lane's segment: the icon it shows collapsed, the word it shows\n * when active. */\nexport interface MediaTypeSegment<T extends string> {\n type: T\n label: string\n icon: LucideIcon\n}\n\n/**\n * The pinned-left media-type group: a track holding one filled pill (the active\n * lane, icon + word) and icon-only siblings. `aria-pressed` carries the state\n * and `aria-label` carries the word the collapsed items drop.\n */\nexport function MediaTypeSegments<T extends string>({\n value,\n segments,\n onChange,\n}: {\n value: T\n segments: readonly MediaTypeSegment<T>[]\n onChange: (type: T) => void\n}) {\n return (\n <div\n role=\"group\"\n aria-label=\"Media type\"\n className=\"flex flex-none items-center gap-0.5 rounded-full border border-border bg-muted p-[3px]\"\n >\n {segments.map(({ type, label, icon: Icon }) => {\n const active = type === value\n return (\n <button\n key={type}\n type=\"button\"\n aria-pressed={active}\n aria-label={label}\n title={label}\n onClick={() => onChange(type)}\n className={`inline-flex h-7 items-center gap-1.5 whitespace-nowrap rounded-full text-[12.5px] transition ${\n active\n ? 'bg-card px-2.5 font-medium text-foreground shadow-sm'\n : 'px-2 text-muted-foreground hover:text-foreground'\n }`}\n >\n <Icon className=\"h-4 w-4 shrink-0\" strokeWidth={1.5} />\n {active && <span>{label}</span>}\n </button>\n )\n })}\n </div>\n )\n}\n\n/**\n * The middle scroller. It hides its scrollbar and fades whichever edge has\n * content behind it, at the DEPTH of what is actually hidden (capped at\n * {@link MAX_FADE}) rather than a fixed gradient that claims more is off-screen\n * than there is. A media-type switch resets the scroll to the start, because\n * the control set itself changed; every other re-render leaves `scrollLeft`\n * alone, so picking a value cannot jump the band back to the beginning.\n */\nexport function ComposerBand({\n bandRef,\n resetKey,\n children,\n}: {\n bandRef: RefObject<HTMLDivElement | null>\n /** Changing this scrolls the band back to the start. */\n resetKey: string\n children: ReactNode\n}) {\n const sync = useCallback(() => {\n const band = bandRef.current\n if (!band) return\n const hiddenStart = band.scrollLeft\n const hiddenEnd = Math.max(0, band.scrollWidth - band.clientWidth - band.scrollLeft)\n const atStart = hiddenStart > 1\n const atEnd = hiddenEnd > 1\n band.dataset.overflow = atStart && atEnd ? 'both' : atStart ? 'start' : atEnd ? 'end' : 'none'\n band.style.setProperty('--fade-start', `${atStart ? Math.min(MAX_FADE, hiddenStart) : 0}px`)\n band.style.setProperty('--fade-end', `${atEnd ? Math.min(MAX_FADE, hiddenEnd) : 0}px`)\n }, [bandRef])\n\n // After every render: the pill set changes with the model and the lane, so\n // the hidden width this reads is only correct once the new pills are laid out.\n useEffect(sync)\n\n useEffect(() => {\n const band = bandRef.current\n window.addEventListener('resize', sync)\n // jsdom and older browsers have no ResizeObserver; the window listener still\n // covers the case that matters (the viewport getting narrower).\n const observer = typeof ResizeObserver === 'undefined' || !band ? null : new ResizeObserver(sync)\n if (band) observer?.observe(band)\n return () => {\n window.removeEventListener('resize', sync)\n observer?.disconnect()\n }\n }, [bandRef, sync])\n\n useEffect(() => {\n const band = bandRef.current\n if (band) band.scrollLeft = 0\n sync()\n }, [bandRef, resetKey, sync])\n\n return (\n <div\n ref={bandRef}\n data-overflow=\"none\"\n onScroll={sync}\n className=\"studio-band flex min-w-0 flex-1 flex-nowrap items-center gap-2 overflow-x-auto\"\n >\n {children}\n </div>\n )\n}\n\n/**\n * Close an open menu once its pill has been scrolled out of the band.\n *\n * `PopoverSurface` re-anchors on scroll, so a menu follows its pill for free —\n * which is right until the pill leaves the band entirely and the menu is left\n * pointing at a clipped edge. The centre is the test rather than either edge: a\n * pill half-way out is still the pill the user opened.\n */\nfunction useCloseWhenScrolledOut(\n open: boolean,\n setOpen: (open: boolean) => void,\n triggerRef: RefObject<HTMLElement | null>,\n bandRef: RefObject<HTMLDivElement | null>,\n) {\n useEffect(() => {\n const band = bandRef.current\n if (!open || !band) return\n const onScroll = () => {\n const trigger = triggerRef.current\n if (!trigger) return\n const anchor = trigger.getBoundingClientRect()\n const box = band.getBoundingClientRect()\n const centre = anchor.left + anchor.width / 2\n if (centre < box.left || centre > box.right) setOpen(false)\n }\n band.addEventListener('scroll', onScroll)\n return () => band.removeEventListener('scroll', onScroll)\n }, [bandRef, open, setOpen, triggerRef])\n}\n\n/** One renderable value: the wire value, untouched, and how it reads. */\nexport interface OptionChoice {\n value: ModelOptionValue\n label: string\n icon?: LucideIcon\n}\n\nfunction MenuRows<T extends ModelOptionValue>({\n value,\n choices,\n onSelect,\n}: {\n value: T | undefined\n choices: readonly { value: T; label: string; icon?: LucideIcon }[]\n onSelect: (value: T) => void\n}) {\n return choices.map((choice) => {\n const Icon = choice.icon\n return (\n <button\n key={String(choice.value)}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={choice.value === value}\n onClick={() => onSelect(choice.value)}\n className={menuRowClass(choice.value === value)}\n >\n {Icon && <Icon aria-hidden className=\"h-3.5 w-3.5 shrink-0\" strokeWidth={1.5} />}\n <span className=\"truncate\">{choice.label}</span>\n {choice.value === value && (\n <CheckGlyph className=\"ml-auto h-3.5 w-3.5 shrink-0 text-primary\" />\n )}\n </button>\n )\n })\n}\n\n/** A standalone enum picker using the studio composer's pill and menu grammar. */\nexport function MenuPill<T extends string>({\n label,\n value,\n choices,\n onSelect,\n className,\n icon: Icon,\n trigger = 'pill',\n}: {\n label: string\n value: T\n choices: readonly { value: T; label: string; icon?: LucideIcon }[]\n onSelect: (value: T) => void\n className?: string\n icon?: LucideIcon\n trigger?: 'pill' | 'text'\n}): JSX.Element {\n const [open, setOpen] = useState(false)\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen)\n const panelId = useId()\n const selected = choices.find((choice) => choice.value === value)\n\n return (\n <div ref={containerRef} className=\"relative inline-flex flex-none\">\n <button\n type=\"button\"\n {...triggerProps}\n aria-controls={open ? panelId : undefined}\n title={label}\n aria-label={label}\n onClick={() => setOpen(!open)}\n className={`${trigger === 'text'\n ? 'inline-flex h-7 flex-none items-center gap-1 whitespace-nowrap rounded-full px-2 text-[12.5px] font-medium text-primary transition hover:bg-accent'\n : PILL} ${className ?? ''}`}\n >\n {Icon && <Icon aria-hidden className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" strokeWidth={1.5} />}\n <span className={PILL_LABEL}>{selected?.label ?? '—'}</span>\n <ChevronDown className={`h-3 w-3 shrink-0 ${trigger === 'text' ? 'text-primary' : 'text-muted-foreground'}`} />\n </button>\n\n <PopoverSurface\n open={open}\n id={panelId}\n role=\"menu\"\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={MENU_PANEL}\n >\n <div className={MENU_HEADER}>{label}</div>\n <MenuRows\n value={value}\n choices={choices}\n onSelect={(next) => {\n onSelect(next)\n setOpen(false)\n }}\n />\n </PopoverSurface>\n </div>\n )\n}\n\n/**\n * A value pill and the menu it opens.\n *\n * The pill shows the VALUE and carries the parameter name in `title` and in its\n * accessible name — a band of eight labelled pills does not fit a chat card,\n * and \"5s\" alone tells a screen-reader user nothing about which parameter it\n * belongs to.\n */\nexport function OptionPill({\n label,\n value,\n choices,\n onSelect,\n bandRef,\n custom,\n icon: Icon,\n}: {\n label: string\n value: ModelOptionValue | undefined\n choices: readonly OptionChoice[]\n onSelect: (value: ModelOptionValue) => void\n bandRef: RefObject<HTMLDivElement | null>\n icon?: LucideIcon\n /** A trailing row that swaps the menu to a form (the gpt-image-2 custom\n * size). Absent for every parameter whose values are an enum. */\n custom?: {\n label: string\n render: (args: { close: () => void }) => ReactNode\n }\n}) {\n const [open, setOpen] = useState(false)\n const [customOpen, setCustomOpen] = useState(false)\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen)\n const panelId = useId()\n useCloseWhenScrolledOut(open, setOpen, triggerRef, bandRef)\n\n const selected = choices.find((choice) => choice.value === value)\n const close = () => {\n setOpen(false)\n setCustomOpen(false)\n }\n\n return (\n <div ref={containerRef} className=\"relative inline-flex flex-none\">\n <button\n type=\"button\"\n {...triggerProps}\n aria-controls={open ? panelId : undefined}\n title={label}\n aria-label={`${label}: ${selected?.label ?? 'not set'}`}\n onClick={() => {\n setCustomOpen(false)\n setOpen(!open)\n }}\n className={PILL}\n >\n {Icon && <Icon aria-hidden className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" strokeWidth={1.5} />}\n <span className={PILL_LABEL}>{selected?.label ?? '—'}</span>\n <ChevronDown className=\"h-3 w-3 shrink-0 text-muted-foreground\" />\n </button>\n\n <PopoverSurface\n open={open}\n id={panelId}\n role={customOpen ? undefined : 'menu'}\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={MENU_PANEL}\n >\n <div className={MENU_HEADER}>{label}</div>\n {customOpen && custom\n ? custom.render({ close })\n : (\n <>\n <MenuRows\n value={value}\n choices={choices}\n onSelect={(next) => {\n onSelect(next)\n close()\n }}\n />\n {custom && (\n <button\n type=\"button\"\n onClick={() => setCustomOpen(true)}\n className={`${menuRowClass(false)} text-muted-foreground`}\n >\n {custom.label}\n </button>\n )}\n </>\n )}\n </PopoverSurface>\n </div>\n )\n}\n\n/**\n * The custom-size form the Size menu swaps to.\n *\n * The reason a size is refused renders next to the fields that are wrong — a\n * toast would be gone by the time the user looks back at the inputs — and Apply\n * refuses rather than disables, so the reason is always reachable.\n */\nexport function CustomSizeForm({\n initial,\n onApply,\n onCancel,\n}: {\n initial?: string\n onApply: (size: string) => void\n onCancel: () => void\n}) {\n const parsed = /^(\\d+)x(\\d+)$/.exec(initial ?? '')\n const [width, setWidth] = useState(parsed?.[1] ?? '')\n const [height, setHeight] = useState(parsed?.[2] ?? '')\n const [error, setError] = useState<string | null>(null)\n const fieldClass = 'h-8 w-[74px] rounded-md border border-input bg-background px-2 text-[13px] tabular-nums'\n\n function apply() {\n const verdict = validateCustomImageSize(Number(width), Number(height))\n if (!verdict.ok) {\n setError(verdict.reason)\n return\n }\n onApply(`${Number(width)}x${Number(height)}`)\n }\n\n return (\n <div className=\"flex w-[228px] flex-col gap-2 p-1.5\">\n <div className=\"flex items-center gap-2\">\n <input\n type=\"number\"\n value={width}\n aria-label=\"Custom width\"\n onChange={(event) => {\n setWidth(event.target.value)\n setError(null)\n }}\n className={fieldClass}\n />\n <span aria-hidden className=\"text-muted-foreground\">×</span>\n <input\n type=\"number\"\n value={height}\n aria-label=\"Custom height\"\n onChange={(event) => {\n setHeight(event.target.value)\n setError(null)\n }}\n className={fieldClass}\n />\n </div>\n {error\n ? <p className=\"text-[12px] text-destructive\">{error}</p>\n : <p className=\"text-[12px] text-muted-foreground\">Multiples of 16, long edge up to 3840, ratio between 1:3 and 3:1.</p>}\n <div className=\"flex items-center justify-end gap-1.5\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"rounded-md px-2.5 py-1 text-[12.5px] font-medium text-muted-foreground transition hover:bg-accent hover:text-foreground\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={apply}\n className=\"rounded-md bg-primary px-2.5 py-1 text-[12.5px] font-medium text-primary-foreground transition hover:opacity-90\"\n >\n Apply\n </button>\n </div>\n </div>\n )\n}\n\n/**\n * The audio switch. It is a toggle rather than a menu because the parameter has\n * exactly two states, and a two-row menu to say \"on\" is a menu that costs a\n * click for nothing.\n */\nexport function AudioTogglePill({ on, onToggle }: { on: boolean; onToggle: (on: boolean) => void }) {\n return (\n <button\n type=\"button\"\n aria-pressed={on}\n title=\"Audio\"\n onClick={() => onToggle(!on)}\n className={`${PILL} ${on ? '' : 'text-muted-foreground'}`}\n >\n {on\n ? <Volume2 className=\"h-4 w-4 shrink-0\" strokeWidth={1.5} />\n : <VolumeX className=\"h-4 w-4 shrink-0\" strokeWidth={1.5} />}\n <span className={PILL_LABEL}>{on ? 'Audio on' : 'Audio off'}</span>\n </button>\n )\n}\n\n/**\n * The reference-image pill: the only control that changes which MODEL runs, so\n * the swap to the image-to-video sibling is the caller's (`onAttach`/`onRemove`)\n * and the pill only reports what is attached.\n *\n * With no `pick` seam it opens a URL form instead of a file dialog — a URL is\n * something a host with no upload endpoint can still supply, and refusing\n * anything that is not `http(s)` keeps a pasted local path from reaching the\n * provider as an unfetchable reference.\n */\nexport function ReferencePill({\n url,\n onAttach,\n onRemove,\n pick,\n bandRef,\n}: {\n url: string | null\n onAttach: (url: string) => void\n onRemove: () => void\n pick?: () => Promise<string | null>\n bandRef: RefObject<HTMLDivElement | null>\n}) {\n const [open, setOpen] = useState(false)\n const [draft, setDraft] = useState('')\n const [error, setError] = useState<string | null>(null)\n const { containerRef, triggerRef, panelRef } = usePopover(open, setOpen)\n const panelId = useId()\n useCloseWhenScrolledOut(open, setOpen, triggerRef, bandRef)\n\n if (url) {\n return (\n <div className={`${PILL} border-primary bg-primary/10 pr-1.5 text-primary hover:bg-primary/10`}>\n <img src={url} alt=\"\" className=\"h-[18px] w-[18px] shrink-0 rounded-[5px] object-cover\" />\n <span className={PILL_LABEL}>Reference</span>\n <button\n type=\"button\"\n aria-label=\"Remove reference image\"\n onClick={onRemove}\n className=\"ml-0.5 inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full transition hover:bg-primary/20\"\n >\n <X className=\"h-3 w-3\" strokeWidth={2} />\n </button>\n </div>\n )\n }\n\n function attach() {\n const value = draft.trim()\n if (!/^https?:\\/\\//i.test(value)) {\n setError('Enter a URL starting with http:// or https://')\n return\n }\n onAttach(value)\n setDraft('')\n setError(null)\n setOpen(false)\n }\n\n return (\n <div ref={containerRef} className=\"relative inline-flex flex-none\">\n <button\n type=\"button\"\n ref={triggerRef}\n // With a `pick` seam the button opens the host's own picker, not a\n // popover — claiming `aria-haspopup` there announces a menu that never\n // appears.\n {...(pick ? {} : { 'aria-haspopup': true as const, 'aria-expanded': open, 'aria-controls': open ? panelId : undefined })}\n title=\"Reference image\"\n onClick={() => {\n if (!pick) {\n setOpen(!open)\n return\n }\n void pick().then((picked) => {\n if (picked) onAttach(picked)\n })\n }}\n className={PILL}\n >\n <ImagePlus className=\"h-4 w-4 shrink-0 text-muted-foreground\" strokeWidth={1.5} />\n <span className={PILL_LABEL}>Reference image</span>\n </button>\n\n {!pick && (\n <PopoverSurface\n open={open}\n id={panelId}\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={MENU_PANEL}\n >\n <div className={MENU_HEADER}>Reference image</div>\n <div className=\"flex w-[260px] flex-col gap-2 p-1.5\">\n <input\n type=\"url\"\n value={draft}\n aria-label=\"Reference image URL\"\n placeholder=\"https://…\"\n onChange={(event) => {\n setDraft(event.target.value)\n setError(null)\n }}\n className=\"h-8 w-full rounded-md border border-input bg-background px-2 text-[13px]\"\n />\n {error && <p className=\"text-[12px] text-destructive\">{error}</p>}\n <div className=\"flex items-center justify-end gap-1.5\">\n <button\n type=\"button\"\n onClick={() => setOpen(false)}\n className=\"rounded-md px-2.5 py-1 text-[12.5px] font-medium text-muted-foreground transition hover:bg-accent hover:text-foreground\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={attach}\n className=\"rounded-md bg-primary px-2.5 py-1 text-[12.5px] font-medium text-primary-foreground transition hover:opacity-90\"\n >\n Attach\n </button>\n </div>\n </div>\n </PopoverSurface>\n )}\n </div>\n )\n}\n\n/**\n * The model pill — first in the band on every lane, and the only pill that is\n * always there. A model with no published option metadata renders this and\n * nothing else, which is the honest reading of \"we do not know what this model\n * takes\".\n */\nexport function ModelPill({\n models,\n value,\n displayName,\n provider,\n unavailable,\n onSelect,\n bandRef,\n}: {\n models: readonly MediaModelOption[]\n value: string\n /** What the pill reads. Falls back to the id — including for a model the\n * catalog does not list, such as an image-to-video sibling. */\n displayName: string\n provider?: string\n /** The selected model is listed but not routable — the pill carries the warning instead of any status line. */\n unavailable?: boolean\n onSelect: (id: string) => void\n bandRef: RefObject<HTMLDivElement | null>\n}) {\n const [open, setOpen] = useState(false)\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen)\n const panelId = useId()\n useCloseWhenScrolledOut(open, setOpen, triggerRef, bandRef)\n\n return (\n <div ref={containerRef} className=\"relative inline-flex flex-none\">\n <button\n type=\"button\"\n {...triggerProps}\n aria-controls={open ? panelId : undefined}\n title=\"Model\"\n aria-label={`Model: ${displayName}${unavailable ? ' (unavailable)' : ''}`}\n onClick={() => setOpen(!open)}\n className={`${PILL}${unavailable ? ' border-warning/50' : ''}`}\n >\n {unavailable && <TriangleAlert aria-hidden className=\"h-3.5 w-3.5 shrink-0 text-warning\" strokeWidth={2} />}\n {provider && <ProviderLogo provider={provider} size={14} />}\n {/* No PILL_LABEL here: text-box trim ends the box at the alphabetic\n baseline, and truncate's overflow:hidden then clips descender ink\n (the g/p tails of \"gpt-image-2\"). A normal line box keeps them. */}\n <span className=\"max-w-[168px] truncate leading-normal\">{displayName}</span>\n <ChevronDown className=\"h-3 w-3 shrink-0 text-muted-foreground\" />\n </button>\n\n <PopoverSurface\n open={open}\n id={panelId}\n role=\"menu\"\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={`${MENU_PANEL} max-w-[320px]`}\n >\n <div className={MENU_HEADER}>Model</div>\n {models.length === 0 && (\n <p className=\"px-2.5 py-2 text-[13px] text-muted-foreground\">No models are available for this media type.</p>\n )}\n {models.map((model) => (\n <button\n key={model.id}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={model.id === value}\n onClick={() => {\n onSelect(model.id)\n setOpen(false)\n }}\n className={menuRowClass(model.id === value)}\n >\n {model.provider && (\n <span className={model.status === 'unavailable' ? 'opacity-45' : undefined}>\n <ProviderLogo provider={model.provider} size={14} />\n </span>\n )}\n <span className={`truncate${model.status === 'unavailable' ? ' opacity-45' : ''}`}>\n {model.name || model.id}\n </span>\n {model.status === 'unavailable' ? (\n <>\n <span className=\"ml-auto shrink-0 text-[11px] text-warning\">Unavailable</span>\n <TriangleAlert aria-hidden className=\"h-3.5 w-3.5 shrink-0 text-warning\" strokeWidth={2} />\n </>\n ) : model.status === 'limited' && (\n <span className=\"ml-auto shrink-0 text-[11px] capitalize text-muted-foreground\">{model.status}</span>\n )}\n {model.id === value && (\n <CheckGlyph className={`${model.status === 'available' ? 'ml-auto ' : ''}h-3.5 w-3.5 shrink-0 text-primary`} />\n )}\n </button>\n ))}\n </PopoverSurface>\n </div>\n )\n}\n\n/**\n * How a wire value reads, with the wire value itself untouched underneath.\n *\n * Keyed on the PARAMETER because the same scalar means different things across\n * them: `5` is \"5s\" of video and `2` is \"×2\" images. Anything this table has no\n * rule for reads as itself with a capital letter — never as an invented word,\n * so `std` renders \"Std\" and not a \"Standard\" nobody published.\n */\nexport function optionValueLabel(param: string, value: ModelOptionValue): string {\n if (typeof value === 'boolean') return value ? 'On' : 'Off'\n const text = String(value)\n if (param === 'n') return `×${text}`\n if (param === 'speed') return `${text}×`\n if (text === 'auto') return 'Auto'\n if (param === 'duration') return /^\\d+(\\.\\d+)?$/.test(text) ? `${text}s` : text\n if (param === 'size') {\n const size = /^(\\d+)x(\\d+)$/.exec(text)\n return size ? `${size[1]}×${size[2]}` : text\n }\n if (param === 'resolution' || param === 'aspect_ratio') return text\n return text.charAt(0).toUpperCase() + text.slice(1)\n}\n","import type { ModelOptionValue } from '../studio'\nimport type { ComposerType } from './studio-composer'\n\nexport interface PersistedComposerSelections {\n v: 1\n type: ComposerType\n selectedModels: Partial<Record<ComposerType, string>>\n /** Option values are model-specific: two models in one lane may publish\n * different enums for the same parameter. */\n optionsByModel: Record<string, Record<string, ModelOptionValue>>\n}\n\nconst COMPOSER_TYPES = ['image', 'video', 'speech'] as const\n\nfunction storageKey(workspaceId: string): string {\n return `studio-composer:${workspaceId}`\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== 'object') return false\n const prototype = Object.getPrototypeOf(value)\n return prototype === Object.prototype || prototype === null\n}\n\nfunction isComposerType(value: unknown): value is ComposerType {\n return COMPOSER_TYPES.some((type) => type === value)\n}\n\nfunction isOptionValue(value: unknown): value is ModelOptionValue {\n return typeof value === 'string' || typeof value === 'boolean'\n || (typeof value === 'number' && Number.isFinite(value))\n}\n\nfunction parseSelections(value: unknown): PersistedComposerSelections | null {\n if (!isPlainObject(value) || value.v !== 1 || !isComposerType(value.type)) return null\n if (!isPlainObject(value.selectedModels) || !isPlainObject(value.optionsByModel)) return null\n\n const selectedModels: Partial<Record<ComposerType, string>> = {}\n for (const type of COMPOSER_TYPES) {\n const modelId = value.selectedModels[type]\n if (typeof modelId === 'string') selectedModels[type] = modelId\n }\n\n const optionsByModel: Record<string, Record<string, ModelOptionValue>> = {}\n for (const [modelId, rawOptions] of Object.entries(value.optionsByModel)) {\n if (!isPlainObject(rawOptions)) continue\n const options: Record<string, ModelOptionValue> = {}\n for (const [param, optionValue] of Object.entries(rawOptions)) {\n if (isOptionValue(optionValue)) options[param] = optionValue\n }\n optionsByModel[modelId] = options\n }\n\n return { v: 1, type: value.type, selectedModels, optionsByModel }\n}\n\nexport function loadComposerSelections(workspaceId: string): PersistedComposerSelections | null {\n if (typeof window === 'undefined') return null\n try {\n const raw = window.localStorage.getItem(storageKey(workspaceId))\n return raw === null ? null : parseSelections(JSON.parse(raw))\n } catch {\n return null\n }\n}\n\nexport function saveComposerSelections(\n workspaceId: string,\n snapshot: PersistedComposerSelections,\n): void {\n if (typeof window === 'undefined') return\n try {\n window.localStorage.setItem(storageKey(workspaceId), JSON.stringify(snapshot))\n } catch {\n // Preferences are best-effort. Storage may be disabled or over quota.\n }\n}\n","import { Info } from 'lucide-react'\n\n/**\n * The one thing a chat-shaped generator has to say about itself: each prompt is\n * a fresh generation, and nothing carries over from the last one.\n *\n * A chat card sets the expectation that the thing on the other side remembers\n * the conversation. This one does not, and the cost of learning that by\n * experiment is a wasted generation. The chip is a soft brand-tinted hint: its\n * primary-tinted surface and primary icon keep it noticeable, while the hard\n * border and shadow read as an alert and were cut after gtm QA (issue #465).\n *\n * The icon is INLINE in the text flow rather than a flex sibling, so a narrow\n * viewport wraps it with the sentence instead of stranding a lone glyph beside\n * a two-line block.\n */\nexport function GenerationNoticeChip({ className }: { className?: string }) {\n return (\n <p\n className={`inline-block rounded-full px-3.5 py-1.5 text-center text-[12px] leading-relaxed text-muted-foreground ${className ?? ''}`}\n style={{ background: 'var(--studio-notice-bg)' }}\n >\n <Info className=\"mr-1.5 inline-block h-[14px] w-[14px] align-[-2px] text-primary\" strokeWidth={1.5} aria-hidden />\n Each prompt starts a new generation — this chat does not remember the last one.\n </p>\n )\n}\n","import {\n Check,\n Download,\n FileText,\n FolderOpen,\n FolderPlus,\n Pause,\n Play,\n Trash2,\n} from 'lucide-react'\nimport {\n type CSSProperties,\n type JSX,\n type KeyboardEvent,\n type MouseEvent,\n useEffect,\n useState,\n} from 'react'\n\nimport { hashSeed, previewWaveformBars } from '../studio/audio-preview'\nimport {\n generationError,\n generationStatus,\n generationVaultPath,\n type Generation,\n} from '../studio/generation'\nimport type { StudioMediaActions, VaultSaveResult } from '../studio/ports'\nimport { usePopover } from '../web-react/controls'\nimport { VaultPathPopover } from './vault-path-popover'\nimport { downloadGenerationsViaAnchor } from './download-generations'\nimport { useStudioPlayback } from './studio-playback'\n\nexport interface MediaTileProps {\n generation: Generation\n context: 'home' | 'generation' | 'history'\n onOpen: (generation: Generation) => void\n actions?: StudioMediaActions\n /** Generation screen passes the batch aspect; omitted → square. */\n aspectRatio?: number\n /** 26 for grids (default), 72 for wide generation/viewer tiles. */\n waveformBars?: number\n selectMode?: boolean\n selected?: boolean\n onToggleSelect?: (id: string) => void\n onRequestDelete?: (generation: Generation) => void\n onSaved?: (results: readonly VaultSaveResult[]) => void\n className?: string\n style?: CSSProperties\n}\n\ntype TileStyle = CSSProperties & { '--r'?: number }\n\nfunction stop(event: MouseEvent<HTMLElement>): void {\n event.stopPropagation()\n}\n\nexport function MediaTile({\n generation,\n context,\n onOpen,\n actions,\n aspectRatio,\n waveformBars = 26,\n selectMode = false,\n selected = false,\n onToggleSelect,\n onRequestDelete,\n onSaved,\n className,\n style,\n}: MediaTileProps): JSX.Element {\n const playback = useStudioPlayback()\n const [waveNode, setWaveNode] = useState<HTMLDivElement | null>(null)\n const [saveOpen, setSaveOpen] = useState(false)\n const [saving, setSaving] = useState(false)\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(saveOpen, setSaveOpen)\n const vaultPath = generationVaultPath(generation)\n const status = generationStatus(generation)\n const isSpeech = generation.type === 'speech'\n const isPlaying = isSpeech && playback.activeId === generation.id && playback.playing\n\n useEffect(() => playback.registerPositionNode(generation.id, waveNode), [\n generation.id,\n playback.registerPositionNode,\n waveNode,\n ])\n\n const classes = [\n 'studio-tile relative isolate m-0 cursor-pointer overflow-hidden rounded-none border-0 bg-accent',\n aspectRatio === undefined ? 'aspect-square' : '',\n 'focus-visible:[outline-offset:-2px]',\n isSpeech ? 'studio-has-player' : '',\n selectMode ? 'studio-selectmode' : '',\n selected ? 'outline outline-2 -outline-offset-2 outline-primary' : '',\n className ?? '',\n ].filter(Boolean).join(' ')\n const tileStyle: TileStyle = aspectRatio === undefined\n ? { ...style }\n : { ...style, aspectRatio, '--r': aspectRatio }\n\n function activate(): void {\n if (selectMode) onToggleSelect?.(generation.id)\n else onOpen(generation)\n }\n\n function onKeyDown(event: KeyboardEvent<HTMLElement>): void {\n if (event.target !== event.currentTarget || (event.key !== 'Enter' && event.key !== ' ')) return\n event.preventDefault()\n activate()\n }\n\n async function save(path: string): Promise<void> {\n if (!actions?.save) return\n setSaving(true)\n try {\n const results = await actions.save({ generations: [generation], path })\n setSaveOpen(false)\n onSaved?.(results)\n } finally {\n setSaving(false)\n }\n }\n\n const bars = isSpeech ? previewWaveformBars(generation.id, waveformBars) : []\n const hue = hashSeed(generation.id) % 360\n const secondHue = (hue + 34) % 360\n\n return (\n <figure\n role=\"button\"\n tabIndex={0}\n aria-label={`${generation.prompt} — open`}\n className={classes}\n style={tileStyle}\n data-selectable={context === 'history'}\n data-selected={selected}\n onClick={activate}\n onKeyDown={onKeyDown}\n >\n <div className=\"absolute inset-0\">\n {status === 'pending' || status === 'running' ? (\n <div className=\"studio-skeleton absolute inset-0\" />\n ) : status === 'failed' ? (\n <div className=\"grid h-full w-full place-items-center bg-accent p-3 text-center text-[12px] text-destructive\">\n {generationError(generation) ?? 'Generation failed'}\n </div>\n ) : generation.result === null ? (\n <div className=\"studio-skeleton absolute inset-0\" />\n ) : generation.type === 'image' ? (\n <img\n src={generation.result}\n alt=\"\"\n className=\"h-full w-full object-cover\"\n loading=\"lazy\"\n draggable={false}\n />\n ) : generation.type === 'video' || generation.type === 'avatar' ? (\n <video\n src={generation.result}\n muted\n playsInline\n preload=\"metadata\"\n className=\"h-full w-full object-cover\"\n />\n ) : generation.type === 'transcription' ? (\n <div className=\"grid h-full w-full place-items-center bg-muted text-muted-foreground\">\n <FileText size={20} strokeWidth={1.5} />\n </div>\n ) : isSpeech ? (\n <div\n className=\"absolute inset-0\"\n style={{ background: `linear-gradient(158deg, hsl(${hue} 38% 24%), hsl(${secondHue} 46% 13%))` }}\n >\n <div\n className=\"studio-wave-layers\"\n ref={setWaveNode}\n style={{ color: `hsl(${hue} 92% 74%)` }}\n >\n <div className=\"studio-wave studio-wave-base\">\n {bars.map((bar, index) => (\n <i key={index} style={{ height: `${bar.heightPct}%`, opacity: bar.opacity }} />\n ))}\n </div>\n <div className=\"studio-wave studio-wave-play\">\n {bars.map((bar, index) => (\n <i key={index} style={{ height: `${bar.heightPct}%`, opacity: bar.opacity }} />\n ))}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n\n <div className=\"studio-tile-scrim absolute inset-0\" />\n\n <div className=\"studio-tile-actions absolute right-2 top-2 flex gap-[5px]\">\n <button\n type=\"button\"\n className=\"studio-ibtn relative grid h-[30px] w-[30px] place-items-center rounded-full\"\n data-tip=\"Download\"\n aria-label=\"Download\"\n onClick={(event) => {\n stop(event)\n void (actions?.download ?? downloadGenerationsViaAnchor)([generation])\n }}\n >\n <Download size={15} strokeWidth={1.5} />\n </button>\n\n {!vaultPath && actions?.save && (\n <div ref={containerRef}>\n <button\n {...triggerProps}\n type=\"button\"\n className=\"studio-ibtn relative grid h-[30px] w-[30px] place-items-center rounded-full\"\n data-tip=\"Save to vault\"\n aria-label=\"Save to vault\"\n onClick={(event) => {\n stop(event)\n setSaveOpen((open) => !open)\n }}\n >\n <FolderPlus size={15} strokeWidth={1.5} />\n </button>\n <VaultPathPopover\n open={saveOpen}\n triggerRef={triggerRef}\n panelRef={panelRef}\n generations={[generation]}\n onSubmit={save}\n onCancel={() => setSaveOpen(false)}\n pending={saving}\n />\n </div>\n )}\n\n {vaultPath && actions?.vaultHref && (\n <a\n href={actions.vaultHref(vaultPath)}\n className=\"studio-ibtn relative grid h-[30px] w-[30px] place-items-center rounded-full\"\n data-tip=\"View in vault\"\n aria-label=\"View in vault\"\n onClick={(event) => {\n stop(event)\n if (actions.onOpenVault) {\n event.preventDefault()\n actions.onOpenVault(generation)\n }\n }}\n >\n <FolderOpen size={15} strokeWidth={1.5} />\n </a>\n )}\n {vaultPath && !actions?.vaultHref && actions?.onOpenVault && (\n <button\n type=\"button\"\n className=\"studio-ibtn relative grid h-[30px] w-[30px] place-items-center rounded-full\"\n data-tip=\"View in vault\"\n aria-label=\"View in vault\"\n onClick={(event) => {\n stop(event)\n actions.onOpenVault?.(generation)\n }}\n >\n <FolderOpen size={15} strokeWidth={1.5} />\n </button>\n )}\n\n {actions?.remove && onRequestDelete && (\n <button\n type=\"button\"\n className=\"studio-ibtn studio-ibtn-danger relative grid h-[30px] w-[30px] place-items-center rounded-full\"\n data-tip=\"Delete\"\n aria-label=\"Delete\"\n onClick={(event) => {\n stop(event)\n onRequestDelete(generation)\n }}\n >\n <Trash2 size={15} strokeWidth={1.5} />\n </button>\n )}\n </div>\n\n <div className=\"studio-tile-badges absolute bottom-2 left-2 flex items-center gap-1.5\">\n {(generation.type === 'video' || generation.type === 'avatar') && (\n <span className=\"studio-chip-dark grid h-[22px] w-[22px] place-items-center rounded-full\" aria-hidden=\"true\">\n <Play size={11} strokeWidth={1.5} fill=\"currentColor\" />\n </span>\n )}\n {isSpeech && (\n <button\n type=\"button\"\n className=\"studio-play-btn studio-chip-dark grid h-[22px] w-[22px] place-items-center rounded-full\"\n aria-label={isPlaying ? `Pause ${generation.prompt}` : `Play ${generation.prompt}`}\n onClick={(event) => {\n stop(event)\n playback.toggle(generation)\n }}\n >\n {isPlaying\n ? <Pause size={11} strokeWidth={1.5} fill=\"currentColor\" />\n : <Play size={11} strokeWidth={1.5} fill=\"currentColor\" />}\n </button>\n )}\n {vaultPath && (\n <span className=\"studio-chip-dark inline-flex h-5 items-center gap-1 rounded-full pl-1.5 pr-2 text-[11px]\">\n <FolderOpen size={12} strokeWidth={1.5} />\n In vault\n </span>\n )}\n </div>\n\n {context === 'history' && (\n <button\n type=\"button\"\n className={`studio-tile-sel studio-chip-dark absolute left-2 top-2 h-6 w-6 place-items-center rounded-full ${selected ? '!bg-primary border-primary' : ''}`}\n aria-pressed={selected}\n aria-label=\"Select this item\"\n onClick={(event) => {\n stop(event)\n onToggleSelect?.(generation.id)\n }}\n >\n <Check\n size={13}\n strokeWidth={1.5}\n className={selected ? 'opacity-100' : 'opacity-0'}\n />\n </button>\n )}\n\n <figcaption className=\"studio-tile-prompt absolute inset-x-[11px] bottom-[9px] m-0 truncate text-[12px] text-white\">\n {generation.prompt}\n </figcaption>\n </figure>\n )\n}\n","import { useEffect, useId, useRef, useState, type FormEvent, type JSX, type RefObject } from 'react'\nimport { defaultVaultPathFor, normalizeVaultPath, type Generation } from '../studio'\nimport { OVERLAY_SHADOW, PopoverSurface } from '../web-react/controls'\n\nexport interface VaultPathPopoverProps {\n open: boolean\n triggerRef: RefObject<HTMLElement | null>\n panelRef: RefObject<HTMLDivElement | null>\n generations: readonly Generation[]\n onSubmit: (path: string) => void | Promise<void>\n onCancel: () => void\n pending?: boolean\n}\n\nexport function VaultPathPopover({\n open,\n triggerRef,\n panelRef,\n generations,\n onSubmit,\n onCancel,\n pending = false,\n}: VaultPathPopoverProps): JSX.Element | null {\n const inputRef = useRef<HTMLInputElement>(null)\n const inputId = useId()\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n if (!open) return\n setError(null)\n inputRef.current?.focus()\n inputRef.current?.select()\n }, [open])\n\n if (!open) return null\n\n async function submit(event: FormEvent) {\n event.preventDefault()\n const normalized = normalizeVaultPath(inputRef.current?.value ?? '')\n if (!normalized) {\n setError('Enter a folder path inside the vault.')\n return\n }\n setError(null)\n try {\n await onSubmit(normalized)\n } catch {\n setError('Could not save to vault. Try again.')\n }\n }\n\n const count = generations.length\n const defaultPath = defaultVaultPathFor(generations)\n return (\n <PopoverSurface\n open={open}\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={`flex w-[262px] flex-col overflow-y-auto rounded-xl border border-border bg-popover p-1.5 text-popover-foreground ${OVERLAY_SHADOW}`}\n >\n <form onSubmit={submit}>\n <label htmlFor={inputId} className=\"block px-0.5 pb-[7px] pt-0.5 text-[12px] text-muted-foreground\">\n Save {count} item{count > 1 ? 's' : ''} to\n </label>\n <input\n key={defaultPath}\n ref={inputRef}\n id={inputId}\n defaultValue={defaultPath}\n spellCheck={false}\n autoComplete=\"off\"\n className=\"h-8 w-full rounded-lg border border-input bg-muted px-2.5 text-[13px] outline-none focus:border-primary focus:ring-[3px] focus:ring-ring/30\"\n />\n {error && <p className=\"pt-1.5 text-[12px] text-destructive\">{error}</p>}\n <p className=\"pt-2 text-[11.5px] text-muted-foreground\">Media stays in Studio until you save it into the vault.</p>\n <div className=\"flex justify-end gap-2 pt-2.5\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"h-[30px] rounded-full border border-border px-3.5 text-[13px] hover:bg-accent\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={pending}\n className=\"h-[30px] rounded-full bg-primary px-3.5 text-[13px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n Save\n </button>\n </div>\n </form>\n </PopoverSurface>\n )\n}\n","import type { DownloadGenerations } from '../studio/ports'\n\n/** Same-origin anchor download, staggered so the browser does not swallow\n * every request after the first. Default when no `download` port is given. */\nexport const downloadGenerationsViaAnchor: DownloadGenerations = (generations) => {\n if (typeof document === 'undefined') return\n\n const downloadable = generations.filter((generation) => generation.result !== null)\n downloadable.forEach((generation, index) => {\n setTimeout(() => {\n if (generation.result === null) return\n const vaultPath = generation.metadata?.vaultPath\n const filename = typeof vaultPath === 'string' && vaultPath.trim()\n ? vaultPath.trim().split('/').filter(Boolean).at(-1) ?? `${generation.type}-${generation.id}`\n : `${generation.type}-${generation.id}`\n const anchor = document.createElement('a')\n anchor.href = generation.result\n anchor.download = filename\n document.body.appendChild(anchor)\n anchor.click()\n anchor.remove()\n }, index * 150)\n })\n}\n","import {\n createContext,\n type JSX,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\n\nimport type { Generation } from '../studio/generation'\n\nexport interface StudioAudioElementLike {\n src: string\n currentTime: number\n readonly duration: number\n play(): Promise<void> | void\n pause(): void\n addEventListener(type: string, listener: () => void): void\n removeEventListener(type: string, listener: () => void): void\n}\n\nexport interface StudioPlayback {\n activeId: string | null\n playing: boolean\n durationSeconds: number\n play(generation: Generation): void\n pause(): void\n toggle(generation: Generation): void\n stop(): void\n seekTo(generation: Generation, seconds: number): void\n seekBy(seconds: number): void\n getPositionSeconds(): number\n registerPositionNode(id: string, node: HTMLElement | null): () => void\n registerTimeNode(node: HTMLElement | null): () => void\n}\n\nconst StudioPlaybackContext = createContext<StudioPlayback | null>(null)\n\nconst createBrowserAudioElement = (): StudioAudioElementLike => new Audio()\n\nexport function formatClock(seconds: number): string {\n const wholeSeconds = Math.max(0, Math.floor(Number.isFinite(seconds) ? seconds : 0))\n return `${Math.floor(wholeSeconds / 60)}:${String(wholeSeconds % 60).padStart(2, '0')}`\n}\n\nfunction metadataDuration(generation: Generation): number {\n const duration = generation.metadata?.durationSeconds\n return typeof duration === 'number' && Number.isFinite(duration) ? Math.max(0, duration) : 0\n}\n\nfunction clampPosition(seconds: number, duration: number): number {\n const finiteSeconds = Number.isFinite(seconds) ? seconds : 0\n return Math.max(0, duration > 0 ? Math.min(finiteSeconds, duration) : finiteSeconds)\n}\n\nexport function StudioPlaybackProvider(props: {\n children: ReactNode\n createAudioElement?: () => StudioAudioElementLike\n}): JSX.Element {\n const [activeId, setActiveId] = useState<string | null>(null)\n const [playing, setPlaying] = useState(false)\n const [durationSeconds, setDurationSeconds] = useState(0)\n\n const activeIdRef = useRef<string | null>(null)\n const playingRef = useRef(false)\n const durationRef = useRef(0)\n const createAudioElementRef = useRef(props.createAudioElement ?? createBrowserAudioElement)\n createAudioElementRef.current = props.createAudioElement ?? createBrowserAudioElement\n const audioRef = useRef<StudioAudioElementLike | null>(null)\n const audioListenersRef = useRef<{\n loadedmetadata: () => void\n ended: () => void\n } | null>(null)\n const positionNodesRef = useRef(new Map<string, Set<HTMLElement>>())\n const timeNodeRef = useRef<HTMLElement | null>(null)\n const animationFrameRef = useRef<number | null>(null)\n const playAttemptRef = useRef(0)\n\n const setActive = useCallback((id: string | null) => {\n activeIdRef.current = id\n setActiveId(id)\n }, [])\n\n const setIsPlaying = useCallback((value: boolean) => {\n playingRef.current = value\n setPlaying(value)\n }, [])\n\n const setDuration = useCallback((value: number) => {\n const normalized = Number.isFinite(value) ? Math.max(0, value) : 0\n durationRef.current = normalized\n setDurationSeconds(normalized)\n }, [])\n\n const paintAll = useCallback(() => {\n const currentId = activeIdRef.current\n const position = currentId ? Math.max(0, audioRef.current?.currentTime ?? 0) : 0\n const duration = durationRef.current\n const fraction = duration > 0 ? Math.min(1, position / duration) : 0\n\n for (const [id, nodes] of positionNodesRef.current) {\n const isActive = id === currentId && (playingRef.current || position > 0)\n for (const node of nodes) {\n node.style.setProperty('--pos', isActive ? fraction.toFixed(4) : '0')\n if (isActive) node.dataset.active = 'true'\n else delete node.dataset.active\n }\n }\n if (timeNodeRef.current) timeNodeRef.current.textContent = formatClock(position)\n }, [])\n\n const cancelAnimation = useCallback(() => {\n if (animationFrameRef.current !== null && typeof cancelAnimationFrame === 'function') {\n cancelAnimationFrame(animationFrameRef.current)\n }\n animationFrameRef.current = null\n }, [])\n\n const startAnimation = useCallback(() => {\n if (animationFrameRef.current !== null || typeof requestAnimationFrame !== 'function') return\n const frame = () => {\n animationFrameRef.current = null\n paintAll()\n if (playingRef.current) animationFrameRef.current = requestAnimationFrame(frame)\n }\n animationFrameRef.current = requestAnimationFrame(frame)\n }, [paintAll])\n\n const ensureAudio = useCallback(() => {\n if (audioRef.current) return audioRef.current\n const audio = createAudioElementRef.current()\n const onLoadedMetadata = () => {\n if (Number.isFinite(audio.duration)) setDuration(audio.duration)\n paintAll()\n }\n const onEnded = () => {\n playAttemptRef.current += 1\n audio.currentTime = 0\n setIsPlaying(false)\n cancelAnimation()\n paintAll()\n }\n audio.addEventListener('loadedmetadata', onLoadedMetadata)\n audio.addEventListener('ended', onEnded)\n audioListenersRef.current = { loadedmetadata: onLoadedMetadata, ended: onEnded }\n audioRef.current = audio\n return audio\n }, [cancelAnimation, paintAll, setDuration, setIsPlaying])\n\n const adopt = useCallback((generation: Generation) => {\n const audio = ensureAudio()\n if (activeIdRef.current !== generation.id) {\n audio.src = generation.result ?? ''\n audio.currentTime = 0\n setDuration(metadataDuration(generation))\n setActive(generation.id)\n }\n return audio\n }, [ensureAudio, setActive, setDuration])\n\n const play = useCallback((generation: Generation) => {\n if (!generation.result) return\n const audio = adopt(generation)\n const attempt = ++playAttemptRef.current\n setIsPlaying(false)\n cancelAnimation()\n paintAll()\n\n try {\n const result = audio.play()\n if (result && typeof result.then === 'function') {\n void result.then(() => {\n if (playAttemptRef.current !== attempt || activeIdRef.current !== generation.id) return\n setIsPlaying(true)\n paintAll()\n startAnimation()\n }, () => {\n if (playAttemptRef.current !== attempt) return\n setIsPlaying(false)\n cancelAnimation()\n paintAll()\n })\n } else {\n setIsPlaying(true)\n paintAll()\n startAnimation()\n }\n } catch {\n if (playAttemptRef.current === attempt) {\n setIsPlaying(false)\n cancelAnimation()\n paintAll()\n }\n }\n }, [adopt, cancelAnimation, paintAll, setIsPlaying, startAnimation])\n\n const pause = useCallback(() => {\n playAttemptRef.current += 1\n audioRef.current?.pause()\n setIsPlaying(false)\n cancelAnimation()\n paintAll()\n }, [cancelAnimation, paintAll, setIsPlaying])\n\n const stop = useCallback(() => {\n playAttemptRef.current += 1\n audioRef.current?.pause()\n if (audioRef.current) audioRef.current.currentTime = 0\n setIsPlaying(false)\n setActive(null)\n cancelAnimation()\n paintAll()\n }, [cancelAnimation, paintAll, setActive, setIsPlaying])\n\n const toggle = useCallback((generation: Generation) => {\n if (activeIdRef.current === generation.id && playingRef.current) pause()\n else play(generation)\n }, [pause, play])\n\n const seekTo = useCallback((generation: Generation, seconds: number) => {\n if (!generation.result) return\n const changedTrack = activeIdRef.current !== generation.id\n const audio = adopt(generation)\n if (changedTrack) {\n playAttemptRef.current += 1\n setIsPlaying(false)\n cancelAnimation()\n }\n audio.currentTime = clampPosition(seconds, durationRef.current)\n paintAll()\n }, [adopt, cancelAnimation, paintAll, setIsPlaying])\n\n const seekBy = useCallback((seconds: number) => {\n if (!activeIdRef.current || !audioRef.current) return\n audioRef.current.currentTime = clampPosition(audioRef.current.currentTime + seconds, durationRef.current)\n paintAll()\n }, [paintAll])\n\n const getPositionSeconds = useCallback(() => audioRef.current?.currentTime ?? 0, [])\n\n const registerPositionNode = useCallback((id: string, node: HTMLElement | null) => {\n if (!node) {\n const nodes = positionNodesRef.current.get(id)\n if (nodes) {\n for (const registered of nodes) {\n registered.style.setProperty('--pos', '0')\n delete registered.dataset.active\n }\n }\n positionNodesRef.current.delete(id)\n return () => {}\n }\n const nodes = positionNodesRef.current.get(id) ?? new Set<HTMLElement>()\n nodes.add(node)\n positionNodesRef.current.set(id, nodes)\n paintAll()\n return () => {\n nodes.delete(node)\n if (nodes.size === 0) positionNodesRef.current.delete(id)\n }\n }, [paintAll])\n\n const registerTimeNode = useCallback((node: HTMLElement | null) => {\n timeNodeRef.current = node\n paintAll()\n return () => {\n if (timeNodeRef.current === node) timeNodeRef.current = null\n }\n }, [paintAll])\n\n useEffect(() => {\n paintAll()\n }, [activeId, durationSeconds, paintAll, playing])\n\n useEffect(() => () => {\n playAttemptRef.current += 1\n cancelAnimation()\n const audio = audioRef.current\n if (!audio) return\n audio.pause()\n const listeners = audioListenersRef.current\n if (listeners) {\n audio.removeEventListener('loadedmetadata', listeners.loadedmetadata)\n audio.removeEventListener('ended', listeners.ended)\n }\n }, [cancelAnimation])\n\n const value = useMemo<StudioPlayback>(() => ({\n activeId,\n playing,\n durationSeconds,\n play,\n pause,\n toggle,\n stop,\n seekTo,\n seekBy,\n getPositionSeconds,\n registerPositionNode,\n registerTimeNode,\n }), [\n activeId,\n durationSeconds,\n getPositionSeconds,\n pause,\n play,\n playing,\n registerPositionNode,\n registerTimeNode,\n seekBy,\n seekTo,\n stop,\n toggle,\n ])\n\n return <StudioPlaybackContext.Provider value={value}>{props.children}</StudioPlaybackContext.Provider>\n}\n\nexport function useStudioPlayback(): StudioPlayback {\n const playback = useContext(StudioPlaybackContext)\n if (!playback) throw new Error('useStudioPlayback must be used within a StudioPlaybackProvider')\n return playback\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type JSX,\n type KeyboardEvent,\n type MouseEvent,\n type PointerEvent,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { Download, FolderOpen, FolderPlus, Pause, Play, Trash2, X } from 'lucide-react'\n\nimport {\n generationAspectRatio,\n generationError,\n generationSpecSegments,\n generationStatus,\n generationVaultPath,\n hashSeed,\n previewWaveformBars,\n relativeTime,\n WIDE_WAVEFORM_BARS,\n type Generation,\n type StudioMediaActions,\n type VaultSaveResult,\n} from '../studio'\nimport { OVERLAY_SHADOW, POPOVER_SURFACE_ATTR, usePopover } from '../web-react/controls'\nimport { downloadGenerationsViaAnchor } from './download-generations'\nimport { formatClock, useStudioPlayback } from './studio-playback'\nimport { VaultPathPopover } from './vault-path-popover'\n\nexport interface MediaViewerModalProps {\n generation: Generation | null\n onClose: () => void\n actions?: StudioMediaActions\n /** Screens own the delete confirm; absent hides the Delete button. */\n onRequestDelete?: (generation: Generation) => void\n /** After a successful save from the footer popover. */\n onSaved?: (results: readonly VaultSaveResult[]) => void\n}\n\nconst TYPE_LABELS: Record<string, string> = {\n image: 'Image',\n video: 'Video',\n speech: 'Audio',\n avatar: 'Avatar',\n transcription: 'Transcript',\n}\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'textarea:not([disabled])',\n 'select:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ')\n\nconst footerButtonClass =\n 'inline-flex h-8 items-center gap-1.5 rounded-full border border-border px-3 text-[12.5px] font-medium hover:bg-accent'\n\nfunction hasOpenPopover(): boolean {\n return typeof document !== 'undefined' && document.querySelector(`[${POPOVER_SURFACE_ATTR}]`) !== null\n}\n\nfunction Waveform({ generation }: { generation: Generation }): JSX.Element {\n const { registerPositionNode } = useStudioPlayback()\n const layersRef = useRef<HTMLDivElement>(null)\n const bars = useMemo(\n () => previewWaveformBars(generation.id, WIDE_WAVEFORM_BARS),\n [generation.id],\n )\n const hue = useMemo(() => hashSeed(generation.id) % 360, [generation.id])\n\n useEffect(() => registerPositionNode(generation.id, layersRef.current), [generation.id, registerPositionNode])\n\n const renderBars = () => bars.map((bar, index) => (\n <i key={index} style={{ height: `${bar.heightPct}%`, opacity: bar.opacity }} />\n ))\n return (\n <div\n className=\"absolute inset-0\"\n style={{ background: `linear-gradient(158deg, hsl(${hue} 38% 24%), hsl(${(hue + 34) % 360} 46% 13%))` }}\n >\n <div ref={layersRef} className=\"studio-wave-layers\" style={{ color: `hsl(${hue} 92% 74%)` }}>\n <div className=\"studio-wave studio-wave-base\">{renderBars()}</div>\n <div className=\"studio-wave studio-wave-play\">{renderBars()}</div>\n </div>\n </div>\n )\n}\n\nfunction AudioTransport({ generation }: { generation: Generation }): JSX.Element {\n const playback = useStudioPlayback()\n const elapsedRef = useRef<HTMLSpanElement>(null)\n const seekRef = useRef<HTMLDivElement>(null)\n const trackRef = useRef<HTMLDivElement>(null)\n const pointerIdRef = useRef<number | null>(null)\n const [ariaPosition, setAriaPosition] = useState(0)\n const isPlaying = playback.activeId === generation.id && playback.playing\n const duration = playback.activeId === generation.id ? playback.durationSeconds : 0\n\n useEffect(() => playback.registerTimeNode(elapsedRef.current), [playback.registerTimeNode])\n useEffect(\n () => playback.registerPositionNode(generation.id, seekRef.current),\n [generation.id, playback.registerPositionNode],\n )\n useEffect(() => {\n setAriaPosition(playback.activeId === generation.id ? playback.getPositionSeconds() : 0)\n }, [generation.id, playback.activeId, playback.durationSeconds, playback.getPositionSeconds, playback.playing])\n\n const syncAriaPosition = useCallback(() => {\n setAriaPosition(playback.activeId === generation.id ? playback.getPositionSeconds() : 0)\n }, [generation.id, playback])\n\n function toggle() {\n playback.toggle(generation)\n syncAriaPosition()\n }\n\n function seekFromClientX(clientX: number) {\n const rect = trackRef.current?.getBoundingClientRect()\n if (!rect || rect.width <= 0 || duration <= 0) return\n const fraction = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width))\n playback.seekTo(generation, fraction * duration)\n setAriaPosition(fraction * duration)\n }\n\n function onPointerDown(event: PointerEvent<HTMLDivElement>) {\n event.currentTarget.focus()\n pointerIdRef.current = event.pointerId\n event.currentTarget.setPointerCapture?.(event.pointerId)\n seekFromClientX(event.clientX)\n }\n\n function onPointerMove(event: PointerEvent<HTMLDivElement>) {\n if (pointerIdRef.current !== event.pointerId) return\n seekFromClientX(event.clientX)\n }\n\n function endPointer(event: PointerEvent<HTMLDivElement>) {\n if (pointerIdRef.current !== event.pointerId) return\n event.currentTarget.releasePointerCapture?.(event.pointerId)\n pointerIdRef.current = null\n syncAriaPosition()\n }\n\n function onKeyDown(event: KeyboardEvent<HTMLDivElement>) {\n if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {\n event.preventDefault()\n playback.seekBy(event.key === 'ArrowLeft' ? -5 : 5)\n syncAriaPosition()\n } else if (event.key === ' ' || event.code === 'Space') {\n event.preventDefault()\n toggle()\n }\n }\n\n const position = Math.max(0, duration > 0 ? Math.min(ariaPosition, duration) : ariaPosition)\n return (\n <div className=\"mt-3.5 flex items-center gap-3 px-0.5\">\n <button\n type=\"button\"\n aria-label={isPlaying ? 'Pause' : 'Play'}\n onClick={toggle}\n className=\"grid h-[38px] w-[38px] shrink-0 place-items-center rounded-full bg-primary text-primary-foreground shadow-raised hover:brightness-110\"\n >\n {isPlaying\n ? <Pause size={15} strokeWidth={1.5} fill=\"currentColor\" />\n : <Play size={15} strokeWidth={1.5} fill=\"currentColor\" />}\n </button>\n <span ref={elapsedRef} className=\"min-w-8 text-[12px] text-muted-foreground tabular-nums\">\n {duration > 0 ? '0:00' : '--:--'}\n </span>\n <div\n ref={seekRef}\n className=\"studio-seek relative flex h-5 min-w-0 flex-1 cursor-pointer items-center\"\n role=\"slider\"\n tabIndex={0}\n aria-label=\"Seek\"\n aria-valuemin={0}\n aria-valuemax={duration}\n aria-valuenow={position}\n aria-valuetext={duration > 0 ? formatClock(position) : '--:--'}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endPointer}\n onPointerCancel={endPointer}\n onKeyDown={onKeyDown}\n >\n <div ref={trackRef} className=\"relative h-1 w-full overflow-hidden rounded-full bg-accent\">\n <div className=\"studio-seek-fill absolute inset-y-0 left-0 bg-primary\" />\n </div>\n <div className=\"studio-seek-thumb absolute h-[13px] w-[13px] -translate-x-1/2 rounded-full bg-primary ring-2 ring-card\" />\n </div>\n <span className=\"text-[12px] text-muted-foreground tabular-nums\">\n {duration > 0 ? formatClock(duration) : '--:--'}\n </span>\n </div>\n )\n}\n\nexport function MediaViewerModal({\n generation,\n onClose,\n actions,\n onRequestDelete,\n onSaved,\n}: MediaViewerModalProps): JSX.Element | null {\n const playback = useStudioPlayback()\n const stopPlayback = playback.stop\n const panelRef = useRef<HTMLDivElement>(null)\n const closeRef = useRef<HTMLButtonElement>(null)\n const priorFocusRef = useRef<HTMLElement | null>(null)\n const openSessionRef = useRef(false)\n const [saveOpen, setSaveOpen] = useState(false)\n const [savePending, setSavePending] = useState(false)\n const popover = usePopover(saveOpen, setSaveOpen)\n const open = generation !== null\n\n const stopAndRestore = useCallback(() => {\n if (!openSessionRef.current) return\n openSessionRef.current = false\n stopPlayback()\n const priorFocus = priorFocusRef.current\n if (priorFocus?.isConnected) priorFocus.focus()\n }, [stopPlayback])\n\n const close = useCallback(() => {\n setSaveOpen(false)\n stopAndRestore()\n onClose()\n }, [onClose, stopAndRestore])\n\n useEffect(() => {\n if (!open) return\n priorFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null\n openSessionRef.current = true\n closeRef.current?.focus()\n return stopAndRestore\n }, [open, stopAndRestore])\n\n useEffect(() => {\n if (!open) return\n function onDocumentKeyDown(event: globalThis.KeyboardEvent) {\n if (event.key !== 'Escape' || event.defaultPrevented || hasOpenPopover()) return\n event.preventDefault()\n close()\n }\n document.addEventListener('keydown', onDocumentKeyDown)\n return () => document.removeEventListener('keydown', onDocumentKeyDown)\n }, [close, open])\n\n if (!generation || typeof document === 'undefined') return null\n\n const ratio = generationAspectRatio(generation)\n const status = generationStatus(generation)\n const vaultPath = generationVaultPath(generation)\n const metaSegments = [\n TYPE_LABELS[generation.type] ?? generation.type,\n generation.model,\n ...generationSpecSegments(generation),\n generation.createdAt ? relativeTime(generation.createdAt) : null,\n vaultPath,\n ].filter((segment): segment is string => typeof segment === 'string' && segment.length > 0)\n\n function onPanelKeyDown(event: KeyboardEvent<HTMLDivElement>) {\n if (event.key !== 'Tab' || hasOpenPopover()) return\n const focusable = panelRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)\n if (!focusable || focusable.length === 0) return\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n const active = document.activeElement\n if (event.shiftKey && active === first) {\n event.preventDefault()\n last?.focus()\n } else if (!event.shiftKey && active === last) {\n event.preventDefault()\n first?.focus()\n }\n }\n\n async function save(path: string) {\n if (!actions?.save || !generation) return\n setSavePending(true)\n try {\n const results = await actions.save({ generations: [generation], path })\n setSaveOpen(false)\n onSaved?.(results)\n } finally {\n setSavePending(false)\n }\n }\n\n function viewVault(event: MouseEvent<HTMLAnchorElement | HTMLButtonElement>) {\n if (!actions?.onOpenVault || !generation) return\n event.preventDefault()\n actions.onOpenVault(generation)\n }\n\n const mediaStyle: CSSProperties = generation.type === 'transcription'\n ? { width: '100%' }\n : {\n width: `min(100%, calc(70vh * ${ratio}))`,\n aspectRatio: ratio,\n }\n const vaultHref = vaultPath && actions?.vaultHref ? actions.vaultHref(vaultPath) : null\n const viewControl = vaultPath && (vaultHref || actions?.onOpenVault)\n const modal = (\n <div\n className=\"studio-layer-viewer studio-backdrop fixed inset-0 grid place-items-center p-6\"\n onMouseDown={(event) => { if (event.target === event.currentTarget) close() }}\n >\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Media detail\"\n onKeyDown={onPanelKeyDown}\n className={`studio-rise relative max-h-[92vh] w-[min(780px,100%)] overflow-auto rounded-[14px] border border-border bg-card p-3.5 ${OVERLAY_SHADOW}`}\n >\n <button\n ref={closeRef}\n type=\"button\"\n aria-label=\"Close\"\n onClick={close}\n className=\"absolute right-3.5 top-3.5 z-10 grid h-8 w-8 place-items-center rounded-full border border-border bg-card hover:bg-accent\"\n >\n <X size={15} strokeWidth={1.5} />\n </button>\n\n <div className=\"flex justify-center\">\n <div className=\"relative overflow-hidden rounded-xl border border-border bg-accent\" style={mediaStyle}>\n {status === 'pending' || status === 'running' ? (\n <div className=\"studio-skeleton absolute inset-0\" />\n ) : status === 'failed' ? (\n <div className=\"grid h-full w-full place-items-center bg-accent p-3 text-center text-[12px] text-destructive\">\n {generationError(generation) ?? 'Generation failed'}\n </div>\n ) : generation.result === null ? (\n <div className=\"studio-skeleton absolute inset-0\" />\n ) : generation.type === 'image' ? (\n <img src={generation.result} className=\"h-full w-full object-cover\" alt={generation.prompt} />\n ) : generation.type === 'video' || generation.type === 'avatar' ? (\n <video src={generation.result} controls playsInline className=\"h-full w-full object-cover\" />\n ) : generation.type === 'transcription' ? (\n <div className=\"max-h-[60vh] overflow-auto whitespace-pre-wrap p-4 text-[13.5px] leading-relaxed\">\n {generation.result ?? ''}\n </div>\n ) : generation.type === 'speech' ? (\n <Waveform generation={generation} />\n ) : null}\n </div>\n </div>\n\n {status !== 'failed' && generation.type === 'speech' && <AudioTransport generation={generation} />}\n\n <p className=\"mx-0.5 mb-1.5 mt-4 max-w-[62ch] text-[15px] leading-normal\">{generation.prompt}</p>\n <div className=\"mx-0.5 flex flex-wrap items-center gap-1.5 text-[12.5px] text-muted-foreground\">\n {metaSegments.join(' · ')}\n </div>\n\n <div className=\"mt-3.5 flex flex-wrap gap-2 border-t border-border pt-4\">\n <button\n type=\"button\"\n onClick={() => { void (actions?.download ?? downloadGenerationsViaAnchor)([generation]) }}\n className={footerButtonClass}\n >\n <Download size={15} strokeWidth={1.5} /> Download\n </button>\n\n {!vaultPath && actions?.save && (\n <div ref={popover.containerRef}>\n <button\n {...popover.triggerProps}\n type=\"button\"\n onClick={() => setSaveOpen((value) => !value)}\n className={footerButtonClass}\n >\n <FolderPlus size={15} strokeWidth={1.5} /> Save to vault\n </button>\n <VaultPathPopover\n open={saveOpen}\n triggerRef={popover.triggerRef}\n panelRef={popover.panelRef}\n generations={[generation]}\n onSubmit={save}\n onCancel={() => setSaveOpen(false)}\n pending={savePending}\n />\n </div>\n )}\n\n {viewControl && (vaultHref ? (\n <a href={vaultHref} onClick={viewVault} className={footerButtonClass}>\n <FolderOpen size={15} strokeWidth={1.5} /> View in vault\n </a>\n ) : (\n <button type=\"button\" onClick={viewVault} className={footerButtonClass}>\n <FolderOpen size={15} strokeWidth={1.5} /> View in vault\n </button>\n ))}\n\n {onRequestDelete && (\n <button\n type=\"button\"\n onClick={() => onRequestDelete(generation)}\n className={`${footerButtonClass} ml-auto text-destructive hover:border-destructive hover:bg-destructive/10`}\n >\n <Trash2 size={15} strokeWidth={1.5} /> Delete\n </button>\n )}\n </div>\n </div>\n </div>\n )\n\n return createPortal(modal, document.body)\n}\n","import {\n type JSX,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react'\n\nimport type { Generation } from '../studio/generation'\nimport type { StudioMediaActions, VaultSaveResult } from '../studio/ports'\nimport { MediaTile } from './media-tile'\nimport { MediaViewerModal } from './media-viewer'\nimport { StudioComposer } from './studio-composer'\nimport { StudioConfirmDialog } from './studio-confirm'\nimport { useStudioPlayback } from './studio-playback'\nimport { useStudioToast } from './studio-toasts'\nimport { useBatchNavigation } from './use-batch-navigation'\nimport { useDeferredDelete } from './use-deferred-delete'\n\nexport interface StudioHomeScreenProps {\n /** Newest first, from the host loader (host runs useStudioGenerations). */\n generations: Generation[]\n onGenerated: (generation: Generation) => void\n onOpenGeneration: (batchKey: string, first: Generation) => void\n onOpenHistory: () => void\n workspaceId?: string\n pickReferenceImage?: () => Promise<string | null>\n actions?: StudioMediaActions\n recentLimit?: number\n className?: string\n}\n\n/**\n * Studio's create-and-recent-media landing screen. The host must render this\n * inside both `StudioToastProvider` and `StudioPlaybackProvider`.\n */\nexport function StudioHomeScreen({\n generations,\n onGenerated,\n onOpenGeneration,\n onOpenHistory,\n workspaceId,\n pickReferenceImage,\n actions,\n recentLimit = 20,\n className,\n}: StudioHomeScreenProps): JSX.Element {\n const [viewer, setViewer] = useState<Generation | null>(null)\n const [confirmTargets, setConfirmTargets] = useState<Generation[] | null>(null)\n const playback = useStudioPlayback()\n const { toast } = useStudioToast()\n const deferredDelete = useDeferredDelete({\n remove: actions?.remove ?? (async () => {}),\n })\n const navigateNewBatch = useBatchNavigation({ seed: generations, onOpenGeneration })\n\n const wrappedOnGenerated = useCallback((generation: Generation) => {\n onGenerated(generation)\n navigateNewBatch(generation)\n }, [navigateNewBatch, onGenerated])\n\n const visible = useMemo(\n () => generations.filter((generation) => !deferredDelete.pendingIds.has(generation.id)),\n [deferredDelete.pendingIds, generations],\n )\n const renderedViewer = viewer\n ? generations.find((generation) => generation.id === viewer.id) ?? viewer\n : null\n const requestDelete = actions?.remove\n ? (generation: Generation) => setConfirmTargets([generation])\n : undefined\n\n const onSaved = useCallback((results: readonly VaultSaveResult[]) => {\n const first = results[0]\n if (first) toast({ message: `Saved to vault · ${first.vaultPath}` })\n }, [toast])\n\n useEffect(() => playback.stop, [playback.stop])\n\n function confirmDelete(): void {\n const targets = confirmTargets\n setConfirmTargets(null)\n if (!targets?.length) return\n if (viewer && targets.some((target) => target.id === viewer.id)) setViewer(null)\n deferredDelete.request(targets)\n }\n\n return (\n <main className={className}>\n <div className=\"studio-home-top mx-auto w-full max-w-[820px] px-6 pt-[clamp(24px,12vh,124px)] max-[900px]:px-4\">\n <h1 className=\"mb-5 text-center text-[30px] font-semibold leading-[1.2] tracking-[-0.02em] [text-wrap:balance] max-[640px]:text-[25px]\">\n What do you want to create?\n </h1>\n <StudioComposer\n variant=\"home\"\n workspaceId={workspaceId}\n pickReferenceImage={pickReferenceImage}\n onGenerated={wrappedOnGenerated}\n />\n </div>\n\n <section className=\"studio-home-recent pb-[72px]\">\n <div className=\"mb-3 mt-[34px] flex items-center justify-between gap-3 px-6 max-[900px]:px-4\">\n <h2 className=\"text-[13px] font-medium tracking-[0.02em] text-muted-foreground\">Recent media</h2>\n <button\n type=\"button\"\n onClick={onOpenHistory}\n className=\"h-[30px] whitespace-nowrap rounded-full border border-border bg-card px-3 text-[13px] shadow-sm hover:bg-accent\"\n >\n View history\n </button>\n </div>\n\n <div className=\"studio-grid studio-grid-library\">\n {visible.length === 0 ? (\n <div className=\"col-span-full flex flex-col items-center py-16 text-center\">\n <p className=\"text-[14px] text-foreground\">Nothing generated yet.</p>\n <p className=\"max-w-[380px] text-[13px] text-muted-foreground\">\n Whatever you make lands here first — it only reaches the vault when you save it.\n </p>\n </div>\n ) : visible.slice(0, recentLimit).map((generation) => (\n <MediaTile\n key={generation.id}\n generation={generation}\n context=\"home\"\n onOpen={setViewer}\n actions={actions}\n onRequestDelete={requestDelete}\n onSaved={onSaved}\n />\n ))}\n </div>\n </section>\n\n <MediaViewerModal\n generation={renderedViewer}\n onClose={() => setViewer(null)}\n actions={actions}\n onRequestDelete={requestDelete}\n onSaved={onSaved}\n />\n <StudioConfirmDialog\n open={confirmTargets !== null}\n count={confirmTargets?.length ?? 0}\n onConfirm={confirmDelete}\n onCancel={() => setConfirmTargets(null)}\n />\n </main>\n )\n}\n","import { useEffect, useId, useRef, type JSX } from 'react'\nimport { createPortal } from 'react-dom'\nimport { OVERLAY_SHADOW } from '../web-react/controls'\n\nexport interface StudioConfirmDialogProps {\n open: boolean\n count: number\n onConfirm: () => void\n onCancel: () => void\n}\n\nexport function StudioConfirmDialog({\n open,\n count,\n onConfirm,\n onCancel,\n}: StudioConfirmDialogProps): JSX.Element | null {\n const panelRef = useRef<HTMLDivElement>(null)\n const cancelRef = useRef<HTMLButtonElement>(null)\n const previousFocusRef = useRef<HTMLElement | null>(null)\n const titleId = useId()\n const descriptionId = useId()\n\n useEffect(() => {\n if (!open) return\n previousFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null\n cancelRef.current?.focus()\n return () => {\n const previous = previousFocusRef.current\n if (previous && document.contains(previous)) previous.focus()\n previousFocusRef.current = null\n }\n }, [open])\n\n if (!open || typeof document === 'undefined') return null\n\n function onKeyDown(event: React.KeyboardEvent) {\n if (event.key === 'Escape') {\n event.preventDefault()\n onCancel()\n return\n }\n if (event.key !== 'Tab') return\n const focusable = panelRef.current?.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n )\n if (!focusable || focusable.length === 0) return\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n const active = document.activeElement as HTMLElement | null\n if (event.shiftKey && active === first) {\n event.preventDefault()\n last?.focus()\n } else if (!event.shiftKey && active === last) {\n event.preventDefault()\n first?.focus()\n }\n }\n\n return createPortal(\n <div\n className=\"studio-layer-confirm studio-backdrop fixed inset-0 grid place-items-center p-6\"\n onMouseDown={(event) => { if (event.target === event.currentTarget) onCancel() }}\n >\n <div\n ref={panelRef}\n role=\"alertdialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={descriptionId}\n onKeyDown={onKeyDown}\n className={`w-[min(360px,100%)] rounded-[14px] border border-border bg-card px-[18px] pb-4 pt-[18px] ${OVERLAY_SHADOW}`}\n >\n <h2 id={titleId} className=\"text-[15.5px] font-semibold tracking-[-0.01em]\">\n Delete {count} item{count > 1 ? 's' : ''}?\n </h2>\n <p id={descriptionId} className=\"mt-[7px] text-[13px] text-muted-foreground\">This cannot be undone.</p>\n <div className=\"flex justify-end gap-2 pt-[18px]\">\n <button\n ref={cancelRef}\n type=\"button\"\n onClick={onCancel}\n className=\"h-[30px] rounded-full border border-border px-3.5 text-[13px] hover:bg-accent\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n className=\"h-[30px] rounded-full bg-destructive px-3.5 text-[13px] font-medium text-destructive-foreground hover:brightness-110\"\n >\n Delete\n </button>\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type JSX,\n type ReactNode,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { X } from 'lucide-react'\nimport { OVERLAY_SHADOW } from '../web-react/controls'\n\nexport interface StudioToastInput {\n message: string\n action?: { label: string; run: () => void }\n durationMs?: number\n /** Fires exactly once when the toast leaves for ANY reason. */\n onDismiss?: (reason: 'timeout' | 'dismissed' | 'action') => void\n}\n\ntype DismissReason = 'timeout' | 'dismissed' | 'action'\ntype ToastRecord = StudioToastInput & { id: string; leaving: boolean }\n\ninterface StudioToastContextValue {\n toast: (input: StudioToastInput) => string\n dismiss: (id: string) => void\n setDockLift: (px: number | null) => void\n}\n\nconst StudioToastContext = createContext<StudioToastContextValue | null>(null)\n\nfunction StudioToast({ record, leave }: { record: ToastRecord; leave: (id: string, reason: DismissReason) => void }) {\n useEffect(() => {\n if (record.leaving) return\n const duration = record.durationMs ?? 3500\n if (duration === 0) return\n const timer = window.setTimeout(() => leave(record.id, 'timeout'), duration)\n return () => window.clearTimeout(timer)\n }, [leave, record.durationMs, record.id, record.leaving])\n\n return (\n <div\n role=\"status\"\n className={`pointer-events-auto flex max-w-[min(94vw,480px)] items-center gap-2.5 rounded-[10px] border border-border bg-card py-2 pl-[13px] pr-2 text-[13px] ${OVERLAY_SHADOW} ${record.leaving ? 'studio-toast-out' : 'studio-toast-in'}`}\n >\n <span className=\"min-w-0 truncate\">{record.message}</span>\n {record.action && (\n <button\n type=\"button\"\n onClick={() => {\n record.action?.run()\n leave(record.id, 'action')\n }}\n className=\"rounded-lg border-0 px-2 py-1 text-[13px] font-semibold text-primary hover:bg-primary/10\"\n >\n {record.action.label}\n </button>\n )}\n <button\n type=\"button\"\n aria-label=\"Dismiss\"\n onClick={() => leave(record.id, 'dismissed')}\n className=\"inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-muted-foreground hover:bg-accent hover:text-foreground\"\n >\n <X className=\"h-3.5 w-3.5\" aria-hidden />\n </button>\n </div>\n )\n}\n\nexport function StudioToastProvider({ children }: { children: ReactNode }): JSX.Element {\n const [toasts, setToasts] = useState<ToastRecord[]>([])\n const [dockLift, setDockLift] = useState<number | null>(null)\n const [mounted, setMounted] = useState(false)\n const sequence = useRef(0)\n const dismissed = useRef(new Set<string>())\n const records = useRef(new Map<string, ToastRecord>())\n\n const leave = useCallback((id: string, reason: DismissReason) => {\n if (dismissed.current.has(id)) return\n const record = records.current.get(id)\n if (!record) return\n dismissed.current.add(id)\n record.onDismiss?.(reason)\n setToasts((current) => current.map((toast) => toast.id === id ? { ...toast, leaving: true } : toast))\n window.setTimeout(() => {\n records.current.delete(id)\n setToasts((current) => current.filter((toast) => toast.id !== id))\n }, 180)\n }, [])\n\n const toast = useCallback((input: StudioToastInput) => {\n const id = `studio-toast-${++sequence.current}`\n const record: ToastRecord = { ...input, id, leaving: false }\n records.current.set(id, record)\n setToasts((current) => [...current, record])\n return id\n }, [])\n\n const dismiss = useCallback((id: string) => leave(id, 'dismissed'), [leave])\n const value = useMemo(() => ({ toast, dismiss, setDockLift }), [dismiss, toast])\n\n // Match the server and first client render to avoid an SSR hydration mismatch (#465).\n useEffect(() => setMounted(true), [])\n\n return (\n <StudioToastContext.Provider value={value}>\n {children}\n {mounted && createPortal(\n <div\n role=\"region\"\n aria-label=\"Notifications\"\n style={{ bottom: dockLift ? dockLift + 10 : 22 }}\n className=\"studio-layer-toasts pointer-events-none fixed left-1/2 flex -translate-x-1/2 flex-col items-center gap-2\"\n >\n {toasts.map((record) => <StudioToast key={record.id} record={record} leave={leave} />)}\n </div>,\n document.body,\n )}\n </StudioToastContext.Provider>\n )\n}\n\nexport function useStudioToast(): StudioToastContextValue {\n const context = useContext(StudioToastContext)\n if (!context) throw new Error('useStudioToast must be used within a StudioToastProvider')\n return context\n}\n","import { useCallback, useRef } from 'react'\nimport { generationBatchKey, type Generation } from '../studio/generation'\n\nexport interface UseBatchNavigationOptions {\n /** Rows whose batch keys are treated as already seen. Read once, at mount. */\n seed: readonly Generation[]\n /**\n * A batch key that never navigates, read on every call — the generation\n * screen passes its own batch so rows landing for the batch already on\n * screen stay put while a NEW dock submit navigates.\n */\n currentBatchKey?: string\n onOpenGeneration: (batchKey: string, first: Generation) => void\n}\n\n/**\n * Returns a callback the screens wrap around `onGenerated`: the first row of a\n * batch not seen before navigates via `onOpenGeneration`, exactly once per\n * batch — a four-image batch arrives as four rows sharing one batch key and\n * must produce one navigation, and rows merely refreshed from the loader\n * (seeded at mount) must produce none.\n */\nexport function useBatchNavigation({\n seed,\n currentBatchKey,\n onOpenGeneration,\n}: UseBatchNavigationOptions): (generation: Generation) => void {\n const seenKeys = useRef<Set<string> | null>(null)\n seenKeys.current ??= new Set(seed.map(generationBatchKey))\n const currentRef = useRef(currentBatchKey)\n currentRef.current = currentBatchKey\n\n return useCallback((generation: Generation) => {\n const key = generationBatchKey(generation)\n const seen = seenKeys.current\n if (key === currentRef.current || !seen || seen.has(key)) return\n seen.add(key)\n onOpenGeneration(key, generation)\n }, [onOpenGeneration])\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type { Generation } from '../studio/generation'\nimport type { DeleteGenerations } from '../studio/ports'\nimport { useStudioPlayback } from './studio-playback'\nimport { useStudioToast } from './studio-toasts'\n\nexport interface UseDeferredDeleteOptions {\n remove: DeleteGenerations\n /** Undo window AND toast lifetime. Default 3500. */\n undoWindowMs?: number\n /** After the server call succeeds for a batch. */\n onCommitted?: (ids: readonly string[]) => void\n /** After a failed server call restored the rows (screens may refetch). */\n onRestoreFailed?: (ids: readonly string[]) => void\n}\n\nexport interface DeferredDelete {\n /** Rows the screens must filter OUT of every render. Survives refetches. */\n pendingIds: ReadonlySet<string>\n request: (generations: readonly Generation[]) => void\n /** Commit every outstanding batch NOW (unmount/navigation). */\n flush: () => void\n}\n\ninterface DeleteBatch {\n ids: readonly string[]\n toastId: string\n status: 'pending' | 'committing'\n}\n\nconst itemLabel = (count: number) => `item${count === 1 ? '' : 's'}`\n\nexport function useDeferredDelete(options: UseDeferredDeleteOptions): DeferredDelete {\n const { activeId, stop } = useStudioPlayback()\n const { dismiss, toast } = useStudioToast()\n const [pendingIds, setPendingIds] = useState<ReadonlySet<string>>(() => new Set())\n const batchesRef = useRef(new Map<string, DeleteBatch>())\n const committedIdsRef = useRef(new Set<string>())\n const sequenceRef = useRef(0)\n const optionsRef = useRef(options)\n const dismissRef = useRef(dismiss)\n optionsRef.current = options\n dismissRef.current = dismiss\n\n const visiblePendingIds = useCallback(() => {\n const ids = new Set(committedIdsRef.current)\n for (const batch of batchesRef.current.values()) {\n for (const id of batch.ids) ids.add(id)\n }\n return ids\n }, [])\n\n const commit = useCallback((batchKey: string) => {\n const batch = batchesRef.current.get(batchKey)\n if (!batch || batch.status !== 'pending') return\n batch.status = 'committing'\n\n void optionsRef.current.remove(batch.ids).then(() => {\n if (batchesRef.current.get(batchKey) !== batch) return\n batchesRef.current.delete(batchKey)\n for (const id of batch.ids) committedIdsRef.current.add(id)\n optionsRef.current.onCommitted?.(batch.ids)\n }, () => {\n if (batchesRef.current.get(batchKey) !== batch) return\n batchesRef.current.delete(batchKey)\n setPendingIds(visiblePendingIds())\n toast({ message: `Could not delete ${batch.ids.length} ${itemLabel(batch.ids.length)}` })\n optionsRef.current.onRestoreFailed?.(batch.ids)\n })\n }, [toast, visiblePendingIds])\n\n const request = useCallback((generations: readonly Generation[]) => {\n if (generations.length === 0) return\n const ids = [...new Set(generations.map((generation) => generation.id))]\n const batchKey = `deferred-delete-${++sequenceRef.current}`\n\n setPendingIds((current) => {\n const next = new Set(current)\n for (const id of ids) next.add(id)\n return next\n })\n if (activeId && ids.includes(activeId)) stop()\n\n const undo = () => {\n const batch = batchesRef.current.get(batchKey)\n if (!batch || batch.status !== 'pending') return\n batchesRef.current.delete(batchKey)\n setPendingIds(visiblePendingIds())\n toast({ message: `Restored ${ids.length} ${itemLabel(ids.length)}` })\n }\n\n const toastId = toast({\n message: `Deleted ${ids.length} ${itemLabel(ids.length)}`,\n action: { label: 'Undo', run: undo },\n durationMs: options.undoWindowMs ?? 3500,\n onDismiss: (reason) => {\n if (reason !== 'action') commit(batchKey)\n },\n })\n batchesRef.current.set(batchKey, { ids, toastId, status: 'pending' })\n }, [activeId, commit, options.undoWindowMs, stop, toast, visiblePendingIds])\n\n const flush = useCallback(() => {\n for (const [batchKey, batch] of batchesRef.current) {\n if (batch.status !== 'pending') continue\n batch.status = 'committing'\n batchesRef.current.delete(batchKey)\n dismissRef.current(batch.toastId)\n void optionsRef.current.remove(batch.ids).catch(() => {})\n }\n }, [])\n\n useEffect(() => {\n window.addEventListener('pagehide', flush)\n return () => {\n window.removeEventListener('pagehide', flush)\n flush()\n }\n }, [flush])\n\n return { pendingIds, request, flush }\n}\n","/**\n * The generation screen: ONE batch's results, with the composer docked under\n * them.\n *\n * The screen is a flex column that fills its host — results scroll, the dock\n * does not. The dock band is deliberately OPAQUE (`bg-background`): it sits\n * above the scrolling results and a translucent band would let a tile read\n * through the composer's own card. The 28px fade above it comes from\n * `.studio-dock::before` in `./studio.css`.\n *\n * The dock's measured height is published two ways, because two different\n * consumers need it: as the `--studio-dock-h` custom property on the screen\n * root (host CSS, and anything nested that must clear the band) and through\n * `useStudioToast().setDockLift`, which lifts the toast stack off the composer.\n * The body's own bottom padding is applied from the measured value directly\n * rather than read back through that property — a CSS custom property a\n * component READS must be one `tokens.css` defines (the theme contract), and a\n * dock height is a layout measurement, not a theme token.\n *\n * A prompt sent from the DOCK starts a NEW batch, which is a different screen.\n * This one reports it (`onOpenGeneration`) exactly once per new batch key and\n * lets the host navigate; every row of that batch still flows through\n * `onGenerated` so the host's list stays whole.\n *\n * The root bakes in `min-h-full` so the sticky composer dock sits at the bottom\n * of the nearest scroll container. A `min-h-*` utility passed through\n * `className` will not reliably win: equal specificity lets the later-in-sheet\n * `.min-h-full` rule take precedence. Do not make this root its own scroll\n * container through `className`; wrap the screen in a\n * `min-h-0 flex-1 overflow-y-auto` container and let the root fill it instead\n * (issue #465, item 5).\n *\n * Assumes a `StudioToastProvider` and a `StudioPlaybackProvider` above it.\n */\n\nimport { ArrowLeft, CircleAlert } from 'lucide-react'\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type JSX,\n} from 'react'\n\nimport {\n generationAspectRatio,\n generationError,\n generationStatus,\n generationsInBatch,\n WIDE_WAVEFORM_BARS,\n type DeleteGenerations,\n type Generation,\n type StudioMediaActions,\n type VaultSaveResult,\n} from '../studio'\nimport { GenerationNoticeChip } from './generation-notice'\nimport { MediaTile } from './media-tile'\nimport { MediaViewerModal } from './media-viewer'\nimport { StudioComposer } from './studio-composer'\nimport { StudioConfirmDialog } from './studio-confirm'\nimport { useStudioPlayback } from './studio-playback'\nimport { useStudioToast } from './studio-toasts'\nimport { useBatchNavigation } from './use-batch-navigation'\nimport { useDeferredDelete } from './use-deferred-delete'\n\nexport interface StudioGenerationScreenProps {\n /** Full merged list from the host (`useStudioGenerations`). */\n generations: Generation[]\n batchKey: string\n onGenerated: (generation: Generation) => void\n /** A dock submit that starts a NEW batch navigates via the host. */\n onOpenGeneration: (batchKey: string, first: Generation) => void\n onBack: () => void\n workspaceId?: string\n pickReferenceImage?: () => Promise<string | null>\n actions?: StudioMediaActions\n className?: string\n}\n\ntype SkeletonStyle = CSSProperties & { '--r'?: number }\n\n/** What the body clears before the dock has ever been measured. */\nconst FALLBACK_DOCK_HEIGHT = 190\n\n/** `useDeferredDelete` needs a remover unconditionally; with no `remove` seam\n * no delete control is rendered, so this is never reached. */\nconst noRemove: DeleteGenerations = async () => {}\n\nfunction isRunning(generation: Generation): boolean {\n const status = generationStatus(generation)\n return status === 'pending' || status === 'running'\n}\n\nexport function StudioGenerationScreen({\n generations,\n batchKey,\n onGenerated,\n onOpenGeneration,\n onBack,\n workspaceId,\n pickReferenceImage,\n actions,\n className,\n}: StudioGenerationScreenProps): JSX.Element {\n const rootRef = useRef<HTMLDivElement>(null)\n const dockRef = useRef<HTMLDivElement>(null)\n const { setDockLift, toast } = useStudioToast()\n const { stop } = useStudioPlayback()\n const stopRef = useRef(stop)\n stopRef.current = stop\n\n const [dockHeight, setDockHeight] = useState(FALLBACK_DOCK_HEIGHT)\n const [viewerId, setViewerId] = useState<string | null>(null)\n const [deleteTarget, setDeleteTarget] = useState<Generation | null>(null)\n\n const remove = actions?.remove\n const { pendingIds, request } = useDeferredDelete({ remove: remove ?? noRemove })\n\n const rows = useMemo(\n () => generationsInBatch(generations, batchKey).filter((row) => !pendingIds.has(row.id)),\n [batchKey, generations, pendingIds],\n )\n const first = rows[0]\n const prompt = first?.prompt ?? ''\n const ratio = first ? generationAspectRatio(first) : 1.5\n const runningCount = rows.filter(isRunning).length\n\n // The rise stagger counts SETTLED rows only, so a batch whose slots finish out\n // of order still lands 60ms apart instead of inheriting a skeleton's slot.\n const settledOrder = new Map<string, number>()\n for (const row of rows) if (!isRunning(row)) settledOrder.set(row.id, settledOrder.size)\n\n const columns = rows.length === 4 ? 2 : Math.min(rows.length, 4) || 1\n const maxWidth = rows.length > 1 || first?.type === 'speech'\n ? 820\n : ratio < 1 ? 380 : 640\n\n const viewerGeneration = viewerId ? rows.find((row) => row.id === viewerId) ?? null : null\n\n const onSaved = useCallback((results: readonly VaultSaveResult[]) => {\n const saved = results[0]\n if (saved) toast({ message: `Saved to vault · ${saved.vaultPath}` })\n }, [toast])\n\n const navigateNewBatch = useBatchNavigation({ seed: [], currentBatchKey: batchKey, onOpenGeneration })\n const handleGenerated = useCallback((generation: Generation) => {\n onGenerated(generation)\n navigateNewBatch(generation)\n }, [navigateNewBatch, onGenerated])\n\n useEffect(() => {\n const dock = dockRef.current\n if (!dock) return\n const apply = (height: number) => {\n // A zero reading means \"not laid out yet\" (jsdom, a hidden host); publishing\n // it would collapse the body's clearance onto a dock that is really there.\n if (height <= 0) return\n rootRef.current?.style.setProperty('--studio-dock-h', `${height}px`)\n setDockHeight(height)\n setDockLift(height)\n }\n const measure = () => apply(dock.getBoundingClientRect().height)\n measure()\n // jsdom and older browsers have no ResizeObserver; the window listener still\n // covers the case that matters (the viewport getting narrower).\n const observer = typeof ResizeObserver === 'undefined'\n ? null\n : new ResizeObserver((entries) => apply(entries[0]?.contentRect.height ?? dock.getBoundingClientRect().height))\n observer?.observe(dock)\n window.addEventListener('resize', measure)\n return () => {\n observer?.disconnect()\n window.removeEventListener('resize', measure)\n setDockLift(null)\n }\n }, [setDockLift])\n\n // Leaving the screen stops whatever it was playing — the audio element lives\n // in the provider ABOVE this component and would otherwise keep going.\n useEffect(() => () => stopRef.current(), [])\n\n function confirmDelete(): void {\n if (!deleteTarget) return\n request([deleteTarget])\n if (viewerId === deleteTarget.id) setViewerId(null)\n setDeleteTarget(null)\n }\n\n return (\n <div ref={rootRef} className={`flex min-h-full flex-col ${className ?? ''}`}>\n <header className=\"studio-gen-head mx-auto flex w-full max-w-[868px] items-center gap-2.5 px-6 pb-4 pt-1 max-[900px]:px-4\">\n <button\n type=\"button\"\n aria-label=\"Back to Studio\"\n onClick={onBack}\n className=\"grid h-8 w-8 flex-none place-items-center rounded-full border border-border bg-card shadow-sm hover:bg-accent\"\n >\n <ArrowLeft size={16} strokeWidth={1.5} />\n </button>\n <p\n title={prompt}\n className=\"min-w-0 max-w-full truncate rounded-full border border-border bg-card px-4 py-2 text-[14px] shadow-sm\"\n >\n {prompt}\n </p>\n </header>\n\n <div\n className=\"studio-gen-body flex-1 px-6 max-[900px]:px-4\"\n style={{ paddingBottom: `${dockHeight + 16}px` }}\n >\n {rows.length === 0 ? (\n <div className=\"mx-auto flex max-w-[520px] flex-col items-center gap-1 py-16 text-center\">\n <p className=\"text-[14px]\">Nothing left from this generation.</p>\n <p className=\"text-[13px] text-muted-foreground\">Send another prompt below to start a new one.</p>\n </div>\n ) : (\n <>\n <div\n className=\"mx-auto grid gap-[3px]\"\n aria-busy={runningCount > 0}\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`, maxWidth }}\n >\n {rows.map((row) => {\n if (isRunning(row)) {\n return <div key={row.id} className=\"studio-skeleton\" style={{ '--r': ratio } as SkeletonStyle} />\n }\n // A failed row is NOT a tile: `MediaTile` reads a null result as\n // \"still running\" and draws a skeleton, which would leave a dead\n // slot sweeping for ever. The cell states the reason instead.\n if (generationStatus(row) === 'failed') {\n const reason = generationError(row)\n return (\n <div\n key={row.id}\n className=\"flex flex-col items-center justify-center gap-1.5 bg-accent p-3 text-center\"\n style={{ aspectRatio: ratio }}\n >\n <CircleAlert aria-hidden className=\"h-4 w-4 flex-none text-destructive\" strokeWidth={2} />\n <p className=\"text-[13px] font-medium text-foreground\">Generation failed</p>\n {reason && reason !== 'Generation failed' && (\n <p className=\"line-clamp-3 text-[12px] text-muted-foreground\">{reason}</p>\n )}\n </div>\n )\n }\n return (\n <div\n key={row.id}\n className=\"studio-rise\"\n style={{ animationDelay: `${(settledOrder.get(row.id) ?? 0) * 60}ms` }}\n >\n <MediaTile\n generation={row}\n context=\"generation\"\n aspectRatio={ratio}\n waveformBars={WIDE_WAVEFORM_BARS}\n actions={actions}\n onOpen={(generation) => setViewerId(generation.id)}\n onRequestDelete={remove ? setDeleteTarget : undefined}\n onSaved={onSaved}\n />\n </div>\n )\n })}\n </div>\n {runningCount > 0 && (\n <p className=\"sr-only\" aria-live=\"polite\">\n Generating {runningCount} result{runningCount > 1 ? 's' : ''}…\n </p>\n )}\n </>\n )}\n </div>\n\n <div\n ref={dockRef}\n className=\"studio-dock sticky bottom-0 z-[5] bg-background px-6 pb-[18px] pt-4 max-[900px]:px-4\"\n >\n <div className=\"mx-auto w-full max-w-[820px]\">\n <div className=\"mb-2.5 flex justify-center\">\n <GenerationNoticeChip />\n </div>\n <StudioComposer\n variant=\"docked\"\n workspaceId={workspaceId}\n pickReferenceImage={pickReferenceImage}\n onGenerated={handleGenerated}\n />\n </div>\n </div>\n\n <MediaViewerModal\n generation={viewerGeneration}\n onClose={() => setViewerId(null)}\n actions={actions}\n onRequestDelete={remove ? setDeleteTarget : undefined}\n onSaved={onSaved}\n />\n <StudioConfirmDialog\n open={deleteTarget !== null}\n count={1}\n onConfirm={confirmDelete}\n onCancel={() => setDeleteTarget(null)}\n />\n </div>\n )\n}\n","/**\n * The studio history screen — the full media library behind the home screen's\n * \"View history\" button: search, a media-type filter, cursor-paged infinite\n * scroll, and the multi-select bar that runs download / save-to-vault / delete\n * over a whole selection at once.\n *\n * It ASSUMES a `StudioToastProvider` and a `StudioPlaybackProvider` above it —\n * the deferred delete it drives lives in both (undo toast, stopping audio for a\n * row that is going away), and every screen in this surface makes the same\n * assumption so a route layout can mount the two providers once.\n *\n * The screen never fetches: `fetchPage` is the product's own paged endpoint and\n * `actions` are its media seams. An ABSENT action hides its control rather than\n * rendering a batch button that does nothing.\n */\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n type CSSProperties,\n type JSX,\n} from 'react'\nimport {\n ArrowLeft,\n AudioLines,\n Download,\n FolderPlus,\n Image,\n LayoutGrid,\n Search,\n Trash2,\n Video,\n X,\n type LucideIcon,\n} from 'lucide-react'\n\nimport type { Generation } from '../studio/generation'\nimport {\n MEDIA_TYPE_FILTERS,\n type FetchGenerationsPage,\n type GenerationPage,\n type MediaTypeFilter,\n type StudioMediaActions,\n type VaultSaveResult,\n} from '../studio/ports'\nimport { POPOVER_SURFACE_ATTR, usePopover } from '../web-react/controls'\nimport { useInfiniteScroll } from '../web-react/session-history'\nimport { MenuPill } from './composer-option-controls'\nimport { downloadGenerationsViaAnchor } from './download-generations'\nimport { MediaTile } from './media-tile'\nimport { MediaViewerModal } from './media-viewer'\nimport { StudioConfirmDialog } from './studio-confirm'\nimport { useStudioPlayback } from './studio-playback'\nimport { useStudioToast } from './studio-toasts'\nimport { useDeferredDelete } from './use-deferred-delete'\nimport { useGenerationHistory } from './use-generation-history'\nimport { VaultPathPopover } from './vault-path-popover'\n\nexport interface StudioHistoryScreenProps {\n fetchPage: FetchGenerationsPage\n /** SSR/loader page 1 for the DEFAULT view (no search, no type filter). */\n initialPage?: GenerationPage\n onBack: () => void\n actions?: StudioMediaActions\n /** Trailing debounce before a keystroke becomes a fetch. */\n searchDebounceMs?: number\n className?: string\n}\n\n/** How many cells the first load and each subsequent page stand in for. */\nconst FIRST_LOAD_SKELETONS = 8\nconst MORE_SKELETONS = 4\n\nconst BAR = 'flex min-h-[44px] flex-wrap items-center justify-between gap-3 px-6 pb-[18px] pt-0.5 max-[900px]:px-4'\nconst SEARCH_INPUT = 'h-8 w-[260px] max-w-[52vw] rounded-full border border-border bg-card pl-8 pr-3 text-[13px] text-foreground outline-none placeholder:text-muted-foreground focus:border-primary focus:ring-[3px] focus:ring-ring/30 max-[640px]:w-full max-[640px]:max-w-none'\nconst OUTLINE_PILL = 'inline-flex h-8 items-center gap-1.5 rounded-full border border-border px-3 text-[12.5px] font-medium hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40'\n\nconst FILTER_ICONS: Record<MediaTypeFilter, LucideIcon> = {\n all: LayoutGrid,\n image: Image,\n video: Video,\n speech: AudioLines,\n}\nconst FILTER_CHOICES = MEDIA_TYPE_FILTERS.map((choice) => ({\n ...choice,\n icon: FILTER_ICONS[choice.value],\n}))\n\n/** The empty-state plural for a type filter, in the filter's own words. */\nconst TYPE_NOUNS: Record<Exclude<MediaTypeFilter, 'all'>, string> = {\n image: 'images',\n video: 'videos',\n speech: 'audio',\n}\n\ntype SkeletonStyle = CSSProperties & { '--r'?: number }\n/** `.studio-skeleton` defaults to the 3:2 generation ratio; the library grid is\n * square, and the ratio is a custom property rather than a utility because a\n * Tailwind `aspect-*` class ties with the stylesheet rule on specificity. */\nconst SQUARE_CELL: SkeletonStyle = { '--r': 1 }\n\nfunction skeletonCells(count: number, keyPrefix: string) {\n return Array.from({ length: count }, (_, index) => (\n <div key={`${keyPrefix}-${index}`} className=\"studio-skeleton\" style={SQUARE_CELL} aria-hidden />\n ))\n}\n\nfunction hasOpenPopover(): boolean {\n return typeof document !== 'undefined' && document.querySelector(`[${POPOVER_SURFACE_ATTR}]`) !== null\n}\n\nexport function StudioHistoryScreen({\n fetchPage,\n initialPage,\n onBack,\n actions,\n searchDebounceMs = 250,\n className,\n}: StudioHistoryScreenProps): JSX.Element {\n const playback = useStudioPlayback()\n const { stop } = playback\n const { toast } = useStudioToast()\n\n const [query, setQuery] = useState('')\n const [debouncedQuery, setDebouncedQuery] = useState('')\n const [type, setType] = useState<MediaTypeFilter>('all')\n const [selectMode, setSelectMode] = useState(false)\n const [selected, setSelected] = useState<ReadonlySet<string>>(() => new Set())\n const [viewer, setViewer] = useState<Generation | null>(null)\n const [confirmTargets, setConfirmTargets] = useState<Generation[] | null>(null)\n const [saveOpen, setSaveOpen] = useState(false)\n const [savePending, setSavePending] = useState(false)\n const savePopover = usePopover(saveOpen, setSaveOpen)\n\n // Trailing debounce. Clearing the search sets both halves at once, and the\n // equality guard is what keeps that from scheduling a redundant timer.\n useEffect(() => {\n if (query === debouncedQuery) return\n const timer = window.setTimeout(() => setDebouncedQuery(query), searchDebounceMs)\n return () => window.clearTimeout(timer)\n }, [debouncedQuery, query, searchDebounceMs])\n\n const history = useGenerationHistory({ fetchPage, q: debouncedQuery, type, initialPage })\n const deferredDelete = useDeferredDelete({\n remove: actions?.remove ?? (async () => {}),\n // Nothing to reload: `pendingIds` already hides the rows and the server has\n // dropped them. A refetch here would only re-request the page we can see.\n })\n const { pendingIds } = deferredDelete\n const rows = useMemo(\n () => history.items.filter((item) => !pendingIds.has(item.id)),\n [history.items, pendingIds],\n )\n const selectedRows = useMemo(() => rows.filter((row) => selected.has(row.id)), [rows, selected])\n\n useEffect(() => {\n if (history.isLoadingFirst || history.isLoadingMore || !playback.activeId) return\n if (rows.some((row) => row.id === playback.activeId) || viewer?.id === playback.activeId) return\n playback.stop()\n }, [history.isLoadingFirst, history.isLoadingMore, playback, rows, viewer])\n\n const sentinelRef = useInfiniteScroll(history.loadMore, {\n enabled: history.hasMore && !history.isLoadingMore && !history.isLoadingFirst && !history.isError,\n })\n\n const exitSelectMode = useCallback(() => {\n setSelectMode(false)\n setSelected(new Set())\n setSaveOpen(false)\n }, [])\n\n const toggleSelect = useCallback((id: string) => {\n if (!selectMode) {\n // Entering select mode hides every tile's play button, so a clip playing\n // underneath would have no control left to stop it.\n stop()\n setSelectMode(true)\n setSelected(new Set([id]))\n return\n }\n setSelected((current) => {\n const next = new Set(current)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n return next\n })\n }, [selectMode, stop])\n\n // The residual Escape: the confirm dialog, the viewer and every popover close\n // themselves, so this handler exists only for the case none of them owns —\n // leaving select mode. It checks for those overlays rather than assuming an\n // order, because two document listeners see the same keydown.\n useEffect(() => {\n if (!selectMode) return\n function onKeyDown(event: globalThis.KeyboardEvent) {\n if (event.key !== 'Escape') return\n if (confirmTargets || viewer || hasOpenPopover()) return\n event.preventDefault()\n exitSelectMode()\n }\n document.addEventListener('keydown', onKeyDown)\n return () => document.removeEventListener('keydown', onKeyDown)\n }, [confirmTargets, exitSelectMode, selectMode, viewer])\n\n useEffect(() => () => stop(), [stop])\n\n const clearFilters = useCallback(() => {\n setQuery('')\n setDebouncedQuery('')\n setType('all')\n }, [])\n\n const onSaved = useCallback((results: readonly VaultSaveResult[]) => {\n const path = results[0]?.vaultPath\n if (!path) return\n toast({\n message: results.length > 1\n ? `Saved ${results.length} items to vault · ${path}`\n : `Saved to vault · ${path}`,\n })\n }, [toast])\n\n function batchDownload() {\n void (actions?.download ?? downloadGenerationsViaAnchor)(selectedRows)\n exitSelectMode()\n }\n\n async function batchSave(path: string) {\n if (!actions?.save) return\n setSavePending(true)\n try {\n const results = await actions.save({ generations: selectedRows, path })\n setSaveOpen(false)\n onSaved(results)\n exitSelectMode()\n } finally {\n setSavePending(false)\n }\n }\n\n function confirmDelete() {\n const targets = confirmTargets ?? []\n setConfirmTargets(null)\n if (targets.length === 0) return\n if (viewer && targets.some((target) => target.id === viewer.id)) setViewer(null)\n deferredDelete.request(targets)\n exitSelectMode()\n }\n\n const viewerRow = viewer ? rows.find((row) => row.id === viewer.id) ?? viewer : null\n const searchTerm = debouncedQuery.trim()\n const isFiltered = query !== '' || debouncedQuery !== '' || type !== 'all'\n const emptyCopy = searchTerm\n ? {\n title: `No media matches “${searchTerm}”.`,\n body: 'Try a shorter word, or drop the type filter.',\n }\n : type !== 'all'\n ? {\n title: `No ${TYPE_NOUNS[type]} yet.`,\n body: 'Generate one from the Studio composer and it will show up here.',\n }\n : {\n title: 'Your history is empty.',\n body: 'Everything you generate is kept here until you delete it.',\n }\n\n return (\n <div className={`studio-hist-wrap pb-[72px] ${className ?? ''}`}>\n {selectMode ? (\n <div className={BAR}>\n <div className=\"flex items-center gap-2 text-[13.5px] font-medium\">\n <button\n type=\"button\"\n aria-label=\"Exit select mode\"\n onClick={exitSelectMode}\n className=\"grid h-[26px] w-[26px] place-items-center rounded-full hover:bg-accent\"\n >\n <X size={15} strokeWidth={1.5} />\n </button>\n {selected.size} selected\n </div>\n\n <div role=\"toolbar\" aria-label=\"Selection actions\" className=\"ml-auto flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n disabled={selected.size === 0}\n onClick={batchDownload}\n className={OUTLINE_PILL}\n >\n <Download size={16} strokeWidth={1.5} /> Download\n </button>\n\n {actions?.save && (\n <div ref={savePopover.containerRef} className=\"inline-flex\">\n <button\n {...savePopover.triggerProps}\n type=\"button\"\n disabled={selected.size === 0}\n onClick={() => setSaveOpen(!saveOpen)}\n className={OUTLINE_PILL}\n >\n <FolderPlus size={16} strokeWidth={1.5} /> Save to vault\n </button>\n <VaultPathPopover\n open={saveOpen}\n triggerRef={savePopover.triggerRef}\n panelRef={savePopover.panelRef}\n generations={selectedRows}\n onSubmit={batchSave}\n onCancel={() => setSaveOpen(false)}\n pending={savePending}\n />\n </div>\n )}\n\n {actions?.remove && (\n <button\n type=\"button\"\n disabled={selected.size === 0}\n onClick={() => setConfirmTargets(selectedRows)}\n className={`${OUTLINE_PILL} text-destructive hover:border-destructive hover:bg-destructive/10`}\n >\n <Trash2 size={16} strokeWidth={1.5} /> Delete\n </button>\n )}\n </div>\n </div>\n ) : (\n <div className={BAR}>\n <button\n type=\"button\"\n aria-label=\"Back to Studio\"\n onClick={onBack}\n className=\"grid h-8 w-8 flex-none place-items-center rounded-full border border-border bg-card shadow-sm hover:bg-accent\"\n >\n <ArrowLeft size={16} strokeWidth={1.5} />\n </button>\n\n <div className=\"ml-auto flex flex-wrap items-center gap-2 max-[640px]:w-full\">\n <div className=\"relative inline-flex items-center max-[640px]:flex-1 max-[640px]:basis-[160px]\">\n <Search\n size={15}\n strokeWidth={1.5}\n aria-hidden\n className=\"pointer-events-none absolute left-[11px] text-muted-foreground\"\n />\n <input\n type=\"text\"\n value={query}\n placeholder=\"Search\"\n aria-label=\"Search prompts\"\n onChange={(event) => setQuery(event.target.value)}\n className={SEARCH_INPUT}\n />\n </div>\n\n <MenuPill\n label=\"Filter by media type\"\n value={type}\n choices={FILTER_CHOICES}\n onSelect={setType}\n trigger=\"text\"\n />\n </div>\n </div>\n )}\n\n {history.isError && rows.length === 0 ? (\n <div className=\"flex flex-col items-center gap-3 px-6 py-16 text-center max-[900px]:px-4\">\n <p className=\"text-[14px] text-foreground\">Could not load media.</p>\n <button type=\"button\" onClick={history.retry} className={OUTLINE_PILL}>Retry</button>\n </div>\n ) : history.isLoadingFirst && rows.length === 0 ? (\n <div className=\"studio-grid studio-grid-library\">\n {skeletonCells(FIRST_LOAD_SKELETONS, 'first')}\n </div>\n ) : rows.length === 0 ? (\n <div className=\"flex flex-col items-center gap-1.5 px-6 py-16 text-center max-[900px]:px-4\">\n <p className=\"text-[14px] text-foreground\">{emptyCopy.title}</p>\n <p className=\"max-w-[380px] text-[13px] text-muted-foreground\">{emptyCopy.body}</p>\n {isFiltered && (\n <button type=\"button\" onClick={clearFilters} className={`${OUTLINE_PILL} mt-2`}>Clear</button>\n )}\n </div>\n ) : (\n <div className={selectMode ? 'studio-selectmode' : undefined}>\n <div className=\"studio-grid studio-grid-library\">\n {rows.map((row) => (\n <MediaTile\n key={row.id}\n generation={row}\n context=\"history\"\n onOpen={setViewer}\n actions={actions}\n selectMode={selectMode}\n selected={selected.has(row.id)}\n onToggleSelect={toggleSelect}\n onRequestDelete={actions?.remove ? (generation) => setConfirmTargets([generation]) : undefined}\n onSaved={onSaved}\n />\n ))}\n {history.isLoadingMore && skeletonCells(MORE_SKELETONS, 'more')}\n </div>\n </div>\n )}\n\n {history.isError && rows.length > 0 && (\n <div className=\"flex items-center justify-center gap-3 px-6 py-4 text-[13px] text-muted-foreground max-[900px]:px-4\">\n <span>Could not load more media.</span>\n <button type=\"button\" onClick={history.retry} className={OUTLINE_PILL}>Retry</button>\n </div>\n )}\n\n <div ref={sentinelRef} aria-hidden />\n\n <MediaViewerModal\n generation={viewerRow}\n onClose={() => setViewer(null)}\n actions={actions}\n onRequestDelete={actions?.remove ? (generation) => setConfirmTargets([generation]) : undefined}\n onSaved={onSaved}\n />\n\n <StudioConfirmDialog\n open={confirmTargets !== null}\n count={confirmTargets?.length ?? 0}\n onConfirm={confirmDelete}\n onCancel={() => setConfirmTargets(null)}\n />\n </div>\n )\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport type { FetchGenerationsPage, GenerationPage, MediaTypeFilter } from '../studio/ports'\nimport { mergeGenerationPages, type Generation } from '../studio/generation'\n\nexport interface UseGenerationHistoryOptions {\n fetchPage: FetchGenerationsPage\n /** ALREADY debounced by the caller. */\n q: string\n type: MediaTypeFilter\n /** SSR/loader page 1 for the DEFAULT view only (q === '' && type === 'all'). */\n initialPage?: GenerationPage\n}\n\nexport interface GenerationHistoryState {\n items: Generation[]\n hasMore: boolean\n isLoadingFirst: boolean\n isLoadingMore: boolean\n isError: boolean\n loadMore: () => void\n retry: () => void\n reload: () => void\n}\n\n/** Content identity keeps inline-equivalent loader pages from reseeding. */\nfunction seedSignature(page: GenerationPage | undefined): string {\n if (!page) return ''\n return `${page.nextCursor ?? ''}|${page.items.map((item) => item.id).join(',')}`\n}\n\n/** Cursor-paged generation history over the product-supplied data port. */\nexport function useGenerationHistory({\n fetchPage,\n q,\n type,\n initialPage,\n}: UseGenerationHistoryOptions): GenerationHistoryState {\n const startsFromSeed = q === '' && type === 'all' && initialPage !== undefined\n const [items, setItems] = useState<Generation[]>(startsFromSeed ? initialPage.items : [])\n const [nextCursor, setNextCursor] = useState<string | null>(\n startsFromSeed ? initialPage.nextCursor ?? null : null,\n )\n const [phase, setPhase] = useState<'idle' | 'loadingFirst' | 'loadingMore' | 'error'>(\n startsFromSeed ? 'idle' : 'loadingFirst',\n )\n const [reloadKey, setReloadKey] = useState(0)\n\n const seqRef = useRef(0)\n const resetAbortRef = useRef<AbortController | null>(null)\n const loadMoreAbortRef = useRef<AbortController | null>(null)\n const loadingFirstRef = useRef(!startsFromSeed)\n const loadingMoreRef = useRef(false)\n const lastOpRef = useRef<'first' | 'more'>('first')\n const seedEligibleRef = useRef(true)\n\n const nextCursorRef = useRef(nextCursor)\n nextCursorRef.current = nextCursor\n const viewRef = useRef({ q, type, fetchPage })\n viewRef.current = { q, type, fetchPage }\n const seedRef = useRef(initialPage)\n seedRef.current = initialPage\n\n const isDefaultView = q === '' && type === 'all'\n const seedKey = useMemo(() => seedSignature(initialPage), [initialPage])\n\n useEffect(() => {\n resetAbortRef.current?.abort()\n loadMoreAbortRef.current?.abort()\n loadingFirstRef.current = false\n loadingMoreRef.current = false\n const seq = ++seqRef.current\n\n if (!isDefaultView) seedEligibleRef.current = false\n const seed = seedRef.current\n if (isDefaultView && seedEligibleRef.current && reloadKey === 0 && seed) {\n setItems(seed.items)\n setNextCursor(seed.nextCursor ?? null)\n setPhase('idle')\n return\n }\n\n const controller = new AbortController()\n resetAbortRef.current = controller\n loadingFirstRef.current = true\n lastOpRef.current = 'first'\n setItems([])\n setNextCursor(null)\n setPhase('loadingFirst')\n\n void (async () => {\n try {\n const current = viewRef.current\n const page = await current.fetchPage({\n q: current.q.trim(),\n type: current.type,\n cursor: null,\n signal: controller.signal,\n })\n if (seq !== seqRef.current) return\n setItems(page.items)\n setNextCursor(page.nextCursor ?? null)\n setPhase('idle')\n } catch {\n if (controller.signal.aborted || seq !== seqRef.current) return\n setPhase('error')\n } finally {\n if (seq === seqRef.current) loadingFirstRef.current = false\n }\n })()\n\n return () => controller.abort()\n }, [q, type, seedKey, isDefaultView, reloadKey])\n\n const loadMore = useCallback(() => {\n const cursor = nextCursorRef.current\n if (!cursor || loadingFirstRef.current || loadingMoreRef.current) return\n\n const current = viewRef.current\n const seq = seqRef.current\n loadMoreAbortRef.current?.abort()\n const controller = new AbortController()\n loadMoreAbortRef.current = controller\n loadingMoreRef.current = true\n lastOpRef.current = 'more'\n setPhase('loadingMore')\n\n void (async () => {\n try {\n const page = await current.fetchPage({\n q: current.q.trim(),\n type: current.type,\n cursor,\n signal: controller.signal,\n })\n if (seq !== seqRef.current) return\n setItems((previous) => mergeGenerationPages(previous, page.items))\n setNextCursor(page.nextCursor ?? null)\n setPhase('idle')\n } catch {\n if (controller.signal.aborted || seq !== seqRef.current) return\n setPhase('error')\n } finally {\n if (seq === seqRef.current) loadingMoreRef.current = false\n }\n })()\n }, [])\n\n const retry = useCallback(() => {\n if (lastOpRef.current === 'more') loadMore()\n else setReloadKey((key) => key + 1)\n }, [loadMore])\n\n const reload = useCallback(() => {\n setReloadKey((key) => key + 1)\n }, [])\n\n useEffect(\n () => () => {\n resetAbortRef.current?.abort()\n loadMoreAbortRef.current?.abort()\n },\n [],\n )\n\n return {\n items,\n hasMore: nextCursor !== null,\n isLoadingFirst: phase === 'loadingFirst',\n isLoadingMore: phase === 'loadingMore',\n isError: phase === 'error',\n loadMore,\n retry,\n reload,\n }\n}\n"],"mappings":"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","names":["useEffect","useMemo","useRef","useState","TriangleAlert","useCallback","useEffect","useState","useCallback","useEffect","useState","jsx","jsxs","useState","useRef","useEffect","useMemo","TriangleAlert","jsx","jsxs","useEffect","useState","useEffect","useId","useRef","useState","jsx","jsxs","useRef","useId","useState","useEffect","useCallback","useEffect","useMemo","useRef","useState","jsx","value","stop","nodes","jsx","jsxs","useState","useEffect","useCallback","useEffect","useMemo","useRef","useState","Download","FolderOpen","FolderPlus","Pause","Play","Trash2","X","jsx","jsxs","useRef","useMemo","useEffect","useState","useCallback","Pause","Play","X","Download","FolderPlus","FolderOpen","Trash2","useCallback","useEffect","useMemo","useState","useEffect","useId","useRef","createPortal","jsx","jsxs","useRef","useId","useEffect","createPortal","createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","createPortal","X","jsx","jsxs","createContext","useEffect","X","useState","useRef","useCallback","toast","useMemo","createPortal","useContext","useCallback","useRef","useRef","useCallback","useCallback","useEffect","useRef","useState","stop","useState","useRef","useCallback","useEffect","jsx","jsxs","useState","useCallback","useMemo","useEffect","useCallback","useEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","useRef","stop","useState","useMemo","useCallback","useEffect","useCallback","useEffect","useMemo","useState","ArrowLeft","AudioLines","Download","FolderPlus","Trash2","Video","X","useCallback","useEffect","useMemo","useRef","useState","useState","useRef","useMemo","useEffect","useCallback","jsx","jsxs","Video","AudioLines","hasOpenPopover","stop","useState","useEffect","useMemo","useCallback","X","Download","FolderPlus","Trash2","ArrowLeft"]}