@proveanything/smartlinks-utils-ui 0.1.12 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-TSDKQOTW.js → chunk-GN2P3MOG.js} +48 -32
- package/dist/chunk-GN2P3MOG.js.map +1 -0
- package/dist/{chunk-ECAGO3HU.js → chunk-XA5J6CZL.js} +672 -25
- package/dist/chunk-XA5J6CZL.js.map +1 -0
- package/dist/components/AssetPicker/index.d.ts +1 -1
- package/dist/components/AssetPicker/index.js +1 -1
- package/dist/components/ConditionsEditor/index.d.ts +7 -0
- package/dist/components/ConditionsEditor/index.js +1 -1
- package/dist/{index-Ba3K3Ehs.d.ts → index-BmKyfKiK.d.ts} +19 -0
- package/dist/index.css +249 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/package.json +17 -10
- package/dist/chunk-ECAGO3HU.js.map +0 -1
- package/dist/chunk-TSDKQOTW.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cn } from './chunk-L7FQ52F5.js';
|
|
2
2
|
import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
3
3
|
import * as SL from '@proveanything/smartlinks';
|
|
4
|
-
import { Filter, Search, LayoutGrid, List, X, Loader2, AlertCircle, ImageOff, Clipboard, Pencil, Check, Upload, Link,
|
|
4
|
+
import { Filter, Search, LayoutGrid, List, X, Loader2, AlertCircle, ImageOff, Clipboard, Pencil, Check, Upload, Link, MicOff, Mic, ChevronDown, ChevronRight, Sparkles, Image, Trash2, FileIcon, Film, Music, FileText } from 'lucide-react';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
// src/components/AssetPicker/types.ts
|
|
@@ -98,6 +98,29 @@ function useAssets({ scope, accept, pageSize }) {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
}, [upload]);
|
|
101
|
+
const uploadFromRemoteUrl = useCallback(async (url, opts) => {
|
|
102
|
+
setUploading(true);
|
|
103
|
+
setUploadProgress(0);
|
|
104
|
+
try {
|
|
105
|
+
const result = await SL.asset.uploadFromUrl({
|
|
106
|
+
url,
|
|
107
|
+
scope,
|
|
108
|
+
metadata: { name: opts?.name, ...opts?.metadata || {} }
|
|
109
|
+
});
|
|
110
|
+
if (mountedRef.current) {
|
|
111
|
+
setAssets((prev) => [result, ...prev]);
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
} catch (err) {
|
|
115
|
+
if (mountedRef.current) setError(err?.message || "Remote URL ingest failed");
|
|
116
|
+
return null;
|
|
117
|
+
} finally {
|
|
118
|
+
if (mountedRef.current) {
|
|
119
|
+
setUploading(false);
|
|
120
|
+
setUploadProgress(0);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}, [scope]);
|
|
101
124
|
const remove = useCallback(async (assetId) => {
|
|
102
125
|
try {
|
|
103
126
|
await SL.asset.remove({ assetId, scope });
|
|
@@ -117,6 +140,7 @@ function useAssets({ scope, accept, pageSize }) {
|
|
|
117
140
|
refresh: fetchAssets,
|
|
118
141
|
upload,
|
|
119
142
|
uploadFromUrl,
|
|
143
|
+
uploadFromRemoteUrl,
|
|
120
144
|
remove,
|
|
121
145
|
uploading,
|
|
122
146
|
uploadProgress
|
|
@@ -187,6 +211,7 @@ var AssetGridItem = ({ asset: asset2, selected, onToggle, onDoubleClick, onDelet
|
|
|
187
211
|
allowDelete && onDelete && /* @__PURE__ */ jsx(
|
|
188
212
|
"button",
|
|
189
213
|
{
|
|
214
|
+
type: "button",
|
|
190
215
|
className: "absolute top-2 left-2 w-6 h-6 rounded-full bg-destructive/80 hover:bg-destructive text-destructive-foreground flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity",
|
|
191
216
|
onClick: (e) => {
|
|
192
217
|
e.stopPropagation();
|
|
@@ -237,6 +262,7 @@ var AssetListItem = ({ asset: asset2, selected, onToggle, onDoubleClick, onDelet
|
|
|
237
262
|
allowDelete && onDelete && /* @__PURE__ */ jsx(
|
|
238
263
|
"button",
|
|
239
264
|
{
|
|
265
|
+
type: "button",
|
|
240
266
|
className: "w-6 h-6 rounded-full bg-destructive/80 hover:bg-destructive text-destructive-foreground flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0",
|
|
241
267
|
onClick: (e) => {
|
|
242
268
|
e.stopPropagation();
|
|
@@ -411,6 +437,7 @@ var UploadZone = ({
|
|
|
411
437
|
) : /* @__PURE__ */ jsxs(
|
|
412
438
|
"button",
|
|
413
439
|
{
|
|
440
|
+
type: "button",
|
|
414
441
|
onClick: () => setEditingName(true),
|
|
415
442
|
className: "flex items-center gap-1 mx-auto px-2 py-1 text-sm text-muted-foreground hover:text-foreground rounded hover:bg-accent transition-colors",
|
|
416
443
|
title: "Rename",
|
|
@@ -430,6 +457,7 @@ var UploadZone = ({
|
|
|
430
457
|
/* @__PURE__ */ jsxs(
|
|
431
458
|
"button",
|
|
432
459
|
{
|
|
460
|
+
type: "button",
|
|
433
461
|
onClick: handleCancelPaste,
|
|
434
462
|
className: "px-3 py-1.5 text-xs font-medium rounded-md border border-border text-muted-foreground hover:bg-accent transition-colors flex items-center gap-1",
|
|
435
463
|
children: [
|
|
@@ -441,6 +469,7 @@ var UploadZone = ({
|
|
|
441
469
|
/* @__PURE__ */ jsxs(
|
|
442
470
|
"button",
|
|
443
471
|
{
|
|
472
|
+
type: "button",
|
|
444
473
|
onClick: handleConfirmPaste,
|
|
445
474
|
className: "px-3 py-1.5 text-xs font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors flex items-center gap-1",
|
|
446
475
|
children: [
|
|
@@ -525,8 +554,9 @@ var UrlImport = ({
|
|
|
525
554
|
}) => {
|
|
526
555
|
const [url, setUrl] = useState("");
|
|
527
556
|
const [error, setError] = useState("");
|
|
528
|
-
const handleSubmit = async (e) => {
|
|
529
|
-
e
|
|
557
|
+
const handleSubmit = useCallback(async (e) => {
|
|
558
|
+
e?.preventDefault();
|
|
559
|
+
e?.stopPropagation();
|
|
530
560
|
if (!url.trim()) return;
|
|
531
561
|
try {
|
|
532
562
|
new URL(url.trim());
|
|
@@ -537,8 +567,8 @@ var UrlImport = ({
|
|
|
537
567
|
setError("");
|
|
538
568
|
const result = await onImport(url.trim());
|
|
539
569
|
if (result) setUrl("");
|
|
540
|
-
};
|
|
541
|
-
return /* @__PURE__ */ jsxs("
|
|
570
|
+
}, [url, onImport]);
|
|
571
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-2", className), children: [
|
|
542
572
|
/* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
|
|
543
573
|
/* @__PURE__ */ jsx(Link, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" }),
|
|
544
574
|
/* @__PURE__ */ jsx(
|
|
@@ -550,6 +580,13 @@ var UrlImport = ({
|
|
|
550
580
|
setUrl(e.target.value);
|
|
551
581
|
setError("");
|
|
552
582
|
},
|
|
583
|
+
onKeyDown: (e) => {
|
|
584
|
+
if (e.key === "Enter") {
|
|
585
|
+
e.preventDefault();
|
|
586
|
+
e.stopPropagation();
|
|
587
|
+
handleSubmit();
|
|
588
|
+
}
|
|
589
|
+
},
|
|
553
590
|
placeholder: "https://example.com/image.png",
|
|
554
591
|
disabled: importing,
|
|
555
592
|
className: cn(
|
|
@@ -564,7 +601,8 @@ var UrlImport = ({
|
|
|
564
601
|
/* @__PURE__ */ jsxs(
|
|
565
602
|
"button",
|
|
566
603
|
{
|
|
567
|
-
type: "
|
|
604
|
+
type: "button",
|
|
605
|
+
onClick: handleSubmit,
|
|
568
606
|
disabled: !url.trim() || importing,
|
|
569
607
|
className: cn(
|
|
570
608
|
"px-3 py-2 text-sm font-medium rounded-md transition-colors",
|
|
@@ -581,6 +619,566 @@ var UrlImport = ({
|
|
|
581
619
|
error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive mt-1 absolute", children: error })
|
|
582
620
|
] });
|
|
583
621
|
};
|
|
622
|
+
var ASPECT_PRESETS = [
|
|
623
|
+
{ key: "square", label: "Square", hint: "1:1", size: "1024x1024" },
|
|
624
|
+
{ key: "landscape", label: "Landscape", hint: "7:4", size: "1792x1024" },
|
|
625
|
+
{ key: "portrait", label: "Portrait", hint: "4:7", size: "1024x1792" },
|
|
626
|
+
{ key: "wide", label: "Wide", hint: "16:9", size: "1536x864" },
|
|
627
|
+
{ key: "tall", label: "Tall", hint: "9:16", size: "864x1536" }
|
|
628
|
+
];
|
|
629
|
+
var QUALITY_OPTIONS = [
|
|
630
|
+
{ value: "standard", label: "Standard" },
|
|
631
|
+
{ value: "hd", label: "HD" }
|
|
632
|
+
];
|
|
633
|
+
var STYLE_OPTIONS = [
|
|
634
|
+
{ value: "vivid", label: "Vivid" },
|
|
635
|
+
{ value: "natural", label: "Natural" }
|
|
636
|
+
];
|
|
637
|
+
function extractImageUrl(response) {
|
|
638
|
+
if (!response) return null;
|
|
639
|
+
if (typeof response === "string") return response;
|
|
640
|
+
if (response.url) return response.url;
|
|
641
|
+
if (response.imageUrl) return response.imageUrl;
|
|
642
|
+
if (response.image_url) return response.image_url;
|
|
643
|
+
if (Array.isArray(response.data) && response.data[0]?.url) return response.data[0].url;
|
|
644
|
+
if (Array.isArray(response.images) && response.images[0]?.url) return response.images[0].url;
|
|
645
|
+
if (response.b64_json) return `data:image/png;base64,${response.b64_json}`;
|
|
646
|
+
if (Array.isArray(response.data) && response.data[0]?.b64_json) {
|
|
647
|
+
return `data:image/png;base64,${response.data[0].b64_json}`;
|
|
648
|
+
}
|
|
649
|
+
return null;
|
|
650
|
+
}
|
|
651
|
+
var AIImageGenerate = ({
|
|
652
|
+
collectionId,
|
|
653
|
+
onSave,
|
|
654
|
+
saving,
|
|
655
|
+
className
|
|
656
|
+
}) => {
|
|
657
|
+
const [prompt, setPrompt] = useState("");
|
|
658
|
+
const [aspect, setAspect] = useState("square");
|
|
659
|
+
const [quality, setQuality] = useState("standard");
|
|
660
|
+
const [style, setStyle] = useState("vivid");
|
|
661
|
+
const [advancedOpen, setAdvancedOpen] = useState(false);
|
|
662
|
+
const [provider, setProvider] = useState("");
|
|
663
|
+
const [model, setModel] = useState("");
|
|
664
|
+
const [generating, setGenerating] = useState(false);
|
|
665
|
+
const [error, setError] = useState(null);
|
|
666
|
+
const [previewUrl, setPreviewUrl] = useState(null);
|
|
667
|
+
const [saved, setSaved] = useState(false);
|
|
668
|
+
const SpeechRecognitionCtor = typeof window !== "undefined" ? window.SpeechRecognition || window.webkitSpeechRecognition : null;
|
|
669
|
+
const voiceSupported = !!SpeechRecognitionCtor;
|
|
670
|
+
const recognitionRef = useRef(null);
|
|
671
|
+
const baseTextRef = useRef("");
|
|
672
|
+
const [listening, setListening] = useState(false);
|
|
673
|
+
const [voiceError, setVoiceError] = useState(null);
|
|
674
|
+
useEffect(() => {
|
|
675
|
+
return () => {
|
|
676
|
+
try {
|
|
677
|
+
recognitionRef.current?.stop();
|
|
678
|
+
} catch {
|
|
679
|
+
}
|
|
680
|
+
recognitionRef.current = null;
|
|
681
|
+
};
|
|
682
|
+
}, []);
|
|
683
|
+
const startListening = useCallback(() => {
|
|
684
|
+
if (!voiceSupported) return;
|
|
685
|
+
setVoiceError(null);
|
|
686
|
+
try {
|
|
687
|
+
const rec = new SpeechRecognitionCtor();
|
|
688
|
+
rec.continuous = true;
|
|
689
|
+
rec.interimResults = true;
|
|
690
|
+
rec.lang = typeof navigator !== "undefined" && navigator.language || "en-US";
|
|
691
|
+
baseTextRef.current = prompt ? prompt.replace(/\s+$/, "") + " " : "";
|
|
692
|
+
rec.onresult = (event) => {
|
|
693
|
+
let finalText = "";
|
|
694
|
+
let interimText = "";
|
|
695
|
+
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
696
|
+
const r = event.results[i];
|
|
697
|
+
if (r.isFinal) finalText += r[0].transcript;
|
|
698
|
+
else interimText += r[0].transcript;
|
|
699
|
+
}
|
|
700
|
+
if (finalText) {
|
|
701
|
+
baseTextRef.current = (baseTextRef.current + finalText).replace(/\s+$/, "") + " ";
|
|
702
|
+
setPrompt(baseTextRef.current);
|
|
703
|
+
} else {
|
|
704
|
+
setPrompt(baseTextRef.current + interimText);
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
rec.onerror = (e) => {
|
|
708
|
+
const code = e?.error || "unknown";
|
|
709
|
+
if (code === "not-allowed" || code === "service-not-allowed") {
|
|
710
|
+
setVoiceError("Microphone permission denied.");
|
|
711
|
+
} else if (code === "no-speech") {
|
|
712
|
+
setVoiceError("No speech detected.");
|
|
713
|
+
} else if (code !== "aborted") {
|
|
714
|
+
setVoiceError(`Voice input error: ${code}`);
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
rec.onend = () => {
|
|
718
|
+
setListening(false);
|
|
719
|
+
};
|
|
720
|
+
recognitionRef.current = rec;
|
|
721
|
+
rec.start();
|
|
722
|
+
setListening(true);
|
|
723
|
+
} catch (err) {
|
|
724
|
+
setVoiceError(err?.message || "Could not start voice input");
|
|
725
|
+
setListening(false);
|
|
726
|
+
}
|
|
727
|
+
}, [voiceSupported, prompt, SpeechRecognitionCtor]);
|
|
728
|
+
const stopListening = useCallback(() => {
|
|
729
|
+
try {
|
|
730
|
+
recognitionRef.current?.stop();
|
|
731
|
+
} catch {
|
|
732
|
+
}
|
|
733
|
+
setListening(false);
|
|
734
|
+
}, []);
|
|
735
|
+
const toggleListening = useCallback(() => {
|
|
736
|
+
if (listening) stopListening();
|
|
737
|
+
else startListening();
|
|
738
|
+
}, [listening, startListening, stopListening]);
|
|
739
|
+
const handleGenerate = useCallback(async () => {
|
|
740
|
+
if (!prompt.trim() || !collectionId) return;
|
|
741
|
+
setGenerating(true);
|
|
742
|
+
setError(null);
|
|
743
|
+
setPreviewUrl(null);
|
|
744
|
+
setSaved(false);
|
|
745
|
+
try {
|
|
746
|
+
const sizeValue = ASPECT_PRESETS.find((a) => a.key === aspect)?.size || "1024x1024";
|
|
747
|
+
const params = {
|
|
748
|
+
prompt: prompt.trim(),
|
|
749
|
+
size: sizeValue,
|
|
750
|
+
quality,
|
|
751
|
+
style
|
|
752
|
+
};
|
|
753
|
+
if (provider.trim()) params.provider = provider.trim();
|
|
754
|
+
if (model.trim()) params.model = model.trim();
|
|
755
|
+
const res = await SL.ai.generateImage(collectionId, params);
|
|
756
|
+
const url = extractImageUrl(res);
|
|
757
|
+
if (!url) {
|
|
758
|
+
setError("AI did not return an image URL.");
|
|
759
|
+
} else {
|
|
760
|
+
setPreviewUrl(url);
|
|
761
|
+
}
|
|
762
|
+
} catch (err) {
|
|
763
|
+
setError(err?.message || "Image generation failed");
|
|
764
|
+
} finally {
|
|
765
|
+
setGenerating(false);
|
|
766
|
+
}
|
|
767
|
+
}, [prompt, aspect, quality, style, provider, model, collectionId]);
|
|
768
|
+
const handleSave = useCallback(async () => {
|
|
769
|
+
if (!previewUrl) return;
|
|
770
|
+
const trimmed = prompt.trim().slice(0, 60).replace(/\s+/g, "-") || "ai-image";
|
|
771
|
+
const result = await onSave(previewUrl, `ai-${trimmed}.png`);
|
|
772
|
+
if (result) {
|
|
773
|
+
setSaved(true);
|
|
774
|
+
setTimeout(() => {
|
|
775
|
+
setPreviewUrl(null);
|
|
776
|
+
setSaved(false);
|
|
777
|
+
}, 1500);
|
|
778
|
+
}
|
|
779
|
+
}, [previewUrl, prompt, onSave]);
|
|
780
|
+
if (!collectionId) {
|
|
781
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-3 rounded-md bg-muted text-muted-foreground text-sm", children: [
|
|
782
|
+
/* @__PURE__ */ jsx(AlertCircle, { className: "w-4 h-4 flex-shrink-0" }),
|
|
783
|
+
"AI image generation requires a collection scope."
|
|
784
|
+
] });
|
|
785
|
+
}
|
|
786
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3", className), children: [
|
|
787
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
788
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
789
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-foreground", children: "Prompt" }),
|
|
790
|
+
voiceSupported && /* @__PURE__ */ jsxs(
|
|
791
|
+
"button",
|
|
792
|
+
{
|
|
793
|
+
type: "button",
|
|
794
|
+
onClick: toggleListening,
|
|
795
|
+
disabled: generating,
|
|
796
|
+
title: listening ? "Stop dictation" : "Dictate prompt",
|
|
797
|
+
className: cn(
|
|
798
|
+
"flex items-center gap-1 px-2 py-0.5 text-[11px] rounded-md border transition-colors",
|
|
799
|
+
listening ? "border-destructive text-destructive bg-destructive/10 animate-pulse" : "border-border text-muted-foreground hover:text-foreground hover:bg-muted"
|
|
800
|
+
),
|
|
801
|
+
children: [
|
|
802
|
+
listening ? /* @__PURE__ */ jsx(MicOff, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(Mic, { className: "w-3 h-3" }),
|
|
803
|
+
listening ? "Listening\u2026" : "Voice"
|
|
804
|
+
]
|
|
805
|
+
}
|
|
806
|
+
)
|
|
807
|
+
] }),
|
|
808
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
809
|
+
/* @__PURE__ */ jsx(
|
|
810
|
+
"textarea",
|
|
811
|
+
{
|
|
812
|
+
value: prompt,
|
|
813
|
+
onChange: (e) => setPrompt(e.target.value),
|
|
814
|
+
onKeyDown: (e) => {
|
|
815
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
816
|
+
e.preventDefault();
|
|
817
|
+
handleGenerate();
|
|
818
|
+
}
|
|
819
|
+
},
|
|
820
|
+
placeholder: "A serene mountain lake at golden hour, photorealistic, 35mm film\u2026",
|
|
821
|
+
rows: 3,
|
|
822
|
+
disabled: generating,
|
|
823
|
+
className: "w-full px-3 py-2 text-sm rounded-md border border-border bg-transparent placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring resize-none"
|
|
824
|
+
}
|
|
825
|
+
),
|
|
826
|
+
listening && /* @__PURE__ */ jsxs("span", { className: "absolute top-2 right-2 flex items-center gap-1 text-[10px] text-destructive", children: [
|
|
827
|
+
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-destructive animate-pulse" }),
|
|
828
|
+
"REC"
|
|
829
|
+
] })
|
|
830
|
+
] }),
|
|
831
|
+
/* @__PURE__ */ jsxs("p", { className: "text-[11px] text-muted-foreground", children: [
|
|
832
|
+
"Tip: \u2318/Ctrl + Enter to generate",
|
|
833
|
+
voiceSupported ? " \xB7 click Voice to dictate" : ""
|
|
834
|
+
] }),
|
|
835
|
+
voiceError && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-destructive", children: voiceError })
|
|
836
|
+
] }),
|
|
837
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
838
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-foreground", children: "Aspect ratio" }),
|
|
839
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: ASPECT_PRESETS.map((a) => {
|
|
840
|
+
const active = aspect === a.key;
|
|
841
|
+
return /* @__PURE__ */ jsxs(
|
|
842
|
+
"button",
|
|
843
|
+
{
|
|
844
|
+
type: "button",
|
|
845
|
+
onClick: () => setAspect(a.key),
|
|
846
|
+
disabled: generating,
|
|
847
|
+
className: cn(
|
|
848
|
+
"px-2.5 py-1 text-xs rounded-md border transition-colors flex items-center gap-1",
|
|
849
|
+
active ? "border-primary bg-primary text-primary-foreground" : "border-border text-muted-foreground hover:text-foreground hover:bg-muted"
|
|
850
|
+
),
|
|
851
|
+
children: [
|
|
852
|
+
/* @__PURE__ */ jsx("span", { children: a.label }),
|
|
853
|
+
/* @__PURE__ */ jsx("span", { className: cn("text-[10px]", active ? "opacity-80" : "opacity-60"), children: a.hint })
|
|
854
|
+
]
|
|
855
|
+
},
|
|
856
|
+
a.key
|
|
857
|
+
);
|
|
858
|
+
}) })
|
|
859
|
+
] }),
|
|
860
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
861
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
862
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-foreground", children: "Quality" }),
|
|
863
|
+
/* @__PURE__ */ jsx(
|
|
864
|
+
"select",
|
|
865
|
+
{
|
|
866
|
+
value: quality,
|
|
867
|
+
onChange: (e) => setQuality(e.target.value),
|
|
868
|
+
disabled: generating,
|
|
869
|
+
className: "text-sm py-2 px-2 rounded-md border border-border bg-transparent text-foreground focus:outline-none focus:ring-1 focus:ring-ring cursor-pointer",
|
|
870
|
+
children: QUALITY_OPTIONS.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
|
|
871
|
+
}
|
|
872
|
+
)
|
|
873
|
+
] }),
|
|
874
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
875
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-foreground", children: "Style" }),
|
|
876
|
+
/* @__PURE__ */ jsx(
|
|
877
|
+
"select",
|
|
878
|
+
{
|
|
879
|
+
value: style,
|
|
880
|
+
onChange: (e) => setStyle(e.target.value),
|
|
881
|
+
disabled: generating,
|
|
882
|
+
className: "text-sm py-2 px-2 rounded-md border border-border bg-transparent text-foreground focus:outline-none focus:ring-1 focus:ring-ring cursor-pointer",
|
|
883
|
+
children: STYLE_OPTIONS.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
|
|
884
|
+
}
|
|
885
|
+
)
|
|
886
|
+
] })
|
|
887
|
+
] }),
|
|
888
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
889
|
+
/* @__PURE__ */ jsxs(
|
|
890
|
+
"button",
|
|
891
|
+
{
|
|
892
|
+
type: "button",
|
|
893
|
+
onClick: () => setAdvancedOpen((v) => !v),
|
|
894
|
+
className: "self-start flex items-center gap-1 text-[11px] text-muted-foreground hover:text-foreground transition-colors",
|
|
895
|
+
children: [
|
|
896
|
+
advancedOpen ? /* @__PURE__ */ jsx(ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3" }),
|
|
897
|
+
"Advanced"
|
|
898
|
+
]
|
|
899
|
+
}
|
|
900
|
+
),
|
|
901
|
+
advancedOpen && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 p-2 rounded-md border border-border bg-muted/20", children: [
|
|
902
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
903
|
+
/* @__PURE__ */ jsx("label", { className: "text-[11px] font-medium text-foreground", children: "Provider" }),
|
|
904
|
+
/* @__PURE__ */ jsx(
|
|
905
|
+
"input",
|
|
906
|
+
{
|
|
907
|
+
type: "text",
|
|
908
|
+
value: provider,
|
|
909
|
+
onChange: (e) => setProvider(e.target.value),
|
|
910
|
+
placeholder: "e.g. openai, google, stability",
|
|
911
|
+
disabled: generating,
|
|
912
|
+
className: "text-xs py-1.5 px-2 rounded-md border border-border bg-transparent text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring"
|
|
913
|
+
}
|
|
914
|
+
)
|
|
915
|
+
] }),
|
|
916
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
917
|
+
/* @__PURE__ */ jsx("label", { className: "text-[11px] font-medium text-foreground", children: "Model" }),
|
|
918
|
+
/* @__PURE__ */ jsx(
|
|
919
|
+
"input",
|
|
920
|
+
{
|
|
921
|
+
type: "text",
|
|
922
|
+
value: model,
|
|
923
|
+
onChange: (e) => setModel(e.target.value),
|
|
924
|
+
placeholder: "e.g. gpt-image-1, imagen-3",
|
|
925
|
+
disabled: generating,
|
|
926
|
+
className: "text-xs py-1.5 px-2 rounded-md border border-border bg-transparent text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring"
|
|
927
|
+
}
|
|
928
|
+
)
|
|
929
|
+
] }),
|
|
930
|
+
/* @__PURE__ */ jsx("p", { className: "col-span-2 text-[10px] text-muted-foreground", children: "Leave blank to use the platform default. Quality and Style options may be ignored by some providers." })
|
|
931
|
+
] })
|
|
932
|
+
] }),
|
|
933
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(
|
|
934
|
+
"button",
|
|
935
|
+
{
|
|
936
|
+
type: "button",
|
|
937
|
+
onClick: handleGenerate,
|
|
938
|
+
disabled: !prompt.trim() || generating,
|
|
939
|
+
className: cn(
|
|
940
|
+
"px-4 py-2 text-sm font-medium rounded-md transition-colors",
|
|
941
|
+
"bg-primary text-primary-foreground hover:bg-primary/90",
|
|
942
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
943
|
+
"flex items-center gap-1.5"
|
|
944
|
+
),
|
|
945
|
+
children: [
|
|
946
|
+
generating ? /* @__PURE__ */ jsx(Loader2, { className: "w-3.5 h-3.5 animate-spin" }) : /* @__PURE__ */ jsx(Sparkles, { className: "w-3.5 h-3.5" }),
|
|
947
|
+
generating ? "Generating\u2026" : "Generate"
|
|
948
|
+
]
|
|
949
|
+
}
|
|
950
|
+
) }),
|
|
951
|
+
error && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2.5 rounded-md bg-destructive/10 text-destructive text-xs", children: [
|
|
952
|
+
/* @__PURE__ */ jsx(AlertCircle, { className: "w-4 h-4 flex-shrink-0" }),
|
|
953
|
+
error
|
|
954
|
+
] }),
|
|
955
|
+
previewUrl && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border border-border rounded-md p-3 bg-muted/30", children: [
|
|
956
|
+
/* @__PURE__ */ jsx("div", { className: "relative rounded overflow-hidden bg-background flex items-center justify-center", style: { minHeight: "12rem" }, children: /* @__PURE__ */ jsx(
|
|
957
|
+
"img",
|
|
958
|
+
{
|
|
959
|
+
src: previewUrl,
|
|
960
|
+
alt: prompt,
|
|
961
|
+
className: "max-w-full max-h-80 object-contain"
|
|
962
|
+
}
|
|
963
|
+
) }),
|
|
964
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
|
|
965
|
+
/* @__PURE__ */ jsx(
|
|
966
|
+
"button",
|
|
967
|
+
{
|
|
968
|
+
type: "button",
|
|
969
|
+
onClick: () => {
|
|
970
|
+
setPreviewUrl(null);
|
|
971
|
+
setSaved(false);
|
|
972
|
+
},
|
|
973
|
+
disabled: saving,
|
|
974
|
+
className: "px-3 py-1.5 text-xs rounded-md border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
|
|
975
|
+
children: "Discard"
|
|
976
|
+
}
|
|
977
|
+
),
|
|
978
|
+
/* @__PURE__ */ jsxs(
|
|
979
|
+
"button",
|
|
980
|
+
{
|
|
981
|
+
type: "button",
|
|
982
|
+
onClick: handleSave,
|
|
983
|
+
disabled: saving || saved,
|
|
984
|
+
className: cn(
|
|
985
|
+
"px-3 py-1.5 text-xs font-medium rounded-md transition-colors flex items-center gap-1.5",
|
|
986
|
+
saved ? "bg-primary text-primary-foreground" : "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
987
|
+
"disabled:opacity-70 disabled:cursor-not-allowed"
|
|
988
|
+
),
|
|
989
|
+
children: [
|
|
990
|
+
saving ? /* @__PURE__ */ jsx(Loader2, { className: "w-3 h-3 animate-spin" }) : saved ? /* @__PURE__ */ jsx(Check, { className: "w-3 h-3" }) : null,
|
|
991
|
+
saved ? "Saved" : saving ? "Saving\u2026" : "Save to library"
|
|
992
|
+
]
|
|
993
|
+
}
|
|
994
|
+
)
|
|
995
|
+
] })
|
|
996
|
+
] })
|
|
997
|
+
] });
|
|
998
|
+
};
|
|
999
|
+
var ORIENTATIONS = [
|
|
1000
|
+
{ value: "", label: "Any shape" },
|
|
1001
|
+
{ value: "landscape", label: "Landscape" },
|
|
1002
|
+
{ value: "portrait", label: "Portrait" },
|
|
1003
|
+
{ value: "squarish", label: "Square" }
|
|
1004
|
+
];
|
|
1005
|
+
function getThumb(p) {
|
|
1006
|
+
return p.thumbUrl || p.thumbnailUrl || p.thumbnail || p.previewUrl || p.urls?.small || p.urls?.thumb || p.src?.medium || p.src?.small || p.url;
|
|
1007
|
+
}
|
|
1008
|
+
function getFullUrl(p) {
|
|
1009
|
+
return p.urls?.full || p.urls?.regular || p.src?.original || p.src?.large || p.url;
|
|
1010
|
+
}
|
|
1011
|
+
var StockPhotoSearch = ({
|
|
1012
|
+
collectionId,
|
|
1013
|
+
onSave,
|
|
1014
|
+
saving,
|
|
1015
|
+
className
|
|
1016
|
+
}) => {
|
|
1017
|
+
const [query, setQuery] = useState("");
|
|
1018
|
+
const [orientation, setOrientation] = useState("");
|
|
1019
|
+
const [searching, setSearching] = useState(false);
|
|
1020
|
+
const [error, setError] = useState(null);
|
|
1021
|
+
const [results, setResults] = useState([]);
|
|
1022
|
+
const [savedUrl, setSavedUrl] = useState(null);
|
|
1023
|
+
const [pendingUrl, setPendingUrl] = useState(null);
|
|
1024
|
+
const handleSearch = useCallback(async () => {
|
|
1025
|
+
if (!query.trim() || !collectionId) return;
|
|
1026
|
+
setSearching(true);
|
|
1027
|
+
setError(null);
|
|
1028
|
+
setResults([]);
|
|
1029
|
+
setSavedUrl(null);
|
|
1030
|
+
try {
|
|
1031
|
+
const params = {
|
|
1032
|
+
query: query.trim(),
|
|
1033
|
+
per_page: 24
|
|
1034
|
+
};
|
|
1035
|
+
if (orientation) params.orientation = orientation;
|
|
1036
|
+
const res = await SL.ai.searchPhotos(collectionId, params);
|
|
1037
|
+
const list = Array.isArray(res) ? res : res?.photos || res?.results || [];
|
|
1038
|
+
setResults(list);
|
|
1039
|
+
if (list.length === 0) {
|
|
1040
|
+
setError("No photos matched your search.");
|
|
1041
|
+
}
|
|
1042
|
+
} catch (err) {
|
|
1043
|
+
setError(err?.message || "Stock photo search failed");
|
|
1044
|
+
} finally {
|
|
1045
|
+
setSearching(false);
|
|
1046
|
+
}
|
|
1047
|
+
}, [query, orientation, collectionId]);
|
|
1048
|
+
const handleSave = useCallback(async (photo) => {
|
|
1049
|
+
const fullUrl = getFullUrl(photo);
|
|
1050
|
+
setPendingUrl(fullUrl);
|
|
1051
|
+
const namePart = (photo.alt || query.trim() || "stock-photo").slice(0, 60).replace(/\s+/g, "-");
|
|
1052
|
+
const result = await onSave(fullUrl, `stock-${namePart}.jpg`);
|
|
1053
|
+
setPendingUrl(null);
|
|
1054
|
+
if (result) {
|
|
1055
|
+
setSavedUrl(fullUrl);
|
|
1056
|
+
setTimeout(() => setSavedUrl(null), 1500);
|
|
1057
|
+
}
|
|
1058
|
+
}, [onSave, query]);
|
|
1059
|
+
if (!collectionId) {
|
|
1060
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-3 rounded-md bg-muted text-muted-foreground text-sm", children: [
|
|
1061
|
+
/* @__PURE__ */ jsx(AlertCircle, { className: "w-4 h-4 flex-shrink-0" }),
|
|
1062
|
+
"Stock photo search requires a collection scope."
|
|
1063
|
+
] });
|
|
1064
|
+
}
|
|
1065
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3", className), children: [
|
|
1066
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2 flex-wrap", children: [
|
|
1067
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-w-[12rem]", children: [
|
|
1068
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" }),
|
|
1069
|
+
/* @__PURE__ */ jsx(
|
|
1070
|
+
"input",
|
|
1071
|
+
{
|
|
1072
|
+
type: "text",
|
|
1073
|
+
value: query,
|
|
1074
|
+
onChange: (e) => setQuery(e.target.value),
|
|
1075
|
+
onKeyDown: (e) => {
|
|
1076
|
+
if (e.key === "Enter") {
|
|
1077
|
+
e.preventDefault();
|
|
1078
|
+
e.stopPropagation();
|
|
1079
|
+
handleSearch();
|
|
1080
|
+
}
|
|
1081
|
+
},
|
|
1082
|
+
placeholder: "Search free stock photos\u2026",
|
|
1083
|
+
disabled: searching,
|
|
1084
|
+
className: "w-full pl-8 pr-3 py-2 text-sm rounded-md border border-border bg-transparent placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
|
1085
|
+
}
|
|
1086
|
+
)
|
|
1087
|
+
] }),
|
|
1088
|
+
/* @__PURE__ */ jsx(
|
|
1089
|
+
"select",
|
|
1090
|
+
{
|
|
1091
|
+
value: orientation,
|
|
1092
|
+
onChange: (e) => setOrientation(e.target.value),
|
|
1093
|
+
disabled: searching,
|
|
1094
|
+
className: "text-sm py-2 px-2 rounded-md border border-border bg-transparent text-foreground focus:outline-none focus:ring-1 focus:ring-ring cursor-pointer",
|
|
1095
|
+
children: ORIENTATIONS.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
|
|
1096
|
+
}
|
|
1097
|
+
),
|
|
1098
|
+
/* @__PURE__ */ jsxs(
|
|
1099
|
+
"button",
|
|
1100
|
+
{
|
|
1101
|
+
type: "button",
|
|
1102
|
+
onClick: handleSearch,
|
|
1103
|
+
disabled: !query.trim() || searching,
|
|
1104
|
+
className: cn(
|
|
1105
|
+
"px-4 py-2 text-sm font-medium rounded-md transition-colors",
|
|
1106
|
+
"bg-primary text-primary-foreground hover:bg-primary/90",
|
|
1107
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1108
|
+
"flex items-center gap-1.5"
|
|
1109
|
+
),
|
|
1110
|
+
children: [
|
|
1111
|
+
searching ? /* @__PURE__ */ jsx(Loader2, { className: "w-3.5 h-3.5 animate-spin" }) : /* @__PURE__ */ jsx(Search, { className: "w-3.5 h-3.5" }),
|
|
1112
|
+
searching ? "Searching\u2026" : "Search"
|
|
1113
|
+
]
|
|
1114
|
+
}
|
|
1115
|
+
)
|
|
1116
|
+
] }),
|
|
1117
|
+
error && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2.5 rounded-md bg-destructive/10 text-destructive text-xs", children: [
|
|
1118
|
+
/* @__PURE__ */ jsx(AlertCircle, { className: "w-4 h-4 flex-shrink-0" }),
|
|
1119
|
+
error
|
|
1120
|
+
] }),
|
|
1121
|
+
results.length > 0 && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2", children: results.map((photo, i) => {
|
|
1122
|
+
const thumb = getThumb(photo);
|
|
1123
|
+
const full = getFullUrl(photo);
|
|
1124
|
+
const isPending = pendingUrl === full;
|
|
1125
|
+
const isSaved = savedUrl === full;
|
|
1126
|
+
return /* @__PURE__ */ jsxs(
|
|
1127
|
+
"div",
|
|
1128
|
+
{
|
|
1129
|
+
className: "group relative aspect-square rounded-md overflow-hidden border border-border bg-muted/30",
|
|
1130
|
+
children: [
|
|
1131
|
+
/* @__PURE__ */ jsx(
|
|
1132
|
+
"img",
|
|
1133
|
+
{
|
|
1134
|
+
src: thumb,
|
|
1135
|
+
alt: photo.alt || "",
|
|
1136
|
+
loading: "lazy",
|
|
1137
|
+
className: "w-full h-full object-cover"
|
|
1138
|
+
}
|
|
1139
|
+
),
|
|
1140
|
+
/* @__PURE__ */ jsx(
|
|
1141
|
+
"button",
|
|
1142
|
+
{
|
|
1143
|
+
type: "button",
|
|
1144
|
+
onClick: () => handleSave(photo),
|
|
1145
|
+
disabled: !!pendingUrl || saving,
|
|
1146
|
+
className: cn(
|
|
1147
|
+
"absolute inset-0 flex items-center justify-center text-xs font-medium",
|
|
1148
|
+
"bg-background/80 opacity-0 group-hover:opacity-100 transition-opacity",
|
|
1149
|
+
"text-foreground gap-1.5",
|
|
1150
|
+
(isPending || isSaved) && "opacity-100"
|
|
1151
|
+
),
|
|
1152
|
+
children: isPending ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1153
|
+
/* @__PURE__ */ jsx(Loader2, { className: "w-3.5 h-3.5 animate-spin" }),
|
|
1154
|
+
" Saving\u2026"
|
|
1155
|
+
] }) : isSaved ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1156
|
+
/* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5" }),
|
|
1157
|
+
" Saved"
|
|
1158
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1159
|
+
/* @__PURE__ */ jsx(Image, { className: "w-3.5 h-3.5" }),
|
|
1160
|
+
" Save"
|
|
1161
|
+
] })
|
|
1162
|
+
}
|
|
1163
|
+
),
|
|
1164
|
+
photo.photographer && /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 inset-x-0 px-1.5 py-0.5 text-[10px] text-background bg-foreground/60 truncate", children: photo.photographerUrl ? /* @__PURE__ */ jsx(
|
|
1165
|
+
"a",
|
|
1166
|
+
{
|
|
1167
|
+
href: photo.photographerUrl,
|
|
1168
|
+
target: "_blank",
|
|
1169
|
+
rel: "noreferrer noopener",
|
|
1170
|
+
onClick: (e) => e.stopPropagation(),
|
|
1171
|
+
className: "hover:underline",
|
|
1172
|
+
children: photo.photographer
|
|
1173
|
+
}
|
|
1174
|
+
) : photo.photographer })
|
|
1175
|
+
]
|
|
1176
|
+
},
|
|
1177
|
+
`${full}-${i}`
|
|
1178
|
+
);
|
|
1179
|
+
}) })
|
|
1180
|
+
] });
|
|
1181
|
+
};
|
|
584
1182
|
var ScopedAssetBrowser = ({ scope, accept, pageSize, viewMode, search, selectedIds, onToggleSelect, onDoubleClickSelect, onDelete, allowDelete, emptyText }) => {
|
|
585
1183
|
const { assets, loading, error, refresh } = useAssets({ scope, accept, pageSize });
|
|
586
1184
|
const filteredAssets = useMemo(() => {
|
|
@@ -597,7 +1195,7 @@ var ScopedAssetBrowser = ({ scope, accept, pageSize, viewMode, search, selectedI
|
|
|
597
1195
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-3 rounded-md bg-destructive/10 text-destructive text-sm", children: [
|
|
598
1196
|
/* @__PURE__ */ jsx(AlertCircle, { className: "w-4 h-4 flex-shrink-0" }),
|
|
599
1197
|
error,
|
|
600
|
-
/* @__PURE__ */ jsx("button", { onClick: refresh, className: "ml-auto underline text-xs", children: "Retry" })
|
|
1198
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: refresh, className: "ml-auto underline text-xs", children: "Retry" })
|
|
601
1199
|
] });
|
|
602
1200
|
}
|
|
603
1201
|
if (filteredAssets.length === 0) {
|
|
@@ -625,6 +1223,8 @@ var AssetPickerContent = ({
|
|
|
625
1223
|
productScope,
|
|
626
1224
|
allowUpload = true,
|
|
627
1225
|
allowUrlImport = true,
|
|
1226
|
+
allowAIGenerate,
|
|
1227
|
+
allowStockPhotos,
|
|
628
1228
|
multiple = false,
|
|
629
1229
|
accept: acceptProp,
|
|
630
1230
|
showTypeFilter,
|
|
@@ -636,7 +1236,7 @@ var AssetPickerContent = ({
|
|
|
636
1236
|
pageSize = 50,
|
|
637
1237
|
onConfirm
|
|
638
1238
|
}) => {
|
|
639
|
-
const { assets, upload, uploadFromUrl, uploading, uploadProgress } = useAssets({
|
|
1239
|
+
const { assets, upload, uploadFromUrl, uploadFromRemoteUrl, uploading, uploadProgress } = useAssets({
|
|
640
1240
|
scope,
|
|
641
1241
|
accept: acceptProp,
|
|
642
1242
|
pageSize
|
|
@@ -657,6 +1257,10 @@ var AssetPickerContent = ({
|
|
|
657
1257
|
return entry?.prefix;
|
|
658
1258
|
}, [acceptProp, mimeFilter]);
|
|
659
1259
|
const shouldShowFilter = showTypeFilter ?? !acceptProp;
|
|
1260
|
+
const collectionId = scope.collectionId;
|
|
1261
|
+
const acceptsImages = !acceptProp || acceptProp.startsWith("image");
|
|
1262
|
+
const aiEnabled = (allowAIGenerate ?? acceptsImages) && !!collectionId;
|
|
1263
|
+
const stockEnabled = (allowStockPhotos ?? acceptsImages) && !!collectionId;
|
|
660
1264
|
const activeScope = useMemo(() => {
|
|
661
1265
|
if (hasProductScope && scopeTab === "product") {
|
|
662
1266
|
return { type: "product", collectionId: productScope.collectionId, productId: productScope.productId };
|
|
@@ -715,6 +1319,14 @@ var AssetPickerContent = ({
|
|
|
715
1319
|
}
|
|
716
1320
|
return result;
|
|
717
1321
|
}, [uploadFromUrl, multiple, onSelect, toSelection]);
|
|
1322
|
+
const handleRemoteIngest = useCallback(async (url, name) => {
|
|
1323
|
+
const result = await uploadFromRemoteUrl(url, { name });
|
|
1324
|
+
if (result && !multiple) {
|
|
1325
|
+
setSelectedIds(/* @__PURE__ */ new Set([result.id]));
|
|
1326
|
+
onSelect?.(toSelection(result));
|
|
1327
|
+
}
|
|
1328
|
+
return result;
|
|
1329
|
+
}, [uploadFromRemoteUrl, multiple, onSelect, toSelection]);
|
|
718
1330
|
const handleDelete = useCallback(async (assetId) => {
|
|
719
1331
|
setSelectedIds((prev) => {
|
|
720
1332
|
const next = new Set(prev);
|
|
@@ -738,13 +1350,16 @@ var AssetPickerContent = ({
|
|
|
738
1350
|
const tabs = [
|
|
739
1351
|
{ key: "browse", label: "Browse", show: true },
|
|
740
1352
|
{ key: "upload", label: "Upload", show: allowUpload },
|
|
741
|
-
{ key: "url", label: "URL", show: allowUrlImport }
|
|
1353
|
+
{ key: "url", label: "URL", show: allowUrlImport },
|
|
1354
|
+
{ key: "ai", label: "AI Generate", show: aiEnabled },
|
|
1355
|
+
{ key: "stock", label: "Stock", show: stockEnabled }
|
|
742
1356
|
];
|
|
743
1357
|
return /* @__PURE__ */ jsxs("div", { className: "smartlinks-ui-asset-picker-content flex flex-col gap-3", children: [
|
|
744
1358
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
745
1359
|
/* @__PURE__ */ jsx("div", { className: "flex gap-1 bg-muted rounded-md p-0.5", children: tabs.filter((t) => t.show).map((t) => /* @__PURE__ */ jsx(
|
|
746
1360
|
"button",
|
|
747
1361
|
{
|
|
1362
|
+
type: "button",
|
|
748
1363
|
onClick: () => setTab(t.key),
|
|
749
1364
|
className: cn(
|
|
750
1365
|
"px-2.5 py-1 text-xs font-medium rounded transition-colors flex items-center gap-1",
|
|
@@ -784,6 +1399,7 @@ var AssetPickerContent = ({
|
|
|
784
1399
|
/* @__PURE__ */ jsx(
|
|
785
1400
|
"button",
|
|
786
1401
|
{
|
|
1402
|
+
type: "button",
|
|
787
1403
|
onClick: () => setViewMode("grid"),
|
|
788
1404
|
className: cn("p-1 rounded", viewMode === "grid" ? "bg-background shadow-sm" : ""),
|
|
789
1405
|
title: "Grid view",
|
|
@@ -793,6 +1409,7 @@ var AssetPickerContent = ({
|
|
|
793
1409
|
/* @__PURE__ */ jsx(
|
|
794
1410
|
"button",
|
|
795
1411
|
{
|
|
1412
|
+
type: "button",
|
|
796
1413
|
onClick: () => setViewMode("list"),
|
|
797
1414
|
className: cn("p-1 rounded", viewMode === "list" ? "bg-background shadow-sm" : ""),
|
|
798
1415
|
title: "List view",
|
|
@@ -805,6 +1422,7 @@ var AssetPickerContent = ({
|
|
|
805
1422
|
/* @__PURE__ */ jsx(
|
|
806
1423
|
"button",
|
|
807
1424
|
{
|
|
1425
|
+
type: "button",
|
|
808
1426
|
onClick: () => setScopeTab("collection"),
|
|
809
1427
|
className: cn(
|
|
810
1428
|
"px-3 py-1.5 text-xs font-medium border-b-2 transition-colors -mb-px",
|
|
@@ -816,6 +1434,7 @@ var AssetPickerContent = ({
|
|
|
816
1434
|
/* @__PURE__ */ jsx(
|
|
817
1435
|
"button",
|
|
818
1436
|
{
|
|
1437
|
+
type: "button",
|
|
819
1438
|
onClick: () => setScopeTab("product"),
|
|
820
1439
|
className: cn(
|
|
821
1440
|
"px-3 py-1.5 text-xs font-medium border-b-2 transition-colors -mb-px",
|
|
@@ -859,6 +1478,22 @@ var AssetPickerContent = ({
|
|
|
859
1478
|
importing: uploading
|
|
860
1479
|
}
|
|
861
1480
|
),
|
|
1481
|
+
tab === "ai" && aiEnabled && /* @__PURE__ */ jsx(
|
|
1482
|
+
AIImageGenerate,
|
|
1483
|
+
{
|
|
1484
|
+
collectionId,
|
|
1485
|
+
onSave: handleRemoteIngest,
|
|
1486
|
+
saving: uploading
|
|
1487
|
+
}
|
|
1488
|
+
),
|
|
1489
|
+
tab === "stock" && stockEnabled && /* @__PURE__ */ jsx(
|
|
1490
|
+
StockPhotoSearch,
|
|
1491
|
+
{
|
|
1492
|
+
collectionId,
|
|
1493
|
+
onSave: handleRemoteIngest,
|
|
1494
|
+
saving: uploading
|
|
1495
|
+
}
|
|
1496
|
+
),
|
|
862
1497
|
onConfirm && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pt-2 border-t border-border", children: [
|
|
863
1498
|
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
864
1499
|
selectedIds.size,
|
|
@@ -868,6 +1503,7 @@ var AssetPickerContent = ({
|
|
|
868
1503
|
/* @__PURE__ */ jsx(
|
|
869
1504
|
"button",
|
|
870
1505
|
{
|
|
1506
|
+
type: "button",
|
|
871
1507
|
onClick: handleConfirm,
|
|
872
1508
|
disabled: selectedIds.size === 0,
|
|
873
1509
|
className: cn(
|
|
@@ -891,20 +1527,31 @@ var PickerDialog = ({ open, onClose, maxWidth, children }) => {
|
|
|
891
1527
|
onClick: onClose
|
|
892
1528
|
}
|
|
893
1529
|
),
|
|
894
|
-
/* @__PURE__ */ jsxs(
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1530
|
+
/* @__PURE__ */ jsxs(
|
|
1531
|
+
"div",
|
|
1532
|
+
{
|
|
1533
|
+
className: "relative z-10 w-full max-h-[85vh] bg-background rounded-xl shadow-2xl border border-border flex flex-col overflow-hidden mx-4",
|
|
1534
|
+
style: { maxWidth: maxWidth || "56rem" },
|
|
1535
|
+
onClick: (e) => e.stopPropagation(),
|
|
1536
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
1537
|
+
onTouchStart: (e) => e.stopPropagation(),
|
|
1538
|
+
children: [
|
|
1539
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-border", children: [
|
|
1540
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Select Asset" }),
|
|
1541
|
+
/* @__PURE__ */ jsx(
|
|
1542
|
+
"button",
|
|
1543
|
+
{
|
|
1544
|
+
type: "button",
|
|
1545
|
+
onClick: onClose,
|
|
1546
|
+
className: "p-1 rounded hover:bg-accent transition-colors",
|
|
1547
|
+
children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4 text-muted-foreground" })
|
|
1548
|
+
}
|
|
1549
|
+
)
|
|
1550
|
+
] }),
|
|
1551
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-y-auto p-4", children })
|
|
1552
|
+
]
|
|
1553
|
+
}
|
|
1554
|
+
)
|
|
908
1555
|
] });
|
|
909
1556
|
};
|
|
910
1557
|
var AssetPicker = (props) => {
|
|
@@ -936,5 +1583,5 @@ var AssetPicker = (props) => {
|
|
|
936
1583
|
};
|
|
937
1584
|
|
|
938
1585
|
export { ASSET_MIME_FILTERS, AssetPicker, useAssets };
|
|
939
|
-
//# sourceMappingURL=chunk-
|
|
940
|
-
//# sourceMappingURL=chunk-
|
|
1586
|
+
//# sourceMappingURL=chunk-XA5J6CZL.js.map
|
|
1587
|
+
//# sourceMappingURL=chunk-XA5J6CZL.js.map
|