import {
  CADENCES,
  DESTINATIONS,
  MAX_IMAGE_COUNT,
  MIN_IMAGE_COUNT,
  buildGenerationRequestBody,
  buildPublishPackage,
  failedOptimisticGeneration,
  generationError,
  generationStatus,
  generationVaultPath,
  isDestinationConnected,
  isGenerationType,
  isLocalGeneration,
  isPublishPackage,
  latestBatchOf,
  mergeLiveGeneration,
  mergeLoaderAndLive,
  modelMessage,
  normalizeImageCount,
  optimisticGeneration,
  outputPathFor,
  preferredModelId,
  relativeTime,
  selectedModelsWithDefaults,
  userSafeGenerationMessage
} from "../chunk-DTS5TZRN.js";

// src/studio-react/studio-workspace.tsx
import { useRef as useRef3, useState as useState3 } from "react";
import { useSearchParams } from "react-router";
import { Button as Button6 } from "@tangle-network/sandbox-ui/primitives";
import { Images as Images2 } from "lucide-react";

// src/studio-react/use-studio-generations.ts
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useRevalidator } from "react-router";
function useStudioGenerations(loaderGenerations, options = {}) {
  const { workspaceId, generationsEndpoint = "/api/generations" } = options;
  const revalidator = useRevalidator();
  const [liveGenerations, setLiveGenerations] = useState([]);
  const mergedGenerations = useMemo(
    () => mergeLoaderAndLive(loaderGenerations, liveGenerations),
    [loaderGenerations, liveGenerations]
  );
  const latestBatch = useMemo(() => latestBatchOf(mergedGenerations), [mergedGenerations]);
  const runningGenerationIds = useMemo(() => mergedGenerations.filter((gen) => {
    const status = generationStatus(gen);
    return status === "pending" || status === "running";
  }).map((gen) => gen.id).filter((id) => !id.startsWith("local-")), [mergedGenerations]);
  const runningIdsRef = useRef(runningGenerationIds);
  runningIdsRef.current = runningGenerationIds;
  const revalidateRef = useRef(revalidator.revalidate);
  revalidateRef.current = revalidator.revalidate;
  const runningKey = runningGenerationIds.join(",");
  useEffect(() => {
    if (!workspaceId || !runningKey) return;
    let cancelled = false;
    const poll = async () => {
      const responses = await Promise.all(runningIdsRef.current.map(async (id) => {
        const res = await fetch(`${generationsEndpoint}?workspaceId=${encodeURIComponent(workspaceId)}&id=${encodeURIComponent(id)}`);
        if (!res.ok) return null;
        const data = await res.json();
        return data.generation ?? null;
      }));
      if (cancelled) return;
      const refreshed = responses.filter((gen) => Boolean(gen));
      if (refreshed.length > 0) {
        setLiveGenerations((current) => refreshed.reduce(mergeLiveGeneration, current));
      }
      if (refreshed.some((gen) => generationStatus(gen) !== "running" && generationStatus(gen) !== "pending")) {
        revalidateRef.current();
      }
    };
    const interval = window.setInterval(() => {
      void poll();
    }, 4e3);
    void poll();
    return () => {
      cancelled = true;
      window.clearInterval(interval);
    };
  }, [runningKey, workspaceId, generationsEndpoint]);
  const onGenerated = useCallback((generation) => {
    setLiveGenerations((current) => mergeLiveGeneration(current, generation));
    if (!isLocalGeneration(generation)) revalidateRef.current();
  }, []);
  return { mergedGenerations, latestBatch, onGenerated };
}

// src/studio-react/composer-hero.tsx
import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
import {
  Badge as Badge2,
  Button as Button2,
  Input as Input7,
  Label as Label2,
  Textarea as Textarea2,
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue
} from "@tangle-network/sandbox-ui/primitives";
import { useIntegrations } from "@tangle-network/sandbox-ui/integrations";
import { Sparkles } from "lucide-react";

// src/studio-react/type-config.ts
import { Film, FileText, Image, Mic, Video } from "lucide-react";
var IMAGE = { label: "Image", icon: Image, color: "bg-blue-500/10 text-blue-600 border-blue-500/20" };
var TYPE_CONFIG = {
  image: IMAGE,
  video: { label: "Video", icon: Video, color: "bg-red-500/10 text-red-600 border-red-500/20" },
  avatar: { label: "Avatar", icon: Film, color: "bg-purple-500/10 text-purple-600 border-purple-500/20" },
  speech: { label: "Audio", icon: Mic, color: "bg-orange-500/10 text-orange-600 border-orange-500/20" },
  transcription: { label: "Transcript", icon: FileText, color: "bg-emerald-500/10 text-emerald-600 border-emerald-500/20" }
};
function typeConfigFor(type) {
  return TYPE_CONFIG[type] ?? IMAGE;
}

// src/studio-react/composer-shell.tsx
import { Label } from "@tangle-network/sandbox-ui/primitives";
import { ChevronRight } from "lucide-react";
import { jsx, jsxs } from "react/jsx-runtime";
function Field({
  label,
  htmlFor,
  className = "space-y-1.5",
  children
}) {
  return /* @__PURE__ */ jsxs("div", { className, children: [
    /* @__PURE__ */ jsx(Label, { htmlFor, className: "text-sm", children: label }),
    children
  ] });
}
function ComposerDisclosure({ summary, children }) {
  return /* @__PURE__ */ jsxs("details", { className: "group rounded-lg border border-border bg-muted/30 transition-colors open:bg-muted/40", children: [
    /* @__PURE__ */ jsxs("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", children: [
      /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5 text-muted-foreground transition-transform group-open:rotate-90" }),
      summary
    ] }),
    /* @__PURE__ */ jsx("div", { className: "border-t border-border px-3 py-3", children })
  ] });
}
function NativeSelect(props) {
  return /* @__PURE__ */ jsx("select", { ...props, className: "h-9 w-full rounded-md border border-input bg-background px-3 text-sm" });
}

// src/studio-react/image-composer.tsx
import { Input } from "@tangle-network/sandbox-ui/primitives";
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
function ImageComposer({
  size,
  quality,
  imageCount,
  onSizeChange,
  onQualityChange,
  onImageCountChange
}) {
  return /* @__PURE__ */ jsxs2(Fragment, { children: [
    /* @__PURE__ */ jsx2(Field, { label: "Size", children: /* @__PURE__ */ jsx2(Input, { value: size, onChange: (event) => onSizeChange(event.target.value) }) }),
    /* @__PURE__ */ jsx2(Field, { label: "Quality", children: /* @__PURE__ */ jsx2(Input, { value: quality, onChange: (event) => onQualityChange(event.target.value) }) }),
    /* @__PURE__ */ jsx2(Field, { label: "Images", children: /* @__PURE__ */ jsx2(Input, { type: "number", min: MIN_IMAGE_COUNT, max: MAX_IMAGE_COUNT, value: imageCount, onChange: (event) => onImageCountChange(normalizeImageCount(event.target.value)) }) })
  ] });
}

// src/studio-react/video-composer.tsx
import { Input as Input2 } from "@tangle-network/sandbox-ui/primitives";
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
function VideoComposer({
  duration,
  resolution,
  aspectRatio,
  referenceImageUrl,
  onDurationChange,
  onResolutionChange,
  onAspectRatioChange,
  onReferenceImageUrlChange
}) {
  return /* @__PURE__ */ jsxs3(Fragment2, { children: [
    /* @__PURE__ */ jsx3(Field, { label: "Duration (s)", children: /* @__PURE__ */ jsx3(Input2, { value: duration, onChange: (event) => onDurationChange(event.target.value) }) }),
    /* @__PURE__ */ jsx3(Field, { label: "Resolution", children: /* @__PURE__ */ jsx3(Input2, { value: resolution, onChange: (event) => onResolutionChange(event.target.value) }) }),
    /* @__PURE__ */ jsx3(Field, { label: "Aspect ratio", children: /* @__PURE__ */ jsx3(Input2, { value: aspectRatio, onChange: (event) => onAspectRatioChange(event.target.value) }) }),
    /* @__PURE__ */ jsx3(Field, { label: "Reference image URL", children: /* @__PURE__ */ jsx3(Input2, { value: referenceImageUrl, onChange: (event) => onReferenceImageUrlChange(event.target.value) }) })
  ] });
}

