@tangle-network/agent-app 0.43.21 → 0.43.23

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.
@@ -121,7 +121,7 @@ function typeConfigFor(type) {
121
121
 
122
122
  // src/studio-react/composer-shell.tsx
123
123
  import { Label } from "@tangle-network/sandbox-ui/primitives";
124
- import { ChevronRight } from "lucide-react";
124
+ import { ChevronRight, Minus, Plus } from "lucide-react";
125
125
  import { jsx, jsxs } from "react/jsx-runtime";
126
126
  function Field({
127
127
  label,
@@ -130,12 +130,51 @@ function Field({
130
130
  children
131
131
  }) {
132
132
  return /* @__PURE__ */ jsxs("div", { className, children: [
133
- /* @__PURE__ */ jsx(Label, { htmlFor, className: "text-sm", children: label }),
133
+ /* @__PURE__ */ jsx(
134
+ Label,
135
+ {
136
+ htmlFor,
137
+ className: "text-[10.5px] font-semibold uppercase tracking-[0.08em] text-muted-foreground",
138
+ children: label
139
+ }
140
+ ),
134
141
  children
135
142
  ] });
136
143
  }
144
+ function Stepper({
145
+ value,
146
+ min,
147
+ max,
148
+ onChange
149
+ }) {
150
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-9 items-center justify-between rounded-md border border-input bg-background px-1.5", children: [
151
+ /* @__PURE__ */ jsx(
152
+ "button",
153
+ {
154
+ type: "button",
155
+ "aria-label": "Decrease",
156
+ onClick: () => onChange(Math.max(min, value - 1)),
157
+ disabled: value <= min,
158
+ 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",
159
+ children: /* @__PURE__ */ jsx(Minus, { className: "h-3.5 w-3.5" })
160
+ }
161
+ ),
162
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium tabular-nums", children: value }),
163
+ /* @__PURE__ */ jsx(
164
+ "button",
165
+ {
166
+ type: "button",
167
+ "aria-label": "Increase",
168
+ onClick: () => onChange(Math.min(max, value + 1)),
169
+ disabled: value >= max,
170
+ 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",
171
+ children: /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" })
172
+ }
173
+ )
174
+ ] });
175
+ }
137
176
  function ComposerDisclosure({ summary, children }) {
138
- return /* @__PURE__ */ jsxs("details", { className: "group rounded-lg border border-border bg-muted/30 transition-colors open:bg-muted/40", children: [
177
+ return /* @__PURE__ */ jsxs("details", { className: "group rounded-lg border border-border bg-background transition-colors", children: [
139
178
  /* @__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: [
140
179
  /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5 text-muted-foreground transition-transform group-open:rotate-90" }),
141
180
  summary
@@ -144,12 +183,12 @@ function ComposerDisclosure({ summary, children }) {
144
183
  ] });
145
184
  }
146
185
  function NativeSelect(props) {
147
- return /* @__PURE__ */ jsx("select", { ...props, className: "h-9 w-full rounded-md border border-input bg-background px-3 text-sm" });
186
+ return /* @__PURE__ */ jsx("select", { ...props, className: "h-9 w-full rounded-md border border-input bg-[var(--md3-surface-container-low)] px-3 text-sm" });
148
187
  }
149
188
 
150
189
  // src/studio-react/image-composer.tsx
151
190
  import { Input } from "@tangle-network/sandbox-ui/primitives";
152
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
191
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
153
192
  function ImageComposer({
154
193
  size,
155
194
  quality,
@@ -158,16 +197,26 @@ function ImageComposer({
158
197
  onQualityChange,
159
198
  onImageCountChange
160
199
  }) {
161
- return /* @__PURE__ */ jsxs2(Fragment, { children: [
162
- /* @__PURE__ */ jsx2(Field, { label: "Size", children: /* @__PURE__ */ jsx2(Input, { value: size, onChange: (event) => onSizeChange(event.target.value) }) }),
163
- /* @__PURE__ */ jsx2(Field, { label: "Quality", children: /* @__PURE__ */ jsx2(Input, { value: quality, onChange: (event) => onQualityChange(event.target.value) }) }),
164
- /* @__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)) }) })
200
+ return /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
201
+ /* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-2 gap-3", children: [
202
+ /* @__PURE__ */ jsx2(Field, { label: "Size", children: /* @__PURE__ */ jsx2(Input, { value: size, onChange: (event) => onSizeChange(event.target.value), className: "bg-background" }) }),
203
+ /* @__PURE__ */ jsx2(Field, { label: "Quality", children: /* @__PURE__ */ jsx2(Input, { value: quality, onChange: (event) => onQualityChange(event.target.value), className: "bg-background" }) })
204
+ ] }),
205
+ /* @__PURE__ */ jsx2(Field, { label: "Images", children: /* @__PURE__ */ jsx2(
206
+ Stepper,
207
+ {
208
+ value: imageCount,
209
+ min: MIN_IMAGE_COUNT,
210
+ max: MAX_IMAGE_COUNT,
211
+ onChange: (value) => onImageCountChange(normalizeImageCount(value))
212
+ }
213
+ ) })
165
214
  ] });
166
215
  }
167
216
 
168
217
  // src/studio-react/video-composer.tsx
169
218
  import { Input as Input2 } from "@tangle-network/sandbox-ui/primitives";
170
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
219
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
171
220
  function VideoComposer({
172
221
  duration,
173
222
  resolution,
@@ -178,11 +227,11 @@ function VideoComposer({
178
227
  onAspectRatioChange,
179
228
  onReferenceImageUrlChange
180
229
  }) {
181
- return /* @__PURE__ */ jsxs3(Fragment2, { children: [
182
- /* @__PURE__ */ jsx3(Field, { label: "Duration (s)", children: /* @__PURE__ */ jsx3(Input2, { value: duration, onChange: (event) => onDurationChange(event.target.value) }) }),
183
- /* @__PURE__ */ jsx3(Field, { label: "Resolution", children: /* @__PURE__ */ jsx3(Input2, { value: resolution, onChange: (event) => onResolutionChange(event.target.value) }) }),
184
- /* @__PURE__ */ jsx3(Field, { label: "Aspect ratio", children: /* @__PURE__ */ jsx3(Input2, { value: aspectRatio, onChange: (event) => onAspectRatioChange(event.target.value) }) }),
185
- /* @__PURE__ */ jsx3(Field, { label: "Reference image URL", children: /* @__PURE__ */ jsx3(Input2, { value: referenceImageUrl, onChange: (event) => onReferenceImageUrlChange(event.target.value) }) })
230
+ return /* @__PURE__ */ jsxs3("div", { className: "grid grid-cols-2 gap-3", children: [
231
+ /* @__PURE__ */ jsx3(Field, { label: "Duration (s)", children: /* @__PURE__ */ jsx3(Input2, { value: duration, onChange: (event) => onDurationChange(event.target.value), className: "bg-background" }) }),
232
+ /* @__PURE__ */ jsx3(Field, { label: "Resolution", children: /* @__PURE__ */ jsx3(Input2, { value: resolution, onChange: (event) => onResolutionChange(event.target.value), className: "bg-background" }) }),
233
+ /* @__PURE__ */ jsx3(Field, { label: "Aspect ratio", children: /* @__PURE__ */ jsx3(Input2, { value: aspectRatio, onChange: (event) => onAspectRatioChange(event.target.value), className: "bg-background" }) }),
234
+ /* @__PURE__ */ jsx3(Field, { label: "Reference image URL", children: /* @__PURE__ */ jsx3(Input2, { value: referenceImageUrl, onChange: (event) => onReferenceImageUrlChange(event.target.value), className: "bg-background" }) })
186
235
  ] });
187
236
  }
188
237
 
@@ -193,7 +242,7 @@ function SpeechComposer({
193
242
  voice,
194
243
  onVoiceChange
195
244
  }) {
196
- return /* @__PURE__ */ jsx4(Field, { label: "Voice", children: /* @__PURE__ */ jsx4(Input3, { value: voice, onChange: (event) => onVoiceChange(event.target.value) }) });
245
+ return /* @__PURE__ */ jsx4(Field, { label: "Voice", children: /* @__PURE__ */ jsx4(Input3, { value: voice, onChange: (event) => onVoiceChange(event.target.value), className: "bg-background" }) });
197
246
  }
198
247
 
199
248
  // src/studio-react/avatar-composer.tsx
@@ -214,7 +263,8 @@ function AvatarComposer({
214
263
  id: "studio-audio-url",
215
264
  value: audioUrl,
216
265
  onChange: (event) => onAudioUrlChange(event.target.value),
217
- placeholder: "https://cdn.example.com/source-audio.mp3"
266
+ placeholder: "https://cdn.example.com/source-audio.mp3",
267
+ className: "bg-background"
218
268
  }
219
269
  ) }),
220
270
  /* @__PURE__ */ jsx5(Field, { label: "Image URL", htmlFor: "studio-avatar-image-url", children: /* @__PURE__ */ jsx5(
@@ -223,7 +273,8 @@ function AvatarComposer({
223
273
  id: "studio-avatar-image-url",
224
274
  value: imageUrl,
225
275
  onChange: (event) => onImageUrlChange(event.target.value),
226
- placeholder: "https://cdn.example.com/portrait.png"
276
+ placeholder: "https://cdn.example.com/portrait.png",
277
+ className: "bg-background"
227
278
  }
228
279
  ) }),
229
280
  /* @__PURE__ */ jsx5(Field, { label: "Avatar ID", htmlFor: "studio-avatar-id", children: /* @__PURE__ */ jsx5(
@@ -232,7 +283,8 @@ function AvatarComposer({
232
283
  id: "studio-avatar-id",
233
284
  value: avatarId,
234
285
  onChange: (event) => onAvatarIdChange(event.target.value),
235
- placeholder: "Optional provider avatar id"
286
+ placeholder: "Optional provider avatar id",
287
+ className: "bg-background"
236
288
  }
237
289
  ) })
238
290
  ] });
@@ -240,7 +292,7 @@ function AvatarComposer({
240
292
 
241
293
  // src/studio-react/transcription-composer.tsx
242
294
  import { Input as Input5 } from "@tangle-network/sandbox-ui/primitives";
243
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
295
+ import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
244
296
  function TranscriptionComposer({
245
297
  audioUrl,
246
298
  language,
@@ -254,7 +306,8 @@ function TranscriptionComposer({
254
306
  id: "studio-audio-url",
255
307
  value: audioUrl,
256
308
  onChange: (event) => onAudioUrlChange(event.target.value),
257
- placeholder: "https://cdn.example.com/source-audio.mp3"
309
+ placeholder: "https://cdn.example.com/source-audio.mp3",
310
+ className: "bg-background"
258
311
  }
259
312
  ) }),
260
313
  /* @__PURE__ */ jsx6(Field, { label: "Language", htmlFor: "studio-transcription-language", children: /* @__PURE__ */ jsx6(
@@ -263,7 +316,8 @@ function TranscriptionComposer({
263
316
  id: "studio-transcription-language",
264
317
  value: language,
265
318
  onChange: (event) => onLanguageChange(event.target.value),
266
- placeholder: "en"
319
+ placeholder: "en",
320
+ className: "bg-background"
267
321
  }
268
322
  ) })
269
323
  ] });
@@ -274,7 +328,7 @@ function TranscriptionOptions({
274
328
  onResponseFormatChange,
275
329
  onTemperatureChange
276
330
  }) {
277
- return /* @__PURE__ */ jsxs5(Fragment3, { children: [
331
+ return /* @__PURE__ */ jsxs5(Fragment, { children: [
278
332
  /* @__PURE__ */ jsx6(Field, { label: "Response format", children: /* @__PURE__ */ jsxs5(NativeSelect, { value: responseFormat, onChange: (event) => onResponseFormatChange(event.target.value), children: [
279
333
  /* @__PURE__ */ jsx6("option", { value: "json", children: "JSON" }),
280
334
  /* @__PURE__ */ jsx6("option", { value: "text", children: "Text" }),
@@ -282,7 +336,7 @@ function TranscriptionOptions({
282
336
  /* @__PURE__ */ jsx6("option", { value: "verbose_json", children: "Verbose JSON" }),
283
337
  /* @__PURE__ */ jsx6("option", { value: "vtt", children: "VTT" })
284
338
  ] }) }),
285
- /* @__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) }) })
339
+ /* @__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), className: "bg-[var(--md3-surface-container-low)]" }) })
286
340
  ] });
287
341
  }
288
342
 
@@ -326,7 +380,7 @@ function PublishPackageComposer({
326
380
  disabled: !connected,
327
381
  "aria-pressed": active,
328
382
  onClick: () => onDestinationToggle(destination.id),
329
- 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"}`,
383
+ 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 bg-[var(--md3-surface-container-low)] hover:bg-muted/50"}`,
330
384
  children: [
331
385
  /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-2", children: [
332
386
  /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-1.5 text-xs font-medium text-foreground", children: [
@@ -341,10 +395,10 @@ function PublishPackageComposer({
341
395
  destination.id
342
396
  );
343
397
  }) }),
344
- /* @__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..." }) }),
345
- /* @__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..." }) }),
398
+ /* @__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...", className: "bg-[var(--md3-surface-container-low)]" }) }),
399
+ /* @__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...", className: "bg-[var(--md3-surface-container-low)]" }) }),
346
400
  /* @__PURE__ */ jsxs6("div", { className: "grid grid-cols-2 gap-3", children: [
347
- /* @__PURE__ */ jsx7(Field, { label: "Mentions", className: "space-y-2", children: /* @__PURE__ */ jsx7(Input6, { value: mentions, onChange: (event) => onMentionsChange(event.target.value), placeholder: "@creator, @partner" }) }),
401
+ /* @__PURE__ */ jsx7(Field, { label: "Mentions", className: "space-y-2", children: /* @__PURE__ */ jsx7(Input6, { value: mentions, onChange: (event) => onMentionsChange(event.target.value), placeholder: "@creator, @partner", className: "bg-[var(--md3-surface-container-low)]" }) }),
348
402
  /* @__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)) }) })
349
403
  ] }),
350
404
  /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 rounded-md bg-muted/40 p-2 text-xs text-muted-foreground", children: [
@@ -355,7 +409,7 @@ function PublishPackageComposer({
355
409
  }
356
410
 
357
411
  // src/studio-react/composer-hero.tsx
358
- import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
412
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
359
413
  var HUB_BASE_URL = "/api/integrations/hub";
360
414
  var SUGGESTIONS = [
361
415
  {
@@ -383,6 +437,8 @@ function ComposerHero({
383
437
  workspaceId,
384
438
  integrationsHref,
385
439
  canManageIntegrations,
440
+ align = "start",
441
+ surfaceClassName = "bg-card",
386
442
  onGenerated
387
443
  }) {
388
444
  const [type, setType] = useState2("image");
@@ -547,57 +603,61 @@ function ComposerHero({
547
603
  }
548
604
  }
549
605
  const mediaTypes = Object.entries(TYPE_CONFIG);
550
- const hasInlineParams = type === "image" || type === "video" || type === "speech";
551
- return /* @__PURE__ */ jsxs7("section", { className: "rounded-xl border border-border bg-card p-5 shadow-sm", children: [
552
- /* @__PURE__ */ jsx8(Field, { label: "Media type", className: "space-y-1.5", children: /* @__PURE__ */ jsx8(
553
- "div",
606
+ return /* @__PURE__ */ jsxs7("section", { className: `rounded-2xl border border-border p-5 shadow-sm ${surfaceClassName}`, children: [
607
+ /* @__PURE__ */ jsx8("div", { className: `mb-5 ${align === "center" ? "text-center" : "text-left"}`, children: /* @__PURE__ */ jsx8(
608
+ "h1",
554
609
  {
555
- role: "tablist",
556
- "aria-label": "Generation type",
557
- className: "grid grid-cols-5 gap-1 rounded-lg border border-border bg-muted/40 p-1",
558
- children: mediaTypes.map(([key, cfg]) => {
559
- const Icon = cfg.icon;
560
- const active = type === key;
561
- return /* @__PURE__ */ jsxs7(
562
- "button",
563
- {
564
- type: "button",
565
- role: "tab",
566
- "aria-selected": active,
567
- onClick: () => changeType(key),
568
- 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"}`,
569
- children: [
570
- /* @__PURE__ */ jsx8(Icon, { className: "h-4 w-4 shrink-0" }),
571
- /* @__PURE__ */ jsx8("span", { className: "truncate", children: cfg.label })
572
- ]
573
- },
574
- key
575
- );
576
- })
610
+ className: `font-semibold tracking-tight text-foreground transition-all duration-300 ${align === "center" ? "text-xl" : "text-base"}`,
611
+ children: "Media Generation"
577
612
  }
578
613
  ) }),
579
- type !== "avatar" && /* @__PURE__ */ jsxs7("div", { className: "mt-4 space-y-2", children: [
580
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "studio-prompt", className: "block text-sm font-medium", children: "What do you want to create?" }),
614
+ /* @__PURE__ */ jsx8("div", { role: "tablist", "aria-label": "Generation type", className: "grid grid-cols-5 gap-1.5", children: mediaTypes.map(([key, cfg]) => {
615
+ const Icon = cfg.icon;
616
+ const active = type === key;
617
+ return /* @__PURE__ */ jsxs7(
618
+ "button",
619
+ {
620
+ type: "button",
621
+ role: "tab",
622
+ "aria-selected": active,
623
+ onClick: () => changeType(key),
624
+ className: `flex flex-col items-center gap-1.5 rounded-lg border px-1 pb-2 pt-2.5 text-[11px] transition-all ${active ? "border-primary/30 bg-primary/10 font-semibold text-primary" : "border-border bg-background font-medium text-muted-foreground hover:border-foreground/20 hover:text-foreground"}`,
625
+ children: [
626
+ /* @__PURE__ */ jsx8(Icon, { className: "h-[17px] w-[17px] shrink-0" }),
627
+ /* @__PURE__ */ jsx8("span", { className: "truncate", children: cfg.label })
628
+ ]
629
+ },
630
+ key
631
+ );
632
+ }) }),
633
+ type !== "avatar" && /* @__PURE__ */ jsxs7("div", { className: "mt-5", children: [
581
634
  /* @__PURE__ */ jsx8(
582
- Textarea2,
635
+ Label2,
583
636
  {
584
- id: "studio-prompt",
585
- value: prompt,
586
- onChange: (event) => setPrompt(event.target.value),
587
- onKeyDown: (event) => {
588
- if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
589
- event.preventDefault();
590
- void generate();
591
- }
592
- },
593
- rows: 4,
594
- placeholder: type === "transcription" ? "Optional vocabulary, speaker names, timestamp style, or context..." : "A vertical hero frame for a product launch teaser, dark cinematic lighting...",
595
- className: "resize-none text-sm"
637
+ htmlFor: "studio-prompt",
638
+ className: "mb-1.5 block text-[10.5px] font-semibold uppercase tracking-[0.08em] text-muted-foreground",
639
+ children: "Prompt"
596
640
  }
597
641
  ),
598
- /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-1.5 text-xs text-muted-foreground", children: [
599
- /* @__PURE__ */ jsx8("span", { children: "Try:" }),
600
- SUGGESTIONS.map((suggestion) => /* @__PURE__ */ jsx8(
642
+ /* @__PURE__ */ jsxs7("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", children: [
643
+ /* @__PURE__ */ jsx8(
644
+ "textarea",
645
+ {
646
+ id: "studio-prompt",
647
+ value: prompt,
648
+ onChange: (event) => setPrompt(event.target.value),
649
+ onKeyDown: (event) => {
650
+ if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
651
+ event.preventDefault();
652
+ void generate();
653
+ }
654
+ },
655
+ rows: 4,
656
+ placeholder: type === "transcription" ? "Optional vocabulary, speaker names, timestamp style, or context..." : "A vertical hero frame for a product launch teaser, dark cinematic lighting...",
657
+ 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"
658
+ }
659
+ ),
660
+ /* @__PURE__ */ jsx8("div", { className: "flex flex-wrap items-center gap-1.5 px-2.5 pb-2.5", children: SUGGESTIONS.map((suggestion) => /* @__PURE__ */ jsx8(
601
661
  "button",
602
662
  {
603
663
  type: "button",
@@ -605,13 +665,13 @@ function ComposerHero({
605
665
  setPrompt(suggestion.prompt);
606
666
  changeType(suggestion.type);
607
667
  },
608
- 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",
668
+ className: "rounded-full border border-border bg-background px-2.5 py-1 text-[11px] font-medium text-muted-foreground transition-colors hover:border-primary/30 hover:text-primary",
609
669
  children: suggestion.label
610
670
  },
611
671
  suggestion.label
612
- ))
672
+ )) })
613
673
  ] }),
614
- 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." })
674
+ type === "transcription" && /* @__PURE__ */ jsx8("p", { className: "mt-2 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." })
615
675
  ] }),
616
676
  type === "avatar" && /* @__PURE__ */ jsx8(
617
677
  AvatarComposer,
@@ -633,33 +693,35 @@ function ComposerHero({
633
693
  onLanguageChange: setTranscriptionLanguage
634
694
  }
635
695
  ),
636
- /* @__PURE__ */ jsxs7("div", { className: "mt-4 grid gap-3 sm:grid-cols-2", children: [
637
- /* @__PURE__ */ jsx8(
638
- Field,
639
- {
640
- label: "Model",
641
- htmlFor: "studio-media-model",
642
- className: `space-y-1.5 ${hasInlineParams ? "" : "sm:col-span-2"}`,
643
- children: /* @__PURE__ */ jsxs7(
644
- Select,
645
- {
646
- value: selectedModel || void 0,
647
- onValueChange: (value) => setSelectedModels((current) => ({ ...current, [type]: value })),
648
- disabled: mediaModelsLoading || Boolean(mediaModelsError) || modelsForType.length === 0,
649
- children: [
650
- /* @__PURE__ */ jsx8(SelectTrigger, { id: "studio-media-model", className: "h-9 w-full", children: /* @__PURE__ */ jsx8(SelectValue, { placeholder: mediaModelsLoading ? "Loading models\u2026" : "Select a model" }) }),
651
- /* @__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: [
652
- /* @__PURE__ */ jsxs7("span", { className: "truncate", children: [
653
- model.name || model.id,
654
- model.provider ? ` \xB7 ${model.provider}` : ""
655
- ] }),
656
- model.status !== "available" && /* @__PURE__ */ jsx8("span", { className: "shrink-0 text-[10px] capitalize text-muted-foreground", children: model.status })
657
- ] }) }, model.id)) })
658
- ]
659
- }
660
- )
661
- }
662
- ),
696
+ /* @__PURE__ */ jsxs7("div", { className: "mt-5 space-y-3", children: [
697
+ /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
698
+ /* @__PURE__ */ jsx8(Field, { label: "Model", htmlFor: "studio-media-model", children: /* @__PURE__ */ jsxs7(
699
+ Select,
700
+ {
701
+ value: selectedModel || void 0,
702
+ onValueChange: (value) => setSelectedModels((current) => ({ ...current, [type]: value })),
703
+ disabled: mediaModelsLoading || Boolean(mediaModelsError) || modelsForType.length === 0,
704
+ children: [
705
+ /* @__PURE__ */ jsx8(SelectTrigger, { id: "studio-media-model", className: "h-9 w-full bg-background", children: selectedModelOption ? /* @__PURE__ */ jsxs7("span", { className: "flex min-w-0 items-center gap-2", children: [
706
+ /* @__PURE__ */ jsx8("span", { className: "truncate", children: selectedModelOption.name || selectedModelOption.id }),
707
+ selectedModelOption.provider && /* @__PURE__ */ jsxs7("span", { className: "shrink-0 text-muted-foreground", children: [
708
+ "\xB7 ",
709
+ selectedModelOption.provider
710
+ ] }),
711
+ selectedModelOption.status !== "available" && /* @__PURE__ */ jsx8("span", { className: "shrink-0 rounded-full bg-warning/10 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-warning", children: selectedModelOption.status })
712
+ ] }) : /* @__PURE__ */ jsx8(SelectValue, { placeholder: mediaModelsLoading ? "Loading models\u2026" : "Select a model" }) }),
713
+ /* @__PURE__ */ jsx8(SelectContent, { className: "bg-background", 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: [
714
+ /* @__PURE__ */ jsxs7("span", { className: "truncate", children: [
715
+ model.name || model.id,
716
+ model.provider ? ` \xB7 ${model.provider}` : ""
717
+ ] }),
718
+ model.status !== "available" && /* @__PURE__ */ jsx8("span", { className: "shrink-0 text-[10px] capitalize text-muted-foreground", children: model.status })
719
+ ] }) }, model.id)) })
720
+ ]
721
+ }
722
+ ) }),
723
+ (mediaModelsError || modelMessage(selectedModelOption, mediaModelsLoading, modelsForType.length)) && /* @__PURE__ */ jsx8("p", { className: `text-xs ${mediaModelsError || selectedModelOption?.status === "unavailable" ? "text-destructive" : "text-muted-foreground"}`, children: mediaModelsError ?? modelMessage(selectedModelOption, mediaModelsLoading, modelsForType.length) })
724
+ ] }),
663
725
  type === "image" && /* @__PURE__ */ jsx8(
664
726
  ImageComposer,
665
727
  {
@@ -686,8 +748,6 @@ function ComposerHero({
686
748
  ),
687
749
  type === "speech" && /* @__PURE__ */ jsx8(SpeechComposer, { voice, onVoiceChange: setVoice })
688
750
  ] }),
689
- (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) }),
690
- error && /* @__PURE__ */ jsx8("div", { className: "mt-3 rounded-md border border-destructive/20 bg-destructive/10 p-3 text-sm text-destructive", children: error }),
691
751
  /* @__PURE__ */ jsxs7("div", { className: "mt-4 space-y-2", children: [
692
752
  /* @__PURE__ */ jsx8(ComposerDisclosure, { summary: "Advanced options", children: /* @__PURE__ */ jsxs7("div", { className: "grid gap-3 sm:grid-cols-2", children: [
693
753
  /* @__PURE__ */ jsx8(Field, { label: "Negative prompt", children: /* @__PURE__ */ jsx8(
@@ -696,10 +756,11 @@ function ComposerHero({
696
756
  value: negativePrompt,
697
757
  onChange: (event) => setNegativePrompt(event.target.value),
698
758
  rows: 2,
699
- placeholder: "Avoid artifacts, off-style composition..."
759
+ placeholder: "Avoid artifacts, off-style composition...",
760
+ className: "bg-[var(--md3-surface-container-low)]"
700
761
  }
701
762
  ) }),
702
- /* @__PURE__ */ jsx8(Field, { label: "Save to", children: /* @__PURE__ */ jsx8(Input7, { value: outputPath, onChange: (event) => setOutputPath(event.target.value) }) }),
763
+ /* @__PURE__ */ jsx8(Field, { label: "Save to", children: /* @__PURE__ */ jsx8(Input7, { value: outputPath, onChange: (event) => setOutputPath(event.target.value), className: "bg-[var(--md3-surface-container-low)]" }) }),
703
764
  type === "transcription" && /* @__PURE__ */ jsx8(
704
765
  TranscriptionOptions,
705
766
  {
@@ -713,7 +774,7 @@ function ComposerHero({
713
774
  /* @__PURE__ */ jsx8(
714
775
  ComposerDisclosure,
715
776
  {
716
- summary: /* @__PURE__ */ jsxs7(Fragment4, { children: [
777
+ summary: /* @__PURE__ */ jsxs7(Fragment2, { children: [
717
778
  "Schedule a post",
718
779
  selectedConnectedDestinations.length > 0 && /* @__PURE__ */ jsx8(Badge2, { variant: "outline", className: "ml-1 text-[10px]", children: selectedConnectedDestinations.length })
719
780
  ] }),
@@ -744,7 +805,8 @@ function ComposerHero({
744
805
  }
745
806
  )
746
807
  ] }),
747
- /* @__PURE__ */ jsxs7(Button2, { onClick: generate, disabled: !canSubmit, size: "lg", className: "mt-4 w-full", children: [
808
+ error && /* @__PURE__ */ jsx8("div", { className: "mt-4 rounded-md border border-destructive/20 bg-destructive/10 p-3 text-sm text-destructive", children: error }),
809
+ /* @__PURE__ */ jsxs7(Button2, { onClick: generate, disabled: !canSubmit, size: "lg", className: "mt-5 w-full", children: [
748
810
  /* @__PURE__ */ jsx8(Sparkles, { className: "mr-2 h-4 w-4" }),
749
811
  "Generate",
750
812
  /* @__PURE__ */ jsx8("span", { className: "ml-2 text-[10px] opacity-60", children: "\u2318\u21B5" })
@@ -864,12 +926,11 @@ import { useMemo as useMemo3 } from "react";
864
926
  import { Link as Link3 } from "react-router";
865
927
  import {
866
928
  Button as Button5,
867
- EmptyState,
868
929
  Tabs,
869
930
  TabsList,
870
931
  TabsTrigger
871
932
  } from "@tangle-network/sandbox-ui/primitives";
872
- import { ArrowLeft, DollarSign, Film as Film2, FolderOpen as FolderOpen2, Sparkles as Sparkles3, X } from "lucide-react";
933
+ import { ArrowLeft, DollarSign, FolderOpen as FolderOpen2, X } from "lucide-react";
873
934
 
874
935
  // src/studio-react/studio-sheet.tsx
875
936
  import * as Dialog from "@radix-ui/react-dialog";
@@ -896,6 +957,10 @@ function StudioSheet({
896
957
  ] }) });
897
958
  }
898
959
 
960
+ // src/studio-react/generation-grid.tsx
961
+ import { EmptyState } from "@tangle-network/sandbox-ui/primitives";
962
+ import { Film as Film2, Sparkles as Sparkles3 } from "lucide-react";
963
+
899
964
  // src/studio-react/generation-card.tsx
900
965
  import { Card, CardContent, Badge as Badge4 } from "@tangle-network/sandbox-ui/primitives";
901
966
  import { Send } from "lucide-react";
@@ -951,11 +1016,36 @@ function GenerationStatusBadge({
951
1016
  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 }) });
952
1017
  }
953
1018
 
1019
+ // src/studio-react/generation-grid.tsx
1020
+ import { jsx as jsx13 } from "react/jsx-runtime";
1021
+ function filterGenerations(generations, typeFilter) {
1022
+ if (!typeFilter || !isGenerationType(typeFilter)) return generations;
1023
+ return generations.filter((generation) => generation.type === typeFilter);
1024
+ }
1025
+ function GenerationGrid({
1026
+ generations,
1027
+ typeFilter,
1028
+ onSelect
1029
+ }) {
1030
+ if (generations.length === 0) {
1031
+ return /* @__PURE__ */ jsx13(
1032
+ EmptyState,
1033
+ {
1034
+ icon: typeFilter ? /* @__PURE__ */ jsx13(Film2, { className: "h-8 w-8 text-muted-foreground/30" }) : /* @__PURE__ */ jsx13(Sparkles3, { className: "h-10 w-10 text-muted-foreground/30" }),
1035
+ title: typeFilter ? `No ${TYPE_CONFIG[typeFilter]?.label ?? typeFilter} generations` : "No generations yet",
1036
+ description: typeFilter ? "Try a different filter or change the type in the composer." : "Everything you and the agent create lives here.",
1037
+ className: "py-16"
1038
+ }
1039
+ );
1040
+ }
1041
+ return /* @__PURE__ */ jsx13("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2", children: generations.map((generation) => /* @__PURE__ */ jsx13(GenerationCard, { generation, onSelect }, generation.id)) });
1042
+ }
1043
+
954
1044
  // src/studio-react/generation-detail.tsx
955
1045
  import { Link as Link2 } from "react-router";
956
1046
  import { Badge as Badge5, Button as Button4 } from "@tangle-network/sandbox-ui/primitives";
957
1047
  import { FolderOpen } from "lucide-react";
958
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1048
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
959
1049
  function GenerationDetail({
960
1050
  generation,
961
1051
  vaultHref,
@@ -966,46 +1056,46 @@ function GenerationDetail({
966
1056
  const vaultPath = generationVaultPath(generation);
967
1057
  const href = vaultHref && vaultPath ? vaultHref(vaultPath) : null;
968
1058
  return /* @__PURE__ */ jsxs12("div", { className: "space-y-4", children: [
969
- /* @__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" }) }) }),
1059
+ /* @__PURE__ */ jsx14("div", { className: "overflow-hidden rounded-lg bg-muted/50", children: generation.type === "image" && generation.result ? /* @__PURE__ */ jsx14("img", { src: generation.result, alt: generation.prompt, className: "max-h-[420px] w-full object-contain" }) : (generation.type === "video" || generation.type === "avatar") && generation.result ? /* @__PURE__ */ jsx14("video", { src: generation.result, controls: true, className: "max-h-[420px] w-full" }) : generation.type === "speech" && generation.result ? /* @__PURE__ */ jsx14("div", { className: "p-6", children: /* @__PURE__ */ jsx14("audio", { src: generation.result, controls: true, className: "w-full" }) }) : /* @__PURE__ */ jsx14("div", { className: "flex h-32 items-center justify-center", children: /* @__PURE__ */ jsx14(Icon, { className: "h-8 w-8 text-muted-foreground/20" }) }) }),
970
1060
  /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-2", children: [
971
- /* @__PURE__ */ jsx13(Badge5, { variant: "outline", className: cfg.color, children: cfg.label }),
972
- /* @__PURE__ */ jsx13(GenerationStatusBadge, { generation, inline: true }),
973
- generationError(generation) && /* @__PURE__ */ jsx13("span", { className: "text-xs text-destructive", children: generationError(generation) })
1061
+ /* @__PURE__ */ jsx14(Badge5, { variant: "outline", className: cfg.color, children: cfg.label }),
1062
+ /* @__PURE__ */ jsx14(GenerationStatusBadge, { generation, inline: true }),
1063
+ generationError(generation) && /* @__PURE__ */ jsx14("span", { className: "text-xs text-destructive", children: generationError(generation) })
974
1064
  ] }),
975
1065
  /* @__PURE__ */ jsxs12("div", { children: [
976
- /* @__PURE__ */ jsx13("span", { className: "mb-1 block text-xs font-medium text-muted-foreground", children: "Prompt" }),
977
- /* @__PURE__ */ jsx13("p", { className: "text-sm text-foreground", children: generation.prompt })
1066
+ /* @__PURE__ */ jsx14("span", { className: "mb-1 block text-xs font-medium text-muted-foreground", children: "Prompt" }),
1067
+ /* @__PURE__ */ jsx14("p", { className: "text-sm text-foreground", children: generation.prompt })
978
1068
  ] }),
979
1069
  /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-4", children: [
980
1070
  generation.model && /* @__PURE__ */ jsxs12("div", { children: [
981
- /* @__PURE__ */ jsx13("span", { className: "block text-[10px] font-medium text-muted-foreground", children: "Model" }),
982
- /* @__PURE__ */ jsx13("span", { className: "text-xs text-foreground", children: generation.model })
1071
+ /* @__PURE__ */ jsx14("span", { className: "block text-[10px] font-medium text-muted-foreground", children: "Model" }),
1072
+ /* @__PURE__ */ jsx14("span", { className: "text-xs text-foreground", children: generation.model })
983
1073
  ] }),
984
1074
  generation.cost != null && /* @__PURE__ */ jsxs12("div", { children: [
985
- /* @__PURE__ */ jsx13("span", { className: "block text-[10px] font-medium text-muted-foreground", children: "Cost" }),
1075
+ /* @__PURE__ */ jsx14("span", { className: "block text-[10px] font-medium text-muted-foreground", children: "Cost" }),
986
1076
  /* @__PURE__ */ jsxs12("span", { className: "text-xs text-foreground", children: [
987
1077
  "$",
988
1078
  generation.cost.toFixed(4)
989
1079
  ] })
990
1080
  ] }),
991
1081
  generation.createdAt && /* @__PURE__ */ jsxs12("div", { children: [
992
- /* @__PURE__ */ jsx13("span", { className: "block text-[10px] font-medium text-muted-foreground", children: "Created" }),
993
- /* @__PURE__ */ jsx13("span", { className: "text-xs text-foreground", children: new Date(generation.createdAt).toLocaleString() })
1082
+ /* @__PURE__ */ jsx14("span", { className: "block text-[10px] font-medium text-muted-foreground", children: "Created" }),
1083
+ /* @__PURE__ */ jsx14("span", { className: "text-xs text-foreground", children: new Date(generation.createdAt).toLocaleString() })
994
1084
  ] })
995
1085
  ] }),
996
1086
  generation.type === "transcription" && generation.result && /* @__PURE__ */ jsxs12("div", { children: [
997
- /* @__PURE__ */ jsx13("span", { className: "mb-1 block text-xs font-medium text-muted-foreground", children: "Transcription" }),
998
- /* @__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 })
1087
+ /* @__PURE__ */ jsx14("span", { className: "mb-1 block text-xs font-medium text-muted-foreground", children: "Transcription" }),
1088
+ /* @__PURE__ */ jsx14("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 })
999
1089
  ] }),
1000
- 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: [
1001
- /* @__PURE__ */ jsx13(FolderOpen, { className: "mr-1.5 h-3.5 w-3.5" }),
1090
+ href && /* @__PURE__ */ jsx14("div", { className: "border-t border-border pt-2", children: /* @__PURE__ */ jsx14(Link2, { to: href, prefetch: "intent", onClick: onNavigate, children: /* @__PURE__ */ jsxs12(Button4, { size: "sm", variant: "outline", children: [
1091
+ /* @__PURE__ */ jsx14(FolderOpen, { className: "mr-1.5 h-3.5 w-3.5" }),
1002
1092
  "Open in Vault"
1003
1093
  ] }) }) })
1004
1094
  ] });
1005
1095
  }
1006
1096
 
1007
1097
  // src/studio-react/library-drawer.tsx
1008
- import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1098
+ import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
1009
1099
  function LibraryDrawer({
1010
1100
  open,
1011
1101
  onOpenChange,
@@ -1017,10 +1107,7 @@ function LibraryDrawer({
1017
1107
  selected,
1018
1108
  onSelect
1019
1109
  }) {
1020
- const visible = useMemo3(() => {
1021
- if (!typeFilter || !isGenerationType(typeFilter)) return generations;
1022
- return generations.filter((generation) => generation.type === typeFilter);
1023
- }, [generations, typeFilter]);
1110
+ const visible = useMemo3(() => filterGenerations(generations, typeFilter), [generations, typeFilter]);
1024
1111
  return /* @__PURE__ */ jsxs13(StudioSheet, { open, onOpenChange, title: "Asset library", children: [
1025
1112
  /* @__PURE__ */ jsxs13("header", { className: "flex shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-3", children: [
1026
1113
  selected ? /* @__PURE__ */ jsxs13(
@@ -1030,30 +1117,30 @@ function LibraryDrawer({
1030
1117
  onClick: () => onSelect(null),
1031
1118
  className: "flex items-center gap-1.5 text-sm font-medium text-foreground transition-colors hover:text-primary",
1032
1119
  children: [
1033
- /* @__PURE__ */ jsx14(ArrowLeft, { className: "h-4 w-4" }),
1120
+ /* @__PURE__ */ jsx15(ArrowLeft, { className: "h-4 w-4" }),
1034
1121
  "Back to library"
1035
1122
  ]
1036
1123
  }
1037
- ) : /* @__PURE__ */ jsx14("h2", { className: "text-sm font-semibold text-foreground", children: "Asset library" }),
1038
- /* @__PURE__ */ jsx14(
1124
+ ) : /* @__PURE__ */ jsx15("h2", { className: "text-sm font-semibold text-foreground", children: "Asset library" }),
1125
+ /* @__PURE__ */ jsx15(
1039
1126
  "button",
1040
1127
  {
1041
1128
  type: "button",
1042
1129
  "aria-label": "Close library",
1043
1130
  onClick: () => onOpenChange(false),
1044
1131
  className: "rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
1045
- children: /* @__PURE__ */ jsx14(X, { className: "h-4 w-4" })
1132
+ children: /* @__PURE__ */ jsx15(X, { className: "h-4 w-4" })
1046
1133
  }
1047
1134
  )
1048
1135
  ] }),
1049
- selected ? /* @__PURE__ */ jsx14("div", { className: "flex-1 overflow-y-auto p-4", children: /* @__PURE__ */ jsx14(
1136
+ selected ? /* @__PURE__ */ jsx15("div", { className: "flex-1 overflow-y-auto p-4", children: /* @__PURE__ */ jsx15(
1050
1137
  GenerationDetail,
1051
1138
  {
1052
1139
  generation: selected,
1053
1140
  vaultHref,
1054
1141
  onNavigate: () => onOpenChange(false)
1055
1142
  }
1056
- ) }) : /* @__PURE__ */ jsxs13(Fragment5, { children: [
1143
+ ) }) : /* @__PURE__ */ jsxs13(Fragment3, { children: [
1057
1144
  /* @__PURE__ */ jsxs13("div", { className: "shrink-0 border-b border-border px-4 pt-3", children: [
1058
1145
  /* @__PURE__ */ jsxs13("div", { className: "mb-2 flex items-center justify-between gap-3", children: [
1059
1146
  /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: [
@@ -1063,36 +1150,28 @@ function LibraryDrawer({
1063
1150
  visible.length !== 1 ? "s" : ""
1064
1151
  ] }),
1065
1152
  /* @__PURE__ */ jsxs13("span", { className: "flex items-center gap-0.5", children: [
1066
- /* @__PURE__ */ jsx14(DollarSign, { className: "h-3 w-3" }),
1153
+ /* @__PURE__ */ jsx15(DollarSign, { className: "h-3 w-3" }),
1067
1154
  totalCost.toFixed(2),
1068
1155
  " spent"
1069
1156
  ] })
1070
1157
  ] }),
1071
- vaultHref && /* @__PURE__ */ jsx14(Link3, { to: vaultHref(), prefetch: "intent", onClick: () => onOpenChange(false), children: /* @__PURE__ */ jsxs13(Button5, { size: "sm", variant: "outline", children: [
1072
- /* @__PURE__ */ jsx14(FolderOpen2, { className: "mr-1.5 h-3.5 w-3.5" }),
1158
+ vaultHref && /* @__PURE__ */ jsx15(Link3, { to: vaultHref(), prefetch: "intent", onClick: () => onOpenChange(false), children: /* @__PURE__ */ jsxs13(Button5, { size: "sm", variant: "outline", children: [
1159
+ /* @__PURE__ */ jsx15(FolderOpen2, { className: "mr-1.5 h-3.5 w-3.5" }),
1073
1160
  "Vault"
1074
1161
  ] }) })
1075
1162
  ] }),
1076
- /* @__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: [
1077
- /* @__PURE__ */ jsx14(TabsTrigger, { value: "all", className: "text-xs", children: "All" }),
1078
- Object.entries(TYPE_CONFIG).map(([key, cfg]) => /* @__PURE__ */ jsx14(TabsTrigger, { value: key, className: "text-xs", children: cfg.label }, key))
1163
+ /* @__PURE__ */ jsx15(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: [
1164
+ /* @__PURE__ */ jsx15(TabsTrigger, { value: "all", className: "text-xs", children: "All" }),
1165
+ Object.entries(TYPE_CONFIG).map(([key, cfg]) => /* @__PURE__ */ jsx15(TabsTrigger, { value: key, className: "text-xs", children: cfg.label }, key))
1079
1166
  ] }) })
1080
1167
  ] }),
1081
- /* @__PURE__ */ jsx14("div", { className: "flex-1 overflow-y-auto p-4", children: visible.length === 0 ? /* @__PURE__ */ jsx14(
1082
- EmptyState,
1083
- {
1084
- 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" }),
1085
- title: typeFilter ? `No ${TYPE_CONFIG[typeFilter]?.label ?? typeFilter} generations` : "No generations yet",
1086
- description: typeFilter ? "Try a different filter or change the type in the composer." : "Everything you and the agent create lives here.",
1087
- className: "py-16"
1088
- }
1089
- ) : /* @__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)) }) })
1168
+ /* @__PURE__ */ jsx15("div", { className: "flex-1 overflow-y-auto p-4", children: /* @__PURE__ */ jsx15(GenerationGrid, { generations: visible, typeFilter, onSelect }) })
1090
1169
  ] })
1091
1170
  ] });
1092
1171
  }
1093
1172
 
1094
1173
  // src/studio-react/studio-workspace.tsx
1095
- import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
1174
+ import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
1096
1175
  function StudioWorkspace({
1097
1176
  generations,
1098
1177
  totalCost,
@@ -1128,7 +1207,7 @@ function StudioWorkspace({
1128
1207
  setDrawerOpen(true);
1129
1208
  }
1130
1209
  return /* @__PURE__ */ jsxs14("div", { className: "min-h-0 flex-1 overflow-y-auto bg-background", children: [
1131
- /* @__PURE__ */ jsx15(
1210
+ /* @__PURE__ */ jsx16(
1132
1211
  StudioHeader,
1133
1212
  {
1134
1213
  count: mergedGenerations.length,
@@ -1136,8 +1215,8 @@ function StudioWorkspace({
1136
1215
  onOpenLibrary: openLibrary
1137
1216
  }
1138
1217
  ),
1139
- /* @__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: [
1140
- /* @__PURE__ */ jsx15(
1218
+ /* @__PURE__ */ jsx16("div", { className: "mx-auto w-full max-w-3xl space-y-4 px-4 py-6 sm:px-6", children: canGenerate ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
1219
+ /* @__PURE__ */ jsx16(
1141
1220
  ComposerHero,
1142
1221
  {
1143
1222
  workspaceId,
@@ -1151,7 +1230,7 @@ function StudioWorkspace({
1151
1230
  }
1152
1231
  }
1153
1232
  ),
1154
- /* @__PURE__ */ jsx15("div", { ref: canvasRef, children: /* @__PURE__ */ jsx15(
1233
+ /* @__PURE__ */ jsx16("div", { ref: canvasRef, children: /* @__PURE__ */ jsx16(
1155
1234
  ResultCanvas,
1156
1235
  {
1157
1236
  batch: latestBatch,
@@ -1160,15 +1239,15 @@ function StudioWorkspace({
1160
1239
  }
1161
1240
  ) })
1162
1241
  ] }) : /* @__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: [
1163
- /* @__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" }) }),
1164
- /* @__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" }),
1165
- /* @__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." }),
1242
+ /* @__PURE__ */ jsx16("div", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-muted", children: /* @__PURE__ */ jsx16(Images2, { className: "h-6 w-6 text-muted-foreground/40" }) }),
1243
+ /* @__PURE__ */ jsx16("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" }),
1244
+ /* @__PURE__ */ jsx16("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." }),
1166
1245
  /* @__PURE__ */ jsxs14(Button6, { size: "sm", variant: "outline", onClick: openLibrary, children: [
1167
- /* @__PURE__ */ jsx15(Images2, { className: "mr-1.5 h-4 w-4" }),
1246
+ /* @__PURE__ */ jsx16(Images2, { className: "mr-1.5 h-4 w-4" }),
1168
1247
  "Open library"
1169
1248
  ] })
1170
1249
  ] }) }),
1171
- /* @__PURE__ */ jsx15(
1250
+ /* @__PURE__ */ jsx16(
1172
1251
  LibraryDrawer,
1173
1252
  {
1174
1253
  open: drawerOpen,
@@ -1190,6 +1269,78 @@ function StudioWorkspace({
1190
1269
  )
1191
1270
  ] });
1192
1271
  }
1272
+
1273
+ // src/studio-react/library-panel.tsx
1274
+ import { useMemo as useMemo4 } from "react";
1275
+ import {
1276
+ Tabs as Tabs2,
1277
+ TabsList as TabsList2,
1278
+ TabsTrigger as TabsTrigger2
1279
+ } from "@tangle-network/sandbox-ui/primitives";
1280
+ import { DollarSign as DollarSign2 } from "lucide-react";
1281
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
1282
+ function LibraryPanel({
1283
+ generations,
1284
+ totalCost,
1285
+ typeFilter,
1286
+ onFilterChange,
1287
+ onSelect
1288
+ }) {
1289
+ const visible = useMemo4(() => filterGenerations(generations, typeFilter), [generations, typeFilter]);
1290
+ return /* @__PURE__ */ jsxs15("div", { className: "flex min-w-0 flex-col", children: [
1291
+ /* @__PURE__ */ jsxs15("div", { className: "mb-4 flex flex-wrap items-center justify-between gap-3", children: [
1292
+ /* @__PURE__ */ jsx17(Tabs2, { value: typeFilter ?? "all", onValueChange: (v) => onFilterChange(v === "all" ? null : v), children: /* @__PURE__ */ jsxs15(TabsList2, { className: "h-9 justify-start gap-1 overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-[var(--md3-surface-container-low)] p-1", children: [
1293
+ /* @__PURE__ */ jsx17(
1294
+ TabsTrigger2,
1295
+ {
1296
+ value: "all",
1297
+ 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",
1298
+ children: "All"
1299
+ }
1300
+ ),
1301
+ Object.entries(TYPE_CONFIG).map(([key, cfg]) => /* @__PURE__ */ jsx17(
1302
+ TabsTrigger2,
1303
+ {
1304
+ value: key,
1305
+ 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",
1306
+ children: cfg.label
1307
+ },
1308
+ key
1309
+ ))
1310
+ ] }) }),
1311
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: [
1312
+ /* @__PURE__ */ jsxs15("span", { children: [
1313
+ visible.length,
1314
+ " generation",
1315
+ visible.length !== 1 ? "s" : ""
1316
+ ] }),
1317
+ /* @__PURE__ */ jsxs15("span", { className: "flex items-center gap-0.5", children: [
1318
+ /* @__PURE__ */ jsx17(DollarSign2, { className: "h-3 w-3" }),
1319
+ totalCost.toFixed(2),
1320
+ " spent"
1321
+ ] })
1322
+ ] })
1323
+ ] }),
1324
+ /* @__PURE__ */ jsx17(GenerationGrid, { generations: visible, typeFilter, onSelect })
1325
+ ] });
1326
+ }
1327
+
1328
+ // src/studio-react/generation-detail-modal.tsx
1329
+ import { Dialog as Dialog2, DialogContent, DialogHeader, DialogTitle } from "@tangle-network/sandbox-ui/primitives";
1330
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
1331
+ function GenerationDetailModal({
1332
+ generation,
1333
+ vaultHref,
1334
+ onClose
1335
+ }) {
1336
+ const cfg = generation ? typeConfigFor(generation.type) : null;
1337
+ return /* @__PURE__ */ jsx18(Dialog2, { open: generation != null, onOpenChange: (open) => {
1338
+ if (!open) onClose();
1339
+ }, children: /* @__PURE__ */ jsxs16(DialogContent, { className: "max-h-[85vh] max-w-2xl overflow-y-auto", children: [
1340
+ /* @__PURE__ */ jsx18(DialogHeader, { children: /* @__PURE__ */ jsx18(DialogTitle, { className: "text-left text-base", children: cfg?.label ?? "Generation" }) }),
1341
+ generation && /* @__PURE__ */ jsx18(GenerationDetail, { generation, vaultHref, onNavigate: onClose })
1342
+ ] }) });
1343
+ }
1193
1344
  export {
1194
1345
  AvatarComposer,
1195
1346
  ComposerDisclosure,
@@ -1197,13 +1348,17 @@ export {
1197
1348
  Field,
1198
1349
  GenerationCard,
1199
1350
  GenerationDetail,
1351
+ GenerationDetailModal,
1352
+ GenerationGrid,
1200
1353
  GenerationStatusBadge,
1201
1354
  ImageComposer,
1202
1355
  LibraryDrawer,
1356
+ LibraryPanel,
1203
1357
  NativeSelect,
1204
1358
  PublishPackageComposer,
1205
1359
  ResultCanvas,
1206
1360
  SpeechComposer,
1361
+ Stepper,
1207
1362
  StudioHeader,
1208
1363
  StudioSheet,
1209
1364
  StudioWorkspace,
@@ -1211,6 +1366,7 @@ export {
1211
1366
  TranscriptionComposer,
1212
1367
  TranscriptionOptions,
1213
1368
  VideoComposer,
1369
+ filterGenerations,
1214
1370
  typeConfigFor,
1215
1371
  useStudioGenerations
1216
1372
  };