labellife-design-tool 1.2.8 → 1.3.0
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/lib/lib/index.js +369 -1160
- package/dist/lib/wordpress.js +369 -1160
- package/dist/types/CanvasEditor.d.ts.map +1 -1
- package/dist/types/elements/ShapeElement.d.ts +1 -0
- package/dist/types/elements/ShapeElement.d.ts.map +1 -1
- package/dist/types/elements/UrlImageElement.d.ts +1 -0
- package/dist/types/elements/UrlImageElement.d.ts.map +1 -1
- package/dist/types/store/simpleStore.d.ts +23 -3
- package/dist/types/store/simpleStore.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/lib/lib/index.js
CHANGED
|
@@ -547,7 +547,7 @@ function initJsxCompat() {
|
|
|
547
547
|
}
|
|
548
548
|
|
|
549
549
|
// src/CanvasEditor.tsx
|
|
550
|
-
import
|
|
550
|
+
import React17, { useRef as useRef4, useEffect as useEffect4, useMemo, useCallback as useCallback4 } from "react";
|
|
551
551
|
import { Stage, Layer, Rect as Rect2 } from "react-konva";
|
|
552
552
|
import {
|
|
553
553
|
PlusCircle
|
|
@@ -1361,61 +1361,6 @@ var UrlImageElement = ({ element, isSelected, onSelect, onChange }) => {
|
|
|
1361
1361
|
}
|
|
1362
1362
|
}));
|
|
1363
1363
|
};
|
|
1364
|
-
// src/constants/CanvasPresets.ts
|
|
1365
|
-
var CANVAS_PRESETS = [
|
|
1366
|
-
{ name: "Instagram Post", width: 1080, height: 1080 },
|
|
1367
|
-
{ name: "Instagram Story", width: 1080, height: 1920 },
|
|
1368
|
-
{ name: "Facebook Post", width: 1200, height: 630 },
|
|
1369
|
-
{ name: "Twitter Post", width: 1024, height: 512 },
|
|
1370
|
-
{ name: "A4", width: 794, height: 1123 },
|
|
1371
|
-
{ name: "Letter", width: 816, height: 1056 },
|
|
1372
|
-
{ name: "YouTube Thumbnail", width: 1280, height: 720 },
|
|
1373
|
-
{ name: "Custom", width: 800, height: 600 }
|
|
1374
|
-
];
|
|
1375
|
-
// src/constants/DefaultColors.ts
|
|
1376
|
-
var DEFAULT_COLORS = [
|
|
1377
|
-
"#000000",
|
|
1378
|
-
"#FFFFFF",
|
|
1379
|
-
"#FF0000",
|
|
1380
|
-
"#00FF00",
|
|
1381
|
-
"#0000FF",
|
|
1382
|
-
"#FFFF00",
|
|
1383
|
-
"#FF00FF",
|
|
1384
|
-
"#00FFFF",
|
|
1385
|
-
"#FFA500",
|
|
1386
|
-
"#800080",
|
|
1387
|
-
"#FFC0CB",
|
|
1388
|
-
"#A52A2A",
|
|
1389
|
-
"#808080",
|
|
1390
|
-
"#C0C0C0",
|
|
1391
|
-
"#FFD700"
|
|
1392
|
-
];
|
|
1393
|
-
// src/constants/FontFamilies.ts
|
|
1394
|
-
var FONT_FAMILIES = [
|
|
1395
|
-
"Arial",
|
|
1396
|
-
"Helvetica",
|
|
1397
|
-
"Times New Roman",
|
|
1398
|
-
"Georgia",
|
|
1399
|
-
"Verdana",
|
|
1400
|
-
"Courier New",
|
|
1401
|
-
"Comic Sans MS",
|
|
1402
|
-
"Impact",
|
|
1403
|
-
"Trebuchet MS",
|
|
1404
|
-
"Palatino",
|
|
1405
|
-
"Garamond",
|
|
1406
|
-
"Bookman",
|
|
1407
|
-
"Tahoma"
|
|
1408
|
-
];
|
|
1409
|
-
// src/config.ts
|
|
1410
|
-
var _unsplashAccessKey = typeof process !== "undefined" && process.env?.UNSPLASH_ACCESS_KEY ? process.env.UNSPLASH_ACCESS_KEY : undefined;
|
|
1411
|
-
var UNSPLASH_ACCESS_KEY = _unsplashAccessKey || "YOUR_UNSPLASH_ACCESS_KEY_HERE";
|
|
1412
|
-
function setUnsplashAccessKey(key) {
|
|
1413
|
-
_unsplashAccessKey = key;
|
|
1414
|
-
}
|
|
1415
|
-
function getUnsplashAccessKey() {
|
|
1416
|
-
return _unsplashAccessKey;
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
1364
|
// src/components/Header.tsx
|
|
1420
1365
|
import React7 from "react";
|
|
1421
1366
|
|
|
@@ -1879,6 +1824,53 @@ var ElementPanel_default = ElementPanel;
|
|
|
1879
1824
|
|
|
1880
1825
|
// src/panels/TextPanel.tsx
|
|
1881
1826
|
import React10 from "react";
|
|
1827
|
+
|
|
1828
|
+
// src/constants/CanvasPresets.ts
|
|
1829
|
+
var CANVAS_PRESETS = [
|
|
1830
|
+
{ name: "Instagram Post", width: 1080, height: 1080 },
|
|
1831
|
+
{ name: "Instagram Story", width: 1080, height: 1920 },
|
|
1832
|
+
{ name: "Facebook Post", width: 1200, height: 630 },
|
|
1833
|
+
{ name: "Twitter Post", width: 1024, height: 512 },
|
|
1834
|
+
{ name: "A4", width: 794, height: 1123 },
|
|
1835
|
+
{ name: "Letter", width: 816, height: 1056 },
|
|
1836
|
+
{ name: "YouTube Thumbnail", width: 1280, height: 720 },
|
|
1837
|
+
{ name: "Custom", width: 800, height: 600 }
|
|
1838
|
+
];
|
|
1839
|
+
// src/constants/DefaultColors.ts
|
|
1840
|
+
var DEFAULT_COLORS = [
|
|
1841
|
+
"#000000",
|
|
1842
|
+
"#FFFFFF",
|
|
1843
|
+
"#FF0000",
|
|
1844
|
+
"#00FF00",
|
|
1845
|
+
"#0000FF",
|
|
1846
|
+
"#FFFF00",
|
|
1847
|
+
"#FF00FF",
|
|
1848
|
+
"#00FFFF",
|
|
1849
|
+
"#FFA500",
|
|
1850
|
+
"#800080",
|
|
1851
|
+
"#FFC0CB",
|
|
1852
|
+
"#A52A2A",
|
|
1853
|
+
"#808080",
|
|
1854
|
+
"#C0C0C0",
|
|
1855
|
+
"#FFD700"
|
|
1856
|
+
];
|
|
1857
|
+
// src/constants/FontFamilies.ts
|
|
1858
|
+
var FONT_FAMILIES = [
|
|
1859
|
+
"Arial",
|
|
1860
|
+
"Helvetica",
|
|
1861
|
+
"Times New Roman",
|
|
1862
|
+
"Georgia",
|
|
1863
|
+
"Verdana",
|
|
1864
|
+
"Courier New",
|
|
1865
|
+
"Comic Sans MS",
|
|
1866
|
+
"Impact",
|
|
1867
|
+
"Trebuchet MS",
|
|
1868
|
+
"Palatino",
|
|
1869
|
+
"Garamond",
|
|
1870
|
+
"Bookman",
|
|
1871
|
+
"Tahoma"
|
|
1872
|
+
];
|
|
1873
|
+
// src/panels/TextPanel.tsx
|
|
1882
1874
|
import {
|
|
1883
1875
|
Bold,
|
|
1884
1876
|
Italic,
|
|
@@ -2725,394 +2717,16 @@ var RightSidebar = ({
|
|
|
2725
2717
|
}), /* @__PURE__ */ React16.createElement("span", null, "Delete"))));
|
|
2726
2718
|
};
|
|
2727
2719
|
var RightSidebar_default = RightSidebar;
|
|
2728
|
-
// src/components/TemplateInputModal.tsx
|
|
2729
|
-
import React17, { useState as useState2, useRef as useRef4 } from "react";
|
|
2730
|
-
import { X, Upload as Upload2, Image as ImageIcon4, ChevronLeft, ChevronRight } from "lucide-react";
|
|
2731
|
-
var TemplateInputModal = ({
|
|
2732
|
-
inputs,
|
|
2733
|
-
onComplete,
|
|
2734
|
-
onCancel
|
|
2735
|
-
}) => {
|
|
2736
|
-
const isLightTheme = document.title.includes("Light Theme");
|
|
2737
|
-
const modalStyle = {
|
|
2738
|
-
backgroundColor: isLightTheme ? "#f8fafc" : "#1f2937",
|
|
2739
|
-
color: isLightTheme ? "#0f172a" : "#ffffff",
|
|
2740
|
-
borderColor: isLightTheme ? "#cbd5e1" : "#374151",
|
|
2741
|
-
boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)"
|
|
2742
|
-
};
|
|
2743
|
-
const headerStyle = {
|
|
2744
|
-
borderBottomColor: isLightTheme ? "#e2e8f0" : "#374151",
|
|
2745
|
-
borderBottomWidth: "1px",
|
|
2746
|
-
borderBottomStyle: "solid"
|
|
2747
|
-
};
|
|
2748
|
-
const footerStyle = {
|
|
2749
|
-
borderTopColor: isLightTheme ? "#e2e8f0" : "#374151",
|
|
2750
|
-
borderTopWidth: "1px",
|
|
2751
|
-
borderTopStyle: "solid"
|
|
2752
|
-
};
|
|
2753
|
-
const inputStyle = {
|
|
2754
|
-
backgroundColor: isLightTheme ? "#ffffff" : "#374151",
|
|
2755
|
-
borderColor: isLightTheme ? "#cbd5e1" : "#4b5563",
|
|
2756
|
-
color: isLightTheme ? "#0f172a" : "#ffffff"
|
|
2757
|
-
};
|
|
2758
|
-
const labelStyle = {
|
|
2759
|
-
color: isLightTheme ? "#0f172a" : "#d1d5db",
|
|
2760
|
-
fontWeight: 500
|
|
2761
|
-
};
|
|
2762
|
-
const helpTextStyle = {
|
|
2763
|
-
color: isLightTheme ? "#64748b" : "#9ca3af"
|
|
2764
|
-
};
|
|
2765
|
-
const primaryButtonStyle = {
|
|
2766
|
-
backgroundColor: "#2563eb",
|
|
2767
|
-
color: "#ffffff"
|
|
2768
|
-
};
|
|
2769
|
-
const secondaryButtonStyle = {
|
|
2770
|
-
backgroundColor: isLightTheme ? "#e2e8f0" : "#374151",
|
|
2771
|
-
color: isLightTheme ? "#0f172a" : "#ffffff",
|
|
2772
|
-
border: "none"
|
|
2773
|
-
};
|
|
2774
|
-
const [values, setValues] = useState2({});
|
|
2775
|
-
const [errors, setErrors] = useState2({});
|
|
2776
|
-
const [currentStep, setCurrentStep] = useState2(0);
|
|
2777
|
-
const fileInputRefs = useRef4({});
|
|
2778
|
-
const sortedInputs = [...inputs].sort((a, b) => (a.config.order || 0) - (b.config.order || 0));
|
|
2779
|
-
const currentInput = sortedInputs[currentStep];
|
|
2780
|
-
const isFirstStep = currentStep === 0;
|
|
2781
|
-
const isLastStep = currentStep === sortedInputs.length - 1;
|
|
2782
|
-
const handleTextChange = (id, value) => {
|
|
2783
|
-
setValues((prev) => ({ ...prev, [id]: value }));
|
|
2784
|
-
if (errors[id]) {
|
|
2785
|
-
setErrors((prev) => {
|
|
2786
|
-
const newErrors = { ...prev };
|
|
2787
|
-
delete newErrors[id];
|
|
2788
|
-
return newErrors;
|
|
2789
|
-
});
|
|
2790
|
-
}
|
|
2791
|
-
};
|
|
2792
|
-
const handleFileChange = (id, file) => {
|
|
2793
|
-
if (!file) {
|
|
2794
|
-
setValues((prev) => {
|
|
2795
|
-
const newValues = { ...prev };
|
|
2796
|
-
delete newValues[id];
|
|
2797
|
-
return newValues;
|
|
2798
|
-
});
|
|
2799
|
-
return;
|
|
2800
|
-
}
|
|
2801
|
-
const config = inputs.find((input) => input.config.id === id)?.config;
|
|
2802
|
-
if (!config)
|
|
2803
|
-
return;
|
|
2804
|
-
if (config.accept && !file.type.match(config.accept.replace("*", ".*"))) {
|
|
2805
|
-
setErrors((prev) => ({
|
|
2806
|
-
...prev,
|
|
2807
|
-
[id]: `File must be of type: ${config.accept}`
|
|
2808
|
-
}));
|
|
2809
|
-
return;
|
|
2810
|
-
}
|
|
2811
|
-
if (config.maxSize && file.size > config.maxSize) {
|
|
2812
|
-
const maxSizeMB = (config.maxSize / 1024 / 1024).toFixed(2);
|
|
2813
|
-
setErrors((prev) => ({
|
|
2814
|
-
...prev,
|
|
2815
|
-
[id]: `File size must be less than ${maxSizeMB}MB`
|
|
2816
|
-
}));
|
|
2817
|
-
return;
|
|
2818
|
-
}
|
|
2819
|
-
const reader = new FileReader;
|
|
2820
|
-
reader.onload = (e) => {
|
|
2821
|
-
const result = e.target?.result;
|
|
2822
|
-
if (typeof result === "string") {
|
|
2823
|
-
setValues((prev) => ({ ...prev, [id]: result }));
|
|
2824
|
-
setErrors((prev) => {
|
|
2825
|
-
const newErrors = { ...prev };
|
|
2826
|
-
delete newErrors[id];
|
|
2827
|
-
return newErrors;
|
|
2828
|
-
});
|
|
2829
|
-
}
|
|
2830
|
-
};
|
|
2831
|
-
reader.onerror = () => {
|
|
2832
|
-
setErrors((prev) => ({
|
|
2833
|
-
...prev,
|
|
2834
|
-
[id]: "Failed to read file"
|
|
2835
|
-
}));
|
|
2836
|
-
};
|
|
2837
|
-
reader.readAsDataURL(file);
|
|
2838
|
-
};
|
|
2839
|
-
const validateCurrentStep = () => {
|
|
2840
|
-
if (!currentInput)
|
|
2841
|
-
return false;
|
|
2842
|
-
const config = currentInput.config;
|
|
2843
|
-
const value = values[config.id];
|
|
2844
|
-
const newErrors = { ...errors };
|
|
2845
|
-
delete newErrors[config.id];
|
|
2846
|
-
if (config.required && !value) {
|
|
2847
|
-
newErrors[config.id] = "This field is required";
|
|
2848
|
-
setErrors(newErrors);
|
|
2849
|
-
return false;
|
|
2850
|
-
}
|
|
2851
|
-
if (config.type === "text" && value) {
|
|
2852
|
-
if (config.minLength && value.length < config.minLength) {
|
|
2853
|
-
newErrors[config.id] = `Minimum length is ${config.minLength} characters`;
|
|
2854
|
-
setErrors(newErrors);
|
|
2855
|
-
return false;
|
|
2856
|
-
}
|
|
2857
|
-
if (config.maxLength && value.length > config.maxLength) {
|
|
2858
|
-
newErrors[config.id] = `Maximum length is ${config.maxLength} characters`;
|
|
2859
|
-
setErrors(newErrors);
|
|
2860
|
-
return false;
|
|
2861
|
-
}
|
|
2862
|
-
}
|
|
2863
|
-
setErrors(newErrors);
|
|
2864
|
-
return true;
|
|
2865
|
-
};
|
|
2866
|
-
const handleNext = () => {
|
|
2867
|
-
if (!validateCurrentStep()) {
|
|
2868
|
-
return;
|
|
2869
|
-
}
|
|
2870
|
-
if (isLastStep) {
|
|
2871
|
-
const allErrors = {};
|
|
2872
|
-
sortedInputs.forEach((input) => {
|
|
2873
|
-
if (input.config.required && !values[input.config.id]) {
|
|
2874
|
-
allErrors[input.config.id] = "This field is required";
|
|
2875
|
-
}
|
|
2876
|
-
});
|
|
2877
|
-
if (Object.keys(allErrors).length > 0) {
|
|
2878
|
-
setErrors(allErrors);
|
|
2879
|
-
const firstErrorIndex = sortedInputs.findIndex((input) => allErrors[input.config.id]);
|
|
2880
|
-
if (firstErrorIndex !== -1) {
|
|
2881
|
-
setCurrentStep(firstErrorIndex);
|
|
2882
|
-
}
|
|
2883
|
-
return;
|
|
2884
|
-
}
|
|
2885
|
-
onComplete(values);
|
|
2886
|
-
} else {
|
|
2887
|
-
setCurrentStep((prev) => prev + 1);
|
|
2888
|
-
}
|
|
2889
|
-
};
|
|
2890
|
-
const handlePrevious = () => {
|
|
2891
|
-
if (!isFirstStep) {
|
|
2892
|
-
setCurrentStep((prev) => prev - 1);
|
|
2893
|
-
}
|
|
2894
|
-
};
|
|
2895
|
-
const handleSkip = () => {
|
|
2896
|
-
if (!currentInput.config.required) {
|
|
2897
|
-
const defaultValue = currentInput.config.defaultValue || "";
|
|
2898
|
-
const valueToSet = defaultValue;
|
|
2899
|
-
setValues((prev) => ({ ...prev, [currentInput.config.id]: valueToSet }));
|
|
2900
|
-
setErrors((prev) => {
|
|
2901
|
-
const newErrors = { ...prev };
|
|
2902
|
-
delete newErrors[currentInput.config.id];
|
|
2903
|
-
return newErrors;
|
|
2904
|
-
});
|
|
2905
|
-
const updatedValues = { ...values, [currentInput.config.id]: valueToSet };
|
|
2906
|
-
if (isLastStep) {
|
|
2907
|
-
const allErrors = {};
|
|
2908
|
-
sortedInputs.forEach((input) => {
|
|
2909
|
-
if (input.config.required && !updatedValues[input.config.id]) {
|
|
2910
|
-
allErrors[input.config.id] = "This field is required";
|
|
2911
|
-
}
|
|
2912
|
-
});
|
|
2913
|
-
if (Object.keys(allErrors).length > 0) {
|
|
2914
|
-
setErrors(allErrors);
|
|
2915
|
-
const firstErrorIndex = sortedInputs.findIndex((input) => allErrors[input.config.id]);
|
|
2916
|
-
if (firstErrorIndex !== -1) {
|
|
2917
|
-
setCurrentStep(firstErrorIndex);
|
|
2918
|
-
}
|
|
2919
|
-
return;
|
|
2920
|
-
}
|
|
2921
|
-
onComplete(updatedValues);
|
|
2922
|
-
} else {
|
|
2923
|
-
setCurrentStep((prev) => prev + 1);
|
|
2924
|
-
}
|
|
2925
|
-
}
|
|
2926
|
-
};
|
|
2927
|
-
const renderInput = (input) => {
|
|
2928
|
-
const { config } = input;
|
|
2929
|
-
const defaultValue = config.defaultValue || "";
|
|
2930
|
-
const value = values[config.id] !== undefined ? values[config.id] : defaultValue;
|
|
2931
|
-
const error = errors[config.id];
|
|
2932
|
-
switch (config.type) {
|
|
2933
|
-
case "image": {
|
|
2934
|
-
const isUrl = value && (value.startsWith("http://") || value.startsWith("https://") || value.startsWith("data:"));
|
|
2935
|
-
const isDefaultValue = value === defaultValue && defaultValue && (defaultValue.startsWith("http://") || defaultValue.startsWith("https://"));
|
|
2936
|
-
return /* @__PURE__ */ React17.createElement("div", {
|
|
2937
|
-
className: "space-y-2"
|
|
2938
|
-
}, /* @__PURE__ */ React17.createElement("label", {
|
|
2939
|
-
className: "block text-sm font-medium",
|
|
2940
|
-
style: labelStyle
|
|
2941
|
-
}, config.label, config.required && /* @__PURE__ */ React17.createElement("span", {
|
|
2942
|
-
className: "text-red-400 ml-1"
|
|
2943
|
-
}, "*")), config.helpText && /* @__PURE__ */ React17.createElement("p", {
|
|
2944
|
-
className: "text-xs",
|
|
2945
|
-
style: helpTextStyle
|
|
2946
|
-
}, config.helpText), isDefaultValue && /* @__PURE__ */ React17.createElement("p", {
|
|
2947
|
-
className: "text-xs text-blue-400"
|
|
2948
|
-
}, "Using default image"), /* @__PURE__ */ React17.createElement("div", {
|
|
2949
|
-
className: "flex items-center space-x-4"
|
|
2950
|
-
}, /* @__PURE__ */ React17.createElement("input", {
|
|
2951
|
-
ref: (el) => {
|
|
2952
|
-
fileInputRefs.current[config.id] = el;
|
|
2953
|
-
},
|
|
2954
|
-
type: "file",
|
|
2955
|
-
accept: config.accept || "image/*",
|
|
2956
|
-
onChange: (e) => handleFileChange(config.id, e.target.files?.[0] || null),
|
|
2957
|
-
className: "hidden"
|
|
2958
|
-
}), /* @__PURE__ */ React17.createElement("button", {
|
|
2959
|
-
type: "button",
|
|
2960
|
-
onClick: () => fileInputRefs.current[config.id]?.click(),
|
|
2961
|
-
className: "flex items-center space-x-2 px-4 py-2 rounded border-2 border-dashed transition-colors",
|
|
2962
|
-
style: {
|
|
2963
|
-
borderColor: value ? "#10b981" : isLightTheme ? "#cbd5e1" : "#4b5563",
|
|
2964
|
-
backgroundColor: value ? "rgba(16, 185, 129, 0.1)" : isLightTheme ? "rgba(226, 232, 240, 0.5)" : "rgba(55, 65, 81, 0.5)",
|
|
2965
|
-
color: value ? "#10b981" : isLightTheme ? "#475569" : "#d1d5db"
|
|
2966
|
-
}
|
|
2967
|
-
}, /* @__PURE__ */ React17.createElement(Upload2, {
|
|
2968
|
-
className: "w-4 h-4"
|
|
2969
|
-
}), /* @__PURE__ */ React17.createElement("span", null, value ? "Change Image" : "Upload Image")), value && /* @__PURE__ */ React17.createElement("div", {
|
|
2970
|
-
className: "flex items-center space-x-2"
|
|
2971
|
-
}, /* @__PURE__ */ React17.createElement(ImageIcon4, {
|
|
2972
|
-
className: "w-5 h-5",
|
|
2973
|
-
style: { color: "#10b981" }
|
|
2974
|
-
}), /* @__PURE__ */ React17.createElement("span", {
|
|
2975
|
-
className: "text-sm",
|
|
2976
|
-
style: { color: isLightTheme ? "#64748b" : "#9ca3af" }
|
|
2977
|
-
}, isUrl && !isDefaultValue ? "Image URL" : isDefaultValue ? "Default image" : "Image selected"), /* @__PURE__ */ React17.createElement("button", {
|
|
2978
|
-
type: "button",
|
|
2979
|
-
onClick: () => {
|
|
2980
|
-
const resetValue = defaultValue || "";
|
|
2981
|
-
setValues((prev) => ({ ...prev, [config.id]: resetValue }));
|
|
2982
|
-
setErrors((prev) => {
|
|
2983
|
-
const newErrors = { ...prev };
|
|
2984
|
-
delete newErrors[config.id];
|
|
2985
|
-
return newErrors;
|
|
2986
|
-
});
|
|
2987
|
-
},
|
|
2988
|
-
className: "text-sm",
|
|
2989
|
-
style: { color: "#ef4444" }
|
|
2990
|
-
}, isDefaultValue ? "Clear" : "Remove"))), value && isUrl && /* @__PURE__ */ React17.createElement("div", {
|
|
2991
|
-
className: "mt-2"
|
|
2992
|
-
}, /* @__PURE__ */ React17.createElement("img", {
|
|
2993
|
-
src: value,
|
|
2994
|
-
alt: "Preview",
|
|
2995
|
-
className: "max-w-xs max-h-32 object-contain rounded border",
|
|
2996
|
-
style: { borderColor: isLightTheme ? "#cbd5e1" : "#4b5563" },
|
|
2997
|
-
onError: (e) => {
|
|
2998
|
-
setErrors((prev) => ({
|
|
2999
|
-
...prev,
|
|
3000
|
-
[config.id]: "Failed to load image"
|
|
3001
|
-
}));
|
|
3002
|
-
}
|
|
3003
|
-
})), error && /* @__PURE__ */ React17.createElement("p", {
|
|
3004
|
-
className: "text-sm",
|
|
3005
|
-
style: { color: "#ef4444" }
|
|
3006
|
-
}, error));
|
|
3007
|
-
}
|
|
3008
|
-
case "text":
|
|
3009
|
-
return /* @__PURE__ */ React17.createElement("div", {
|
|
3010
|
-
className: "space-y-2"
|
|
3011
|
-
}, /* @__PURE__ */ React17.createElement("label", {
|
|
3012
|
-
className: "block text-sm font-medium",
|
|
3013
|
-
style: labelStyle
|
|
3014
|
-
}, config.label, config.required && /* @__PURE__ */ React17.createElement("span", {
|
|
3015
|
-
className: "text-red-400 ml-1"
|
|
3016
|
-
}, "*")), config.helpText && /* @__PURE__ */ React17.createElement("p", {
|
|
3017
|
-
className: "text-xs",
|
|
3018
|
-
style: helpTextStyle
|
|
3019
|
-
}, config.helpText), /* @__PURE__ */ React17.createElement("input", {
|
|
3020
|
-
type: "text",
|
|
3021
|
-
value,
|
|
3022
|
-
onChange: (e) => handleTextChange(config.id, e.target.value),
|
|
3023
|
-
placeholder: config.placeholder || "Enter text here...",
|
|
3024
|
-
maxLength: config.maxLength,
|
|
3025
|
-
className: "w-full px-3 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500",
|
|
3026
|
-
style: {
|
|
3027
|
-
backgroundColor: "#ffffff",
|
|
3028
|
-
color: "#0f172a",
|
|
3029
|
-
borderColor: error ? "#ef4444" : "#cbd5e1"
|
|
3030
|
-
}
|
|
3031
|
-
}), config.maxLength && /* @__PURE__ */ React17.createElement("p", {
|
|
3032
|
-
className: "text-xs text-right",
|
|
3033
|
-
style: helpTextStyle
|
|
3034
|
-
}, value.length, " / ", config.maxLength), error && /* @__PURE__ */ React17.createElement("p", {
|
|
3035
|
-
className: "text-sm",
|
|
3036
|
-
style: { color: "#ef4444" }
|
|
3037
|
-
}, error));
|
|
3038
|
-
default:
|
|
3039
|
-
return null;
|
|
3040
|
-
}
|
|
3041
|
-
};
|
|
3042
|
-
if (!currentInput) {
|
|
3043
|
-
return null;
|
|
3044
|
-
}
|
|
3045
|
-
return /* @__PURE__ */ React17.createElement("div", {
|
|
3046
|
-
className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
|
|
3047
|
-
}, /* @__PURE__ */ React17.createElement("div", {
|
|
3048
|
-
className: "rounded-lg w-full max-w-2xl max-h-[90vh] overflow-hidden flex flex-col",
|
|
3049
|
-
style: modalStyle
|
|
3050
|
-
}, /* @__PURE__ */ React17.createElement("div", {
|
|
3051
|
-
className: "p-6 border-b flex items-center justify-between",
|
|
3052
|
-
style: headerStyle
|
|
3053
|
-
}, /* @__PURE__ */ React17.createElement("div", null, /* @__PURE__ */ React17.createElement("h2", {
|
|
3054
|
-
className: "text-xl font-semibold",
|
|
3055
|
-
style: { color: isLightTheme ? "#0f172a" : "#ffffff" }
|
|
3056
|
-
}, inputs.some((input) => input.config.required) ? "Template Input Required" : "Template Customization"), /* @__PURE__ */ React17.createElement("p", {
|
|
3057
|
-
className: "text-sm mt-1",
|
|
3058
|
-
style: { color: isLightTheme ? "#64748b" : "#9ca3af" }
|
|
3059
|
-
}, "Step ", currentStep + 1, " of ", sortedInputs.length, !inputs.some((input) => input.config.required) && /* @__PURE__ */ React17.createElement("span", {
|
|
3060
|
-
style: { color: "#2563eb", marginLeft: "8px" }
|
|
3061
|
-
}, "(All fields optional)"))), /* @__PURE__ */ React17.createElement("button", {
|
|
3062
|
-
onClick: onCancel,
|
|
3063
|
-
className: "transition-colors",
|
|
3064
|
-
style: { color: isLightTheme ? "#64748b" : "#9ca3af" }
|
|
3065
|
-
}, /* @__PURE__ */ React17.createElement(X, {
|
|
3066
|
-
className: "w-5 h-5"
|
|
3067
|
-
}))), /* @__PURE__ */ React17.createElement("div", {
|
|
3068
|
-
className: "px-6 pt-4"
|
|
3069
|
-
}, /* @__PURE__ */ React17.createElement("div", {
|
|
3070
|
-
className: "w-full rounded-full h-2",
|
|
3071
|
-
style: { backgroundColor: isLightTheme ? "#e2e8f0" : "#374151" }
|
|
3072
|
-
}, /* @__PURE__ */ React17.createElement("div", {
|
|
3073
|
-
className: "h-2 rounded-full transition-all duration-300",
|
|
3074
|
-
style: {
|
|
3075
|
-
backgroundColor: "#2563eb",
|
|
3076
|
-
width: `${(currentStep + 1) / sortedInputs.length * 100}%`
|
|
3077
|
-
}
|
|
3078
|
-
}))), /* @__PURE__ */ React17.createElement("div", {
|
|
3079
|
-
className: "flex-1 overflow-y-auto p-6"
|
|
3080
|
-
}, /* @__PURE__ */ React17.createElement("div", {
|
|
3081
|
-
className: "space-y-4"
|
|
3082
|
-
}, renderInput(currentInput))), /* @__PURE__ */ React17.createElement("div", {
|
|
3083
|
-
className: "p-6 border-t flex items-center justify-between",
|
|
3084
|
-
style: footerStyle
|
|
3085
|
-
}, /* @__PURE__ */ React17.createElement("button", {
|
|
3086
|
-
onClick: onCancel,
|
|
3087
|
-
className: "px-4 py-2 rounded transition-colors",
|
|
3088
|
-
style: secondaryButtonStyle
|
|
3089
|
-
}, "Cancel"), /* @__PURE__ */ React17.createElement("div", {
|
|
3090
|
-
className: "flex items-center space-x-3"
|
|
3091
|
-
}, !isFirstStep && /* @__PURE__ */ React17.createElement("button", {
|
|
3092
|
-
onClick: handlePrevious,
|
|
3093
|
-
className: "px-4 py-2 rounded transition-colors flex items-center space-x-2",
|
|
3094
|
-
style: secondaryButtonStyle
|
|
3095
|
-
}, /* @__PURE__ */ React17.createElement(ChevronLeft, {
|
|
3096
|
-
className: "w-4 h-4"
|
|
3097
|
-
}), /* @__PURE__ */ React17.createElement("span", null, "Previous")), !currentInput.config.required && /* @__PURE__ */ React17.createElement("button", {
|
|
3098
|
-
onClick: handleSkip,
|
|
3099
|
-
className: "px-4 py-2 rounded transition-colors",
|
|
3100
|
-
style: { ...secondaryButtonStyle, opacity: 0.9 }
|
|
3101
|
-
}, "Skip"), /* @__PURE__ */ React17.createElement("button", {
|
|
3102
|
-
onClick: handleNext,
|
|
3103
|
-
className: "px-4 py-2 rounded transition-colors flex items-center space-x-2",
|
|
3104
|
-
style: primaryButtonStyle
|
|
3105
|
-
}, /* @__PURE__ */ React17.createElement("span", null, isLastStep ? "Complete" : "Next"), !isLastStep && /* @__PURE__ */ React17.createElement(ChevronRight, {
|
|
3106
|
-
className: "w-4 h-4"
|
|
3107
|
-
}))))));
|
|
3108
|
-
};
|
|
3109
|
-
var TemplateInputModal_default = TemplateInputModal;
|
|
3110
|
-
|
|
3111
2720
|
// src/store/simpleStore.ts
|
|
3112
2721
|
class SimpleCanvasStore {
|
|
3113
2722
|
_design;
|
|
3114
2723
|
_activePageId;
|
|
3115
2724
|
_activePanelId;
|
|
2725
|
+
_selectedId;
|
|
2726
|
+
_selectedIds;
|
|
2727
|
+
_tool;
|
|
2728
|
+
_zoom;
|
|
2729
|
+
_selectedShape;
|
|
3116
2730
|
_listeners = {};
|
|
3117
2731
|
constructor(initialDesign) {
|
|
3118
2732
|
this._design = {
|
|
@@ -3127,6 +2741,11 @@ class SimpleCanvasStore {
|
|
|
3127
2741
|
};
|
|
3128
2742
|
this._activePageId = initialDesign?.pages?.[0]?.id || null;
|
|
3129
2743
|
this._activePanelId = null;
|
|
2744
|
+
this._selectedId = null;
|
|
2745
|
+
this._selectedIds = [];
|
|
2746
|
+
this._tool = "select";
|
|
2747
|
+
this._zoom = 1;
|
|
2748
|
+
this._selectedShape = "rect";
|
|
3130
2749
|
}
|
|
3131
2750
|
on(event, callback) {
|
|
3132
2751
|
this._listeners[event] = callback;
|
|
@@ -3166,12 +2785,27 @@ class SimpleCanvasStore {
|
|
|
3166
2785
|
get activePanelId() {
|
|
3167
2786
|
return this._activePanelId;
|
|
3168
2787
|
}
|
|
2788
|
+
get selectedId() {
|
|
2789
|
+
return this._selectedId;
|
|
2790
|
+
}
|
|
2791
|
+
get selectedIds() {
|
|
2792
|
+
return this._selectedIds;
|
|
2793
|
+
}
|
|
2794
|
+
get tool() {
|
|
2795
|
+
return this._tool;
|
|
2796
|
+
}
|
|
2797
|
+
get zoom() {
|
|
2798
|
+
return this._zoom;
|
|
2799
|
+
}
|
|
2800
|
+
get selectedShape() {
|
|
2801
|
+
return this._selectedShape;
|
|
2802
|
+
}
|
|
3169
2803
|
setDesign(design) {
|
|
3170
2804
|
this._design = design;
|
|
3171
2805
|
if (design.pages.find((p) => p.id === this._activePageId)) {} else if (design.pages.length > 0) {
|
|
3172
2806
|
this._activePageId = design.pages[0].id;
|
|
3173
2807
|
}
|
|
3174
|
-
this.emit("designChanged",
|
|
2808
|
+
this.emit("designChanged", this._design);
|
|
3175
2809
|
this.emit("activePageChanged", this._activePageId);
|
|
3176
2810
|
}
|
|
3177
2811
|
updateDesign(updates) {
|
|
@@ -3213,18 +2847,12 @@ class SimpleCanvasStore {
|
|
|
3213
2847
|
this._design.pages = remainingPages;
|
|
3214
2848
|
this.emit("designChanged", this._design);
|
|
3215
2849
|
}
|
|
3216
|
-
setActivePage(pageId) {
|
|
3217
|
-
const page = this._design.pages.find((p) => p.id === pageId);
|
|
3218
|
-
if (page) {
|
|
3219
|
-
this._activePageId = pageId;
|
|
3220
|
-
this.emit("activePageChanged", pageId);
|
|
3221
|
-
this.emit("designChanged", this._design);
|
|
3222
|
-
}
|
|
3223
|
-
}
|
|
3224
2850
|
addElement(element) {
|
|
3225
2851
|
const page = this.activePage;
|
|
3226
|
-
if (!page)
|
|
2852
|
+
if (!page) {
|
|
2853
|
+
console.warn("addElement: No active page!");
|
|
3227
2854
|
return;
|
|
2855
|
+
}
|
|
3228
2856
|
const newElement = {
|
|
3229
2857
|
id: element.id || `element-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
3230
2858
|
type: element.type,
|
|
@@ -3242,30 +2870,30 @@ class SimpleCanvasStore {
|
|
|
3242
2870
|
page.elements.push(newElement);
|
|
3243
2871
|
this.emit("designChanged", this._design);
|
|
3244
2872
|
}
|
|
3245
|
-
updateElement(elementId, updates) {
|
|
3246
|
-
for (const page of this._design.pages) {
|
|
3247
|
-
const elementIndex = page.elements.findIndex((e) => e.id === elementId);
|
|
3248
|
-
if (elementIndex !== -1) {
|
|
3249
|
-
page.elements[elementIndex] = { ...page.elements[elementIndex], ...updates };
|
|
3250
|
-
this.emit("designChanged", this._design);
|
|
3251
|
-
return;
|
|
3252
|
-
}
|
|
3253
|
-
}
|
|
3254
|
-
}
|
|
3255
|
-
deleteElement(elementId) {
|
|
3256
|
-
for (const page of this._design.pages) {
|
|
3257
|
-
const elementIndex = page.elements.findIndex((e) => e.id === elementId);
|
|
3258
|
-
if (elementIndex !== -1) {
|
|
3259
|
-
page.elements.splice(elementIndex, 1);
|
|
3260
|
-
this.emit("designChanged", this._design);
|
|
3261
|
-
return;
|
|
3262
|
-
}
|
|
3263
|
-
}
|
|
3264
|
-
}
|
|
3265
2873
|
openSidePanel(panelId) {
|
|
3266
2874
|
this._activePanelId = panelId;
|
|
3267
2875
|
this.emit("activePanelChanged", panelId);
|
|
3268
2876
|
}
|
|
2877
|
+
setSelectedId(selectedId) {
|
|
2878
|
+
this._selectedId = selectedId;
|
|
2879
|
+
this.emit("selectedIdChanged", selectedId);
|
|
2880
|
+
}
|
|
2881
|
+
setSelectedIds(selectedIds) {
|
|
2882
|
+
this._selectedIds = selectedIds;
|
|
2883
|
+
this.emit("selectedIdsChanged", selectedIds);
|
|
2884
|
+
}
|
|
2885
|
+
setTool(tool) {
|
|
2886
|
+
this._tool = tool;
|
|
2887
|
+
this.emit("toolChanged", tool);
|
|
2888
|
+
}
|
|
2889
|
+
setZoom(zoom) {
|
|
2890
|
+
this._zoom = zoom;
|
|
2891
|
+
this.emit("zoomChanged", zoom);
|
|
2892
|
+
}
|
|
2893
|
+
setSelectedShape(shape) {
|
|
2894
|
+
this._selectedShape = shape;
|
|
2895
|
+
this.emit("selectedShapeChanged", shape);
|
|
2896
|
+
}
|
|
3269
2897
|
async toBlob(type = "png") {
|
|
3270
2898
|
return new Promise((resolve, reject) => {
|
|
3271
2899
|
try {
|
|
@@ -3295,6 +2923,34 @@ class SimpleCanvasStore {
|
|
|
3295
2923
|
}
|
|
3296
2924
|
});
|
|
3297
2925
|
}
|
|
2926
|
+
setActivePage(pageId) {
|
|
2927
|
+
const page = this._design.pages.find((p) => p.id === pageId);
|
|
2928
|
+
if (page) {
|
|
2929
|
+
this._activePageId = pageId;
|
|
2930
|
+
this.emit("activePageChanged", pageId);
|
|
2931
|
+
this.emit("designChanged", this._design);
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
updateElement(elementId, updates) {
|
|
2935
|
+
for (const page of this._design.pages) {
|
|
2936
|
+
const elementIndex = page.elements.findIndex((e) => e.id === elementId);
|
|
2937
|
+
if (elementIndex !== -1) {
|
|
2938
|
+
page.elements[elementIndex] = { ...page.elements[elementIndex], ...updates };
|
|
2939
|
+
this.emit("designChanged", this._design);
|
|
2940
|
+
return;
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
deleteElement(elementId) {
|
|
2945
|
+
for (const page of this._design.pages) {
|
|
2946
|
+
const elementIndex = page.elements.findIndex((e) => e.id === elementId);
|
|
2947
|
+
if (elementIndex !== -1) {
|
|
2948
|
+
page.elements.splice(elementIndex, 1);
|
|
2949
|
+
this.emit("designChanged", this._design);
|
|
2950
|
+
return;
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
3298
2954
|
async loadJSON(jsonData) {
|
|
3299
2955
|
return new Promise((resolve, reject) => {
|
|
3300
2956
|
try {
|
|
@@ -3329,190 +2985,84 @@ var CanvasEditor = ({
|
|
|
3329
2985
|
width: 800,
|
|
3330
2986
|
height: 600
|
|
3331
2987
|
});
|
|
3332
|
-
const
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
name: "Untitled Design",
|
|
3339
|
-
width: 800,
|
|
3340
|
-
height: 600,
|
|
3341
|
-
pages: [
|
|
3342
|
-
{
|
|
3343
|
-
id: "1",
|
|
3344
|
-
name: "Page 1",
|
|
3345
|
-
elements: [],
|
|
3346
|
-
background: "#ffffff"
|
|
3347
|
-
}
|
|
3348
|
-
],
|
|
3349
|
-
fonts: FONT_FAMILIES,
|
|
3350
|
-
colors: DEFAULT_COLORS
|
|
3351
|
-
};
|
|
3352
|
-
});
|
|
3353
|
-
const [currentPageId, setCurrentPageId] = useState3(() => {
|
|
3354
|
-
if (externalStore?.design.pages && externalStore.design.pages.length > 0) {
|
|
3355
|
-
return externalStore.design.pages[0].id;
|
|
3356
|
-
}
|
|
3357
|
-
if (externalStore?.activePageId) {
|
|
3358
|
-
return externalStore.activePageId;
|
|
3359
|
-
}
|
|
3360
|
-
return "1";
|
|
3361
|
-
});
|
|
3362
|
-
const [selectedId, setSelectedId] = useState3(null);
|
|
3363
|
-
const [selectedIds, setSelectedIds] = useState3([]);
|
|
3364
|
-
const [tool, setTool] = useState3("select");
|
|
3365
|
-
const [activePanelId, setActivePanelId] = useState3("elements");
|
|
2988
|
+
const stageRef = useRef4(null);
|
|
2989
|
+
const fileInputRef = useRef4(null);
|
|
2990
|
+
const jsonInputRef = useRef4(null);
|
|
2991
|
+
const containerRef = useRef4(null);
|
|
2992
|
+
const currentPage = store.design.pages.find((p) => p.id === store.activePageId) || store.design.pages[0] || null;
|
|
2993
|
+
const selectedElement = currentPage?.elements.find((el) => el.id === store.selectedId) || null;
|
|
3366
2994
|
useEffect4(() => {
|
|
3367
2995
|
if (externalStore) {
|
|
3368
|
-
const handleDesignChange = (newDesign) => {
|
|
3369
|
-
|
|
3370
|
-
};
|
|
3371
|
-
const
|
|
3372
|
-
|
|
3373
|
-
};
|
|
3374
|
-
const
|
|
3375
|
-
|
|
3376
|
-
};
|
|
2996
|
+
const handleDesignChange = (newDesign) => {};
|
|
2997
|
+
const handleActivePageChange = (pageId) => {};
|
|
2998
|
+
const handleActivePanelChange = (panelId) => {};
|
|
2999
|
+
const handleSelectedIdChange = (selectedId) => {};
|
|
3000
|
+
const handleSelectedIdsChange = (selectedIds) => {};
|
|
3001
|
+
const handleToolChange = (tool) => {};
|
|
3002
|
+
const handleZoomChange = (zoom) => {};
|
|
3003
|
+
const handleSelectedShapeChange = (shape) => {};
|
|
3377
3004
|
externalStore.on("designChanged", handleDesignChange);
|
|
3378
3005
|
externalStore.on("activePageChanged", handleActivePageChange);
|
|
3379
3006
|
externalStore.on("activePanelChanged", handleActivePanelChange);
|
|
3007
|
+
externalStore.on("selectedIdChanged", handleSelectedIdChange);
|
|
3008
|
+
externalStore.on("selectedIdsChanged", handleSelectedIdsChange);
|
|
3009
|
+
externalStore.on("toolChanged", handleToolChange);
|
|
3010
|
+
externalStore.on("zoomChanged", handleZoomChange);
|
|
3011
|
+
externalStore.on("selectedShapeChanged", handleSelectedShapeChange);
|
|
3380
3012
|
return () => {
|
|
3381
3013
|
externalStore.off("designChanged");
|
|
3382
3014
|
externalStore.off("activePageChanged");
|
|
3383
3015
|
externalStore.off("activePanelChanged");
|
|
3016
|
+
externalStore.off("selectedIdChanged");
|
|
3017
|
+
externalStore.off("selectedIdsChanged");
|
|
3018
|
+
externalStore.off("toolChanged");
|
|
3019
|
+
externalStore.off("zoomChanged");
|
|
3020
|
+
externalStore.off("selectedShapeChanged");
|
|
3384
3021
|
};
|
|
3385
3022
|
}
|
|
3386
3023
|
}, [externalStore]);
|
|
3387
|
-
const
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
const [selectedShape, setSelectedShape] = useState3("rect");
|
|
3393
|
-
const [history, setHistory] = useState3([]);
|
|
3394
|
-
const [historyIndex, setHistoryIndex] = useState3(-1);
|
|
3395
|
-
const [showInputModal, setShowInputModal] = useState3(false);
|
|
3396
|
-
const [pendingInputs, setPendingInputs] = useState3([]);
|
|
3397
|
-
const stageRef = useRef5(null);
|
|
3398
|
-
const fileInputRef = useRef5(null);
|
|
3399
|
-
const jsonInputRef = useRef5(null);
|
|
3400
|
-
const containerRef = useRef5(null);
|
|
3401
|
-
const currentPage = design.pages.find((p) => p.id === currentPageId) || design.pages[0] || null;
|
|
3402
|
-
const selectedElement = currentPage?.elements.find((el) => el.id === selectedId) || null;
|
|
3403
|
-
const saveToHistory = useCallback4((newDesign) => {
|
|
3404
|
-
const newHistory = history.slice(0, historyIndex + 1);
|
|
3405
|
-
newHistory.push(JSON.parse(JSON.stringify(newDesign)));
|
|
3406
|
-
setHistory(newHistory);
|
|
3407
|
-
setHistoryIndex(newHistory.length - 1);
|
|
3408
|
-
}, [history, historyIndex]);
|
|
3409
|
-
const undo = useCallback4(() => {
|
|
3410
|
-
if (historyIndex > 0) {
|
|
3411
|
-
setHistoryIndex(historyIndex - 1);
|
|
3412
|
-
setDesign(JSON.parse(JSON.stringify(history[historyIndex - 1])));
|
|
3413
|
-
}
|
|
3414
|
-
}, [history, historyIndex]);
|
|
3415
|
-
const redo = useCallback4(() => {
|
|
3416
|
-
if (historyIndex < history.length - 1) {
|
|
3417
|
-
setHistoryIndex(historyIndex + 1);
|
|
3418
|
-
setDesign(JSON.parse(JSON.stringify(history[historyIndex + 1])));
|
|
3024
|
+
const handleStageClick = useCallback4((e) => {
|
|
3025
|
+
const clickedOnEmpty = e.target === e.target.getStage();
|
|
3026
|
+
if (clickedOnEmpty) {
|
|
3027
|
+
store.setSelectedId(null);
|
|
3028
|
+
store.setSelectedIds([]);
|
|
3419
3029
|
}
|
|
3420
|
-
}, [
|
|
3030
|
+
}, [store]);
|
|
3421
3031
|
const addText = useCallback4(() => {
|
|
3422
|
-
|
|
3423
|
-
|
|
3032
|
+
if (!store.activePage)
|
|
3033
|
+
return;
|
|
3034
|
+
store.activePage.addElement({
|
|
3424
3035
|
type: "text",
|
|
3425
|
-
|
|
3426
|
-
x: design.width / 2 - 50,
|
|
3427
|
-
y: design.height / 2 -
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
text: "Click to edit text",
|
|
3433
|
-
fontSize: 24,
|
|
3434
|
-
fontFamily: "Arial",
|
|
3435
|
-
fill: "#000000",
|
|
3436
|
-
align: "left",
|
|
3437
|
-
lineHeight: 1.2,
|
|
3438
|
-
letterSpacing: 0,
|
|
3439
|
-
textCase: "none",
|
|
3440
|
-
strikethrough: false
|
|
3441
|
-
};
|
|
3442
|
-
const newDesign = {
|
|
3443
|
-
...design,
|
|
3444
|
-
pages: design.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
|
|
3445
|
-
};
|
|
3446
|
-
setDesign(newDesign);
|
|
3447
|
-
saveToHistory(newDesign);
|
|
3448
|
-
if (externalStore) {
|
|
3449
|
-
externalStore.setDesign(newDesign);
|
|
3450
|
-
}
|
|
3451
|
-
setSelectedId(newElement.id);
|
|
3452
|
-
setTool("select");
|
|
3453
|
-
}, [currentPageId, saveToHistory, design.width, design.height, externalStore]);
|
|
3036
|
+
text: "Edit this text",
|
|
3037
|
+
x: store.design.width / 2 - 50,
|
|
3038
|
+
y: store.design.height / 2 - 15,
|
|
3039
|
+
width: 100,
|
|
3040
|
+
height: 30
|
|
3041
|
+
});
|
|
3042
|
+
}, [store]);
|
|
3454
3043
|
const addShape = useCallback4((shapeType) => {
|
|
3455
|
-
|
|
3456
|
-
|
|
3044
|
+
if (!store.activePage)
|
|
3045
|
+
return;
|
|
3046
|
+
store.activePage.addElement({
|
|
3457
3047
|
type: "shape",
|
|
3458
|
-
name: shapeType.charAt(0).toUpperCase() + shapeType.slice(1),
|
|
3459
|
-
x: design.width / 2 - 50,
|
|
3460
|
-
y: design.height / 2 - 50,
|
|
3461
|
-
width: 100,
|
|
3462
|
-
height: 100,
|
|
3463
|
-
rotation: 0,
|
|
3464
|
-
visible: true,
|
|
3465
|
-
locked: false,
|
|
3466
|
-
opacity: 1,
|
|
3467
|
-
fill: "#4299e1",
|
|
3468
|
-
stroke: "#000000",
|
|
3469
|
-
strokeWidth: 0,
|
|
3470
3048
|
shapeType,
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
setDesign((prev) => {
|
|
3476
|
-
const newDesign = {
|
|
3477
|
-
...prev,
|
|
3478
|
-
pages: prev.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
|
|
3479
|
-
};
|
|
3480
|
-
saveToHistory(newDesign);
|
|
3481
|
-
return newDesign;
|
|
3049
|
+
x: store.design.width / 2 - 50,
|
|
3050
|
+
y: store.design.height / 2 - 50,
|
|
3051
|
+
width: 100,
|
|
3052
|
+
height: 100
|
|
3482
3053
|
});
|
|
3483
|
-
|
|
3484
|
-
}, [currentPageId, saveToHistory, design.width, design.height]);
|
|
3485
|
-
const handleStageClick = useCallback4((e) => {
|
|
3486
|
-
const clickedOnEmpty = e.target === e.target.getStage();
|
|
3487
|
-
if (clickedOnEmpty) {
|
|
3488
|
-
setSelectedId(null);
|
|
3489
|
-
setSelectedIds([]);
|
|
3490
|
-
}
|
|
3491
|
-
}, []);
|
|
3054
|
+
}, [store]);
|
|
3492
3055
|
const updateElement = useCallback4((id, attrs) => {
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
pages: prev.pages.map((page) => ({
|
|
3496
|
-
...page,
|
|
3497
|
-
elements: page.elements.map((el) => el.id === id ? { ...el, ...attrs } : el)
|
|
3498
|
-
}))
|
|
3499
|
-
}));
|
|
3500
|
-
}, []);
|
|
3056
|
+
store.updateElement(id, attrs);
|
|
3057
|
+
}, [store]);
|
|
3501
3058
|
const deleteSelected = useCallback4(() => {
|
|
3502
|
-
if (selectedId || selectedIds.length > 0) {
|
|
3503
|
-
const idsToDelete = selectedIds.length > 0 ? selectedIds : [selectedId];
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
...page,
|
|
3508
|
-
elements: page.elements.filter((el) => !idsToDelete.includes(el.id))
|
|
3509
|
-
}))
|
|
3510
|
-
}));
|
|
3511
|
-
setSelectedId(null);
|
|
3512
|
-
setSelectedIds([]);
|
|
3513
|
-
saveToHistory(design);
|
|
3059
|
+
if (store.selectedId || store.selectedIds.length > 0) {
|
|
3060
|
+
const idsToDelete = store.selectedIds.length > 0 ? store.selectedIds : [store.selectedId];
|
|
3061
|
+
idsToDelete.forEach((id) => store.deleteElement(id));
|
|
3062
|
+
store.setSelectedId(null);
|
|
3063
|
+
store.setSelectedIds([]);
|
|
3514
3064
|
}
|
|
3515
|
-
}, [
|
|
3065
|
+
}, [store]);
|
|
3516
3066
|
const duplicateSelected = useCallback4(() => {
|
|
3517
3067
|
if (selectedElement) {
|
|
3518
3068
|
const newElement = {
|
|
@@ -3522,603 +3072,254 @@ var CanvasEditor = ({
|
|
|
3522
3072
|
x: selectedElement.x + 20,
|
|
3523
3073
|
y: selectedElement.y + 20
|
|
3524
3074
|
};
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3075
|
+
store.activePage?.addElement(newElement);
|
|
3076
|
+
store.setSelectedId(newElement.id);
|
|
3077
|
+
}
|
|
3078
|
+
}, [selectedElement, store]);
|
|
3079
|
+
const moveElementUp = useCallback4((id) => {}, [store]);
|
|
3080
|
+
const moveElementDown = useCallback4((id) => {}, [store]);
|
|
3081
|
+
const addPage = useCallback4(() => {
|
|
3082
|
+
store.addPage();
|
|
3083
|
+
}, [store]);
|
|
3084
|
+
const deletePage = useCallback4((pageId) => {
|
|
3085
|
+
store.deletePages([pageId]);
|
|
3086
|
+
}, [store]);
|
|
3087
|
+
const panelConfigs = useMemo(() => {
|
|
3088
|
+
const builtInConfigs = {
|
|
3089
|
+
elements: { id: "elements", title: "Elements", component: ElementPanel_default, props: { onAddShape: addShape, store } },
|
|
3090
|
+
text: { id: "text", title: "Text", component: TextPanel_default, props: { selectedElement, updateElement, onAddText: addText, store } },
|
|
3091
|
+
image: { id: "image", title: "Image", component: ImagePanel_default, props: { selectedElement, updateElement, store } },
|
|
3092
|
+
background: { id: "background", title: "Background", component: BackgroundPanel_default, props: { store } },
|
|
3093
|
+
design: { id: "design", title: "Design", component: DesignPanel_default, props: { store } },
|
|
3094
|
+
variables: { id: "variables", title: "Variables", component: VariablesPanel_default, props: { store } },
|
|
3095
|
+
export: { id: "export", title: "Export", component: ExportPanel_default, props: { store } }
|
|
3096
|
+
};
|
|
3097
|
+
const mergedConfigs = { ...builtInConfigs };
|
|
3098
|
+
if (config?.panels) {
|
|
3099
|
+
config.panels.forEach((panelConfig) => {
|
|
3100
|
+
if (typeof panelConfig === "string") {} else {
|
|
3101
|
+
const customPanelConfig = {
|
|
3102
|
+
id: panelConfig.id,
|
|
3103
|
+
title: panelConfig.title,
|
|
3104
|
+
component: panelConfig.component,
|
|
3105
|
+
props: panelConfig.props || {},
|
|
3106
|
+
...panelConfig.icon && typeof panelConfig.icon.type === "string" ? {
|
|
3107
|
+
icon: panelConfig.icon.type
|
|
3108
|
+
} : {}
|
|
3109
|
+
};
|
|
3110
|
+
mergedConfigs[panelConfig.id] = customPanelConfig;
|
|
3111
|
+
}
|
|
3532
3112
|
});
|
|
3533
|
-
setSelectedId(newElement.id);
|
|
3534
3113
|
}
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
const index = page.elements.findIndex((el) => el.id === id);
|
|
3542
|
-
if (index < page.elements.length - 1) {
|
|
3543
|
-
const newElements = [...page.elements];
|
|
3544
|
-
[newElements[index], newElements[index + 1]] = [
|
|
3545
|
-
newElements[index + 1],
|
|
3546
|
-
newElements[index]
|
|
3547
|
-
];
|
|
3548
|
-
return { ...page, elements: newElements };
|
|
3114
|
+
const orderedConfigs = [];
|
|
3115
|
+
if (config?.panels) {
|
|
3116
|
+
config.panels.forEach((panelConfig) => {
|
|
3117
|
+
if (typeof panelConfig === "string") {
|
|
3118
|
+
if (mergedConfigs[panelConfig]) {
|
|
3119
|
+
orderedConfigs.push(mergedConfigs[panelConfig]);
|
|
3549
3120
|
}
|
|
3121
|
+
} else {
|
|
3122
|
+
orderedConfigs.push(mergedConfigs[panelConfig.id]);
|
|
3550
3123
|
}
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
}, [
|
|
3555
|
-
const
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3124
|
+
});
|
|
3125
|
+
}
|
|
3126
|
+
return orderedConfigs.length > 0 ? orderedConfigs : Object.values(builtInConfigs);
|
|
3127
|
+
}, [addShape, addText, config, selectedElement, updateElement, store]);
|
|
3128
|
+
const DynamicPanelRenderer = useMemo(() => {
|
|
3129
|
+
const activePanel = panelConfigs.find((panel) => panel.id === store.activePanelId);
|
|
3130
|
+
if (!activePanel)
|
|
3131
|
+
return null;
|
|
3132
|
+
const PanelComponent = activePanel.component;
|
|
3133
|
+
return /* @__PURE__ */ React17.createElement(PanelComponent, {
|
|
3134
|
+
key: activePanel.id,
|
|
3135
|
+
...activePanel.props
|
|
3136
|
+
});
|
|
3137
|
+
}, [panelConfigs, store.activePanelId]);
|
|
3138
|
+
const handleExportPNG = useCallback4(() => {
|
|
3139
|
+
exportToPNG(stageRef.current, store.design);
|
|
3140
|
+
}, [store.design]);
|
|
3141
|
+
const handleExportJPG = useCallback4(() => {
|
|
3142
|
+
exportToJPG(stageRef.current, store.design);
|
|
3143
|
+
}, [store.design]);
|
|
3144
|
+
const handleExportJSON = useCallback4(() => {
|
|
3145
|
+
exportToJSON(store.design);
|
|
3146
|
+
}, [store.design]);
|
|
3147
|
+
const handleImportJSON = useCallback4((e) => {
|
|
3148
|
+
const file = e.target.files?.[0];
|
|
3149
|
+
if (file) {
|
|
3150
|
+
const reader = new FileReader;
|
|
3151
|
+
reader.onload = (event) => {
|
|
3152
|
+
try {
|
|
3153
|
+
const jsonData = JSON.parse(event.target?.result);
|
|
3154
|
+
importFromJSON(jsonData, (loadedDesign) => {
|
|
3155
|
+
store.setDesign(loadedDesign);
|
|
3156
|
+
}, (errorMessage) => {
|
|
3157
|
+
console.error("Import error:", errorMessage);
|
|
3158
|
+
}, () => {
|
|
3159
|
+
console.log("Import requires user inputs - not implemented");
|
|
3160
|
+
});
|
|
3161
|
+
} catch (error) {
|
|
3162
|
+
console.error("Invalid JSON file:", error);
|
|
3569
3163
|
}
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
}));
|
|
3573
|
-
}, [currentPageId]);
|
|
3574
|
-
const addPage = useCallback4(() => {
|
|
3575
|
-
const newPage = {
|
|
3576
|
-
id: Date.now().toString(),
|
|
3577
|
-
name: `Page ${design.pages.length + 1}`,
|
|
3578
|
-
elements: [],
|
|
3579
|
-
background: "#ffffff",
|
|
3580
|
-
backgroundImageObject: undefined
|
|
3581
|
-
};
|
|
3582
|
-
setDesign((prev) => ({
|
|
3583
|
-
...prev,
|
|
3584
|
-
pages: [...prev.pages, newPage]
|
|
3585
|
-
}));
|
|
3586
|
-
setCurrentPageId(newPage.id);
|
|
3587
|
-
}, [design.pages.length]);
|
|
3588
|
-
const deletePage = useCallback4((pageId) => {
|
|
3589
|
-
if (design.pages.length > 1) {
|
|
3590
|
-
setDesign((prev) => ({
|
|
3591
|
-
...prev,
|
|
3592
|
-
pages: prev.pages.filter((p) => p.id !== pageId)
|
|
3593
|
-
}));
|
|
3594
|
-
if (currentPageId === pageId) {
|
|
3595
|
-
setCurrentPageId(design.pages[0].id);
|
|
3596
|
-
}
|
|
3164
|
+
};
|
|
3165
|
+
reader.readAsText(file);
|
|
3597
3166
|
}
|
|
3598
|
-
}, [
|
|
3167
|
+
}, [store]);
|
|
3599
3168
|
const handleImageUpload = useCallback4((e) => {
|
|
3600
3169
|
const file = e.target.files?.[0];
|
|
3601
3170
|
if (file) {
|
|
3602
3171
|
const reader = new FileReader;
|
|
3603
3172
|
reader.onload = (event) => {
|
|
3604
3173
|
const img = new window.Image;
|
|
3605
|
-
img.src = event.target?.result;
|
|
3606
3174
|
img.onload = () => {
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
locked: false,
|
|
3618
|
-
opacity: 1,
|
|
3619
|
-
src: event.target?.result,
|
|
3620
|
-
cropX: 0,
|
|
3621
|
-
cropY: 0,
|
|
3622
|
-
cropWidth: img.naturalWidth,
|
|
3623
|
-
cropHeight: img.naturalHeight,
|
|
3624
|
-
mask: undefined
|
|
3625
|
-
};
|
|
3626
|
-
setDesign((prev) => ({
|
|
3627
|
-
...prev,
|
|
3628
|
-
pages: prev.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
|
|
3629
|
-
}));
|
|
3630
|
-
saveToHistory(design);
|
|
3175
|
+
if (store.activePage) {
|
|
3176
|
+
store.activePage.addElement({
|
|
3177
|
+
type: "image",
|
|
3178
|
+
src: event.target?.result,
|
|
3179
|
+
x: store.design.width / 2 - img.width / 2,
|
|
3180
|
+
y: store.design.height / 2 - img.height / 2,
|
|
3181
|
+
width: img.width,
|
|
3182
|
+
height: img.height
|
|
3183
|
+
});
|
|
3184
|
+
}
|
|
3631
3185
|
};
|
|
3186
|
+
img.src = event.target?.result;
|
|
3632
3187
|
};
|
|
3633
3188
|
reader.readAsDataURL(file);
|
|
3634
3189
|
}
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
},
|
|
3639
|
-
const searchUnsplash = useCallback4(async () => {
|
|
3640
|
-
if (!unsplashQuery)
|
|
3641
|
-
return;
|
|
3642
|
-
if (UNSPLASH_ACCESS_KEY === "YOUR_UNSPLASH_ACCESS_KEY_HERE" || !UNSPLASH_ACCESS_KEY) {
|
|
3643
|
-
console.warn("Unsplash API key is not configured. Please set UNSPLASH_ACCESS_KEY in src/config.ts");
|
|
3644
|
-
const mockResults = Array(9).fill(null).map((_, i) => ({
|
|
3645
|
-
id: `unsplash-mock-${i}`,
|
|
3646
|
-
urls: {
|
|
3647
|
-
regular: `https://source.unsplash.com/400x300/?${unsplashQuery}&sig=${i}`,
|
|
3648
|
-
thumb: `https://source.unsplash.com/200x150/?${unsplashQuery}&sig=${i}`
|
|
3649
|
-
},
|
|
3650
|
-
user: { name: "Mock User" }
|
|
3651
|
-
}));
|
|
3652
|
-
setUnsplashResults(mockResults);
|
|
3653
|
-
return;
|
|
3654
|
-
}
|
|
3655
|
-
try {
|
|
3656
|
-
const response = await fetch(`https://api.unsplash.com/search/photos?query=${encodeURIComponent(unsplashQuery)}&per_page=9`, {
|
|
3657
|
-
headers: {
|
|
3658
|
-
Authorization: `Client-ID ${UNSPLASH_ACCESS_KEY}`
|
|
3659
|
-
}
|
|
3660
|
-
});
|
|
3661
|
-
if (!response.ok) {
|
|
3662
|
-
console.error("Failed to fetch from Unsplash:", response.statusText);
|
|
3663
|
-
setUnsplashResults([]);
|
|
3664
|
-
return;
|
|
3665
|
-
}
|
|
3666
|
-
const data = await response.json();
|
|
3667
|
-
setUnsplashResults(data.results.map((img) => ({
|
|
3668
|
-
id: img.id,
|
|
3669
|
-
urls: { regular: img.urls.regular, thumb: img.urls.thumb },
|
|
3670
|
-
user: { name: img.user.name }
|
|
3671
|
-
})));
|
|
3672
|
-
} catch (error) {
|
|
3673
|
-
console.error("Error searching Unsplash:", error);
|
|
3674
|
-
setUnsplashResults([]);
|
|
3675
|
-
}
|
|
3676
|
-
}, [unsplashQuery]);
|
|
3677
|
-
const addUnsplashImage = useCallback4((imageUrl) => {
|
|
3678
|
-
if (unsplashMode === "element") {
|
|
3679
|
-
const img = new window.Image;
|
|
3680
|
-
img.crossOrigin = "anonymous";
|
|
3681
|
-
img.src = imageUrl;
|
|
3682
|
-
img.onload = () => {
|
|
3683
|
-
const newElement = {
|
|
3684
|
-
id: Date.now().toString(),
|
|
3685
|
-
type: "image",
|
|
3686
|
-
name: "Unsplash Image",
|
|
3687
|
-
x: 100,
|
|
3688
|
-
y: 100,
|
|
3689
|
-
width: img.naturalWidth,
|
|
3690
|
-
height: img.naturalHeight,
|
|
3691
|
-
rotation: 0,
|
|
3692
|
-
visible: true,
|
|
3693
|
-
locked: false,
|
|
3694
|
-
opacity: 1,
|
|
3695
|
-
src: imageUrl,
|
|
3696
|
-
cropX: 0,
|
|
3697
|
-
cropY: 0,
|
|
3698
|
-
cropWidth: img.naturalWidth,
|
|
3699
|
-
cropHeight: img.naturalHeight,
|
|
3700
|
-
mask: undefined
|
|
3701
|
-
};
|
|
3702
|
-
setDesign((prev) => ({
|
|
3703
|
-
...prev,
|
|
3704
|
-
pages: prev.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
|
|
3705
|
-
}));
|
|
3706
|
-
saveToHistory(design);
|
|
3707
|
-
};
|
|
3708
|
-
} else if (unsplashMode === "background") {
|
|
3709
|
-
const bgImg = new window.Image;
|
|
3710
|
-
bgImg.crossOrigin = "anonymous";
|
|
3711
|
-
bgImg.src = imageUrl;
|
|
3712
|
-
bgImg.onload = () => {
|
|
3713
|
-
setDesign((prev) => ({
|
|
3714
|
-
...prev,
|
|
3715
|
-
pages: prev.pages.map((p) => p.id === currentPageId ? {
|
|
3716
|
-
...p,
|
|
3717
|
-
background: `url(${imageUrl})`,
|
|
3718
|
-
backgroundImageObject: bgImg
|
|
3719
|
-
} : p)
|
|
3720
|
-
}));
|
|
3721
|
-
saveToHistory(design);
|
|
3722
|
-
};
|
|
3723
|
-
}
|
|
3724
|
-
setShowUnsplash(false);
|
|
3725
|
-
setUnsplashQuery("");
|
|
3726
|
-
setUnsplashResults([]);
|
|
3727
|
-
setUnsplashMode("element");
|
|
3728
|
-
}, [currentPageId, saveToHistory, unsplashMode]);
|
|
3729
|
-
const handleImportJSON = (event) => {
|
|
3730
|
-
importFromJSON(event, (newDesign) => {
|
|
3731
|
-
if (newDesign && newDesign.pages && newDesign.pages.length > 0) {
|
|
3732
|
-
setDesign(newDesign);
|
|
3733
|
-
setSelectedId(null);
|
|
3734
|
-
setSelectedIds([]);
|
|
3735
|
-
const firstPageId = newDesign.pages[0]?.id;
|
|
3736
|
-
setCurrentPageId(firstPageId || "1");
|
|
3737
|
-
saveToHistory(newDesign);
|
|
3738
|
-
} else {
|
|
3739
|
-
alert("Invalid design structure in JSON file. Could not load.");
|
|
3740
|
-
}
|
|
3741
|
-
}, (errorMessage) => {
|
|
3742
|
-
alert(`Error importing JSON: ${errorMessage}`);
|
|
3743
|
-
}, (inputs, onComplete) => {
|
|
3744
|
-
setPendingInputs(inputs);
|
|
3745
|
-
setShowInputModal(true);
|
|
3746
|
-
window.__pendingImportComplete = onComplete;
|
|
3747
|
-
});
|
|
3748
|
-
if (jsonInputRef.current) {
|
|
3749
|
-
jsonInputRef.current.value = "";
|
|
3750
|
-
}
|
|
3751
|
-
};
|
|
3752
|
-
const handleInputModalComplete = (values) => {
|
|
3753
|
-
setShowInputModal(false);
|
|
3754
|
-
const onComplete = window.__pendingImportComplete;
|
|
3755
|
-
if (onComplete) {
|
|
3756
|
-
onComplete(values);
|
|
3757
|
-
delete window.__pendingImportComplete;
|
|
3758
|
-
}
|
|
3759
|
-
setPendingInputs([]);
|
|
3760
|
-
};
|
|
3761
|
-
const handleInputModalCancel = () => {
|
|
3762
|
-
setShowInputModal(false);
|
|
3763
|
-
setPendingInputs([]);
|
|
3764
|
-
delete window.__pendingImportComplete;
|
|
3765
|
-
};
|
|
3766
|
-
const panelConfigs = useMemo(() => {
|
|
3767
|
-
const builtInConfigs = {
|
|
3768
|
-
elements: {
|
|
3769
|
-
id: "elements",
|
|
3770
|
-
title: "Elements",
|
|
3771
|
-
component: ElementPanel_default,
|
|
3772
|
-
props: { onAddShape: addShape, store }
|
|
3773
|
-
},
|
|
3774
|
-
text: {
|
|
3775
|
-
id: "text",
|
|
3776
|
-
title: "Text",
|
|
3777
|
-
component: TextPanel_default,
|
|
3778
|
-
props: {
|
|
3779
|
-
selectedElement,
|
|
3780
|
-
updateElement,
|
|
3781
|
-
setTool,
|
|
3782
|
-
onAddText: addText,
|
|
3783
|
-
store
|
|
3784
|
-
}
|
|
3785
|
-
},
|
|
3786
|
-
image: {
|
|
3787
|
-
id: "image",
|
|
3788
|
-
title: "Images",
|
|
3789
|
-
component: ImagePanel_default,
|
|
3790
|
-
props: {
|
|
3791
|
-
selectedElement,
|
|
3792
|
-
updateElement,
|
|
3793
|
-
onUploadClick: () => fileInputRef.current?.click(),
|
|
3794
|
-
onUnsplashClick: () => {
|
|
3795
|
-
setShowUnsplash(true);
|
|
3796
|
-
setUnsplashMode("element");
|
|
3797
|
-
},
|
|
3798
|
-
canvasWidth: design.width,
|
|
3799
|
-
canvasHeight: design.height,
|
|
3800
|
-
store
|
|
3801
|
-
}
|
|
3802
|
-
},
|
|
3803
|
-
design: {
|
|
3804
|
-
id: "design",
|
|
3805
|
-
title: "Design",
|
|
3806
|
-
component: DesignPanel_default,
|
|
3807
|
-
props: {
|
|
3808
|
-
design,
|
|
3809
|
-
currentPage,
|
|
3810
|
-
selectedElement,
|
|
3811
|
-
setDesign,
|
|
3812
|
-
updateElement,
|
|
3813
|
-
onSetUnsplashBackground: () => {
|
|
3814
|
-
setShowUnsplash(true);
|
|
3815
|
-
setUnsplashMode("background");
|
|
3816
|
-
},
|
|
3817
|
-
config,
|
|
3818
|
-
store
|
|
3819
|
-
}
|
|
3820
|
-
},
|
|
3821
|
-
background: {
|
|
3822
|
-
id: "background",
|
|
3823
|
-
title: "Background",
|
|
3824
|
-
component: BackgroundPanel_default,
|
|
3825
|
-
props: {
|
|
3826
|
-
design,
|
|
3827
|
-
currentPage,
|
|
3828
|
-
setDesign,
|
|
3829
|
-
onSetUnsplashBackground: () => {
|
|
3830
|
-
setShowUnsplash(true);
|
|
3831
|
-
setUnsplashMode("background");
|
|
3832
|
-
},
|
|
3833
|
-
store
|
|
3834
|
-
}
|
|
3835
|
-
},
|
|
3836
|
-
...config?.variables ? {
|
|
3837
|
-
variables: {
|
|
3838
|
-
id: "variables",
|
|
3839
|
-
title: "Variables",
|
|
3840
|
-
component: VariablesPanel_default,
|
|
3841
|
-
props: {
|
|
3842
|
-
config,
|
|
3843
|
-
design,
|
|
3844
|
-
setDesign,
|
|
3845
|
-
store
|
|
3846
|
-
}
|
|
3847
|
-
}
|
|
3848
|
-
} : {},
|
|
3849
|
-
...config?.export ? {
|
|
3850
|
-
export: {
|
|
3851
|
-
id: "export",
|
|
3852
|
-
title: "Export",
|
|
3853
|
-
component: ExportPanel_default,
|
|
3854
|
-
props: {
|
|
3855
|
-
onExportToPNG: config.export?.png ? () => {
|
|
3856
|
-
if (stageRef.current)
|
|
3857
|
-
exportToPNG(stageRef.current, design);
|
|
3858
|
-
} : undefined,
|
|
3859
|
-
onExportToJPG: config.export?.jpg ? () => {
|
|
3860
|
-
if (stageRef.current)
|
|
3861
|
-
exportToJPG(stageRef.current, design);
|
|
3862
|
-
} : undefined,
|
|
3863
|
-
onExportToJSON: config.export?.json ? () => exportToJSON(design) : undefined,
|
|
3864
|
-
onImportJSON: () => jsonInputRef.current?.click(),
|
|
3865
|
-
store
|
|
3866
|
-
}
|
|
3867
|
-
}
|
|
3868
|
-
} : {}
|
|
3869
|
-
};
|
|
3870
|
-
if (!config?.panels || config.panels.length === 0) {
|
|
3871
|
-
return [
|
|
3872
|
-
"text",
|
|
3873
|
-
"elements",
|
|
3874
|
-
"image",
|
|
3875
|
-
"design",
|
|
3876
|
-
"background",
|
|
3877
|
-
...config?.variables ? ["variables"] : [],
|
|
3878
|
-
...config?.export ? ["export"] : []
|
|
3879
|
-
].filter((id) => builtInConfigs[id]).map((id) => builtInConfigs[id]);
|
|
3880
|
-
}
|
|
3881
|
-
const ordered = [];
|
|
3882
|
-
for (const panel of config.panels) {
|
|
3883
|
-
if (typeof panel === "string") {
|
|
3884
|
-
const config2 = builtInConfigs[panel];
|
|
3885
|
-
if (config2) {
|
|
3886
|
-
ordered.push(config2);
|
|
3887
|
-
}
|
|
3888
|
-
} else {
|
|
3889
|
-
ordered.push({
|
|
3890
|
-
id: panel.id,
|
|
3891
|
-
title: panel.title,
|
|
3892
|
-
component: panel.component,
|
|
3893
|
-
props: { ...panel.props, store }
|
|
3894
|
-
});
|
|
3895
|
-
}
|
|
3896
|
-
}
|
|
3897
|
-
return ordered;
|
|
3898
|
-
}, [
|
|
3899
|
-
addShape,
|
|
3900
|
-
addText,
|
|
3901
|
-
config,
|
|
3902
|
-
currentPage,
|
|
3903
|
-
design,
|
|
3904
|
-
selectedElement,
|
|
3905
|
-
setTool,
|
|
3906
|
-
updateElement,
|
|
3907
|
-
store
|
|
3908
|
-
]);
|
|
3909
|
-
const DynamicPanelRenderer = () => {
|
|
3910
|
-
const activePanelConfig = panelConfigs.find((p) => p.id === activePanelId);
|
|
3911
|
-
if (!activePanelConfig) {
|
|
3912
|
-
return /* @__PURE__ */ React18.createElement("div", {
|
|
3913
|
-
className: "text-white"
|
|
3914
|
-
}, "Panel not found");
|
|
3915
|
-
}
|
|
3916
|
-
const PanelComponent = activePanelConfig.component;
|
|
3917
|
-
return /* @__PURE__ */ React18.createElement(PanelComponent, {
|
|
3918
|
-
...activePanelConfig.props
|
|
3919
|
-
});
|
|
3920
|
-
};
|
|
3921
|
-
useEffect4(() => {
|
|
3922
|
-
const handleKeyDown = (e) => {
|
|
3923
|
-
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement)
|
|
3924
|
-
return;
|
|
3925
|
-
if (e.metaKey || e.ctrlKey) {
|
|
3926
|
-
switch (e.key) {
|
|
3927
|
-
case "z":
|
|
3928
|
-
if (e.shiftKey) {
|
|
3929
|
-
redo();
|
|
3930
|
-
} else {
|
|
3931
|
-
undo();
|
|
3932
|
-
}
|
|
3933
|
-
e.preventDefault();
|
|
3934
|
-
break;
|
|
3935
|
-
case "c":
|
|
3936
|
-
break;
|
|
3937
|
-
case "v":
|
|
3938
|
-
break;
|
|
3939
|
-
case "d":
|
|
3940
|
-
duplicateSelected();
|
|
3941
|
-
e.preventDefault();
|
|
3942
|
-
break;
|
|
3943
|
-
case "s":
|
|
3944
|
-
exportToJSON(design);
|
|
3945
|
-
e.preventDefault();
|
|
3946
|
-
break;
|
|
3947
|
-
}
|
|
3948
|
-
} else {
|
|
3949
|
-
switch (e.key) {
|
|
3950
|
-
case "Delete":
|
|
3951
|
-
case "Backspace":
|
|
3952
|
-
deleteSelected();
|
|
3953
|
-
break;
|
|
3954
|
-
case "Escape":
|
|
3955
|
-
setSelectedId(null);
|
|
3956
|
-
setSelectedIds([]);
|
|
3957
|
-
break;
|
|
3958
|
-
}
|
|
3959
|
-
}
|
|
3960
|
-
};
|
|
3961
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
3962
|
-
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
3963
|
-
}, [deleteSelected, duplicateSelected, exportToJSON, undo, redo]);
|
|
3964
|
-
useEffect4(() => {
|
|
3965
|
-
if (history.length === 0) {
|
|
3966
|
-
setHistory([JSON.parse(JSON.stringify(design))]);
|
|
3967
|
-
setHistoryIndex(0);
|
|
3968
|
-
}
|
|
3969
|
-
}, []);
|
|
3970
|
-
return /* @__PURE__ */ React18.createElement("div", {
|
|
3971
|
-
className: "h-screen flex flex-col bg-gray-900"
|
|
3972
|
-
}, /* @__PURE__ */ React18.createElement(Header_default, {
|
|
3190
|
+
}, [store]);
|
|
3191
|
+
return /* @__PURE__ */ React17.createElement("div", {
|
|
3192
|
+
className: "w-full h-full flex flex-col bg-gray-900"
|
|
3193
|
+
}, /* @__PURE__ */ React17.createElement(Header_default, {
|
|
3973
3194
|
name,
|
|
3974
|
-
zoom,
|
|
3975
|
-
historyIndex,
|
|
3976
|
-
historyLength:
|
|
3977
|
-
onUndo:
|
|
3978
|
-
onRedo:
|
|
3979
|
-
onZoomIn: () => setZoom(Math.min(3, zoom + 0.1)),
|
|
3980
|
-
onZoomOut: () => setZoom(Math.max(0.1, zoom - 0.1)),
|
|
3981
|
-
onZoomReset: () => setZoom(1),
|
|
3982
|
-
onSetActivePanel:
|
|
3983
|
-
}), /* @__PURE__ */
|
|
3195
|
+
zoom: store.zoom,
|
|
3196
|
+
historyIndex: 0,
|
|
3197
|
+
historyLength: 0,
|
|
3198
|
+
onUndo: () => {},
|
|
3199
|
+
onRedo: () => {},
|
|
3200
|
+
onZoomIn: () => store.setZoom(Math.min(3, store.zoom + 0.1)),
|
|
3201
|
+
onZoomOut: () => store.setZoom(Math.max(0.1, store.zoom - 0.1)),
|
|
3202
|
+
onZoomReset: () => store.setZoom(1),
|
|
3203
|
+
onSetActivePanel: store.openSidePanel
|
|
3204
|
+
}), /* @__PURE__ */ React17.createElement("div", {
|
|
3984
3205
|
className: "flex-1 flex overflow-hidden"
|
|
3985
|
-
}, /* @__PURE__ */
|
|
3206
|
+
}, /* @__PURE__ */ React17.createElement("div", {
|
|
3986
3207
|
className: "w-80 bg-gray-800 border-r border-gray-700 flex"
|
|
3987
|
-
}, /* @__PURE__ */
|
|
3988
|
-
tool,
|
|
3989
|
-
activePanel: activePanelId,
|
|
3990
|
-
onSetTool: setTool,
|
|
3991
|
-
onSetActivePanel:
|
|
3208
|
+
}, /* @__PURE__ */ React17.createElement(LeftMenu_default, {
|
|
3209
|
+
tool: store.tool,
|
|
3210
|
+
activePanel: store.activePanelId || "elements",
|
|
3211
|
+
onSetTool: store.setTool,
|
|
3212
|
+
onSetActivePanel: store.openSidePanel,
|
|
3992
3213
|
config
|
|
3993
|
-
}), /* @__PURE__ */
|
|
3214
|
+
}), /* @__PURE__ */ React17.createElement("div", {
|
|
3994
3215
|
className: "flex-1 p-4 overflow-y-auto"
|
|
3995
|
-
}, /* @__PURE__ */
|
|
3216
|
+
}, /* @__PURE__ */ React17.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React17.createElement("div", {
|
|
3996
3217
|
className: "flex-1 bg-gray-700 overflow-hidden relative",
|
|
3997
3218
|
ref: containerRef
|
|
3998
|
-
}, /* @__PURE__ */
|
|
3219
|
+
}, !currentPage ? /* @__PURE__ */ React17.createElement("div", {
|
|
3220
|
+
className: "absolute inset-0 flex items-center justify-center text-gray-400"
|
|
3221
|
+
}, /* @__PURE__ */ React17.createElement("div", {
|
|
3222
|
+
className: "text-center"
|
|
3223
|
+
}, /* @__PURE__ */ React17.createElement("p", {
|
|
3224
|
+
className: "mb-4"
|
|
3225
|
+
}, "No pages available"), /* @__PURE__ */ React17.createElement("button", {
|
|
3226
|
+
onClick: () => store.addPage(),
|
|
3227
|
+
className: "px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
|
3228
|
+
}, "Add Page"))) : /* @__PURE__ */ React17.createElement("div", {
|
|
3999
3229
|
className: "absolute inset-0 flex items-center justify-center"
|
|
4000
|
-
}, /* @__PURE__ */
|
|
3230
|
+
}, /* @__PURE__ */ React17.createElement("div", {
|
|
4001
3231
|
className: "bg-white shadow-2xl",
|
|
4002
3232
|
style: {
|
|
4003
|
-
transform: `scale(${zoom})`,
|
|
3233
|
+
transform: `scale(${store.zoom})`,
|
|
4004
3234
|
transformOrigin: "center center"
|
|
4005
3235
|
}
|
|
4006
|
-
}, /* @__PURE__ */
|
|
3236
|
+
}, /* @__PURE__ */ React17.createElement(Stage, {
|
|
4007
3237
|
ref: stageRef,
|
|
4008
|
-
width: design.width,
|
|
4009
|
-
height: design.height,
|
|
3238
|
+
width: store.design.width,
|
|
3239
|
+
height: store.design.height,
|
|
4010
3240
|
onClick: handleStageClick,
|
|
4011
3241
|
onTap: handleStageClick
|
|
4012
|
-
}, /* @__PURE__ */
|
|
3242
|
+
}, /* @__PURE__ */ React17.createElement(Layer, null, /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement(Rect2, {
|
|
4013
3243
|
x: 0,
|
|
4014
3244
|
y: 0,
|
|
4015
|
-
width: design.width,
|
|
4016
|
-
height: design.height,
|
|
3245
|
+
width: store.design.width,
|
|
3246
|
+
height: store.design.height,
|
|
4017
3247
|
fill: currentPage.backgroundImageObject ? undefined : currentPage.background,
|
|
4018
3248
|
fillPatternImage: currentPage.backgroundImageObject,
|
|
4019
3249
|
fillPatternRepeat: "no-repeat"
|
|
4020
3250
|
}), currentPage.elements.map((element) => {
|
|
4021
3251
|
switch (element.type) {
|
|
4022
3252
|
case "text":
|
|
4023
|
-
return /* @__PURE__ */
|
|
3253
|
+
return /* @__PURE__ */ React17.createElement(EditableTextElement, {
|
|
3254
|
+
key: element.id,
|
|
3255
|
+
element,
|
|
3256
|
+
isSelected: element.id === store.selectedId,
|
|
3257
|
+
onSelect: () => {
|
|
3258
|
+
store.setSelectedId(element.id);
|
|
3259
|
+
store.setSelectedIds([]);
|
|
3260
|
+
},
|
|
3261
|
+
onChange: (attrs) => updateElement(element.id, attrs)
|
|
3262
|
+
});
|
|
3263
|
+
case "image":
|
|
3264
|
+
return /* @__PURE__ */ React17.createElement(UrlImageElement, {
|
|
4024
3265
|
key: element.id,
|
|
4025
3266
|
element,
|
|
4026
|
-
isSelected: element.id === selectedId,
|
|
3267
|
+
isSelected: element.id === store.selectedId,
|
|
4027
3268
|
onSelect: () => {
|
|
4028
|
-
setSelectedId(element.id);
|
|
4029
|
-
setSelectedIds([]);
|
|
3269
|
+
store.setSelectedId(element.id);
|
|
3270
|
+
store.setSelectedIds([]);
|
|
3271
|
+
},
|
|
3272
|
+
onChange: (attrs) => updateElement(element.id, attrs)
|
|
3273
|
+
});
|
|
3274
|
+
case "shape":
|
|
3275
|
+
return /* @__PURE__ */ React17.createElement(ShapeElement, {
|
|
3276
|
+
key: element.id,
|
|
3277
|
+
element,
|
|
3278
|
+
isSelected: element.id === store.selectedId,
|
|
3279
|
+
onSelect: () => {
|
|
3280
|
+
store.setSelectedId(element.id);
|
|
3281
|
+
store.setSelectedIds([]);
|
|
4030
3282
|
},
|
|
4031
3283
|
onChange: (attrs) => updateElement(element.id, attrs)
|
|
4032
3284
|
});
|
|
4033
3285
|
default:
|
|
4034
3286
|
return null;
|
|
4035
3287
|
}
|
|
4036
|
-
})))))), config?.multiPage && /* @__PURE__ */
|
|
3288
|
+
})))))), config?.multiPage && /* @__PURE__ */ React17.createElement("div", {
|
|
4037
3289
|
className: "absolute bottom-4 left-4 flex items-center space-x-2"
|
|
4038
|
-
}, design.pages.map((page, index) => /* @__PURE__ */
|
|
3290
|
+
}, store.design.pages.map((page, index) => /* @__PURE__ */ React17.createElement("button", {
|
|
4039
3291
|
key: page.id,
|
|
4040
|
-
onClick: () =>
|
|
4041
|
-
className: `px-3 py-1 rounded text-sm ${page.id ===
|
|
4042
|
-
}, "Page ", index + 1)), /* @__PURE__ */
|
|
3292
|
+
onClick: () => store.setActivePage(page.id),
|
|
3293
|
+
className: `px-3 py-1 rounded text-sm ${page.id === store.activePageId ? "bg-blue-600 text-white" : "bg-gray-800 text-gray-300 hover:bg-gray-700"}`
|
|
3294
|
+
}, "Page ", index + 1)), /* @__PURE__ */ React17.createElement("button", {
|
|
4043
3295
|
onClick: addPage,
|
|
4044
|
-
className: "
|
|
3296
|
+
className: "px-3 py-1 rounded text-sm bg-gray-800 text-gray-300 hover:bg-gray-700",
|
|
4045
3297
|
title: "Add Page"
|
|
4046
|
-
}, /* @__PURE__ */
|
|
3298
|
+
}, /* @__PURE__ */ React17.createElement(PlusCircle, {
|
|
4047
3299
|
className: "w-4 h-4"
|
|
4048
|
-
})))), /* @__PURE__ */
|
|
4049
|
-
currentPageElements: currentPage
|
|
3300
|
+
})))), /* @__PURE__ */ React17.createElement(RightSidebar_default, {
|
|
3301
|
+
currentPageElements: currentPage?.elements || [],
|
|
4050
3302
|
selectedElement,
|
|
4051
|
-
selectedId,
|
|
4052
|
-
onSelectElement: setSelectedId,
|
|
3303
|
+
selectedId: store.selectedId,
|
|
3304
|
+
onSelectElement: store.setSelectedId,
|
|
4053
3305
|
onUpdateElement: updateElement,
|
|
4054
3306
|
onDuplicateSelected: duplicateSelected,
|
|
4055
3307
|
onMoveElementUp: moveElementUp,
|
|
4056
3308
|
onMoveElementDown: moveElementDown,
|
|
4057
3309
|
onDeleteSelected: deleteSelected
|
|
4058
|
-
})), /* @__PURE__ */
|
|
3310
|
+
})), /* @__PURE__ */ React17.createElement("input", {
|
|
4059
3311
|
ref: fileInputRef,
|
|
4060
3312
|
type: "file",
|
|
4061
3313
|
accept: "image/*",
|
|
4062
3314
|
onChange: handleImageUpload,
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
}), /* @__PURE__ */ React18.createElement("input", {
|
|
3315
|
+
style: { display: "none" }
|
|
3316
|
+
}), /* @__PURE__ */ React17.createElement("input", {
|
|
4066
3317
|
ref: jsonInputRef,
|
|
4067
3318
|
type: "file",
|
|
4068
3319
|
accept: ".json",
|
|
4069
3320
|
onChange: handleImportJSON,
|
|
4070
|
-
|
|
4071
|
-
})
|
|
4072
|
-
inputs: pendingInputs,
|
|
4073
|
-
onComplete: handleInputModalComplete,
|
|
4074
|
-
onCancel: handleInputModalCancel
|
|
4075
|
-
}), showUnsplash && /* @__PURE__ */ React18.createElement("div", {
|
|
4076
|
-
className: "fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 p-8"
|
|
4077
|
-
}, /* @__PURE__ */ React18.createElement("div", {
|
|
4078
|
-
className: "bg-gray-800 rounded-lg w-full max-w-4xl max-h-full overflow-hidden flex flex-col"
|
|
4079
|
-
}, /* @__PURE__ */ React18.createElement("div", {
|
|
4080
|
-
className: "p-6 border-b border-gray-700"
|
|
4081
|
-
}, /* @__PURE__ */ React18.createElement("h3", {
|
|
4082
|
-
className: "text-xl font-semibold text-white mb-4"
|
|
4083
|
-
}, "Search Unsplash"), /* @__PURE__ */ React18.createElement("div", {
|
|
4084
|
-
className: "flex space-x-4"
|
|
4085
|
-
}, /* @__PURE__ */ React18.createElement("input", {
|
|
4086
|
-
type: "text",
|
|
4087
|
-
value: unsplashQuery,
|
|
4088
|
-
onChange: (e) => setUnsplashQuery(e.target.value),
|
|
4089
|
-
onKeyDown: (e) => e.key === "Enter" && searchUnsplash(),
|
|
4090
|
-
placeholder: "Search for images...",
|
|
4091
|
-
className: "flex-1 bg-gray-700 text-white border border-gray-600 rounded px-4 py-2 focus:border-blue-500 focus:outline-none",
|
|
4092
|
-
autoFocus: true
|
|
4093
|
-
}), /* @__PURE__ */ React18.createElement("button", {
|
|
4094
|
-
onClick: searchUnsplash,
|
|
4095
|
-
className: "px-6 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
|
4096
|
-
}, "Search"), /* @__PURE__ */ React18.createElement("button", {
|
|
4097
|
-
onClick: () => {
|
|
4098
|
-
setShowUnsplash(false);
|
|
4099
|
-
setUnsplashQuery("");
|
|
4100
|
-
setUnsplashResults([]);
|
|
4101
|
-
},
|
|
4102
|
-
className: "px-6 py-2 bg-gray-700 text-white rounded hover:bg-gray-600"
|
|
4103
|
-
}, "Cancel"))), /* @__PURE__ */ React18.createElement("div", {
|
|
4104
|
-
className: "flex-1 overflow-y-auto p-6"
|
|
4105
|
-
}, unsplashResults.length > 0 ? /* @__PURE__ */ React18.createElement("div", {
|
|
4106
|
-
className: "grid grid-cols-3 gap-4"
|
|
4107
|
-
}, unsplashResults.map((result) => /* @__PURE__ */ React18.createElement("button", {
|
|
4108
|
-
key: result.id,
|
|
4109
|
-
onClick: () => addUnsplashImage(result.urls.regular),
|
|
4110
|
-
className: "relative group overflow-hidden rounded-lg aspect-square"
|
|
4111
|
-
}, /* @__PURE__ */ React18.createElement("img", {
|
|
4112
|
-
src: result.urls.thumb,
|
|
4113
|
-
alt: "",
|
|
4114
|
-
className: "w-full h-full object-cover group-hover:scale-110 transition-transform duration-200"
|
|
4115
|
-
}), /* @__PURE__ */ React18.createElement("div", {
|
|
4116
|
-
className: "absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-50 transition-opacity duration-200 flex items-center justify-center"
|
|
4117
|
-
}, /* @__PURE__ */ React18.createElement(PlusCircle, {
|
|
4118
|
-
className: "w-8 h-8 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-200"
|
|
4119
|
-
}))))) : /* @__PURE__ */ React18.createElement("div", {
|
|
4120
|
-
className: "text-center text-gray-400 py-12"
|
|
4121
|
-
}, "Enter a search term to find images")))));
|
|
3321
|
+
style: { display: "none" }
|
|
3322
|
+
}));
|
|
4122
3323
|
};
|
|
4123
3324
|
var CanvasEditor_default = CanvasEditor;
|
|
4124
3325
|
// src/context/CanvasStoreContext.tsx
|
|
@@ -4131,6 +3332,14 @@ var useCanvasStore = () => {
|
|
|
4131
3332
|
}
|
|
4132
3333
|
return store;
|
|
4133
3334
|
};
|
|
3335
|
+
// src/config.ts
|
|
3336
|
+
var _unsplashAccessKey = typeof process !== "undefined" && process.env?.UNSPLASH_ACCESS_KEY ? process.env.UNSPLASH_ACCESS_KEY : undefined;
|
|
3337
|
+
function setUnsplashAccessKey(key) {
|
|
3338
|
+
_unsplashAccessKey = key;
|
|
3339
|
+
}
|
|
3340
|
+
function getUnsplashAccessKey() {
|
|
3341
|
+
return _unsplashAccessKey;
|
|
3342
|
+
}
|
|
4134
3343
|
|
|
4135
3344
|
// src/lib/index.ts
|
|
4136
3345
|
initJsxCompat();
|