// src/studio-react/speech-composer.tsx
import { Input as Input3 } from "@tangle-network/sandbox-ui/primitives";
import { jsx as jsx4 } from "react/jsx-runtime";
function SpeechComposer({
  voice,
  onVoiceChange
}) {
  return /* @__PURE__ */ jsx4(Field, { label: "Voice", children: /* @__PURE__ */ jsx4(Input3, { value: voice, onChange: (event) => onVoiceChange(event.target.value) }) });
}

// src/studio-react/avatar-composer.tsx
import { Input as Input4 } from "@tangle-network/sandbox-ui/primitives";
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
function AvatarComposer({
  audioUrl,
  imageUrl,
  avatarId,
  onAudioUrlChange,
  onImageUrlChange,
  onAvatarIdChange
}) {
  return /* @__PURE__ */ jsxs4("div", { className: "mt-4 grid gap-3 sm:grid-cols-2", children: [
    /* @__PURE__ */ jsx5(Field, { label: "Audio URL", htmlFor: "studio-audio-url", children: /* @__PURE__ */ jsx5(
      Input4,
      {
        id: "studio-audio-url",
        value: audioUrl,
        onChange: (event) => onAudioUrlChange(event.target.value),
        placeholder: "https://cdn.example.com/source-audio.mp3"
      }
    ) }),
    /* @__PURE__ */ jsx5(Field, { label: "Image URL", htmlFor: "studio-avatar-image-url", children: /* @__PURE__ */ jsx5(
      Input4,
      {
        id: "studio-avatar-image-url",
        value: imageUrl,
        onChange: (event) => onImageUrlChange(event.target.value),
        placeholder: "https://cdn.example.com/portrait.png"
      }
    ) }),
    /* @__PURE__ */ jsx5(Field, { label: "Avatar ID", htmlFor: "studio-avatar-id", children: /* @__PURE__ */ jsx5(
      Input4,
      {
        id: "studio-avatar-id",
        value: avatarId,
        onChange: (event) => onAvatarIdChange(event.target.value),
        placeholder: "Optional provider avatar id"
      }
    ) })
  ] });
}

// src/studio-react/transcription-composer.tsx
import { Input as Input5 } from "@tangle-network/sandbox-ui/primitives";
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
function TranscriptionComposer({
  audioUrl,
  language,
  onAudioUrlChange,
  onLanguageChange
}) {
  return /* @__PURE__ */ jsxs5("div", { className: "mt-4 grid gap-3 sm:grid-cols-2", children: [
    /* @__PURE__ */ jsx6(Field, { label: "Audio URL", htmlFor: "studio-audio-url", children: /* @__PURE__ */ jsx6(
      Input5,
      {
        id: "studio-audio-url",
        value: audioUrl,
        onChange: (event) => onAudioUrlChange(event.target.value),
        placeholder: "https://cdn.example.com/source-audio.mp3"
      }
    ) }),
    /* @__PURE__ */ jsx6(Field, { label: "Language", htmlFor: "studio-transcription-language", children: /* @__PURE__ */ jsx6(
      Input5,
      {
        id: "studio-transcription-language",
        value: language,
        onChange: (event) => onLanguageChange(event.target.value),
        placeholder: "en"
      }
    ) })
  ] });
}
function TranscriptionOptions({
  responseFormat,
  temperature,
  onResponseFormatChange,
  onTemperatureChange
}) {
  return /* @__PURE__ */ jsxs5(Fragment3, { children: [
    /* @__PURE__ */ jsx6(Field, { label: "Response format", children: /* @__PURE__ */ jsxs5(NativeSelect, { value: responseFormat, onChange: (event) => onResponseFormatChange(event.target.value), children: [
      /* @__PURE__ */ jsx6("option", { value: "json", children: "JSON" }),
      /* @__PURE__ */ jsx6("option", { value: "text", children: "Text" }),
      /* @__PURE__ */ jsx6("option", { value: "srt", children: "SRT" }),
      /* @__PURE__ */ jsx6("option", { value: "verbose_json", children: "Verbose JSON" }),
      /* @__PURE__ */ jsx6("option", { value: "vtt", children: "VTT" })
    ] }) }),
    /* @__PURE__ */ jsx6(Field, { label: "Temperature", children: /* @__PURE__ */ jsx6(Input5, { type: "number", min: "0", max: "1", step: "0.1", value: temperature, onChange: (event) => onTemperatureChange(event.target.value) }) })
  ] });
}

// src/studio-react/publish-package-composer.tsx
import { Link } from "react-router";
import { Badge, Button, Input as Input6, Textarea } from "@tangle-network/sandbox-ui/primitives";
import { AlertTriangle, CalendarClock, Check } from "lucide-react";
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
function PublishPackageComposer({
  caption,
  postDescription,
  mentions,
  cadence,
  selectedDestinations,
  connections,
  connectionError,
  connectionsLoading,
  integrationsHref,
  canManageIntegrations,
  onCaptionChange,
  onDescriptionChange,
  onMentionsChange,
  onCadenceChange,
  onDestinationToggle
}) {
  return /* @__PURE__ */ jsxs6("div", { className: "space-y-3", children: [
    /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-3", children: [
      connectionError ? /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 rounded-md border border-warning/20 bg-warning/5 px-2.5 py-1.5 text-xs text-warning", children: [
        /* @__PURE__ */ jsx7(AlertTriangle, { className: "h-3.5 w-3.5 shrink-0" }),
        "Couldn't load connected apps. Check Integrations."
      ] }) : /* @__PURE__ */ jsx7("p", { className: "text-xs text-muted-foreground", children: connectionsLoading ? "Checking connected apps\u2026" : "Stage captions, destinations, cadence. Saved with the generated asset." }),
      integrationsHref && canManageIntegrations && /* @__PURE__ */ jsx7(Link, { to: integrationsHref, prefetch: "intent", className: "shrink-0", children: /* @__PURE__ */ jsx7(Button, { variant: "outline", size: "sm", children: "Connect" }) })
    ] }),
    /* @__PURE__ */ jsx7("div", { className: "grid gap-2", children: DESTINATIONS.map((destination) => {
      const connected = isDestinationConnected(destination, connections);
      const active = connected && selectedDestinations.includes(destination.id);
      return /* @__PURE__ */ jsxs6(
        "button",
        {
          type: "button",
          disabled: !connected,
          "aria-pressed": active,
          onClick: () => onDestinationToggle(destination.id),
          className: `rounded-md border p-2 text-left transition-colors disabled:cursor-not-allowed disabled:opacity-60 ${active ? "border-primary bg-primary/5 ring-1 ring-primary/20" : "border-border hover:bg-muted/50"}`,
          children: [
            /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-2", children: [
              /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-1.5 text-xs font-medium text-foreground", children: [
                active && /* @__PURE__ */ jsx7(Check, { className: "h-3.5 w-3.5 text-primary" }),
                destination.label
              ] }),
              /* @__PURE__ */ jsx7(Badge, { variant: active || connected ? "default" : "outline", children: active ? "Selected" : connected ? "Ready" : "Not connected" })
            ] }),
            /* @__PURE__ */ jsx7("p", { className: "mt-1 text-xs text-muted-foreground", children: destination.fields })
          ]
        },
        destination.id
      );
    }) }),
    /* @__PURE__ */ jsx7(Field, { label: "Caption", className: "space-y-2", children: /* @__PURE__ */ jsx7(Textarea, { value: caption, onChange: (event) => onCaptionChange(event.target.value), rows: 3, placeholder: "Write or generate the caption for selected destinations..." }) }),
    /* @__PURE__ */ jsx7(Field, { label: "Description / CTA", className: "space-y-2", children: /* @__PURE__ */ jsx7(Textarea, { value: postDescription, onChange: (event) => onDescriptionChange(event.target.value), rows: 2, placeholder: "Release note, product context, link, or approval instruction..." }) }),
    /* @__PURE__ */ jsxs6("div", { className: "grid grid-cols-2 gap-3", children: [
      /* @__PURE__ */ jsx7(Field, { label: "Mentions", className: "space-y-2", children: /* @__PURE__ */ jsx7(Input6, { value: mentions, onChange: (event) => onMentionsChange(event.target.value), placeholder: "@creator, @partner" }) }),
      /* @__PURE__ */ jsx7(Field, { label: "Cadence", className: "space-y-2", children: /* @__PURE__ */ jsx7(NativeSelect, { value: cadence, onChange: (event) => onCadenceChange(event.target.value), children: CADENCES.map((option) => /* @__PURE__ */ jsx7("option", { value: option, children: option }, option)) }) })
    ] }),
    /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 rounded-md bg-muted/40 p-2 text-xs text-muted-foreground", children: [
      /* @__PURE__ */ jsx7(CalendarClock, { className: "h-3.5 w-3.5" }),
      "Publish packages stay attached to generated media and can run through connected GTM apps."
    ] })
  ] });
}

