diff --git a/src/components/editor/EditorApp.tsx b/src/components/editor/EditorApp.tsx
index 34df60a..4f5e61f 100644
--- a/src/components/editor/EditorApp.tsx
+++ b/src/components/editor/EditorApp.tsx
@@ -236,7 +236,7 @@ function EditorAppInner({ initialCategory }: EditorAppProps) {
{currentTemplate.name}
-
+
{/* Mobile Tabs */}
@@ -278,7 +278,7 @@ function EditorAppInner({ initialCategory }: EditorAppProps) {
{/* The topbar ExportBar always mounts and owns the shortcuts, so this second one opts out. */}
-
+
;
templateId: string;
+ svg: string | null;
/**
* Whether this bar owns the keyboard shortcuts. Pass false on a second
* ExportBar so Ctrl/Cmd+S and Ctrl/Cmd+Shift+C fire once, not once per bar.
@@ -24,22 +26,32 @@ export function ExportBar({
downloadUrl,
params,
templateId,
+ svg,
shortcuts = true,
}: ExportBarProps) {
const [downloading, setDownloading] = useState(false);
const [copied, setCopied] = useState(null);
const downloadRef = useRef(downloadUrl);
const apiUrlRef = useRef(apiUrl);
+ const svgRef = useRef(svg);
+ const hasLocalImage = containsLocalImage(params);
downloadRef.current = downloadUrl;
apiUrlRef.current = apiUrl;
+ svgRef.current = svg;
const handleDownload = useCallback(async () => {
setDownloading(true);
try {
- const res = await fetch(downloadRef.current);
- if (!res.ok) throw new Error('Download failed');
- const blob = await res.blob();
+ let blob: Blob;
+ if (hasLocalImage) {
+ if (!svgRef.current) throw new Error('Preview is not ready');
+ blob = await svgToPngBlob(svgRef.current);
+ } else {
+ const res = await fetch(downloadRef.current);
+ if (!res.ok) throw new Error('Download failed');
+ blob = await res.blob();
+ }
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
@@ -55,7 +67,11 @@ export function ExportBar({
} finally {
setDownloading(false);
}
- }, [templateId]);
+ }, [hasLocalImage, templateId]);
+
+ const showLocalImageWarning = useCallback(() => {
+ window.showToast?.('Local images cannot be included in a shareable URL.', 'error');
+ }, []);
const copyToClipboard = useCallback(async (text: string, label: string) => {
try {
@@ -96,13 +112,14 @@ export function ExportBar({
// Ctrl/Cmd+Shift+C → Copy API URL
if (e.key === 'C' && e.shiftKey) {
e.preventDefault();
- copyToClipboard(apiUrlRef.current, 'url');
+ if (hasLocalImage) showLocalImageWarning();
+ else copyToClipboard(apiUrlRef.current, 'url');
}
}
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
- }, [handleDownload, copyToClipboard, shortcuts]);
+ }, [handleDownload, copyToClipboard, hasLocalImage, showLocalImageWarning, shortcuts]);
const metaTags = generateMetaTags({
title: params.title ? String(params.title) : undefined,
@@ -126,7 +143,7 @@ export function ExportBar({