@tangle-network/agent-app 0.45.65 → 0.46.1
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.
- package/dist/assistant/index.js +3 -3
- package/dist/chat-react/index.js +2 -2
- package/dist/chunk-2RTYQU4W.js +441 -0
- package/dist/chunk-2RTYQU4W.js.map +1 -0
- package/dist/{chunk-23J72UUA.js → chunk-DINGA2MO.js} +94 -560
- package/dist/chunk-DINGA2MO.js.map +1 -0
- package/dist/{chunk-AWM4H5XR.js → chunk-MBKNKAN2.js} +6 -4
- package/dist/{chunk-AWM4H5XR.js.map → chunk-MBKNKAN2.js.map} +1 -1
- package/dist/chunk-YDOQE47G.js +518 -0
- package/dist/chunk-YDOQE47G.js.map +1 -0
- package/dist/stories/studio/fixtures.d.ts +0 -4
- package/dist/studio/generation.d.ts +16 -74
- package/dist/studio/index.d.ts +2 -2
- package/dist/studio/index.js +27 -25
- package/dist/studio/model-options.d.ts +61 -0
- package/dist/studio-react/composer-option-controls.d.ts +140 -0
- package/dist/studio-react/generation-notice.d.ts +18 -0
- package/dist/studio-react/index.d.ts +6 -12
- package/dist/studio-react/index.js +902 -827
- package/dist/studio-react/index.js.map +1 -1
- package/dist/studio-react/studio-composer.d.ts +34 -0
- package/dist/studio-react/studio-workspace.d.ts +2 -4
- package/dist/studio-react/studio.css +51 -0
- package/dist/theme/tokens.css +18 -0
- package/dist/web-react/index.js +11 -11
- package/package.json +1 -1
- package/dist/chunk-23J72UUA.js.map +0 -1
- package/dist/chunk-HSBJB46C.js +0 -305
- package/dist/chunk-HSBJB46C.js.map +0 -1
- package/dist/chunk-MLG6XKPV.js +0 -44
- package/dist/chunk-MLG6XKPV.js.map +0 -1
- package/dist/studio-react/avatar-composer.d.ts +0 -8
- package/dist/studio-react/composer-hero.d.ts +0 -12
- package/dist/studio-react/composer-shell.d.ts +0 -18
- package/dist/studio-react/image-composer.d.ts +0 -8
- package/dist/studio-react/publish-package-composer.d.ts +0 -18
- package/dist/studio-react/speech-composer.d.ts +0 -4
- package/dist/studio-react/transcription-composer.d.ts +0 -12
- package/dist/studio-react/video-composer.d.ts +0 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/studio-react/studio-workspace.tsx","../../src/studio-react/use-studio-generations.ts","../../src/studio-react/composer-hero.tsx","../../src/studio-react/type-config.ts","../../src/studio-react/composer-shell.tsx","../../src/studio-react/image-composer.tsx","../../src/studio-react/video-composer.tsx","../../src/studio-react/speech-composer.tsx","../../src/studio-react/avatar-composer.tsx","../../src/studio-react/transcription-composer.tsx","../../src/studio-react/publish-package-composer.tsx","../../src/studio-react/studio-header.tsx","../../src/studio-react/result-canvas.tsx","../../src/studio-react/library-drawer.tsx","../../src/studio-react/studio-sheet.tsx","../../src/studio-react/generation-grid.tsx","../../src/studio-react/generation-card.tsx","../../src/studio-react/generation-detail.tsx","../../src/studio-react/library-panel.tsx","../../src/studio-react/generation-detail-modal.tsx"],"sourcesContent":["import { useRef, useState } from 'react'\nimport { useSearchParams } from 'react-router'\nimport { Button } from '@tangle-network/sandbox-ui/primitives'\nimport { Images } from 'lucide-react'\nimport type { Generation } from '../studio'\nimport { useStudioGenerations } from './use-studio-generations'\nimport { ComposerHero } from './composer-hero'\nimport { StudioHeader } from './studio-header'\nimport { ResultCanvas } from './result-canvas'\nimport { LibraryDrawer } from './library-drawer'\n\nexport type StudioRole = 'owner' | 'admin' | 'editor' | 'viewer'\n\nexport interface StudioWorkspaceProps {\n generations: Generation[]\n totalCost: number\n workspaceId?: string\n role: StudioRole\n /** Polling endpoint override (default `/api/generations`). */\n generationsEndpoint?: string\n /** Build a vault link, optionally to a specific file. Defaults to `/app/<workspaceId>/vault`. */\n vaultHref?: (filePath?: string | null) => string\n /** Integrations page href for the publish-package \"Connect\" link. Defaults to `/app/<workspaceId>/integrations`. */\n integrationsHref?: string\n}\n\n/**\n * The full studio surface: header + composer + result canvas + library drawer,\n * with the generation orchestrator (merge/poll/revalidate) wired in. The host\n * route owns the loader (auth, RBAC, the generation query) and the server\n * endpoints (`/api/generate`, `/api/media-models`, `/api/generations`); this\n * shell renders that data and drives the live UI. Role gates the composer\n * (viewers get a read-only library) and the integration-management affordances.\n */\nexport function StudioWorkspace({\n generations,\n totalCost,\n workspaceId,\n role,\n generationsEndpoint,\n vaultHref,\n integrationsHref,\n}: StudioWorkspaceProps) {\n const [searchParams, setSearchParams] = useSearchParams()\n const typeFilter = searchParams.get('type')\n const [drawerOpen, setDrawerOpen] = useState(false)\n const [selected, setSelected] = useState<Generation | null>(null)\n const canvasRef = useRef<HTMLDivElement>(null)\n const canGenerate = role !== 'viewer'\n const canManageIntegrations = role === 'owner' || role === 'admin'\n // Default the navigation hrefs to the conventional /app/<workspaceId>/… routes;\n // a host on a different route scheme passes its own builders.\n const resolvedVaultHref = vaultHref ?? (workspaceId\n ? (filePath?: string | null) => (filePath\n ? `/app/${workspaceId}/vault?file=${encodeURIComponent(filePath)}`\n : `/app/${workspaceId}/vault`)\n : undefined)\n const resolvedIntegrationsHref = integrationsHref\n ?? (workspaceId ? `/app/${workspaceId}/integrations` : undefined)\n\n const { mergedGenerations, latestBatch, onGenerated } = useStudioGenerations(generations, {\n workspaceId,\n generationsEndpoint,\n })\n\n function setFilter(type: string | null) {\n if (type) setSearchParams({ type })\n else setSearchParams({})\n }\n\n function openLibrary() {\n setSelected(null)\n setDrawerOpen(true)\n }\n\n function openDetail(generation: Generation) {\n setSelected(generation)\n setDrawerOpen(true)\n }\n\n return (\n <div className=\"min-h-0 flex-1 overflow-y-auto bg-background\">\n <StudioHeader\n count={mergedGenerations.length}\n canGenerate={canGenerate}\n onOpenLibrary={openLibrary}\n />\n\n <div className=\"mx-auto w-full max-w-3xl space-y-4 px-4 py-6 sm:px-6\">\n {canGenerate ? (\n <>\n <ComposerHero\n workspaceId={workspaceId}\n integrationsHref={resolvedIntegrationsHref}\n canManageIntegrations={canManageIntegrations}\n onGenerated={(generation) => {\n onGenerated(generation)\n requestAnimationFrame(() => {\n canvasRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' })\n })\n }}\n />\n <div ref={canvasRef}>\n <ResultCanvas\n batch={latestBatch}\n onOpenLibrary={openLibrary}\n onSelect={openDetail}\n />\n </div>\n </>\n ) : (\n <section className=\"flex flex-col items-center justify-center gap-3 rounded-xl border border-border bg-card p-10 text-center shadow-sm\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-muted\">\n <Images className=\"h-6 w-6 text-muted-foreground/40\" />\n </div>\n <p className=\"text-sm font-medium text-foreground\">\n {mergedGenerations.length > 0\n ? `${mergedGenerations.length} asset${mergedGenerations.length !== 1 ? 's' : ''} in this workspace`\n : 'No generations yet'}\n </p>\n <p className=\"max-w-sm text-xs text-muted-foreground\">\n Team generations appear in the library.\n </p>\n <Button size=\"sm\" variant=\"outline\" onClick={openLibrary}>\n <Images className=\"mr-1.5 h-4 w-4\" />\n Open library\n </Button>\n </section>\n )}\n </div>\n\n <LibraryDrawer\n open={drawerOpen}\n onOpenChange={(open) => { setDrawerOpen(open); if (!open) setSelected(null) }}\n generations={mergedGenerations}\n totalCost={totalCost}\n typeFilter={typeFilter}\n onFilterChange={setFilter}\n vaultHref={resolvedVaultHref}\n selected={selected}\n onSelect={(generation) => { setSelected(generation); if (generation) setDrawerOpen(true) }}\n />\n </div>\n )\n}\n","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","import { useEffect, useMemo, useRef, useState } from 'react'\nimport {\n Badge, Button, Input, Label, Textarea,\n Select, SelectContent, SelectItem, SelectTrigger, SelectValue,\n} from '@tangle-network/sandbox-ui/primitives'\nimport { useIntegrations } from '@tangle-network/sandbox-ui/integrations'\nimport { Sparkles } from 'lucide-react'\nimport {\n type Generation,\n type GenerationType,\n type MediaModelCatalogResponse,\n CADENCES,\n DESTINATIONS,\n buildGenerationRequestBody,\n buildPublishPackage,\n failedOptimisticGeneration,\n isDestinationConnected,\n modelMessage,\n normalizeImageCount,\n optimisticGeneration,\n outputPathFor,\n preferredModelId,\n selectedModelsWithDefaults,\n userSafeGenerationMessage,\n} from '../studio'\nimport { TYPE_CONFIG, typeConfigFor } from './type-config'\nimport { ProviderLogo } from '../web-react/provider-logo'\nimport { ComposerDisclosure, Field } from './composer-shell'\nimport { ImageComposer } from './image-composer'\nimport { VideoComposer } from './video-composer'\nimport { SpeechComposer } from './speech-composer'\nimport { AvatarComposer } from './avatar-composer'\nimport { TranscriptionComposer, TranscriptionOptions } from './transcription-composer'\nimport { PublishPackageComposer } from './publish-package-composer'\n\nconst HUB_BASE_URL = '/api/integrations/hub'\n\nconst SUGGESTIONS: Array<{ label: string; prompt: string; type: GenerationType }> = [\n {\n label: 'Storyboard frame',\n type: 'image',\n prompt: 'A vertical storyboard frame for a product launch teaser — dark cinematic lighting, sleek studio aesthetic, 9:16 composition.',\n },\n {\n label: 'Launch teaser clip',\n type: 'video',\n prompt: 'A 6-second vertical launch teaser: animated product reveal, dynamic camera move, hero music swell.',\n },\n {\n label: 'Scratch voiceover',\n type: 'speech',\n prompt: 'A confident 12-second scratch voiceover for a product launch teaser: warm tone, conversational pace.',\n },\n {\n label: 'Transcribe dailies',\n type: 'transcription',\n prompt: 'Transcribe the latest dailies recording with timestamps, speaker labels, and key story beats highlighted.',\n },\n]\n\nexport function ComposerHero({\n workspaceId,\n integrationsHref,\n canManageIntegrations,\n align = 'start',\n surfaceClassName = 'bg-card',\n onGenerated,\n}: {\n workspaceId?: string\n integrationsHref?: string\n canManageIntegrations: boolean\n /** Heading treatment: `center` (focus mode) vs `start` (composer as a left rail). */\n align?: 'center' | 'start'\n /** Background of the composer card. Host apps pass their own surface token so\n * the card can share a tone with the app shell (e.g. the sidebar). */\n surfaceClassName?: string\n onGenerated: (generation: Generation) => void\n}) {\n const [type, setType] = useState<GenerationType>('image')\n const [prompt, setPrompt] = useState('')\n const [negativePrompt, setNegativePrompt] = useState('')\n const [outputPath, setOutputPath] = useState(outputPathFor('image'))\n const [caption, setCaption] = useState('')\n const [postDescription, setPostDescription] = useState('')\n const [mentions, setMentions] = useState('')\n const [cadence, setCadence] = useState(CADENCES[0] ?? 'Manual approval')\n const [selectedDestinations, setSelectedDestinations] = useState<string[]>([])\n const [size, setSize] = useState('1536x1024')\n const [quality, setQuality] = useState('high')\n const [imageCount, setImageCount] = useState(1)\n const [duration, setDuration] = useState('6')\n const [resolution, setResolution] = useState('720p')\n const [aspectRatio, setAspectRatio] = useState('16:9')\n const [referenceImageUrl, setReferenceImageUrl] = useState('')\n const [voice, setVoice] = useState('alloy')\n const [avatarAudioUrl, setAvatarAudioUrl] = useState('')\n const [avatarImageUrl, setAvatarImageUrl] = useState('')\n const [avatarId, setAvatarId] = useState('')\n const [transcriptionAudioUrl, setTranscriptionAudioUrl] = useState('')\n const [transcriptionLanguage, setTranscriptionLanguage] = useState('')\n const [transcriptionResponseFormat, setTranscriptionResponseFormat] = useState('json')\n const [transcriptionTemperature, setTranscriptionTemperature] = useState('0')\n const [mediaModels, setMediaModels] = useState<MediaModelCatalogResponse | null>(null)\n const [mediaModelsLoading, setMediaModelsLoading] = useState(false)\n const [mediaModelsError, setMediaModelsError] = useState<string | null>(null)\n const [selectedModels, setSelectedModels] = useState<Partial<Record<GenerationType, string>>>({})\n const submitLockRef = useRef(false)\n const [isSubmitting, setIsSubmitting] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const modelsForType = mediaModels?.models[type] ?? []\n const selectedModel = selectedModels[type] ?? preferredModelId(type, mediaModels) ?? ''\n const selectedModelOption = modelsForType.find((model) => model.id === selectedModel)\n const modelReady = Boolean(selectedModelOption)\n && selectedModelOption?.status !== 'unavailable'\n && !mediaModelsLoading\n && !mediaModelsError\n const hasRequiredInput = type === 'transcription'\n ? Boolean(transcriptionAudioUrl.trim())\n : type === 'avatar'\n ? Boolean(avatarAudioUrl.trim())\n : Boolean(prompt.trim())\n const canSubmit = Boolean(workspaceId)\n && modelReady\n && hasRequiredInput\n && !isSubmitting\n const integrations = useIntegrations({ apiBaseUrl: HUB_BASE_URL })\n const selectedConnectedDestinations = useMemo(() => selectedDestinations.filter((destinationId) => {\n const destination = DESTINATIONS.find((item) => item.id === destinationId)\n return Boolean(destination && isDestinationConnected(destination, integrations.connections))\n }), [integrations.connections, selectedDestinations])\n\n useEffect(() => {\n if (!workspaceId) return\n let cancelled = false\n setMediaModelsLoading(true)\n setMediaModelsError(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 setMediaModels(data)\n setSelectedModels((current) => selectedModelsWithDefaults(current, data))\n })\n .catch(() => {\n if (cancelled) return\n setMediaModels(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 setMediaModelsError('Could not load media models')\n })\n .finally(() => {\n if (!cancelled) setMediaModelsLoading(false)\n })\n\n return () => {\n cancelled = true\n }\n }, [workspaceId])\n\n function changeType(next: GenerationType) {\n setType(next)\n setOutputPath(outputPathFor(next))\n }\n\n async function generate() {\n if (!workspaceId || submitLockRef.current) return\n const promptText = prompt.trim()\n const avatarAudioUrlText = avatarAudioUrl.trim()\n const transcriptionAudioUrlText = transcriptionAudioUrl.trim()\n if (type !== 'transcription' && type !== 'avatar' && !promptText) {\n setError('prompt is required')\n return\n }\n if (type === 'avatar' && !avatarAudioUrlText) {\n setError('audioUrl is required')\n return\n }\n if (type === 'transcription' && !transcriptionAudioUrlText) {\n setError('audioUrl is required')\n return\n }\n if (!selectedModelOption || selectedModelOption.status === 'unavailable') {\n setError(`Select an available ${typeConfigFor(type).label} model`)\n return\n }\n if (cadence === 'Publish now' && selectedConnectedDestinations.length === 0) {\n setError('Select a connected destination to publish now')\n return\n }\n submitLockRef.current = true\n setIsSubmitting(true)\n setError(null)\n const clientRequestId = crypto.randomUUID()\n const requestedImageCount = type === 'image' ? normalizeImageCount(imageCount) : 1\n if (type === 'image' && requestedImageCount !== imageCount) setImageCount(requestedImageCount)\n const localGenerations = Array.from({ length: requestedImageCount }, (_, outputIndex) => optimisticGeneration({\n type,\n // avatar hides the prompt field (promptText is stale); transcription's is\n // an optional vocab hint. Never surface the source audio URL as the prompt.\n prompt: type === 'avatar' ? '' : promptText,\n model: selectedModel,\n clientRequestId,\n outputIndex: type === 'image' ? outputIndex : undefined,\n outputCount: type === 'image' ? requestedImageCount : undefined,\n }))\n localGenerations.slice().reverse().forEach(onGenerated)\n setPrompt('')\n let receivedServerGeneration = false\n try {\n const body = buildGenerationRequestBody({\n workspaceId,\n clientRequestId,\n type,\n model: selectedModel,\n prompt,\n negativePrompt,\n outputPath,\n publishPackage: buildPublishPackage({\n caption,\n postDescription,\n mentions,\n cadence,\n destinations: selectedConnectedDestinations,\n }),\n image: { size, quality, count: requestedImageCount },\n video: { duration, resolution, aspectRatio, referenceImageUrl },\n speech: { voice },\n avatar: { audioUrl: avatarAudioUrl, imageUrl: avatarImageUrl, avatarId },\n transcription: {\n audioUrl: transcriptionAudioUrl,\n language: transcriptionLanguage,\n responseFormat: transcriptionResponseFormat,\n temperature: transcriptionTemperature,\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 mediaTypes = Object.entries(TYPE_CONFIG) as Array<[GenerationType, typeof TYPE_CONFIG[string]]>\n\n return (\n <section className={`rounded-2xl border border-border p-5 shadow-sm ${surfaceClassName}`}>\n <div className={`mb-5 ${align === 'center' ? 'text-center' : 'text-left'}`}>\n <h2\n className={`font-semibold tracking-tight text-foreground transition-all duration-300 ${\n align === 'center' ? 'text-xl' : 'text-base'\n }`}\n >\n Media Generation\n </h2>\n </div>\n\n <div role=\"tablist\" aria-label=\"Generation type\" className=\"grid grid-cols-5 gap-1.5\">\n {mediaTypes.map(([key, cfg]) => {\n const Icon = cfg.icon\n const active = type === key\n return (\n <button\n key={key}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n onClick={() => changeType(key)}\n className={`flex flex-col items-center gap-1.5 rounded-lg border px-1 pb-2 pt-2.5 text-xs transition-all ${\n active\n ? 'border-primary/30 bg-primary/10 font-semibold text-primary'\n : 'border-border bg-background font-medium text-muted-foreground hover:border-foreground/20 hover:text-foreground'\n }`}\n >\n <Icon className=\"h-[17px] w-[17px] shrink-0\" />\n <span className=\"truncate\">{cfg.label}</span>\n </button>\n )\n })}\n </div>\n\n {type !== 'avatar' && (\n <div className=\"mt-5\">\n <Label\n htmlFor=\"studio-prompt\"\n className=\"mb-1.5 block text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\"\n >\n Prompt\n </Label>\n <div className=\"rounded-xl border border-border bg-background transition-colors focus-within:border-primary/30 focus-within:ring-[3px] focus-within:ring-primary/10\">\n <textarea\n id=\"studio-prompt\"\n value={prompt}\n onChange={(event) => setPrompt(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n void generate()\n }\n }}\n rows={4}\n placeholder={type === 'transcription'\n ? 'Optional vocabulary, speaker names, timestamp style, or context...'\n : 'A vertical hero frame for a product launch teaser, dark cinematic lighting...'}\n className=\"block min-h-[96px] w-full resize-none border-0 bg-transparent px-3.5 pb-1.5 pt-3 text-sm leading-relaxed outline-none placeholder:text-muted-foreground\"\n />\n <div className=\"flex flex-wrap items-center gap-1.5 px-2.5 pb-2.5\">\n {SUGGESTIONS.map((suggestion) => (\n <button\n key={suggestion.label}\n type=\"button\"\n onClick={() => {\n setPrompt(suggestion.prompt)\n changeType(suggestion.type)\n }}\n className=\"rounded-full border border-border bg-background px-2.5 py-1 text-xs font-medium text-muted-foreground transition-colors hover:border-primary/30 hover:text-primary\"\n >\n {suggestion.label}\n </button>\n ))}\n </div>\n </div>\n {type === 'transcription' && (\n <p className=\"mt-2 text-xs text-muted-foreground\">\n Optional — biases spelling, vocabulary, and speaker names (not an instruction).\n </p>\n )}\n </div>\n )}\n\n {type === 'avatar' && (\n <AvatarComposer\n audioUrl={avatarAudioUrl}\n imageUrl={avatarImageUrl}\n avatarId={avatarId}\n onAudioUrlChange={setAvatarAudioUrl}\n onImageUrlChange={setAvatarImageUrl}\n onAvatarIdChange={setAvatarId}\n />\n )}\n {type === 'transcription' && (\n <TranscriptionComposer\n audioUrl={transcriptionAudioUrl}\n language={transcriptionLanguage}\n onAudioUrlChange={setTranscriptionAudioUrl}\n onLanguageChange={setTranscriptionLanguage}\n />\n )}\n\n <div className=\"mt-5 space-y-3\">\n <div className=\"space-y-1.5\">\n <Field label=\"Model\" htmlFor=\"studio-media-model\">\n <Select\n value={selectedModel || undefined}\n onValueChange={(value) => setSelectedModels((current) => ({ ...current, [type]: value }))}\n disabled={mediaModelsLoading || Boolean(mediaModelsError) || modelsForType.length === 0}\n >\n <SelectTrigger id=\"studio-media-model\" className=\"h-9 w-full bg-background\">\n {selectedModelOption ? (\n <span className=\"flex min-w-0 items-center gap-2\">\n {selectedModelOption.provider && (\n <ProviderLogo provider={selectedModelOption.provider} size={14} />\n )}\n <span className=\"truncate\">{selectedModelOption.name || selectedModelOption.id}</span>\n {selectedModelOption.provider && (\n <span className=\"shrink-0 text-muted-foreground\">· {selectedModelOption.provider}</span>\n )}\n {selectedModelOption.status !== 'available' && (\n <span className=\"shrink-0 rounded-full bg-warning/10 px-1.5 py-0.5 text-xs font-semibold uppercase tracking-[0.05em] text-warning\">\n {selectedModelOption.status}\n </span>\n )}\n </span>\n ) : (\n <SelectValue placeholder={mediaModelsLoading ? 'Loading models…' : 'Select a model'} />\n )}\n </SelectTrigger>\n <SelectContent className=\"bg-background\">\n {modelsForType.map((model) => (\n <SelectItem key={model.id} value={model.id} disabled={model.status === 'unavailable'}>\n <span className=\"flex w-full items-center justify-between gap-3\">\n <span className=\"flex min-w-0 items-center gap-2\">\n {model.provider && <ProviderLogo provider={model.provider} size={14} />}\n <span className=\"truncate\">\n {model.name || model.id}{model.provider ? ` · ${model.provider}` : ''}\n </span>\n </span>\n {model.status !== 'available' && (\n <span className=\"shrink-0 text-xs capitalize text-muted-foreground\">{model.status}</span>\n )}\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n {(mediaModelsError || modelMessage(selectedModelOption, mediaModelsLoading, modelsForType.length)) && (\n <p className={`text-xs ${mediaModelsError || selectedModelOption?.status === 'unavailable' ? 'text-destructive' : 'text-muted-foreground'}`}>\n {mediaModelsError ?? modelMessage(selectedModelOption, mediaModelsLoading, modelsForType.length)}\n </p>\n )}\n </div>\n {type === 'image' && (\n <ImageComposer\n size={size}\n quality={quality}\n imageCount={imageCount}\n onSizeChange={setSize}\n onQualityChange={setQuality}\n onImageCountChange={setImageCount}\n />\n )}\n {type === 'video' && (\n <VideoComposer\n duration={duration}\n resolution={resolution}\n aspectRatio={aspectRatio}\n referenceImageUrl={referenceImageUrl}\n onDurationChange={setDuration}\n onResolutionChange={setResolution}\n onAspectRatioChange={setAspectRatio}\n onReferenceImageUrlChange={setReferenceImageUrl}\n />\n )}\n {type === 'speech' && (\n <SpeechComposer voice={voice} onVoiceChange={setVoice} />\n )}\n </div>\n\n <div className=\"mt-4 space-y-2\">\n <ComposerDisclosure summary=\"Advanced options\">\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <Field label=\"Negative prompt\">\n <Textarea\n value={negativePrompt}\n onChange={(event) => setNegativePrompt(event.target.value)}\n rows={2}\n placeholder=\"Avoid artifacts, off-style composition...\"\n className=\"bg-background\"\n />\n </Field>\n <Field label=\"Save to\">\n <Input value={outputPath} onChange={(event) => setOutputPath(event.target.value)} className=\"bg-background\" />\n </Field>\n {type === 'transcription' && (\n <TranscriptionOptions\n responseFormat={transcriptionResponseFormat}\n temperature={transcriptionTemperature}\n onResponseFormatChange={setTranscriptionResponseFormat}\n onTemperatureChange={setTranscriptionTemperature}\n />\n )}\n </div>\n </ComposerDisclosure>\n\n <ComposerDisclosure\n summary={(\n <>\n Schedule a post\n {selectedConnectedDestinations.length > 0 && (\n <Badge variant=\"outline\" className=\"ml-1 text-xs\">\n {selectedConnectedDestinations.length}\n </Badge>\n )}\n </>\n )}\n >\n <PublishPackageComposer\n caption={caption}\n postDescription={postDescription}\n mentions={mentions}\n cadence={cadence}\n selectedDestinations={selectedDestinations}\n connections={integrations.connections}\n connectionError={integrations.error}\n connectionsLoading={integrations.isLoading}\n integrationsHref={integrationsHref}\n canManageIntegrations={canManageIntegrations}\n onCaptionChange={setCaption}\n onDescriptionChange={setPostDescription}\n onMentionsChange={setMentions}\n onCadenceChange={setCadence}\n onDestinationToggle={(destination) => {\n const destinationConfig = DESTINATIONS.find((item) => item.id === destination)\n if (!destinationConfig || !isDestinationConnected(destinationConfig, integrations.connections)) return\n setSelectedDestinations((current) => current.includes(destination)\n ? current.filter((item) => item !== destination)\n : [...current, destination])\n }}\n />\n </ComposerDisclosure>\n </div>\n\n {error && (\n <div className=\"mt-4 rounded-md border border-destructive/20 bg-destructive/10 p-3 text-sm text-destructive\">\n {error}\n </div>\n )}\n\n <Button\n onClick={generate}\n disabled={!canSubmit}\n size=\"lg\"\n className=\"mt-5 w-full disabled:bg-muted disabled:text-muted-foreground disabled:opacity-100\"\n >\n <Sparkles className=\"mr-2 h-4 w-4\" />\n Generate\n <span className=\"ml-2 text-xs opacity-60\">⌘↵</span>\n </Button>\n </section>\n )\n}\n","import { FileText, Image, Mic, User, Video } from 'lucide-react'\n\n/** Define configuration options for a type including label, icon, and color properties */\nexport interface TypeConfig {\n label: string\n icon: typeof Image\n color: string\n}\n\n/* Type badges sit on top of media thumbnails, where a per-type hue is\n illegible and off-token — every type gets the same neutral scrim chip\n (no backdrop-blur, so the thumbnail doesn't smear through). The type\n icon inside the badge carries the identity instead of a color. */\nconst MEDIA_SCRIM = 'bg-black/60 text-white border-white/10'\n\nconst IMAGE: TypeConfig = { label: 'Image', icon: Image, color: MEDIA_SCRIM }\n\n// string-keyed so list cards can index by Generation.type\n/** Map type keys to their corresponding configuration objects including labels, icons, and colors */\nexport const TYPE_CONFIG: Record<string, TypeConfig> = {\n image: IMAGE,\n video: { label: 'Video', icon: Video, color: MEDIA_SCRIM },\n avatar: { label: 'Avatar', icon: User, color: MEDIA_SCRIM },\n speech: { label: 'Audio', icon: Mic, color: MEDIA_SCRIM },\n transcription: { label: 'Transcript', icon: FileText, color: MEDIA_SCRIM },\n}\n\n// Safe lookup for an arbitrary `Generation.type` — always defined (the table is\n// declared `Record<string, …>`, so a raw index is `T | undefined`). Falls back\n// to the image config, matching the prior `?? TYPE_CONFIG.image` call sites.\n/** Resolve the configuration object for a given type or return the default image configuration */\nexport function typeConfigFor(type: string): TypeConfig {\n return TYPE_CONFIG[type] ?? IMAGE\n}\n","import type { ReactNode, SelectHTMLAttributes } from 'react'\nimport { Label } from '@tangle-network/sandbox-ui/primitives'\nimport { ChevronRight, Minus, Plus } from 'lucide-react'\n\nexport function Field({\n label,\n htmlFor,\n className = 'space-y-1.5',\n children,\n}: {\n label: string\n htmlFor?: string\n className?: string\n children: ReactNode\n}) {\n return (\n <div className={className}>\n <Label\n htmlFor={htmlFor}\n className=\"text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\"\n >\n {label}\n </Label>\n {children}\n </div>\n )\n}\n\nexport function Stepper({\n value,\n min,\n max,\n onChange,\n}: {\n value: number\n min: number\n max: number\n onChange: (value: number) => void\n}) {\n return (\n <div className=\"flex h-9 items-center justify-between rounded-md border border-input bg-background px-1.5\">\n <button\n type=\"button\"\n aria-label=\"Decrease\"\n onClick={() => onChange(Math.max(min, value - 1))}\n disabled={value <= min}\n className=\"flex h-6 w-6 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-40\"\n >\n <Minus className=\"h-3.5 w-3.5\" />\n </button>\n <span className=\"text-sm font-medium tabular-nums\">{value}</span>\n <button\n type=\"button\"\n aria-label=\"Increase\"\n onClick={() => onChange(Math.min(max, value + 1))}\n disabled={value >= max}\n className=\"flex h-6 w-6 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-40\"\n >\n <Plus className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n )\n}\n\nexport function ComposerDisclosure({ summary, children }: { summary: ReactNode; children: ReactNode }) {\n return (\n <details className=\"group rounded-lg border border-border bg-background transition-colors\">\n <summary className=\"flex cursor-pointer list-none items-center gap-1.5 px-3 py-2.5 text-xs font-medium text-foreground/80 transition-colors hover:text-foreground [&::-webkit-details-marker]:hidden\">\n <ChevronRight className=\"h-3.5 w-3.5 text-muted-foreground transition-transform group-open:rotate-90\" />\n {summary}\n </summary>\n <div className=\"border-t border-border px-3 py-3\">{children}</div>\n </details>\n )\n}\n\nexport function NativeSelect(props: SelectHTMLAttributes<HTMLSelectElement>) {\n return (\n <select {...props} className=\"h-9 w-full rounded-md border border-input bg-background px-3 text-sm\" />\n )\n}\n","import { Input } from '@tangle-network/sandbox-ui/primitives'\nimport {\n IMAGE_QUALITIES,\n IMAGE_SIZE_HINT,\n IMAGE_SIZE_PATTERN,\n MIN_IMAGE_COUNT,\n MAX_IMAGE_COUNT,\n normalizeImageCount,\n} from '../studio'\nimport { Field, NativeSelect, Stepper } from './composer-shell'\n\nexport function ImageComposer({\n size,\n quality,\n imageCount,\n onSizeChange,\n onQualityChange,\n onImageCountChange,\n}: {\n size: string\n quality: string\n imageCount: number\n onSizeChange: (value: string) => void\n onQualityChange: (value: string) => void\n onImageCountChange: (value: number) => void\n}) {\n return (\n <div className=\"space-y-3\">\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Size\">\n <Input\n value={size}\n onChange={(event) => onSizeChange(event.target.value)}\n pattern={IMAGE_SIZE_PATTERN}\n placeholder={IMAGE_SIZE_HINT}\n className=\"bg-background\"\n />\n </Field>\n <Field label=\"Quality\">\n <NativeSelect value={quality} onChange={(event) => onQualityChange(event.target.value)}>\n {IMAGE_QUALITIES.map((option) => (\n <option key={option} value={option}>{option.charAt(0).toUpperCase() + option.slice(1)}</option>\n ))}\n </NativeSelect>\n </Field>\n </div>\n <Field label=\"Images\">\n <Stepper\n value={imageCount}\n min={MIN_IMAGE_COUNT}\n max={MAX_IMAGE_COUNT}\n onChange={(value) => onImageCountChange(normalizeImageCount(value))}\n />\n </Field>\n </div>\n )\n}\n","import { Input } from '@tangle-network/sandbox-ui/primitives'\nimport { VIDEO_ASPECT_RATIOS, VIDEO_DURATIONS, VIDEO_RESOLUTIONS } from '../studio'\nimport { Field, NativeSelect } from './composer-shell'\n\nexport function VideoComposer({\n duration,\n resolution,\n aspectRatio,\n referenceImageUrl,\n onDurationChange,\n onResolutionChange,\n onAspectRatioChange,\n onReferenceImageUrlChange,\n}: {\n duration: string\n resolution: string\n aspectRatio: string\n referenceImageUrl: string\n onDurationChange: (value: string) => void\n onResolutionChange: (value: string) => void\n onAspectRatioChange: (value: string) => void\n onReferenceImageUrlChange: (value: string) => void\n}) {\n return (\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Duration (s)\">\n <NativeSelect value={duration} onChange={(event) => onDurationChange(event.target.value)}>\n {VIDEO_DURATIONS.map((option) => <option key={option} value={option}>{option}</option>)}\n </NativeSelect>\n </Field>\n <Field label=\"Resolution\">\n <NativeSelect value={resolution} onChange={(event) => onResolutionChange(event.target.value)}>\n {VIDEO_RESOLUTIONS.map((option) => <option key={option} value={option}>{option}</option>)}\n </NativeSelect>\n </Field>\n <Field label=\"Aspect ratio\">\n <NativeSelect value={aspectRatio} onChange={(event) => onAspectRatioChange(event.target.value)}>\n {VIDEO_ASPECT_RATIOS.map((option) => <option key={option} value={option}>{option}</option>)}\n </NativeSelect>\n </Field>\n <Field label=\"Reference image URL\"><Input value={referenceImageUrl} onChange={(event) => onReferenceImageUrlChange(event.target.value)} className=\"bg-background\" /></Field>\n </div>\n )\n}\n","import { Input } from '@tangle-network/sandbox-ui/primitives'\nimport { Field } from './composer-shell'\n\nexport function SpeechComposer({\n voice,\n onVoiceChange,\n}: {\n voice: string\n onVoiceChange: (value: string) => void\n}) {\n return (\n <Field label=\"Voice\"><Input value={voice} onChange={(event) => onVoiceChange(event.target.value)} className=\"bg-background\" /></Field>\n )\n}\n","import { Input } from '@tangle-network/sandbox-ui/primitives'\nimport { Field } from './composer-shell'\n\nexport function AvatarComposer({\n audioUrl,\n imageUrl,\n avatarId,\n onAudioUrlChange,\n onImageUrlChange,\n onAvatarIdChange,\n}: {\n audioUrl: string\n imageUrl: string\n avatarId: string\n onAudioUrlChange: (value: string) => void\n onImageUrlChange: (value: string) => void\n onAvatarIdChange: (value: string) => void\n}) {\n return (\n <div className=\"mt-4 grid gap-3 sm:grid-cols-2\">\n <Field label=\"Audio URL\" htmlFor=\"studio-audio-url\">\n <Input\n id=\"studio-audio-url\"\n value={audioUrl}\n onChange={(event) => onAudioUrlChange(event.target.value)}\n placeholder=\"https://cdn.example.com/source-audio.mp3\"\n className=\"bg-background\"\n />\n </Field>\n <Field label=\"Image URL\" htmlFor=\"studio-avatar-image-url\">\n <Input\n id=\"studio-avatar-image-url\"\n value={imageUrl}\n onChange={(event) => onImageUrlChange(event.target.value)}\n placeholder=\"https://cdn.example.com/portrait.png\"\n className=\"bg-background\"\n />\n </Field>\n <Field label=\"Avatar ID\" htmlFor=\"studio-avatar-id\">\n <Input\n id=\"studio-avatar-id\"\n value={avatarId}\n onChange={(event) => onAvatarIdChange(event.target.value)}\n placeholder=\"Optional provider avatar id\"\n className=\"bg-background\"\n />\n </Field>\n </div>\n )\n}\n","import { Input } from '@tangle-network/sandbox-ui/primitives'\nimport { Field, NativeSelect } from './composer-shell'\n\nexport function TranscriptionComposer({\n audioUrl,\n language,\n onAudioUrlChange,\n onLanguageChange,\n}: {\n audioUrl: string\n language: string\n onAudioUrlChange: (value: string) => void\n onLanguageChange: (value: string) => void\n}) {\n return (\n <div className=\"mt-4 grid gap-3 sm:grid-cols-2\">\n <Field label=\"Audio URL\" htmlFor=\"studio-audio-url\">\n <Input\n id=\"studio-audio-url\"\n value={audioUrl}\n onChange={(event) => onAudioUrlChange(event.target.value)}\n placeholder=\"https://cdn.example.com/source-audio.mp3\"\n className=\"bg-background\"\n />\n </Field>\n <Field label=\"Language\" htmlFor=\"studio-transcription-language\">\n <Input\n id=\"studio-transcription-language\"\n value={language}\n onChange={(event) => onLanguageChange(event.target.value)}\n placeholder=\"en\"\n className=\"bg-background\"\n />\n </Field>\n </div>\n )\n}\n\nexport function TranscriptionOptions({\n responseFormat,\n temperature,\n onResponseFormatChange,\n onTemperatureChange,\n}: {\n responseFormat: string\n temperature: string\n onResponseFormatChange: (value: string) => void\n onTemperatureChange: (value: string) => void\n}) {\n return (\n <>\n <Field label=\"Response format\">\n <NativeSelect value={responseFormat} onChange={(event) => onResponseFormatChange(event.target.value)}>\n <option value=\"json\">JSON</option>\n <option value=\"text\">Text</option>\n <option value=\"srt\">SRT</option>\n <option value=\"verbose_json\">Verbose JSON</option>\n <option value=\"vtt\">VTT</option>\n </NativeSelect>\n </Field>\n <Field label=\"Temperature\"><Input type=\"number\" min=\"0\" max=\"1\" step=\"0.1\" value={temperature} onChange={(event) => onTemperatureChange(event.target.value)} className=\"bg-background\" /></Field>\n </>\n )\n}\n","import { Link } from 'react-router'\nimport { Badge, Button, Input, Textarea } from '@tangle-network/sandbox-ui/primitives'\nimport { ProviderIcon, type IntegrationConnection } from '@tangle-network/sandbox-ui/integrations'\nimport { AlertTriangle, Check } from 'lucide-react'\nimport { CADENCES, DESTINATIONS, isDestinationConnected } from '../studio'\nimport { Field, NativeSelect } from './composer-shell'\n\nexport function PublishPackageComposer({\n caption,\n postDescription,\n mentions,\n cadence,\n selectedDestinations,\n connections,\n connectionError,\n connectionsLoading,\n integrationsHref,\n canManageIntegrations,\n onCaptionChange,\n onDescriptionChange,\n onMentionsChange,\n onCadenceChange,\n onDestinationToggle,\n}: {\n caption: string\n postDescription: string\n mentions: string\n cadence: string\n selectedDestinations: string[]\n connections: IntegrationConnection[]\n connectionError: Error | null\n connectionsLoading: boolean\n integrationsHref?: string\n canManageIntegrations: boolean\n onCaptionChange: (value: string) => void\n onDescriptionChange: (value: string) => void\n onMentionsChange: (value: string) => void\n onCadenceChange: (value: string) => void\n onDestinationToggle: (destination: string) => void\n}) {\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-3\">\n {connectionError ? (\n <div className=\"flex items-center gap-2 rounded-md border border-warning/25 bg-warning/10 px-2.5 py-1.5 text-xs text-warning\">\n <AlertTriangle className=\"h-3.5 w-3.5 shrink-0\" />\n Couldn't load connected apps. Check Integrations.\n </div>\n ) : (\n <p className=\"text-xs text-muted-foreground\">\n {connectionsLoading\n ? 'Checking connected apps…'\n : 'Saved with the generated asset.'}\n </p>\n )}\n {integrationsHref && canManageIntegrations && (\n <Link to={integrationsHref} prefetch=\"intent\" className=\"shrink-0\">\n <Button variant=\"outline\" size=\"sm\">Connect</Button>\n </Link>\n )}\n </div>\n <div className=\"grid gap-2\">\n {DESTINATIONS.map((destination) => {\n const connected = isDestinationConnected(destination, connections)\n const active = connected && selectedDestinations.includes(destination.id)\n return (\n <button\n key={destination.id}\n type=\"button\"\n disabled={!connected}\n aria-pressed={active}\n onClick={() => onDestinationToggle(destination.id)}\n className={`rounded-md border p-2 text-left transition-colors disabled:cursor-not-allowed disabled:opacity-60 ${\n active\n ? 'border-primary bg-primary/10 ring-1 ring-primary/20'\n : 'border-border bg-background hover:bg-accent'\n }`}\n >\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"flex items-center gap-1.5 text-xs font-medium text-foreground\">\n {active && <Check className=\"h-3.5 w-3.5 text-primary\" />}\n <ProviderIcon id={destination.providerIds[0] ?? destination.id} displayName={destination.label} size={16} className=\"rounded\" />\n {destination.label}\n </span>\n <Badge variant={active || connected ? 'default' : 'outline'}>{active ? 'Selected' : connected ? 'Ready' : 'Not connected'}</Badge>\n </div>\n <p className=\"mt-1 text-xs text-muted-foreground\">{destination.fields}</p>\n </button>\n )\n })}\n </div>\n <Field label=\"Caption\" className=\"space-y-2\">\n <Textarea value={caption} onChange={(event) => onCaptionChange(event.target.value)} rows={3} placeholder=\"Write or generate the caption for selected destinations...\" className=\"bg-background\" />\n </Field>\n <Field label=\"Description / CTA\" className=\"space-y-2\">\n <Textarea value={postDescription} onChange={(event) => onDescriptionChange(event.target.value)} rows={2} placeholder=\"Release note, product context, link, or approval instruction...\" className=\"bg-background\" />\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Mentions\" className=\"space-y-2\">\n <Input value={mentions} onChange={(event) => onMentionsChange(event.target.value)} placeholder=\"@creator, @partner\" className=\"bg-background\" />\n </Field>\n <Field label=\"Cadence\" className=\"space-y-2\">\n <NativeSelect value={cadence} onChange={(event) => onCadenceChange(event.target.value)}>\n {CADENCES.map((option) => <option key={option} value={option}>{option}</option>)}\n </NativeSelect>\n </Field>\n </div>\n </div>\n )\n}\n","import { Button } from '@tangle-network/sandbox-ui/primitives'\nimport { Images } from 'lucide-react'\n\nexport function StudioHeader({\n count,\n onOpenLibrary,\n canGenerate,\n}: {\n count: number\n onOpenLibrary: () => void\n canGenerate: boolean\n}) {\n return (\n <header className=\"sticky top-0 z-20 border-b border-border bg-card\">\n <div className=\"mx-auto flex w-full max-w-3xl items-center justify-between gap-3 px-4 py-3 sm:px-6\">\n <div className=\"min-w-0\">\n <h1 className=\"text-lg font-semibold tracking-tight text-foreground\">Studio</h1>\n <p className=\"truncate text-xs text-muted-foreground\">\n {canGenerate\n ? 'Generate images, video, voice, avatars, and transcripts.'\n : \"Browse your team's generations.\"}\n </p>\n </div>\n <Button size=\"sm\" variant=\"outline\" onClick={onOpenLibrary} className=\"shrink-0\">\n <Images className=\"mr-1.5 h-4 w-4\" />\n Library\n {count > 0 && (\n <span className=\"ml-2 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary/15 px-1.5 text-xs font-semibold text-primary\">\n {count}\n </span>\n )}\n </Button>\n </div>\n </header>\n )\n}\n","import { Badge } from '@tangle-network/sandbox-ui/primitives'\nimport { ArrowRight, Sparkles } from 'lucide-react'\nimport {\n type Generation,\n generationError,\n generationStatus,\n} from '../studio'\nimport { typeConfigFor } from './type-config'\n\nexport function ResultCanvas({\n batch,\n onOpenLibrary,\n onSelect,\n}: {\n batch: Generation[]\n onOpenLibrary: () => void\n onSelect: (generation: Generation) => void\n}) {\n const cardClass = 'rounded-xl border border-border bg-card shadow-sm'\n\n if (batch.length === 0) {\n return (\n <section className={`${cardClass} flex min-h-[180px] flex-col items-center justify-center gap-2 p-8 text-center`}>\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-muted\">\n <Sparkles className=\"h-6 w-6 text-muted-foreground/40\" />\n </div>\n <p className=\"text-sm font-medium text-foreground\">Your creations appear here</p>\n <p className=\"max-w-xs text-xs text-muted-foreground\">\n Generate above — results appear here and are saved to your library.\n </p>\n </section>\n )\n }\n\n const cfg = typeConfigFor(batch[0]?.type ?? 'image')\n const Icon = cfg.icon\n const statuses = batch.map(generationStatus)\n const runLabel = statuses.some((s) => s === 'pending' || s === 'running')\n ? 'Generating…'\n : statuses.every((s) => s === 'failed')\n ? 'Last run failed'\n : 'Latest creation'\n const isWorking = statuses.some((s) => s === 'pending' || s === 'running')\n\n return (\n <section className={`${cardClass} p-5`}>\n <div className=\"mb-3 flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"outline\" className={`${cfg.color} gap-1 text-xs`}>\n <Icon className=\"h-3 w-3\" />\n {cfg.label}\n </Badge>\n <span className=\"text-sm font-medium text-foreground\">{runLabel}</span>\n {isWorking && <span className=\"h-2 w-2 animate-pulse rounded-full bg-primary\" />}\n </div>\n <button\n type=\"button\"\n onClick={onOpenLibrary}\n className=\"flex items-center gap-1 text-xs font-medium text-primary transition-colors hover:text-primary/80\"\n >\n View in Library\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n\n <div className={`grid gap-3 ${batch.length === 1 ? 'grid-cols-1' : 'grid-cols-2'}`}>\n {batch.map((generation) => (\n <button\n key={generation.id}\n type=\"button\"\n onClick={() => onSelect(generation)}\n className=\"studio-bloom group relative aspect-video overflow-hidden rounded-lg border border-border bg-secondary transition-colors hover:border-primary/40\"\n >\n <CanvasTile generation={generation} />\n </button>\n ))}\n </div>\n\n {batch.length > 1 && !isWorking && (\n <p className=\"mt-2 text-xs text-muted-foreground\">{batch.length} results from this run</p>\n )}\n </section>\n )\n}\n\nfunction CanvasTile({ generation }: { generation: Generation }) {\n const cfg = typeConfigFor(generation.type)\n const Icon = cfg.icon\n const status = generationStatus(generation)\n\n if (status === 'pending' || status === 'running') {\n return <div className=\"studio-shimmer absolute inset-0 h-full w-full\" />\n }\n if (status === 'failed') {\n return (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center gap-2 p-4 text-center\">\n <Icon className=\"h-6 w-6 text-destructive/50\" />\n <p className=\"line-clamp-3 text-xs text-destructive\">{generationError(generation) ?? 'Generation failed'}</p>\n </div>\n )\n }\n if (generation.type === 'image' && generation.result) {\n return <img src={generation.result} alt={generation.prompt} className=\"absolute inset-0 h-full w-full object-contain\" />\n }\n if ((generation.type === 'video' || generation.type === 'avatar') && generation.result) {\n return <video src={generation.result} controls className=\"absolute inset-0 h-full w-full object-contain\" />\n }\n if (generation.type === 'speech' && generation.result) {\n return (\n <div className=\"absolute inset-0 flex items-center justify-center p-4\">\n <audio src={generation.result} controls className=\"w-full\" />\n </div>\n )\n }\n if (generation.type === 'transcription' && generation.result) {\n return (\n <div className=\"absolute inset-0 overflow-y-auto p-4\">\n <p className=\"whitespace-pre-wrap text-xs text-foreground\">{generation.result}</p>\n </div>\n )\n }\n return (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <Icon className=\"h-8 w-8 text-muted-foreground/20\" />\n </div>\n )\n}\n","import { useMemo } from 'react'\nimport { Link } from 'react-router'\nimport {\n Button,\n Tabs, TabsList, TabsTrigger,\n} from '@tangle-network/sandbox-ui/primitives'\nimport { ArrowLeft, DollarSign, FolderOpen, X } from 'lucide-react'\nimport { type Generation } from '../studio'\nimport { TYPE_CONFIG } from './type-config'\nimport { StudioSheet } from './studio-sheet'\nimport { GenerationGrid, filterGenerations } from './generation-grid'\nimport { GenerationDetail } from './generation-detail'\n\nexport function LibraryDrawer({\n open,\n onOpenChange,\n generations,\n totalCost,\n typeFilter,\n onFilterChange,\n vaultHref,\n selected,\n onSelect,\n}: {\n open: boolean\n onOpenChange: (open: boolean) => void\n generations: Generation[]\n totalCost: number\n typeFilter: string | null\n onFilterChange: (type: string | null) => void\n vaultHref?: (filePath?: string | null) => string\n selected: Generation | null\n onSelect: (generation: Generation | null) => void\n}) {\n const visible = useMemo(() => filterGenerations(generations, typeFilter), [generations, typeFilter])\n\n return (\n <StudioSheet open={open} onOpenChange={onOpenChange} title=\"Asset library\">\n <header className=\"flex shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-3\">\n {selected ? (\n <button\n type=\"button\"\n onClick={() => onSelect(null)}\n className=\"flex items-center gap-1.5 text-sm font-medium text-foreground transition-colors hover:text-primary\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n Back to library\n </button>\n ) : (\n <h2 className=\"text-sm font-semibold text-foreground\">Asset library</h2>\n )}\n <button\n type=\"button\"\n aria-label=\"Close library\"\n onClick={() => onOpenChange(false)}\n className=\"rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </header>\n\n {selected ? (\n <div className=\"flex-1 overflow-y-auto p-4\">\n <GenerationDetail\n generation={selected}\n vaultHref={vaultHref}\n onNavigate={() => onOpenChange(false)}\n />\n </div>\n ) : (\n <>\n <div className=\"shrink-0 border-b border-border px-4 pt-3\">\n <div className=\"mb-2 flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-3 text-xs text-muted-foreground\">\n <span>{visible.length} generation{visible.length !== 1 ? 's' : ''}</span>\n <span className=\"flex items-center gap-0.5\">\n <DollarSign className=\"h-3 w-3\" />\n {totalCost.toFixed(2)} spent\n </span>\n </div>\n {vaultHref && (\n <Link to={vaultHref()} prefetch=\"intent\" onClick={() => onOpenChange(false)}>\n <Button size=\"sm\" variant=\"outline\">\n <FolderOpen className=\"mr-1.5 h-3.5 w-3.5\" />\n Vault\n </Button>\n </Link>\n )}\n </div>\n <Tabs value={typeFilter ?? 'all'} onValueChange={(v) => onFilterChange(v === 'all' ? null : v)}>\n <TabsList className=\"h-9 w-full justify-start gap-1 overflow-x-auto bg-transparent\">\n <TabsTrigger value=\"all\" className=\"text-xs\">All</TabsTrigger>\n {Object.entries(TYPE_CONFIG).map(([key, cfg]) => (\n <TabsTrigger key={key} value={key} className=\"text-xs\">{cfg.label}</TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n </div>\n\n <div className=\"flex-1 overflow-y-auto p-4\">\n <GenerationGrid generations={visible} typeFilter={typeFilter} onSelect={onSelect} />\n </div>\n </>\n )}\n </StudioSheet>\n )\n}\n","import type { ReactNode } from 'react'\nimport * as Dialog from '@radix-ui/react-dialog'\n\n/**\n * Right-side overlay sheet built on Radix Dialog — gives focus-trap, scroll-lock,\n * and Escape-to-close for free. Slide/fade come from the studio-sheet-* classes in\n * ./studio.css (driven by Radix data-state), not tailwindcss-animate.\n */\nexport function StudioSheet({\n open,\n onOpenChange,\n title,\n children,\n}: {\n open: boolean\n onOpenChange: (open: boolean) => void\n title: string\n children: ReactNode\n}) {\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"studio-sheet-overlay fixed inset-0 z-50 bg-black/50\" />\n <Dialog.Content\n className=\"studio-sheet-content fixed inset-y-0 right-0 z-50 flex w-[min(92vw,30rem)] flex-col border-l border-card-edge bg-popover shadow-[var(--shadow-overlay)] focus:outline-none\"\n aria-describedby={undefined}\n >\n <Dialog.Title className=\"sr-only\">{title}</Dialog.Title>\n {children}\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n )\n}\n","import { EmptyState } from '@tangle-network/sandbox-ui/primitives'\nimport { Film, Sparkles } from 'lucide-react'\nimport { type Generation, isGenerationType } from '../studio'\nimport { TYPE_CONFIG } from './type-config'\nimport { GenerationCard } from './generation-card'\n\n/** The visible set for the active type tab (all generations when unfiltered). */\nexport function filterGenerations(generations: Generation[], typeFilter: string | null): Generation[] {\n if (!typeFilter || !isGenerationType(typeFilter)) return generations\n return generations.filter((generation) => generation.type === typeFilter)\n}\n\n/**\n * Chrome-less asset grid — the `GenerationCard` grid plus its empty state, with\n * no surrounding tabs/stats/sheet chrome. Composed by both the inline\n * `LibraryPanel` and the `LibraryDrawer`'s list view so the grid and its\n * empty-state copy stay in one place. `generations` is the already-filtered\n * visible set; `typeFilter` only tunes the empty-state message.\n */\nexport function GenerationGrid({\n generations,\n typeFilter,\n onSelect,\n}: {\n generations: Generation[]\n typeFilter: string | null\n onSelect: (generation: Generation) => void\n}) {\n if (generations.length === 0) {\n return (\n <EmptyState\n icon={typeFilter\n ? <Film className=\"h-8 w-8 text-muted-foreground/30\" />\n : <Sparkles className=\"h-10 w-10 text-muted-foreground/30\" />}\n title={typeFilter\n ? `No ${TYPE_CONFIG[typeFilter]?.label ?? typeFilter} generations`\n : 'No generations yet'}\n description={typeFilter\n ? 'Try a different filter or change the type in the composer.'\n : 'Everything you and the agent create lives here.'}\n className=\"py-16\"\n />\n )\n }\n return (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {generations.map((generation) => (\n <GenerationCard key={generation.id} generation={generation} onSelect={onSelect} />\n ))}\n </div>\n )\n}\n","import { Card, CardContent, Badge } from '@tangle-network/sandbox-ui/primitives'\nimport { Send } from 'lucide-react'\nimport {\n type Generation,\n DESTINATIONS,\n generationError,\n generationStatus,\n isPublishPackage,\n relativeTime,\n} from '../studio'\nimport { typeConfigFor } from './type-config'\n\nexport function GenerationCard({\n generation,\n onSelect,\n}: {\n generation: Generation\n onSelect: (generation: Generation) => void\n}) {\n const cfg = typeConfigFor(generation.type)\n const Icon = cfg.icon\n const status = generationStatus(generation)\n const publishPackage = generation.metadata?.publishPackage\n return (\n <button type=\"button\" onClick={() => onSelect(generation)} className=\"group text-left animate-row-in\">\n <Card className=\"overflow-hidden transition-all group-hover:border-primary/50 group-hover:shadow-md\">\n <div className=\"relative aspect-video bg-secondary\">\n {generation.type === 'image' && generation.result ? (\n <img src={generation.result} alt={generation.prompt} className=\"h-full w-full object-cover\" />\n ) : (generation.type === 'video' || generation.type === 'avatar') && generation.result ? (\n <video src={generation.result} className=\"h-full w-full object-cover\" muted />\n ) : generation.type === 'speech' && generation.result ? (\n <div className=\"flex h-full items-center justify-center\">\n <Icon className=\"h-6 w-6 text-muted-foreground/40\" />\n </div>\n ) : generation.type === 'transcription' && generation.result ? (\n <div className=\"flex h-full items-center justify-center p-4\">\n <p className=\"line-clamp-5 text-xs text-muted-foreground\">{generation.result}</p>\n </div>\n ) : status === 'pending' || status === 'running' ? (\n <div className=\"shimmer h-full w-full\" />\n ) : (\n <div className=\"flex h-full items-center justify-center\">\n <Icon className=\"h-8 w-8 text-muted-foreground/20\" />\n </div>\n )}\n <div className=\"absolute left-2 top-2\">\n <Badge variant=\"outline\" className={`${cfg.color} gap-1 text-xs`}>\n <Icon className=\"h-3 w-3\" />\n {cfg.label}\n </Badge>\n </div>\n <GenerationStatusBadge generation={generation} />\n </div>\n <CardContent className=\"p-3\">\n <p className=\"mb-2 line-clamp-2 text-sm font-medium text-foreground\">{generation.prompt}</p>\n {status === 'failed' && (\n <p className=\"mb-2 line-clamp-2 text-xs text-destructive\">{generationError(generation)}</p>\n )}\n <div className=\"flex items-center justify-between\">\n {generation.model && (\n <span className=\"truncate text-xs text-muted-foreground\">{generation.model}</span>\n )}\n <div className=\"flex shrink-0 items-center gap-2\">\n {generation.cost != null && (\n <span className=\"text-xs text-muted-foreground\">${generation.cost.toFixed(3)}</span>\n )}\n <span className=\"text-xs text-muted-foreground\">{relativeTime(generation.createdAt)}</span>\n </div>\n </div>\n {isPublishPackage(publishPackage) && (\n <div className=\"mt-3 rounded-md border border-border bg-secondary p-2\">\n <div className=\"mb-1 flex items-center gap-1.5 text-xs font-medium text-foreground\">\n <Send className=\"h-3 w-3\" />\n {(publishPackage.destinations ?? [])\n .map((id) => DESTINATIONS.find((destination) => destination.id === id)?.label ?? id)\n .join(', ') || 'Publish package'}\n </div>\n <p className=\"line-clamp-2 text-xs text-muted-foreground\">\n {publishPackage.caption || 'Caption pending'}\n </p>\n </div>\n )}\n </CardContent>\n </Card>\n </button>\n )\n}\n\nexport function GenerationStatusBadge({\n generation,\n inline = false,\n}: {\n generation: Generation\n inline?: boolean\n}) {\n const status = generationStatus(generation)\n if (status === 'succeeded') return null\n\n const label = status === 'failed' ? 'Failed' : status === 'running' ? 'Running' : 'Pending'\n // Solid tint mixed onto the card surface — the badge floats over media, so an\n // alpha fill would let the thumbnail bleed through.\n const className = status === 'failed'\n ? 'border-destructive/30 bg-[color-mix(in_srgb,hsl(var(--destructive))_10%,hsl(var(--card)))] text-destructive'\n : 'border-warning/30 bg-[color-mix(in_srgb,hsl(var(--warning))_10%,hsl(var(--card)))] text-warning'\n\n return (\n <div className={inline ? '' : 'absolute bottom-2 left-2'}>\n <Badge variant=\"outline\" className={`${className} text-xs`}>\n {label}\n </Badge>\n </div>\n )\n}\n","import { Link } from 'react-router'\nimport { Badge, Button } from '@tangle-network/sandbox-ui/primitives'\nimport { FolderOpen } from 'lucide-react'\nimport {\n type Generation,\n generationError,\n generationVaultPath,\n} from '../studio'\nimport { typeConfigFor } from './type-config'\nimport { GenerationStatusBadge } from './generation-card'\n\nexport function GenerationDetail({\n generation,\n vaultHref,\n onNavigate,\n}: {\n generation: Generation\n vaultHref?: (filePath?: string | null) => string\n onNavigate?: () => void\n}) {\n const cfg = typeConfigFor(generation.type)\n const Icon = cfg.icon\n // Only offer the vault link when the generation actually persisted a file.\n // generationVaultPath is null for failed/pending/running and storage-failed\n // generations; without this guard vaultHref(null) falls back to the vault\n // root, rendering a button that opens nothing relevant.\n const vaultPath = generationVaultPath(generation)\n const href = vaultHref && vaultPath ? vaultHref(vaultPath) : null\n\n return (\n <div className=\"space-y-4\">\n <div className=\"overflow-hidden rounded-lg bg-secondary\">\n {generation.type === 'image' && generation.result ? (\n <img src={generation.result} alt={generation.prompt} className=\"max-h-[420px] w-full object-contain\" />\n ) : (generation.type === 'video' || generation.type === 'avatar') && generation.result ? (\n <video src={generation.result} controls className=\"max-h-[420px] w-full\" />\n ) : generation.type === 'speech' && generation.result ? (\n <div className=\"p-6\">\n <audio src={generation.result} controls className=\"w-full\" />\n </div>\n ) : (\n <div className=\"flex h-32 items-center justify-center\">\n <Icon className=\"h-8 w-8 text-muted-foreground/20\" />\n </div>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"outline\" className={`${cfg.color} gap-1`}>\n <Icon className=\"h-3 w-3\" />\n {cfg.label}\n </Badge>\n <GenerationStatusBadge generation={generation} inline />\n {generationError(generation) && (\n <span className=\"text-xs text-destructive\">{generationError(generation)}</span>\n )}\n </div>\n\n <div>\n <span className=\"mb-1 block text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\">Prompt</span>\n <p className=\"text-sm text-foreground\">{generation.prompt}</p>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-4\">\n {generation.model && (\n <div>\n <span className=\"block text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\">Model</span>\n <span className=\"text-xs text-foreground\">{generation.model}</span>\n </div>\n )}\n {generation.cost != null && (\n <div>\n <span className=\"block text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\">Cost</span>\n <span className=\"text-xs text-foreground\">${generation.cost.toFixed(3)}</span>\n </div>\n )}\n {generation.createdAt && (\n <div>\n <span className=\"block text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\">Created</span>\n <span className=\"text-xs text-foreground\">\n {new Date(generation.createdAt).toLocaleString('en-US', { dateStyle: 'medium', timeStyle: 'short' })}\n </span>\n </div>\n )}\n </div>\n\n {generation.type === 'transcription' && generation.result && (\n <div>\n <span className=\"mb-1 block text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\">Transcription</span>\n <pre className=\"max-h-64 overflow-y-auto whitespace-pre-wrap rounded-lg bg-secondary p-4 font-mono text-[13px] tabular-nums text-foreground\">\n {generation.result}\n </pre>\n </div>\n )}\n\n {href && (\n <div className=\"border-t border-border pt-2\">\n <Link to={href} prefetch=\"intent\" onClick={onNavigate}>\n <Button size=\"sm\" variant=\"outline\">\n <FolderOpen className=\"mr-1.5 h-3.5 w-3.5\" />\n Open in Vault\n </Button>\n </Link>\n </div>\n )}\n </div>\n )\n}\n","import { useMemo } from 'react'\nimport {\n Tabs, TabsList, TabsTrigger,\n} from '@tangle-network/sandbox-ui/primitives'\nimport { DollarSign } from 'lucide-react'\nimport { type Generation } from '../studio'\nimport { TYPE_CONFIG } from './type-config'\nimport { GenerationGrid, filterGenerations } from './generation-grid'\n\n/**\n * Inline asset gallery — the same filter + stats + card grid as the library\n * drawer's list view, but with no sheet chrome so it can sit on the page beside\n * the composer. In-flight generations need no special handling: they arrive at\n * the front of `generations` (via `useStudioGenerations.mergedGenerations`) and\n * `GenerationCard` renders their `pending`/`running` shimmer.\n */\nexport function LibraryPanel({\n generations,\n totalCost,\n typeFilter,\n onFilterChange,\n onSelect,\n}: {\n generations: Generation[]\n totalCost: number\n typeFilter: string | null\n onFilterChange: (type: string | null) => void\n onSelect: (generation: Generation) => void\n}) {\n const visible = useMemo(() => filterGenerations(generations, typeFilter), [generations, typeFilter])\n\n return (\n <div className=\"flex min-w-0 flex-col\">\n <div className=\"mb-4 flex flex-wrap items-center justify-between gap-3\">\n <Tabs value={typeFilter ?? 'all'} onValueChange={(v) => onFilterChange(v === 'all' ? null : v)}>\n <TabsList className=\"h-9 justify-start gap-1 overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-background p-1\">\n <TabsTrigger\n value=\"all\"\n className=\"rounded-md px-3 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground data-[state=active]:bg-primary/10 data-[state=active]:font-semibold data-[state=active]:text-primary data-[state=active]:shadow-none\"\n >\n All\n </TabsTrigger>\n {Object.entries(TYPE_CONFIG).map(([key, cfg]) => (\n <TabsTrigger\n key={key}\n value={key}\n className=\"rounded-md px-3 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground data-[state=active]:bg-primary/10 data-[state=active]:font-semibold data-[state=active]:text-primary data-[state=active]:shadow-none\"\n >\n {cfg.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n <div className=\"flex items-center gap-3 text-xs text-muted-foreground\">\n <span>{visible.length} generation{visible.length !== 1 ? 's' : ''}</span>\n <span className=\"flex items-center gap-0.5\">\n <DollarSign className=\"h-3 w-3\" />\n {totalCost.toFixed(2)} spent\n </span>\n </div>\n </div>\n\n <GenerationGrid generations={visible} typeFilter={typeFilter} onSelect={onSelect} />\n </div>\n )\n}\n","import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@tangle-network/sandbox-ui/primitives'\nimport { type Generation } from '../studio'\nimport { typeConfigFor } from './type-config'\nimport { GenerationDetail } from './generation-detail'\n\n/**\n * Centered detail view for a single generation. Opens when `generation` is set\n * and reports dismissal through `onClose`. GenerationDetail renders the media,\n * type badge, prompt and metadata; the dialog title carries the a11y label.\n */\nexport function GenerationDetailModal({\n generation,\n vaultHref,\n onClose,\n}: {\n generation: Generation | null\n vaultHref?: (filePath?: string | null) => string\n onClose: () => void\n}) {\n const cfg = generation ? typeConfigFor(generation.type) : null\n return (\n <Dialog open={generation != null} onOpenChange={(open) => { if (!open) onClose() }}>\n <DialogContent className=\"max-h-[85vh] max-w-2xl overflow-y-auto border-card-edge bg-popover shadow-[var(--shadow-overlay)]\">\n <DialogHeader>\n <DialogTitle className=\"text-left text-[15px] font-semibold\">{cfg ? `${cfg.label} generation` : 'Generation'}</DialogTitle>\n </DialogHeader>\n {generation && (\n <GenerationDetail generation={generation} vaultHref={vaultHref} onNavigate={onClose} />\n )}\n </DialogContent>\n </Dialog>\n )\n}\n"],"mappings":"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","names":["useRef","useState","Button","Images","useEffect","useMemo","useRef","useState","Badge","Button","Input","Label","Textarea","jsx","jsxs","Input","jsx","jsxs","Input","Input","jsx","Input","Input","jsx","jsxs","Input","Input","jsx","jsxs","Input","Input","jsx","jsxs","Input","Fragment","jsx","jsxs","useState","useRef","useMemo","useEffect","Label","Textarea","Input","Badge","Button","Button","jsx","jsxs","Badge","Sparkles","jsx","jsxs","Sparkles","Badge","useMemo","Link","Button","FolderOpen","jsx","jsxs","Sparkles","Badge","jsx","jsxs","Badge","jsx","Sparkles","Link","Badge","Button","jsx","jsxs","Badge","Link","Button","Fragment","jsx","jsxs","useMemo","Link","Button","FolderOpen","Fragment","jsx","jsxs","useState","useRef","Images","Button","useMemo","Tabs","TabsList","TabsTrigger","DollarSign","jsx","jsxs","useMemo","Tabs","TabsList","TabsTrigger","DollarSign","Dialog","jsx","jsxs","Dialog"]}
|
|
1
|
+
{"version":3,"sources":["../../src/studio-react/studio-workspace.tsx","../../src/studio-react/use-studio-generations.ts","../../src/studio-react/studio-composer.tsx","../../src/studio-react/composer-option-controls.tsx","../../src/studio-react/studio-header.tsx","../../src/studio-react/result-canvas.tsx","../../src/studio-react/type-config.ts","../../src/studio-react/library-drawer.tsx","../../src/studio-react/studio-sheet.tsx","../../src/studio-react/generation-grid.tsx","../../src/studio-react/generation-card.tsx","../../src/studio-react/generation-detail.tsx","../../src/studio-react/generation-notice.tsx","../../src/studio-react/library-panel.tsx","../../src/studio-react/generation-detail-modal.tsx"],"sourcesContent":["import { useRef, useState } from 'react'\nimport { useSearchParams } from 'react-router'\nimport { Button } from '@tangle-network/sandbox-ui/primitives'\nimport { Images } from 'lucide-react'\nimport type { Generation } from '../studio'\nimport { useStudioGenerations } from './use-studio-generations'\nimport { StudioComposer } from './studio-composer'\nimport { StudioHeader } from './studio-header'\nimport { ResultCanvas } from './result-canvas'\nimport { LibraryDrawer } from './library-drawer'\n\nexport type StudioRole = 'owner' | 'admin' | 'editor' | 'viewer'\n\nexport interface StudioWorkspaceProps {\n generations: Generation[]\n totalCost: number\n workspaceId?: string\n role: StudioRole\n /** Polling endpoint override (default `/api/generations`). */\n generationsEndpoint?: string\n /** Build a vault link, optionally to a specific file. Defaults to `/app/<workspaceId>/vault`. */\n vaultHref?: (filePath?: string | null) => string\n}\n\n/**\n * The full studio surface: header + composer + result canvas + library drawer,\n * with the generation orchestrator (merge/poll/revalidate) wired in. The host\n * route owns the loader (auth, RBAC, the generation query) and the server\n * endpoints (`/api/generate`, `/api/media-models`, `/api/generations`); this\n * shell renders that data and drives the live UI. Role gates the composer\n * (viewers get a read-only library).\n */\nexport function StudioWorkspace({\n generations,\n totalCost,\n workspaceId,\n role,\n generationsEndpoint,\n vaultHref,\n}: StudioWorkspaceProps) {\n const [searchParams, setSearchParams] = useSearchParams()\n const typeFilter = searchParams.get('type')\n const [drawerOpen, setDrawerOpen] = useState(false)\n const [selected, setSelected] = useState<Generation | null>(null)\n const canvasRef = useRef<HTMLDivElement>(null)\n const canGenerate = role !== 'viewer'\n // Default vault navigation to the conventional /app/<workspaceId>/… route;\n // a host on a different route scheme passes its own builder.\n const resolvedVaultHref = vaultHref ?? (workspaceId\n ? (filePath?: string | null) => (filePath\n ? `/app/${workspaceId}/vault?file=${encodeURIComponent(filePath)}`\n : `/app/${workspaceId}/vault`)\n : undefined)\n\n const { mergedGenerations, latestBatch, onGenerated } = useStudioGenerations(generations, {\n workspaceId,\n generationsEndpoint,\n })\n\n function setFilter(type: string | null) {\n if (type) setSearchParams({ type })\n else setSearchParams({})\n }\n\n function openLibrary() {\n setSelected(null)\n setDrawerOpen(true)\n }\n\n function openDetail(generation: Generation) {\n setSelected(generation)\n setDrawerOpen(true)\n }\n\n return (\n <div className=\"min-h-0 flex-1 overflow-y-auto bg-background\">\n <StudioHeader\n count={mergedGenerations.length}\n canGenerate={canGenerate}\n onOpenLibrary={openLibrary}\n />\n\n <div className=\"mx-auto w-full max-w-3xl space-y-4 px-4 py-6 sm:px-6\">\n {canGenerate ? (\n <>\n <StudioComposer\n workspaceId={workspaceId}\n onGenerated={(generation) => {\n onGenerated(generation)\n requestAnimationFrame(() => {\n canvasRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' })\n })\n }}\n />\n <div ref={canvasRef}>\n <ResultCanvas\n batch={latestBatch}\n onOpenLibrary={openLibrary}\n onSelect={openDetail}\n />\n </div>\n </>\n ) : (\n <section className=\"flex flex-col items-center justify-center gap-3 rounded-xl border border-border bg-card p-10 text-center shadow-sm\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-muted\">\n <Images className=\"h-6 w-6 text-muted-foreground/40\" />\n </div>\n <p className=\"text-sm font-medium text-foreground\">\n {mergedGenerations.length > 0\n ? `${mergedGenerations.length} asset${mergedGenerations.length !== 1 ? 's' : ''} in this workspace`\n : 'No generations yet'}\n </p>\n <p className=\"max-w-sm text-xs text-muted-foreground\">\n Team generations appear in the library.\n </p>\n <Button size=\"sm\" variant=\"outline\" onClick={openLibrary}>\n <Images className=\"mr-1.5 h-4 w-4\" />\n Open library\n </Button>\n </section>\n )}\n </div>\n\n <LibraryDrawer\n open={drawerOpen}\n onOpenChange={(open) => { setDrawerOpen(open); if (!open) setSelected(null) }}\n generations={mergedGenerations}\n totalCost={totalCost}\n typeFilter={typeFilter}\n onFilterChange={setFilter}\n vaultHref={resolvedVaultHref}\n selected={selected}\n onSelect={(generation) => { setSelected(generation); if (generation) setDrawerOpen(true) }}\n />\n </div>\n )\n}\n","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 { AudioLines, ArrowUp, Image as ImageIcon, Video } from 'lucide-react'\nimport {\n type Generation,\n type MediaModelCatalogResponse,\n type MediaModelOption,\n type ModelOptionMetadata,\n type ModelOptionValue,\n type ModelOptionsMetadata,\n buildGenerationRequestBody,\n curateComposerModels,\n failedOptimisticGeneration,\n imageToVideoSibling,\n modelMessage,\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\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)) 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 and available 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 && model.status !== 'unavailable')\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 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 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) {\n if (!catalogLoading) setError('Select an available model')\n return\n }\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 type,\n prompt: promptText,\n model: modelId,\n clientRequestId,\n outputIndex: type === 'image' ? outputIndex : undefined,\n outputCount: type === 'image' ? imageCount : undefined,\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 statusMessage = unlistedSibling\n ? null\n : modelMessage(modelOption, catalogLoading, curatedModels.length)\n const notice = catalogError ?? error ?? statusMessage\n const noticeIsProblem = Boolean(catalogError || error || modelOption?.status === 'unavailable')\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 <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 <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 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 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] ${noticeIsProblem ? 'text-destructive' : 'text-muted-foreground'}`}>\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 ReactNode,\n type RefObject,\n} from 'react'\nimport { ImagePlus, 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'\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}\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}: {\n label: string\n value: ModelOptionValue | undefined\n choices: readonly OptionChoice[]\n onSelect: (value: ModelOptionValue) => void\n bandRef: RefObject<HTMLDivElement | null>\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 <span>{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 {choices.map((choice) => (\n <button\n key={String(choice.value)}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={choice.value === value}\n onClick={() => {\n onSelect(choice.value)\n close()\n }}\n className={menuRowClass(choice.value === value)}\n >\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 {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>{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>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>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 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 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}`}\n onClick={() => setOpen(!open)}\n className={PILL}\n >\n {provider && <ProviderLogo provider={provider} size={14} />}\n <span className=\"max-w-[168px] truncate\">{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 disabled={model.status === 'unavailable'}\n onClick={() => {\n onSelect(model.id)\n setOpen(false)\n }}\n className={`${menuRowClass(model.id === value)} disabled:opacity-50`}\n >\n {model.provider && <ProviderLogo provider={model.provider} size={14} />}\n <span className=\"truncate\">{model.name || model.id}</span>\n {model.status !== 'available' && (\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 { Button } from '@tangle-network/sandbox-ui/primitives'\nimport { Images } from 'lucide-react'\n\nexport function StudioHeader({\n count,\n onOpenLibrary,\n canGenerate,\n}: {\n count: number\n onOpenLibrary: () => void\n canGenerate: boolean\n}) {\n return (\n <header className=\"sticky top-0 z-20 border-b border-border bg-card\">\n <div className=\"mx-auto flex w-full max-w-3xl items-center justify-between gap-3 px-4 py-3 sm:px-6\">\n <div className=\"min-w-0\">\n <h1 className=\"text-lg font-semibold tracking-tight text-foreground\">Studio</h1>\n <p className=\"truncate text-xs text-muted-foreground\">\n {canGenerate\n ? 'Generate images, video, voice, avatars, and transcripts.'\n : \"Browse your team's generations.\"}\n </p>\n </div>\n <Button size=\"sm\" variant=\"outline\" onClick={onOpenLibrary} className=\"shrink-0\">\n <Images className=\"mr-1.5 h-4 w-4\" />\n Library\n {count > 0 && (\n <span className=\"ml-2 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary/15 px-1.5 text-xs font-semibold text-primary\">\n {count}\n </span>\n )}\n </Button>\n </div>\n </header>\n )\n}\n","import { Badge } from '@tangle-network/sandbox-ui/primitives'\nimport { ArrowRight, Sparkles } from 'lucide-react'\nimport {\n type Generation,\n generationError,\n generationStatus,\n} from '../studio'\nimport { typeConfigFor } from './type-config'\n\nexport function ResultCanvas({\n batch,\n onOpenLibrary,\n onSelect,\n}: {\n batch: Generation[]\n onOpenLibrary: () => void\n onSelect: (generation: Generation) => void\n}) {\n const cardClass = 'rounded-xl border border-border bg-card shadow-sm'\n\n if (batch.length === 0) {\n return (\n <section className={`${cardClass} flex min-h-[180px] flex-col items-center justify-center gap-2 p-8 text-center`}>\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-muted\">\n <Sparkles className=\"h-6 w-6 text-muted-foreground/40\" />\n </div>\n <p className=\"text-sm font-medium text-foreground\">Your creations appear here</p>\n <p className=\"max-w-xs text-xs text-muted-foreground\">\n Generate above — results appear here and are saved to your library.\n </p>\n </section>\n )\n }\n\n const cfg = typeConfigFor(batch[0]?.type ?? 'image')\n const Icon = cfg.icon\n const statuses = batch.map(generationStatus)\n const runLabel = statuses.some((s) => s === 'pending' || s === 'running')\n ? 'Generating…'\n : statuses.every((s) => s === 'failed')\n ? 'Last run failed'\n : 'Latest creation'\n const isWorking = statuses.some((s) => s === 'pending' || s === 'running')\n\n return (\n <section className={`${cardClass} p-5`}>\n <div className=\"mb-3 flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"outline\" className={`${cfg.color} gap-1 text-xs`}>\n <Icon className=\"h-3 w-3\" />\n {cfg.label}\n </Badge>\n <span className=\"text-sm font-medium text-foreground\">{runLabel}</span>\n {isWorking && <span className=\"h-2 w-2 animate-pulse rounded-full bg-primary\" />}\n </div>\n <button\n type=\"button\"\n onClick={onOpenLibrary}\n className=\"flex items-center gap-1 text-xs font-medium text-primary transition-colors hover:text-primary/80\"\n >\n View in Library\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n\n <div className={`grid gap-3 ${batch.length === 1 ? 'grid-cols-1' : 'grid-cols-2'}`}>\n {batch.map((generation) => (\n <button\n key={generation.id}\n type=\"button\"\n onClick={() => onSelect(generation)}\n className=\"studio-bloom group relative aspect-video overflow-hidden rounded-lg border border-border bg-secondary transition-colors hover:border-primary/40\"\n >\n <CanvasTile generation={generation} />\n </button>\n ))}\n </div>\n\n {batch.length > 1 && !isWorking && (\n <p className=\"mt-2 text-xs text-muted-foreground\">{batch.length} results from this run</p>\n )}\n </section>\n )\n}\n\nfunction CanvasTile({ generation }: { generation: Generation }) {\n const cfg = typeConfigFor(generation.type)\n const Icon = cfg.icon\n const status = generationStatus(generation)\n\n if (status === 'pending' || status === 'running') {\n return <div className=\"studio-shimmer absolute inset-0 h-full w-full\" />\n }\n if (status === 'failed') {\n return (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center gap-2 p-4 text-center\">\n <Icon className=\"h-6 w-6 text-destructive/50\" />\n <p className=\"line-clamp-3 text-xs text-destructive\">{generationError(generation) ?? 'Generation failed'}</p>\n </div>\n )\n }\n if (generation.type === 'image' && generation.result) {\n return <img src={generation.result} alt={generation.prompt} className=\"absolute inset-0 h-full w-full object-contain\" />\n }\n if ((generation.type === 'video' || generation.type === 'avatar') && generation.result) {\n return <video src={generation.result} controls className=\"absolute inset-0 h-full w-full object-contain\" />\n }\n if (generation.type === 'speech' && generation.result) {\n return (\n <div className=\"absolute inset-0 flex items-center justify-center p-4\">\n <audio src={generation.result} controls className=\"w-full\" />\n </div>\n )\n }\n if (generation.type === 'transcription' && generation.result) {\n return (\n <div className=\"absolute inset-0 overflow-y-auto p-4\">\n <p className=\"whitespace-pre-wrap text-xs text-foreground\">{generation.result}</p>\n </div>\n )\n }\n return (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <Icon className=\"h-8 w-8 text-muted-foreground/20\" />\n </div>\n )\n}\n","import { FileText, Image, Mic, User, Video } from 'lucide-react'\n\n/** Define configuration options for a type including label, icon, and color properties */\nexport interface TypeConfig {\n label: string\n icon: typeof Image\n color: string\n}\n\n/* Type badges sit on top of media thumbnails, where a per-type hue is\n illegible and off-token — every type gets the same neutral scrim chip\n (no backdrop-blur, so the thumbnail doesn't smear through). The type\n icon inside the badge carries the identity instead of a color. */\nconst MEDIA_SCRIM = 'bg-black/60 text-white border-white/10'\n\nconst IMAGE: TypeConfig = { label: 'Image', icon: Image, color: MEDIA_SCRIM }\n\n// string-keyed so list cards can index by Generation.type\n/** Map type keys to their corresponding configuration objects including labels, icons, and colors */\nexport const TYPE_CONFIG: Record<string, TypeConfig> = {\n image: IMAGE,\n video: { label: 'Video', icon: Video, color: MEDIA_SCRIM },\n avatar: { label: 'Avatar', icon: User, color: MEDIA_SCRIM },\n speech: { label: 'Audio', icon: Mic, color: MEDIA_SCRIM },\n transcription: { label: 'Transcript', icon: FileText, color: MEDIA_SCRIM },\n}\n\n// Safe lookup for an arbitrary `Generation.type` — always defined (the table is\n// declared `Record<string, …>`, so a raw index is `T | undefined`). Falls back\n// to the image config, matching the prior `?? TYPE_CONFIG.image` call sites.\n/** Resolve the configuration object for a given type or return the default image configuration */\nexport function typeConfigFor(type: string): TypeConfig {\n return TYPE_CONFIG[type] ?? IMAGE\n}\n","import { useMemo } from 'react'\nimport { Link } from 'react-router'\nimport {\n Button,\n Tabs, TabsList, TabsTrigger,\n} from '@tangle-network/sandbox-ui/primitives'\nimport { ArrowLeft, DollarSign, FolderOpen, X } from 'lucide-react'\nimport { type Generation } from '../studio'\nimport { TYPE_CONFIG } from './type-config'\nimport { StudioSheet } from './studio-sheet'\nimport { GenerationGrid, filterGenerations } from './generation-grid'\nimport { GenerationDetail } from './generation-detail'\n\nexport function LibraryDrawer({\n open,\n onOpenChange,\n generations,\n totalCost,\n typeFilter,\n onFilterChange,\n vaultHref,\n selected,\n onSelect,\n}: {\n open: boolean\n onOpenChange: (open: boolean) => void\n generations: Generation[]\n totalCost: number\n typeFilter: string | null\n onFilterChange: (type: string | null) => void\n vaultHref?: (filePath?: string | null) => string\n selected: Generation | null\n onSelect: (generation: Generation | null) => void\n}) {\n const visible = useMemo(() => filterGenerations(generations, typeFilter), [generations, typeFilter])\n\n return (\n <StudioSheet open={open} onOpenChange={onOpenChange} title=\"Asset library\">\n <header className=\"flex shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-3\">\n {selected ? (\n <button\n type=\"button\"\n onClick={() => onSelect(null)}\n className=\"flex items-center gap-1.5 text-sm font-medium text-foreground transition-colors hover:text-primary\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n Back to library\n </button>\n ) : (\n <h2 className=\"text-sm font-semibold text-foreground\">Asset library</h2>\n )}\n <button\n type=\"button\"\n aria-label=\"Close library\"\n onClick={() => onOpenChange(false)}\n className=\"rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </header>\n\n {selected ? (\n <div className=\"flex-1 overflow-y-auto p-4\">\n <GenerationDetail\n generation={selected}\n vaultHref={vaultHref}\n onNavigate={() => onOpenChange(false)}\n />\n </div>\n ) : (\n <>\n <div className=\"shrink-0 border-b border-border px-4 pt-3\">\n <div className=\"mb-2 flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-3 text-xs text-muted-foreground\">\n <span>{visible.length} generation{visible.length !== 1 ? 's' : ''}</span>\n <span className=\"flex items-center gap-0.5\">\n <DollarSign className=\"h-3 w-3\" />\n {totalCost.toFixed(2)} spent\n </span>\n </div>\n {vaultHref && (\n <Link to={vaultHref()} prefetch=\"intent\" onClick={() => onOpenChange(false)}>\n <Button size=\"sm\" variant=\"outline\">\n <FolderOpen className=\"mr-1.5 h-3.5 w-3.5\" />\n Vault\n </Button>\n </Link>\n )}\n </div>\n <Tabs value={typeFilter ?? 'all'} onValueChange={(v) => onFilterChange(v === 'all' ? null : v)}>\n <TabsList className=\"h-9 w-full justify-start gap-1 overflow-x-auto bg-transparent\">\n <TabsTrigger value=\"all\" className=\"text-xs\">All</TabsTrigger>\n {Object.entries(TYPE_CONFIG).map(([key, cfg]) => (\n <TabsTrigger key={key} value={key} className=\"text-xs\">{cfg.label}</TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n </div>\n\n <div className=\"flex-1 overflow-y-auto p-4\">\n <GenerationGrid generations={visible} typeFilter={typeFilter} onSelect={onSelect} />\n </div>\n </>\n )}\n </StudioSheet>\n )\n}\n","import type { ReactNode } from 'react'\nimport * as Dialog from '@radix-ui/react-dialog'\n\n/**\n * Right-side overlay sheet built on Radix Dialog — gives focus-trap, scroll-lock,\n * and Escape-to-close for free. Slide/fade come from the studio-sheet-* classes in\n * ./studio.css (driven by Radix data-state), not tailwindcss-animate.\n */\nexport function StudioSheet({\n open,\n onOpenChange,\n title,\n children,\n}: {\n open: boolean\n onOpenChange: (open: boolean) => void\n title: string\n children: ReactNode\n}) {\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"studio-sheet-overlay fixed inset-0 z-50 bg-black/50\" />\n <Dialog.Content\n className=\"studio-sheet-content fixed inset-y-0 right-0 z-50 flex w-[min(92vw,30rem)] flex-col border-l border-card-edge bg-popover shadow-[var(--shadow-overlay)] focus:outline-none\"\n aria-describedby={undefined}\n >\n <Dialog.Title className=\"sr-only\">{title}</Dialog.Title>\n {children}\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n )\n}\n","import { EmptyState } from '@tangle-network/sandbox-ui/primitives'\nimport { Film, Sparkles } from 'lucide-react'\nimport { type Generation, isGenerationType } from '../studio'\nimport { TYPE_CONFIG } from './type-config'\nimport { GenerationCard } from './generation-card'\n\n/** The visible set for the active type tab (all generations when unfiltered). */\nexport function filterGenerations(generations: Generation[], typeFilter: string | null): Generation[] {\n if (!typeFilter || !isGenerationType(typeFilter)) return generations\n return generations.filter((generation) => generation.type === typeFilter)\n}\n\n/**\n * Chrome-less asset grid — the `GenerationCard` grid plus its empty state, with\n * no surrounding tabs/stats/sheet chrome. Composed by both the inline\n * `LibraryPanel` and the `LibraryDrawer`'s list view so the grid and its\n * empty-state copy stay in one place. `generations` is the already-filtered\n * visible set; `typeFilter` only tunes the empty-state message.\n */\nexport function GenerationGrid({\n generations,\n typeFilter,\n onSelect,\n}: {\n generations: Generation[]\n typeFilter: string | null\n onSelect: (generation: Generation) => void\n}) {\n if (generations.length === 0) {\n return (\n <EmptyState\n icon={typeFilter\n ? <Film className=\"h-8 w-8 text-muted-foreground/30\" />\n : <Sparkles className=\"h-10 w-10 text-muted-foreground/30\" />}\n title={typeFilter\n ? `No ${TYPE_CONFIG[typeFilter]?.label ?? typeFilter} generations`\n : 'No generations yet'}\n description={typeFilter\n ? 'Try a different filter or change the type in the composer.'\n : 'Everything you and the agent create lives here.'}\n className=\"py-16\"\n />\n )\n }\n return (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {generations.map((generation) => (\n <GenerationCard key={generation.id} generation={generation} onSelect={onSelect} />\n ))}\n </div>\n )\n}\n","import { Card, CardContent, Badge } from '@tangle-network/sandbox-ui/primitives'\nimport {\n type Generation,\n generationError,\n generationStatus,\n relativeTime,\n} from '../studio'\nimport { typeConfigFor } from './type-config'\n\nexport function GenerationCard({\n generation,\n onSelect,\n}: {\n generation: Generation\n onSelect: (generation: Generation) => void\n}) {\n const cfg = typeConfigFor(generation.type)\n const Icon = cfg.icon\n const status = generationStatus(generation)\n return (\n <button type=\"button\" onClick={() => onSelect(generation)} className=\"group text-left animate-row-in\">\n <Card className=\"overflow-hidden transition-all group-hover:border-primary/50 group-hover:shadow-md\">\n <div className=\"relative aspect-video bg-secondary\">\n {generation.type === 'image' && generation.result ? (\n <img src={generation.result} alt={generation.prompt} className=\"h-full w-full object-cover\" />\n ) : (generation.type === 'video' || generation.type === 'avatar') && generation.result ? (\n <video src={generation.result} className=\"h-full w-full object-cover\" muted />\n ) : generation.type === 'speech' && generation.result ? (\n <div className=\"flex h-full items-center justify-center\">\n <Icon className=\"h-6 w-6 text-muted-foreground/40\" />\n </div>\n ) : generation.type === 'transcription' && generation.result ? (\n <div className=\"flex h-full items-center justify-center p-4\">\n <p className=\"line-clamp-5 text-xs text-muted-foreground\">{generation.result}</p>\n </div>\n ) : status === 'pending' || status === 'running' ? (\n <div className=\"shimmer h-full w-full\" />\n ) : (\n <div className=\"flex h-full items-center justify-center\">\n <Icon className=\"h-8 w-8 text-muted-foreground/20\" />\n </div>\n )}\n <div className=\"absolute left-2 top-2\">\n <Badge variant=\"outline\" className={`${cfg.color} gap-1 text-xs`}>\n <Icon className=\"h-3 w-3\" />\n {cfg.label}\n </Badge>\n </div>\n <GenerationStatusBadge generation={generation} />\n </div>\n <CardContent className=\"p-3\">\n <p className=\"mb-2 line-clamp-2 text-sm font-medium text-foreground\">{generation.prompt}</p>\n {status === 'failed' && (\n <p className=\"mb-2 line-clamp-2 text-xs text-destructive\">{generationError(generation)}</p>\n )}\n <div className=\"flex items-center justify-between\">\n {generation.model && (\n <span className=\"truncate text-xs text-muted-foreground\">{generation.model}</span>\n )}\n <div className=\"flex shrink-0 items-center gap-2\">\n {generation.cost != null && (\n <span className=\"text-xs text-muted-foreground\">${generation.cost.toFixed(3)}</span>\n )}\n <span className=\"text-xs text-muted-foreground\">{relativeTime(generation.createdAt)}</span>\n </div>\n </div>\n </CardContent>\n </Card>\n </button>\n )\n}\n\nexport function GenerationStatusBadge({\n generation,\n inline = false,\n}: {\n generation: Generation\n inline?: boolean\n}) {\n const status = generationStatus(generation)\n if (status === 'succeeded') return null\n\n const label = status === 'failed' ? 'Failed' : status === 'running' ? 'Running' : 'Pending'\n // Solid tint mixed onto the card surface — the badge floats over media, so an\n // alpha fill would let the thumbnail bleed through.\n const className = status === 'failed'\n ? 'border-destructive/30 bg-[color-mix(in_srgb,hsl(var(--destructive))_10%,hsl(var(--card)))] text-destructive'\n : 'border-warning/30 bg-[color-mix(in_srgb,hsl(var(--warning))_10%,hsl(var(--card)))] text-warning'\n\n return (\n <div className={inline ? '' : 'absolute bottom-2 left-2'}>\n <Badge variant=\"outline\" className={`${className} text-xs`}>\n {label}\n </Badge>\n </div>\n )\n}\n","import { Link } from 'react-router'\nimport { Badge, Button } from '@tangle-network/sandbox-ui/primitives'\nimport { FolderOpen } from 'lucide-react'\nimport {\n type Generation,\n generationError,\n generationVaultPath,\n} from '../studio'\nimport { typeConfigFor } from './type-config'\nimport { GenerationStatusBadge } from './generation-card'\n\nexport function GenerationDetail({\n generation,\n vaultHref,\n onNavigate,\n}: {\n generation: Generation\n vaultHref?: (filePath?: string | null) => string\n onNavigate?: () => void\n}) {\n const cfg = typeConfigFor(generation.type)\n const Icon = cfg.icon\n // Only offer the vault link when the generation actually persisted a file.\n // generationVaultPath is null for failed/pending/running and storage-failed\n // generations; without this guard vaultHref(null) falls back to the vault\n // root, rendering a button that opens nothing relevant.\n const vaultPath = generationVaultPath(generation)\n const href = vaultHref && vaultPath ? vaultHref(vaultPath) : null\n\n return (\n <div className=\"space-y-4\">\n <div className=\"overflow-hidden rounded-lg bg-secondary\">\n {generation.type === 'image' && generation.result ? (\n <img src={generation.result} alt={generation.prompt} className=\"max-h-[420px] w-full object-contain\" />\n ) : (generation.type === 'video' || generation.type === 'avatar') && generation.result ? (\n <video src={generation.result} controls className=\"max-h-[420px] w-full\" />\n ) : generation.type === 'speech' && generation.result ? (\n <div className=\"p-6\">\n <audio src={generation.result} controls className=\"w-full\" />\n </div>\n ) : (\n <div className=\"flex h-32 items-center justify-center\">\n <Icon className=\"h-8 w-8 text-muted-foreground/20\" />\n </div>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"outline\" className={`${cfg.color} gap-1`}>\n <Icon className=\"h-3 w-3\" />\n {cfg.label}\n </Badge>\n <GenerationStatusBadge generation={generation} inline />\n {generationError(generation) && (\n <span className=\"text-xs text-destructive\">{generationError(generation)}</span>\n )}\n </div>\n\n <div>\n <span className=\"mb-1 block text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\">Prompt</span>\n <p className=\"text-sm text-foreground\">{generation.prompt}</p>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-4\">\n {generation.model && (\n <div>\n <span className=\"block text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\">Model</span>\n <span className=\"text-xs text-foreground\">{generation.model}</span>\n </div>\n )}\n {generation.cost != null && (\n <div>\n <span className=\"block text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\">Cost</span>\n <span className=\"text-xs text-foreground\">${generation.cost.toFixed(3)}</span>\n </div>\n )}\n {generation.createdAt && (\n <div>\n <span className=\"block text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\">Created</span>\n <span className=\"text-xs text-foreground\">\n {new Date(generation.createdAt).toLocaleString('en-US', { dateStyle: 'medium', timeStyle: 'short' })}\n </span>\n </div>\n )}\n </div>\n\n {generation.type === 'transcription' && generation.result && (\n <div>\n <span className=\"mb-1 block text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground\">Transcription</span>\n <pre className=\"max-h-64 overflow-y-auto whitespace-pre-wrap rounded-lg bg-secondary p-4 font-mono text-[13px] tabular-nums text-foreground\">\n {generation.result}\n </pre>\n </div>\n )}\n\n {href && (\n <div className=\"border-t border-border pt-2\">\n <Link to={href} prefetch=\"intent\" onClick={onNavigate}>\n <Button size=\"sm\" variant=\"outline\">\n <FolderOpen className=\"mr-1.5 h-3.5 w-3.5\" />\n Open in Vault\n </Button>\n </Link>\n </div>\n )}\n </div>\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. So the notice sits above the composer as a\n * statement of fact rather than a warning — `text-foreground`, not muted, since\n * a rule the reader must know before typing cannot be the quietest text on the\n * page.\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 border px-3.5 py-1.5 text-center text-[12.5px] font-medium leading-relaxed text-foreground shadow-sm ${className ?? ''}`}\n style={{ background: 'var(--studio-notice-bg)', borderColor: 'var(--studio-notice-border)' }}\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 { useMemo } from 'react'\nimport {\n Tabs, TabsList, TabsTrigger,\n} from '@tangle-network/sandbox-ui/primitives'\nimport { DollarSign } from 'lucide-react'\nimport { type Generation } from '../studio'\nimport { TYPE_CONFIG } from './type-config'\nimport { GenerationGrid, filterGenerations } from './generation-grid'\n\n/**\n * Inline asset gallery — the same filter + stats + card grid as the library\n * drawer's list view, but with no sheet chrome so it can sit on the page beside\n * the composer. In-flight generations need no special handling: they arrive at\n * the front of `generations` (via `useStudioGenerations.mergedGenerations`) and\n * `GenerationCard` renders their `pending`/`running` shimmer.\n */\nexport function LibraryPanel({\n generations,\n totalCost,\n typeFilter,\n onFilterChange,\n onSelect,\n}: {\n generations: Generation[]\n totalCost: number\n typeFilter: string | null\n onFilterChange: (type: string | null) => void\n onSelect: (generation: Generation) => void\n}) {\n const visible = useMemo(() => filterGenerations(generations, typeFilter), [generations, typeFilter])\n\n return (\n <div className=\"flex min-w-0 flex-col\">\n <div className=\"mb-4 flex flex-wrap items-center justify-between gap-3\">\n <Tabs value={typeFilter ?? 'all'} onValueChange={(v) => onFilterChange(v === 'all' ? null : v)}>\n <TabsList className=\"h-9 justify-start gap-1 overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-background p-1\">\n <TabsTrigger\n value=\"all\"\n className=\"rounded-md px-3 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground data-[state=active]:bg-primary/10 data-[state=active]:font-semibold data-[state=active]:text-primary data-[state=active]:shadow-none\"\n >\n All\n </TabsTrigger>\n {Object.entries(TYPE_CONFIG).map(([key, cfg]) => (\n <TabsTrigger\n key={key}\n value={key}\n className=\"rounded-md px-3 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground data-[state=active]:bg-primary/10 data-[state=active]:font-semibold data-[state=active]:text-primary data-[state=active]:shadow-none\"\n >\n {cfg.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n <div className=\"flex items-center gap-3 text-xs text-muted-foreground\">\n <span>{visible.length} generation{visible.length !== 1 ? 's' : ''}</span>\n <span className=\"flex items-center gap-0.5\">\n <DollarSign className=\"h-3 w-3\" />\n {totalCost.toFixed(2)} spent\n </span>\n </div>\n </div>\n\n <GenerationGrid generations={visible} typeFilter={typeFilter} onSelect={onSelect} />\n </div>\n )\n}\n","import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@tangle-network/sandbox-ui/primitives'\nimport { type Generation } from '../studio'\nimport { typeConfigFor } from './type-config'\nimport { GenerationDetail } from './generation-detail'\n\n/**\n * Centered detail view for a single generation. Opens when `generation` is set\n * and reports dismissal through `onClose`. GenerationDetail renders the media,\n * type badge, prompt and metadata; the dialog title carries the a11y label.\n */\nexport function GenerationDetailModal({\n generation,\n vaultHref,\n onClose,\n}: {\n generation: Generation | null\n vaultHref?: (filePath?: string | null) => string\n onClose: () => void\n}) {\n const cfg = generation ? typeConfigFor(generation.type) : null\n return (\n <Dialog open={generation != null} onOpenChange={(open) => { if (!open) onClose() }}>\n <DialogContent className=\"max-h-[85vh] max-w-2xl overflow-y-auto border-card-edge bg-popover shadow-[var(--shadow-overlay)]\">\n <DialogHeader>\n <DialogTitle className=\"text-left text-[15px] font-semibold\">{cfg ? `${cfg.label} generation` : 'Generation'}</DialogTitle>\n </DialogHeader>\n {generation && (\n <GenerationDetail generation={generation} vaultHref={vaultHref} onNavigate={onClose} />\n )}\n </DialogContent>\n </Dialog>\n )\n}\n"],"mappings":"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","names":["useRef","useState","Button","Images","useEffect","useMemo","useRef","useState","useCallback","useEffect","useState","useCallback","useEffect","useState","jsx","jsxs","useState","useRef","useEffect","useMemo","jsx","jsxs","Video","jsx","jsxs","useMemo","Link","Button","FolderOpen","X","jsx","jsxs","Sparkles","Badge","jsx","jsxs","Badge","jsx","Sparkles","Badge","Button","jsx","jsxs","Badge","Button","Fragment","jsx","jsxs","useMemo","X","Link","Button","FolderOpen","Fragment","jsx","jsxs","useState","useRef","Images","Button","jsx","jsxs","useMemo","Tabs","TabsList","TabsTrigger","DollarSign","jsx","jsxs","useMemo","Tabs","TabsList","TabsTrigger","DollarSign","Dialog","jsx","jsxs","Dialog"]}
|