// src/studio-react/composer-hero.tsx
import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
var HUB_BASE_URL = "/api/integrations/hub";
var SUGGESTIONS = [
  {
    label: "Storyboard frame",
    type: "image",
    prompt: "A vertical storyboard frame for a product launch teaser \u2014 dark cinematic lighting, sleek studio aesthetic, 9:16 composition."
  },
  {
    label: "Launch teaser clip",
    type: "video",
    prompt: "A 6-second vertical launch teaser: animated product reveal, dynamic camera move, hero music swell."
  },
  {
    label: "Scratch voiceover",
    type: "speech",
    prompt: "A confident 12-second scratch voiceover for a product launch teaser: warm tone, conversational pace."
  },
  {
    label: "Transcribe dailies",
    type: "transcription",
    prompt: "Transcribe the latest dailies recording with timestamps, speaker labels, and key story beats highlighted."
  }
];
function ComposerHero({
  workspaceId,
  integrationsHref,
  canManageIntegrations,
  onGenerated
}) {
  const [type, setType] = useState2("image");
  const [prompt, setPrompt] = useState2("");
  const [negativePrompt, setNegativePrompt] = useState2("");
  const [outputPath, setOutputPath] = useState2(outputPathFor("image"));
  const [caption, setCaption] = useState2("");
  const [postDescription, setPostDescription] = useState2("");
  const [mentions, setMentions] = useState2("");
  const [cadence, setCadence] = useState2(CADENCES[0] ?? "Manual approval");
  const [selectedDestinations, setSelectedDestinations] = useState2([]);
  const [size, setSize] = useState2("1536x1024");
  const [quality, setQuality] = useState2("high");
  const [imageCount, setImageCount] = useState2(1);
  const [duration, setDuration] = useState2("6");
  const [resolution, setResolution] = useState2("720p");
  const [aspectRatio, setAspectRatio] = useState2("16:9");
  const [referenceImageUrl, setReferenceImageUrl] = useState2("");
  const [voice, setVoice] = useState2("alloy");
  const [avatarAudioUrl, setAvatarAudioUrl] = useState2("");
  const [avatarImageUrl, setAvatarImageUrl] = useState2("");
  const [avatarId, setAvatarId] = useState2("");
  const [transcriptionAudioUrl, setTranscriptionAudioUrl] = useState2("");
  const [transcriptionLanguage, setTranscriptionLanguage] = useState2("");
  const [transcriptionResponseFormat, setTranscriptionResponseFormat] = useState2("json");
  const [transcriptionTemperature, setTranscriptionTemperature] = useState2("0");
  const [mediaModels, setMediaModels] = useState2(null);
  const [mediaModelsLoading, setMediaModelsLoading] = useState2(false);
  const [mediaModelsError, setMediaModelsError] = useState2(null);
  const [selectedModels, setSelectedModels] = useState2({});
  const submitLockRef = useRef2(false);
  const [isSubmitting, setIsSubmitting] = useState2(false);
  const [error, setError] = useState2(null);
  const modelsForType = mediaModels?.models[type] ?? [];
  const selectedModel = selectedModels[type] ?? preferredModelId(type, mediaModels) ?? "";
  const selectedModelOption = modelsForType.find((model) => model.id === selectedModel);
  const modelReady = Boolean(selectedModelOption) && selectedModelOption?.status !== "unavailable" && !mediaModelsLoading && !mediaModelsError;
  const hasRequiredInput = type === "transcription" ? Boolean(transcriptionAudioUrl.trim()) : type === "avatar" ? Boolean(avatarAudioUrl.trim()) : Boolean(prompt.trim());
  const canSubmit = Boolean(workspaceId) && modelReady && hasRequiredInput && !isSubmitting;
  const integrations = useIntegrations({ apiBaseUrl: HUB_BASE_URL });
  const selectedConnectedDestinations = useMemo2(() => selectedDestinations.filter((destinationId) => {
    const destination = DESTINATIONS.find((item) => item.id === destinationId);
    return Boolean(destination && isDestinationConnected(destination, integrations.connections));
  }), [integrations.connections, selectedDestinations]);
  useEffect2(() => {
    if (!workspaceId) return;
    let cancelled = false;
    setMediaModelsLoading(true);
    setMediaModelsError(null);
    fetch(`/api/media-models?workspaceId=${encodeURIComponent(workspaceId)}`).then(async (res) => {
      const data = await res.json();
      if (!res.ok) throw new Error(data.error ?? "Could not load media models");
      return data;
    }).then((data) => {
      if (cancelled) return;
      setMediaModels(data);
      setSelectedModels((current) => selectedModelsWithDefaults(current, data));
    }).catch((err) => {
      if (cancelled) return;
      setMediaModels(null);
      setMediaModelsError(err instanceof Error ? err.message : "Could not load media models");
    }).finally(() => {
      if (!cancelled) setMediaModelsLoading(false);
    });
    return () => {
      cancelled = true;
    };
  }, [workspaceId]);
  function changeType(next) {
    setType(next);
    setOutputPath(outputPathFor(next));
  }
  async function generate() {
    if (!workspaceId || submitLockRef.current) return;
    const promptText = prompt.trim();
    const avatarAudioUrlText = avatarAudioUrl.trim();
    const transcriptionAudioUrlText = transcriptionAudioUrl.trim();
    if (type !== "transcription" && type !== "avatar" && !promptText) {
      setError("prompt is required");
      return;
    }
    if (type === "avatar" && !avatarAudioUrlText) {
      setError("audioUrl is required");
      return;
    }
    if (type === "transcription" && !transcriptionAudioUrlText) {
      setError("audioUrl is required");
      return;
    }
    if (!selectedModelOption || selectedModelOption.status === "unavailable") {
      setError(`Select an available ${typeConfigFor(type).label} model`);
      return;
    }
    if (cadence === "Publish now" && selectedConnectedDestinations.length === 0) {
      setError("Select a connected destination to publish now");
      return;
    }
    submitLockRef.current = true;
    setIsSubmitting(true);
    setError(null);
    const clientRequestId = crypto.randomUUID();
    const requestedImageCount = type === "image" ? normalizeImageCount(imageCount) : 1;
    if (type === "image" && requestedImageCount !== imageCount) setImageCount(requestedImageCount);
    const localGenerations = Array.from({ length: requestedImageCount }, (_, outputIndex) => optimisticGeneration({
      type,
      // avatar hides the prompt field (promptText is stale); transcription's is
      // an optional vocab hint. Never surface the source audio URL as the prompt.
      prompt: type === "avatar" ? "" : promptText,
      model: selectedModel,
      clientRequestId,
      outputIndex: type === "image" ? outputIndex : void 0,
      outputCount: type === "image" ? requestedImageCount : void 0
    }));
    localGenerations.slice().reverse().forEach(onGenerated);
    setPrompt("");
    let receivedServerGeneration = false;
    try {
      const body = buildGenerationRequestBody({
        workspaceId,
        clientRequestId,
        type,
        model: selectedModel,
        prompt,
        negativePrompt,
        outputPath,
        publishPackage: buildPublishPackage({
          caption,
          postDescription,
          mentions,
          cadence,
          destinations: selectedConnectedDestinations
        }),
        image: { size, quality, count: requestedImageCount },
        video: { duration, resolution, aspectRatio, referenceImageUrl },
        speech: { voice },
        avatar: { audioUrl: avatarAudioUrl, imageUrl: avatarImageUrl, avatarId },
        transcription: {
          audioUrl: transcriptionAudioUrl,
          language: transcriptionLanguage,
          responseFormat: transcriptionResponseFormat,
          temperature: transcriptionTemperature
        }
      });
      const res = await fetch("/api/generate", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body)
      });
      const data = await res.json();
      const serverGenerations = data.generations?.length ? data.generations : data.generation ? [data.generation] : [];
      if (serverGenerations.length > 0) {
        receivedServerGeneration = true;
        serverGenerations.slice().reverse().forEach(onGenerated);
      }
      if (!res.ok || serverGenerations.length === 0) throw new Error(data.error ?? "Generation failed");
    } catch (err) {
      if (!receivedServerGeneration) localGenerations.map(failedOptimisticGeneration).forEach(onGenerated);
      setError(err instanceof Error ? userSafeGenerationMessage(err.message) : "Generation failed");
    } finally {
      submitLockRef.current = false;
      setIsSubmitting(false);
    }
  }
  const mediaTypes = Object.entries(TYPE_CONFIG);
  const hasInlineParams = type === "image" || type === "video" || type === "speech";
  return /* @__PURE__ */ jsxs7("section", { className: "rounded-xl border border-border bg-card p-5 shadow-sm", children: [
    /* @__PURE__ */ jsx8(Field, { label: "Media type", className: "space-y-1.5", children: /* @__PURE__ */ jsx8(
      "div",
      {
        role: "tablist",
        "aria-label": "Generation type",
        className: "grid grid-cols-5 gap-1 rounded-lg border border-border bg-muted/40 p-1",
        children: mediaTypes.map(([key, cfg]) => {
          const Icon = cfg.icon;
          const active = type === key;
          return /* @__PURE__ */ jsxs7(
            "button",
            {
              type: "button",
              role: "tab",
              "aria-selected": active,
              onClick: () => changeType(key),
              className: `flex items-center justify-center gap-1.5 rounded-md px-2 py-2 text-xs font-medium transition-all ${active ? "bg-primary/15 text-primary shadow-sm ring-1 ring-inset ring-primary/30" : "text-muted-foreground hover:bg-foreground/[0.04] hover:text-foreground"}`,
              children: [
                /* @__PURE__ */ jsx8(Icon, { className: "h-4 w-4 shrink-0" }),
                /* @__PURE__ */ jsx8("span", { className: "truncate", children: cfg.label })
              ]
            },
            key
          );
        })
      }
    ) }),
    type !== "avatar" && /* @__PURE__ */ jsxs7("div", { className: "mt-4 space-y-2", children: [
      /* @__PURE__ */ jsx8(Label2, { htmlFor: "studio-prompt", className: "block text-sm font-medium", children: "What do you want to create?" }),
      /* @__PURE__ */ jsx8(
        Textarea2,
        {
          id: "studio-prompt",
          value: prompt,
          onChange: (event) => setPrompt(event.target.value),
          onKeyDown: (event) => {
            if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
              event.preventDefault();
              void generate();
            }
          },
          rows: 4,
          placeholder: type === "transcription" ? "Optional vocabulary, speaker names, timestamp style, or context..." : "A vertical hero frame for a product launch teaser, dark cinematic lighting...",
          className: "resize-none text-sm"
        }
      ),
      /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-1.5 text-xs text-muted-foreground", children: [
        /* @__PURE__ */ jsx8("span", { children: "Try:" }),
        SUGGESTIONS.map((suggestion) => /* @__PURE__ */ jsx8(
          "button",
          {
            type: "button",
            onClick: () => {
              setPrompt(suggestion.prompt);
              changeType(suggestion.type);
            },
            className: "rounded-full border border-border bg-background px-2.5 py-1 text-xs text-foreground/80 transition-colors hover:border-primary/40 hover:bg-muted",
            children: suggestion.label
          },
          suggestion.label
        ))
      ] }),
      type === "transcription" && /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: "Optional \u2014 biases the transcript's spelling, vocabulary, and speaker names. It isn't an instruction for the model to follow." })
    ] }),
    type === "avatar" && /* @__PURE__ */ jsx8(
      AvatarComposer,
      {
        audioUrl: avatarAudioUrl,
        imageUrl: avatarImageUrl,
        avatarId,
        onAudioUrlChange: setAvatarAudioUrl,
        onImageUrlChange: setAvatarImageUrl,
        onAvatarIdChange: setAvatarId
      }
    ),
    type === "transcription" && /* @__PURE__ */ jsx8(
      TranscriptionComposer,
      {
        audioUrl: transcriptionAudioUrl,
        language: transcriptionLanguage,
        onAudioUrlChange: setTranscriptionAudioUrl,
        onLanguageChange: setTranscriptionLanguage
      }
    ),
    /* @__PURE__ */ jsxs7("div", { className: "mt-4 grid gap-3 sm:grid-cols-2", children: [
      /* @__PURE__ */ jsx8(
        Field,
        {
          label: "Model",
          htmlFor: "studio-media-model",
          className: `space-y-1.5 ${hasInlineParams ? "" : "sm:col-span-2"}`,
          children: /* @__PURE__ */ jsxs7(
            Select,
            {
              value: selectedModel || void 0,
              onValueChange: (value) => setSelectedModels((current) => ({ ...current, [type]: value })),
              disabled: mediaModelsLoading || Boolean(mediaModelsError) || modelsForType.length === 0,
              children: [
                /* @__PURE__ */ jsx8(SelectTrigger, { id: "studio-media-model", className: "h-9 w-full", children: /* @__PURE__ */ jsx8(SelectValue, { placeholder: mediaModelsLoading ? "Loading models\u2026" : "Select a model" }) }),
                /* @__PURE__ */ jsx8(SelectContent, { children: modelsForType.map((model) => /* @__PURE__ */ jsx8(SelectItem, { value: model.id, disabled: model.status === "unavailable", children: /* @__PURE__ */ jsxs7("span", { className: "flex w-full items-center justify-between gap-3", children: [
                  /* @__PURE__ */ jsxs7("span", { className: "truncate", children: [
                    model.name || model.id,
                    model.provider ? ` \xB7 ${model.provider}` : ""
                  ] }),
                  model.status !== "available" && /* @__PURE__ */ jsx8("span", { className: "shrink-0 text-[10px] capitalize text-muted-foreground", children: model.status })
                ] }) }, model.id)) })
              ]
            }
          )
        }
      ),
      type === "image" && /* @__PURE__ */ jsx8(
        ImageComposer,
        {
          size,
          quality,
          imageCount,
          onSizeChange: setSize,
          onQualityChange: setQuality,
          onImageCountChange: setImageCount
        }
      ),
      type === "video" && /* @__PURE__ */ jsx8(
        VideoComposer,
        {
          duration,
          resolution,
          aspectRatio,
          referenceImageUrl,
          onDurationChange: setDuration,
          onResolutionChange: setResolution,
          onAspectRatioChange: setAspectRatio,
          onReferenceImageUrlChange: setReferenceImageUrl
        }
      ),
      type === "speech" && /* @__PURE__ */ jsx8(SpeechComposer, { voice, onVoiceChange: setVoice })
    ] }),
    (mediaModelsError || modelMessage(selectedModelOption, mediaModelsLoading, modelsForType.length)) && /* @__PURE__ */ jsx8("p", { className: `mt-2 text-xs ${mediaModelsError || selectedModelOption?.status === "unavailable" ? "text-destructive" : "text-muted-foreground"}`, children: mediaModelsError ?? modelMessage(selectedModelOption, mediaModelsLoading, modelsForType.length) }),
    error && /* @__PURE__ */ jsx8("div", { className: "mt-3 rounded-md border border-destructive/20 bg-destructive/10 p-3 text-sm text-destructive", children: error }),
    /* @__PURE__ */ jsxs7("div", { className: "mt-4 space-y-2", children: [
      /* @__PURE__ */ jsx8(ComposerDisclosure, { summary: "Advanced options", children: /* @__PURE__ */ jsxs7("div", { className: "grid gap-3 sm:grid-cols-2", children: [
        /* @__PURE__ */ jsx8(Field, { label: "Negative prompt", children: /* @__PURE__ */ jsx8(
          Textarea2,
          {
            value: negativePrompt,
            onChange: (event) => setNegativePrompt(event.target.value),
            rows: 2,
            placeholder: "Avoid artifacts, off-style composition..."
          }
        ) }),
        /* @__PURE__ */ jsx8(Field, { label: "Save to", children: /* @__PURE__ */ jsx8(Input7, { value: outputPath, onChange: (event) => setOutputPath(event.target.value) }) }),
        type === "transcription" && /* @__PURE__ */ jsx8(
          TranscriptionOptions,
          {
            responseFormat: transcriptionResponseFormat,
            temperature: transcriptionTemperature,
            onResponseFormatChange: setTranscriptionResponseFormat,
            onTemperatureChange: setTranscriptionTemperature
          }
        )
      ] }) }),
      /* @__PURE__ */ jsx8(
        ComposerDisclosure,
        {
          summary: /* @__PURE__ */ jsxs7(Fragment4, { children: [
            "Schedule a post",
            selectedConnectedDestinations.length > 0 && /* @__PURE__ */ jsx8(Badge2, { variant: "outline", className: "ml-1 text-[10px]", children: selectedConnectedDestinations.length })
          ] }),
          children: /* @__PURE__ */ jsx8(
            PublishPackageComposer,
            {
              caption,
              postDescription,
              mentions,
              cadence,
              selectedDestinations,
              connections: integrations.connections,
              connectionError: integrations.error,
              connectionsLoading: integrations.isLoading,
              integrationsHref,
              canManageIntegrations,
              onCaptionChange: setCaption,
              onDescriptionChange: setPostDescription,
              onMentionsChange: setMentions,
              onCadenceChange: setCadence,
              onDestinationToggle: (destination) => {
                const destinationConfig = DESTINATIONS.find((item) => item.id === destination);
                if (!destinationConfig || !isDestinationConnected(destinationConfig, integrations.connections)) return;
                setSelectedDestinations((current) => current.includes(destination) ? current.filter((item) => item !== destination) : [...current, destination]);
              }
            }
          )
        }
      )
    ] }),
    /* @__PURE__ */ jsxs7(Button2, { onClick: generate, disabled: !canSubmit, size: "lg", className: "mt-4 w-full", children: [
      /* @__PURE__ */ jsx8(Sparkles, { className: "mr-2 h-4 w-4" }),
      "Generate",
      /* @__PURE__ */ jsx8("span", { className: "ml-2 text-[10px] opacity-60", children: "\u2318\u21B5" })
    ] })
  ] });
}

// src/studio-react/studio-header.tsx
import { Button as Button3 } from "@tangle-network/sandbox-ui/primitives";
import { Images } from "lucide-react";
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
function StudioHeader({
  count,
  onOpenLibrary,
  canGenerate
}) {
  return /* @__PURE__ */ jsx9("header", { className: "sticky top-0 z-20 border-b border-border bg-background/80 backdrop-blur-md", children: /* @__PURE__ */ jsxs8("div", { className: "mx-auto flex w-full max-w-3xl items-center justify-between gap-3 px-4 py-3 sm:px-6", children: [
    /* @__PURE__ */ jsxs8("div", { className: "min-w-0", children: [
      /* @__PURE__ */ jsx9("h1", { className: "text-lg font-semibold tracking-tight text-foreground", children: "Studio" }),
      /* @__PURE__ */ jsx9("p", { className: "truncate text-xs text-muted-foreground", children: canGenerate ? "Generate images, video, voice, avatars, and transcripts." : "Browse images, video, voice, avatars, and transcripts your team has created." })
    ] }),
    /* @__PURE__ */ jsxs8(Button3, { size: "sm", variant: "outline", onClick: onOpenLibrary, className: "shrink-0", children: [
      /* @__PURE__ */ jsx9(Images, { className: "mr-1.5 h-4 w-4" }),
      "Library",
      count > 0 && /* @__PURE__ */ jsx9("span", { className: "ml-2 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary/15 px-1.5 text-[10px] font-semibold text-primary", children: count })
    ] })
  ] }) });
}

// src/studio-react/result-canvas.tsx
import { Badge as Badge3 } from "@tangle-network/sandbox-ui/primitives";
import { ArrowRight, Sparkles as Sparkles2 } from "lucide-react";
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
function ResultCanvas({
  batch,
  onOpenLibrary,
  onSelect
}) {
  const cardClass = "rounded-xl border border-border bg-card shadow-sm";
  if (batch.length === 0) {
    return /* @__PURE__ */ jsxs9("section", { className: `${cardClass} flex min-h-[180px] flex-col items-center justify-center gap-2 p-8 text-center`, children: [
      /* @__PURE__ */ jsx10("div", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-muted", children: /* @__PURE__ */ jsx10(Sparkles2, { className: "h-6 w-6 text-muted-foreground/40" }) }),
      /* @__PURE__ */ jsx10("p", { className: "text-sm font-medium text-foreground", children: "Your creations appear here" }),
      /* @__PURE__ */ jsx10("p", { className: "max-w-xs text-xs text-muted-foreground", children: "Write a prompt above and hit Generate \u2014 your latest result blooms here, and everything lives in your library." })
    ] });
  }
  const cfg = typeConfigFor(batch[0]?.type ?? "image");
  const statuses = batch.map(generationStatus);
  const runLabel = statuses.some((s) => s === "pending" || s === "running") ? "Generating\u2026" : statuses.every((s) => s === "failed") ? "Last run failed" : "Latest creation";
  const isWorking = statuses.some((s) => s === "pending" || s === "running");
  return /* @__PURE__ */ jsxs9("section", { className: `${cardClass} p-5`, children: [
    /* @__PURE__ */ jsxs9("div", { className: "mb-3 flex items-center justify-between gap-3", children: [
      /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
        /* @__PURE__ */ jsx10(Badge3, { variant: "outline", className: `${cfg.color} text-[10px]`, children: cfg.label }),
        /* @__PURE__ */ jsx10("span", { className: "text-sm font-medium text-foreground", children: runLabel }),
        isWorking && /* @__PURE__ */ jsx10("span", { className: "h-2 w-2 animate-pulse rounded-full bg-primary" })
      ] }),
      /* @__PURE__ */ jsxs9(
        "button",
        {
          type: "button",
          onClick: onOpenLibrary,
          className: "flex items-center gap-1 text-xs font-medium text-primary transition-colors hover:text-primary/80",
          children: [
            "View in Library",
            /* @__PURE__ */ jsx10(ArrowRight, { className: "h-3.5 w-3.5" })
          ]
        }
      )
    ] }),
    /* @__PURE__ */ jsx10("div", { className: `grid gap-3 ${batch.length === 1 ? "grid-cols-1" : "grid-cols-2"}`, children: batch.map((generation) => /* @__PURE__ */ jsx10(
      "button",
      {
        type: "button",
        onClick: () => onSelect(generation),
        className: "studio-bloom group relative aspect-video overflow-hidden rounded-lg border border-border bg-muted/40 transition-colors hover:border-primary/40",
        children: /* @__PURE__ */ jsx10(CanvasTile, { generation })
      },
      generation.id
    )) }),
    batch.length > 1 && /* @__PURE__ */ jsxs9("p", { className: "mt-2 text-xs text-muted-foreground", children: [
      batch.length,
      " results from this run"
    ] })
  ] });
}
function CanvasTile({ generation }) {
  const cfg = typeConfigFor(generation.type);
  const Icon = cfg.icon;
  const status = generationStatus(generation);
  if (status === "pending" || status === "running") {
    return /* @__PURE__ */ jsx10("div", { className: "studio-shimmer absolute inset-0 h-full w-full" });
  }
  if (status === "failed") {
    return /* @__PURE__ */ jsxs9("div", { className: "absolute inset-0 flex flex-col items-center justify-center gap-2 p-4 text-center", children: [
      /* @__PURE__ */ jsx10(Icon, { className: "h-6 w-6 text-destructive/50" }),
      /* @__PURE__ */ jsx10("p", { className: "line-clamp-3 text-xs text-destructive", children: generationError(generation) ?? "Generation failed" })
    ] });
  }
  if (generation.type === "image" && generation.result) {
    return /* @__PURE__ */ jsx10("img", { src: generation.result, alt: generation.prompt, className: "absolute inset-0 h-full w-full object-contain" });
  }
  if ((generation.type === "video" || generation.type === "avatar") && generation.result) {
    return /* @__PURE__ */ jsx10("video", { src: generation.result, controls: true, className: "absolute inset-0 h-full w-full object-contain" });
  }
  if (generation.type === "speech" && generation.result) {
    return /* @__PURE__ */ jsx10("div", { className: "absolute inset-0 flex items-center justify-center p-4", children: /* @__PURE__ */ jsx10("audio", { src: generation.result, controls: true, className: "w-full" }) });
  }
  if (generation.type === "transcription" && generation.result) {
    return /* @__PURE__ */ jsx10("div", { className: "absolute inset-0 overflow-y-auto p-4", children: /* @__PURE__ */ jsx10("p", { className: "whitespace-pre-wrap text-xs text-foreground", children: generation.result }) });
  }
  return /* @__PURE__ */ jsx10("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx10(Icon, { className: "h-8 w-8 text-muted-foreground/20" }) });
}

// src/studio-react/library-drawer.tsx
import { useMemo as useMemo3 } from "react";
import { Link as Link3 } from "react-router";
import {
  Button as Button5,
  EmptyState,
  Tabs,
  TabsList,
  TabsTrigger
} from "@tangle-network/sandbox-ui/primitives";
import { ArrowLeft, DollarSign, Film as Film2, FolderOpen as FolderOpen2, Sparkles as Sparkles3, X } from "lucide-react";

// src/studio-react/studio-sheet.tsx
import * as Dialog from "@radix-ui/react-dialog";
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
function StudioSheet({
  open,
  onOpenChange,
  title,
  children
}) {
  return /* @__PURE__ */ jsx11(Dialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs10(Dialog.Portal, { children: [
    /* @__PURE__ */ jsx11(Dialog.Overlay, { className: "studio-sheet-overlay fixed inset-0 z-50 bg-black/50 backdrop-blur-sm" }),
    /* @__PURE__ */ jsxs10(
      Dialog.Content,
      {
        className: "studio-sheet-content fixed inset-y-0 right-0 z-50 flex w-[min(92vw,30rem)] flex-col border-l border-border bg-card shadow-lg focus:outline-none",
        "aria-describedby": void 0,
        children: [
          /* @__PURE__ */ jsx11(Dialog.Title, { className: "sr-only", children: title }),
          children
        ]
      }
    )
  ] }) });
}

// src/studio-react/generation-card.tsx
import { Card, CardContent, Badge as Badge4 } from "@tangle-network/sandbox-ui/primitives";
import { Send } from "lucide-react";
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
function GenerationCard({
  generation,
  onSelect
}) {
  const cfg = typeConfigFor(generation.type);
  const Icon = cfg.icon;
  const status = generationStatus(generation);
  const publishPackage = generation.metadata?.publishPackage;
  return /* @__PURE__ */ jsx12("button", { type: "button", onClick: () => onSelect(generation), className: "group text-left animate-row-in", children: /* @__PURE__ */ jsxs11(Card, { className: "overflow-hidden transition-all group-hover:border-primary/50 group-hover:shadow-md", children: [
    /* @__PURE__ */ jsxs11("div", { className: "relative aspect-video bg-muted/50", children: [
      generation.type === "image" && generation.result ? /* @__PURE__ */ jsx12("img", { src: generation.result, alt: generation.prompt, className: "h-full w-full object-cover" }) : (generation.type === "video" || generation.type === "avatar") && generation.result ? /* @__PURE__ */ jsx12("video", { src: generation.result, className: "h-full w-full object-cover", muted: true }) : generation.type === "speech" && generation.result ? /* @__PURE__ */ jsx12("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
        /* @__PURE__ */ jsx12(Icon, { className: "h-6 w-6 text-muted-foreground/40" }),
        /* @__PURE__ */ jsx12("span", { className: "text-xs text-muted-foreground", children: "Audio" })
      ] }) }) : generation.type === "transcription" && generation.result ? /* @__PURE__ */ jsx12("div", { className: "flex h-full items-center justify-center p-4", children: /* @__PURE__ */ jsx12("p", { className: "line-clamp-5 text-xs text-muted-foreground", children: generation.result }) }) : status === "pending" || status === "running" ? /* @__PURE__ */ jsx12("div", { className: "shimmer h-full w-full" }) : /* @__PURE__ */ jsx12("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx12(Icon, { className: "h-8 w-8 text-muted-foreground/20" }) }),
      /* @__PURE__ */ jsx12("div", { className: "absolute left-2 top-2", children: /* @__PURE__ */ jsx12(Badge4, { variant: "outline", className: `${cfg.color} text-[10px] backdrop-blur-sm`, children: cfg.label }) }),
      /* @__PURE__ */ jsx12(GenerationStatusBadge, { generation })
    ] }),
    /* @__PURE__ */ jsxs11(CardContent, { className: "p-3", children: [
      /* @__PURE__ */ jsx12("p", { className: "mb-2 line-clamp-2 text-xs text-foreground", children: generation.prompt }),
      status === "failed" && /* @__PURE__ */ jsx12("p", { className: "mb-2 line-clamp-2 text-[10px] text-destructive", children: generationError(generation) }),
      /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between", children: [
        generation.model && /* @__PURE__ */ jsx12("span", { className: "truncate text-[10px] text-muted-foreground", children: generation.model }),
        /* @__PURE__ */ jsxs11("div", { className: "flex shrink-0 items-center gap-2", children: [
          generation.cost != null && /* @__PURE__ */ jsxs11("span", { className: "text-[10px] text-muted-foreground", children: [
            "$",
            generation.cost.toFixed(3)
          ] }),
          /* @__PURE__ */ jsx12("span", { className: "text-[10px] text-muted-foreground", children: relativeTime(generation.createdAt) })
        ] })
      ] }),
      isPublishPackage(publishPackage) && /* @__PURE__ */ jsxs11("div", { className: "mt-3 rounded-md border border-border bg-muted/30 p-2", children: [
        /* @__PURE__ */ jsxs11("div", { className: "mb-1 flex items-center gap-1.5 text-[10px] font-medium text-foreground", children: [
          /* @__PURE__ */ jsx12(Send, { className: "h-3 w-3" }),
          (publishPackage.destinations ?? []).join(", ") || "Publish package"
        ] }),
        /* @__PURE__ */ jsx12("p", { className: "line-clamp-2 text-[10px] text-muted-foreground", children: publishPackage.caption || "Caption pending" })
      ] })
    ] })
  ] }) });
}
function GenerationStatusBadge({
  generation,
  inline = false
}) {
  const status = generationStatus(generation);
  if (status === "succeeded") return null;
  const label = status === "failed" ? "Failed" : status === "running" ? "Running" : "Pending";
  const className = status === "failed" ? "border-destructive/25 bg-destructive/10 text-destructive" : "border-warning/25 bg-warning/10 text-warning";
  return /* @__PURE__ */ jsx12("div", { className: inline ? "" : "absolute bottom-2 left-2", children: /* @__PURE__ */ jsx12(Badge4, { variant: "outline", className: `${className} text-[10px] backdrop-blur-sm`, children: label }) });
}

// src/studio-react/generation-detail.tsx
import { Link as Link2 } from "react-router";
import { Badge as Badge5, Button as Button4 } from "@tangle-network/sandbox-ui/primitives";
import { FolderOpen } from "lucide-react";
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
function GenerationDetail({
  generation,
  vaultHref,
  onNavigate
}) {
  const cfg = typeConfigFor(generation.type);
  const Icon = cfg.icon;
  const vaultPath = generationVaultPath(generation);
  const href = vaultHref && vaultPath ? vaultHref(vaultPath) : null;
  return /* @__PURE__ */ jsxs12("div", { className: "space-y-4", children: [
    /* @__PURE__ */ jsx13("div", { className: "overflow-hidden rounded-lg bg-muted/50", children: generation.type === "image" && generation.result ? /* @__PURE__ */ jsx13("img", { src: generation.result, alt: generation.prompt, className: "max-h-[420px] w-full object-contain" }) : (generation.type === "video" || generation.type === "avatar") && generation.result ? /* @__PURE__ */ jsx13("video", { src: generation.result, controls: true, className: "max-h-[420px] w-full" }) : generation.type === "speech" && generation.result ? /* @__PURE__ */ jsx13("div", { className: "p-6", children: /* @__PURE__ */ jsx13("audio", { src: generation.result, controls: true, className: "w-full" }) }) : /* @__PURE__ */ jsx13("div", { className: "flex h-32 items-center justify-center", children: /* @__PURE__ */ jsx13(Icon, { className: "h-8 w-8 text-muted-foreground/20" }) }) }),
    /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-2", children: [
      /* @__PURE__ */ jsx13(Badge5, { variant: "outline", className: cfg.color, children: cfg.label }),
      /* @__PURE__ */ jsx13(GenerationStatusBadge, { generation, inline: true }),
      generationError(generation) && /* @__PURE__ */ jsx13("span", { className: "text-xs text-destructive", children: generationError(generation) })
    ] }),
    /* @__PURE__ */ jsxs12("div", { children: [
      /* @__PURE__ */ jsx13("span", { className: "mb-1 block text-xs font-medium text-muted-foreground", children: "Prompt" }),
      /* @__PURE__ */ jsx13("p", { className: "text-sm text-foreground", children: generation.prompt })
    ] }),
    /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-4", children: [
      generation.model && /* @__PURE__ */ jsxs12("div", { children: [
        /* @__PURE__ */ jsx13("span", { className: "block text-[10px] font-medium text-muted-foreground", children: "Model" }),
        /* @__PURE__ */ jsx13("span", { className: "text-xs text-foreground", children: generation.model })
      ] }),
      generation.cost != null && /* @__PURE__ */ jsxs12("div", { children: [
        /* @__PURE__ */ jsx13("span", { className: "block text-[10px] font-medium text-muted-foreground", children: "Cost" }),
        /* @__PURE__ */ jsxs12("span", { className: "text-xs text-foreground", children: [
          "$",
          generation.cost.toFixed(4)
        ] })
      ] }),
      generation.createdAt && /* @__PURE__ */ jsxs12("div", { children: [
        /* @__PURE__ */ jsx13("span", { className: "block text-[10px] font-medium text-muted-foreground", children: "Created" }),
        /* @__PURE__ */ jsx13("span", { className: "text-xs text-foreground", children: new Date(generation.createdAt).toLocaleString() })
      ] })
    ] }),
    generation.type === "transcription" && generation.result && /* @__PURE__ */ jsxs12("div", { children: [
      /* @__PURE__ */ jsx13("span", { className: "mb-1 block text-xs font-medium text-muted-foreground", children: "Transcription" }),
      /* @__PURE__ */ jsx13("pre", { className: "max-h-64 overflow-y-auto whitespace-pre-wrap rounded-lg bg-muted/50 p-4 text-sm text-foreground", children: generation.result })
    ] }),
    href && /* @__PURE__ */ jsx13("div", { className: "border-t border-border pt-2", children: /* @__PURE__ */ jsx13(Link2, { to: href, prefetch: "intent", onClick: onNavigate, children: /* @__PURE__ */ jsxs12(Button4, { size: "sm", variant: "outline", children: [
      /* @__PURE__ */ jsx13(FolderOpen, { className: "mr-1.5 h-3.5 w-3.5" }),
      "Open in Vault"
    ] }) }) })
  ] });
}

// src/studio-react/library-drawer.tsx
import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
function LibraryDrawer({
  open,
  onOpenChange,
  generations,
  totalCost,
  typeFilter,
  onFilterChange,
  vaultHref,
  selected,
  onSelect
}) {
  const visible = useMemo3(() => {
    if (!typeFilter || !isGenerationType(typeFilter)) return generations;
    return generations.filter((generation) => generation.type === typeFilter);
  }, [generations, typeFilter]);
  return /* @__PURE__ */ jsxs13(StudioSheet, { open, onOpenChange, title: "Asset library", children: [
    /* @__PURE__ */ jsxs13("header", { className: "flex shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-3", children: [
      selected ? /* @__PURE__ */ jsxs13(
        "button",
        {
          type: "button",
          onClick: () => onSelect(null),
          className: "flex items-center gap-1.5 text-sm font-medium text-foreground transition-colors hover:text-primary",
          children: [
            /* @__PURE__ */ jsx14(ArrowLeft, { className: "h-4 w-4" }),
            "Back to library"
          ]
        }
      ) : /* @__PURE__ */ jsx14("h2", { className: "text-sm font-semibold text-foreground", children: "Asset library" }),
      /* @__PURE__ */ jsx14(
        "button",
        {
          type: "button",
          "aria-label": "Close library",
          onClick: () => onOpenChange(false),
          className: "rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
          children: /* @__PURE__ */ jsx14(X, { className: "h-4 w-4" })
        }
      )
    ] }),
    selected ? /* @__PURE__ */ jsx14("div", { className: "flex-1 overflow-y-auto p-4", children: /* @__PURE__ */ jsx14(
      GenerationDetail,
      {
        generation: selected,
        vaultHref,
        onNavigate: () => onOpenChange(false)
      }
    ) }) : /* @__PURE__ */ jsxs13(Fragment5, { children: [
      /* @__PURE__ */ jsxs13("div", { className: "shrink-0 border-b border-border px-4 pt-3", children: [
        /* @__PURE__ */ jsxs13("div", { className: "mb-2 flex items-center justify-between gap-3", children: [
          /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: [
            /* @__PURE__ */ jsxs13("span", { children: [
              visible.length,
              " generation",
              visible.length !== 1 ? "s" : ""
            ] }),
            /* @__PURE__ */ jsxs13("span", { className: "flex items-center gap-0.5", children: [
              /* @__PURE__ */ jsx14(DollarSign, { className: "h-3 w-3" }),
              totalCost.toFixed(2),
              " spent"
            ] })
          ] }),
          vaultHref && /* @__PURE__ */ jsx14(Link3, { to: vaultHref(), prefetch: "intent", onClick: () => onOpenChange(false), children: /* @__PURE__ */ jsxs13(Button5, { size: "sm", variant: "outline", children: [
            /* @__PURE__ */ jsx14(FolderOpen2, { className: "mr-1.5 h-3.5 w-3.5" }),
            "Vault"
          ] }) })
        ] }),
        /* @__PURE__ */ jsx14(Tabs, { value: typeFilter ?? "all", onValueChange: (v) => onFilterChange(v === "all" ? null : v), children: /* @__PURE__ */ jsxs13(TabsList, { className: "h-9 w-full justify-start gap-1 overflow-x-auto bg-transparent", children: [
          /* @__PURE__ */ jsx14(TabsTrigger, { value: "all", className: "text-xs", children: "All" }),
          Object.entries(TYPE_CONFIG).map(([key, cfg]) => /* @__PURE__ */ jsx14(TabsTrigger, { value: key, className: "text-xs", children: cfg.label }, key))
        ] }) })
      ] }),
      /* @__PURE__ */ jsx14("div", { className: "flex-1 overflow-y-auto p-4", children: visible.length === 0 ? /* @__PURE__ */ jsx14(
        EmptyState,
        {
          icon: typeFilter ? /* @__PURE__ */ jsx14(Film2, { className: "h-8 w-8 text-muted-foreground/30" }) : /* @__PURE__ */ jsx14(Sparkles3, { className: "h-10 w-10 text-muted-foreground/30" }),
          title: typeFilter ? `No ${TYPE_CONFIG[typeFilter]?.label ?? typeFilter} generations` : "No generations yet",
          description: typeFilter ? "Try a different filter or change the type in the composer." : "Everything you and the agent create lives here.",
          className: "py-16"
        }
      ) : /* @__PURE__ */ jsx14("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2", children: visible.map((generation) => /* @__PURE__ */ jsx14(GenerationCard, { generation, onSelect }, generation.id)) }) })
    ] })
  ] });
}

// src/studio-react/studio-workspace.tsx
import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
function StudioWorkspace({
  generations,
  totalCost,
  workspaceId,
  role,
  generationsEndpoint,
  vaultHref,
  integrationsHref
}) {
  const [searchParams, setSearchParams] = useSearchParams();
  const typeFilter = searchParams.get("type");
  const [drawerOpen, setDrawerOpen] = useState3(false);
  const [selected, setSelected] = useState3(null);
  const canvasRef = useRef3(null);
  const canGenerate = role !== "viewer";
  const canManageIntegrations = role === "owner" || role === "admin";
  const resolvedVaultHref = vaultHref ?? (workspaceId ? (filePath) => filePath ? `/app/${workspaceId}/vault?file=${encodeURIComponent(filePath)}` : `/app/${workspaceId}/vault` : void 0);
  const resolvedIntegrationsHref = integrationsHref ?? (workspaceId ? `/app/${workspaceId}/integrations` : void 0);
  const { mergedGenerations, latestBatch, onGenerated } = useStudioGenerations(generations, {
    workspaceId,
    generationsEndpoint
  });
  function setFilter(type) {
    if (type) setSearchParams({ type });
    else setSearchParams({});
  }
  function openLibrary() {
    setSelected(null);
    setDrawerOpen(true);
  }
  function openDetail(generation) {
    setSelected(generation);
    setDrawerOpen(true);
  }
  return /* @__PURE__ */ jsxs14("div", { className: "min-h-0 flex-1 overflow-y-auto bg-background", children: [
    /* @__PURE__ */ jsx15(
      StudioHeader,
      {
        count: mergedGenerations.length,
        canGenerate,
        onOpenLibrary: openLibrary
      }
    ),
    /* @__PURE__ */ jsx15("div", { className: "mx-auto w-full max-w-3xl space-y-4 px-4 py-6 sm:px-6", children: canGenerate ? /* @__PURE__ */ jsxs14(Fragment6, { children: [
      /* @__PURE__ */ jsx15(
        ComposerHero,
        {
          workspaceId,
          integrationsHref: resolvedIntegrationsHref,
          canManageIntegrations,
          onGenerated: (generation) => {
            onGenerated(generation);
            requestAnimationFrame(() => {
              canvasRef.current?.scrollIntoView({ behavior: "smooth", block: "center" });
            });
          }
        }
      ),
      /* @__PURE__ */ jsx15("div", { ref: canvasRef, children: /* @__PURE__ */ jsx15(
        ResultCanvas,
        {
          batch: latestBatch,
          onOpenLibrary: openLibrary,
          onSelect: openDetail
        }
      ) })
    ] }) : /* @__PURE__ */ jsxs14("section", { className: "flex flex-col items-center justify-center gap-3 rounded-xl border border-border bg-card p-10 text-center shadow-sm", children: [
      /* @__PURE__ */ jsx15("div", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-muted", children: /* @__PURE__ */ jsx15(Images2, { className: "h-6 w-6 text-muted-foreground/40" }) }),
      /* @__PURE__ */ jsx15("p", { className: "text-sm font-medium text-foreground", children: mergedGenerations.length > 0 ? `${mergedGenerations.length} asset${mergedGenerations.length !== 1 ? "s" : ""} in this workspace` : "No generations yet" }),
      /* @__PURE__ */ jsx15("p", { className: "max-w-sm text-xs text-muted-foreground", children: "When workspace members generate images, video, voice, avatars, or transcripts, they appear in the library." }),
      /* @__PURE__ */ jsxs14(Button6, { size: "sm", variant: "outline", onClick: openLibrary, children: [
        /* @__PURE__ */ jsx15(Images2, { className: "mr-1.5 h-4 w-4" }),
        "Open library"
      ] })
    ] }) }),
    /* @__PURE__ */ jsx15(
      LibraryDrawer,
      {
        open: drawerOpen,
        onOpenChange: (open) => {
          setDrawerOpen(open);
          if (!open) setSelected(null);
        },
        generations: mergedGenerations,
        totalCost,
        typeFilter,
        onFilterChange: setFilter,
        vaultHref: resolvedVaultHref,
        selected,
        onSelect: (generation) => {
          setSelected(generation);
          if (generation) setDrawerOpen(true);
        }
      }
    )
  ] });
}
export {
  AvatarComposer,
  ComposerDisclosure,
  ComposerHero,
  Field,
  GenerationCard,
  GenerationDetail,
  GenerationStatusBadge,
  ImageComposer,
  LibraryDrawer,
  NativeSelect,
  PublishPackageComposer,
  ResultCanvas,
  SpeechComposer,
  StudioHeader,
  StudioSheet,
  StudioWorkspace,
  TYPE_CONFIG,
  TranscriptionComposer,
  TranscriptionOptions,
  VideoComposer,
  typeConfigFor,
  useStudioGenerations
};
//# sourceMappingURL=index.js.map