labellife-design-tool 1.2.9 → 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 +346 -1174
- package/dist/lib/wordpress.js +346 -1174
- package/dist/types/CanvasEditor.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,14 +2847,6 @@ 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
2852
|
if (!page) {
|
|
@@ -3242,34 +2868,32 @@ class SimpleCanvasStore {
|
|
|
3242
2868
|
...element
|
|
3243
2869
|
};
|
|
3244
2870
|
page.elements.push(newElement);
|
|
3245
|
-
console.log(`addElement: Added element ${newElement.id} to page. Total elements: ${page.elements.length}`);
|
|
3246
2871
|
this.emit("designChanged", this._design);
|
|
3247
|
-
console.log("addElement: Emitted designChanged event");
|
|
3248
|
-
}
|
|
3249
|
-
updateElement(elementId, updates) {
|
|
3250
|
-
for (const page of this._design.pages) {
|
|
3251
|
-
const elementIndex = page.elements.findIndex((e) => e.id === elementId);
|
|
3252
|
-
if (elementIndex !== -1) {
|
|
3253
|
-
page.elements[elementIndex] = { ...page.elements[elementIndex], ...updates };
|
|
3254
|
-
this.emit("designChanged", this._design);
|
|
3255
|
-
return;
|
|
3256
|
-
}
|
|
3257
|
-
}
|
|
3258
|
-
}
|
|
3259
|
-
deleteElement(elementId) {
|
|
3260
|
-
for (const page of this._design.pages) {
|
|
3261
|
-
const elementIndex = page.elements.findIndex((e) => e.id === elementId);
|
|
3262
|
-
if (elementIndex !== -1) {
|
|
3263
|
-
page.elements.splice(elementIndex, 1);
|
|
3264
|
-
this.emit("designChanged", this._design);
|
|
3265
|
-
return;
|
|
3266
|
-
}
|
|
3267
|
-
}
|
|
3268
2872
|
}
|
|
3269
2873
|
openSidePanel(panelId) {
|
|
3270
2874
|
this._activePanelId = panelId;
|
|
3271
2875
|
this.emit("activePanelChanged", panelId);
|
|
3272
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
|
+
}
|
|
3273
2897
|
async toBlob(type = "png") {
|
|
3274
2898
|
return new Promise((resolve, reject) => {
|
|
3275
2899
|
try {
|
|
@@ -3299,6 +2923,34 @@ class SimpleCanvasStore {
|
|
|
3299
2923
|
}
|
|
3300
2924
|
});
|
|
3301
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
|
+
}
|
|
3302
2954
|
async loadJSON(jsonData) {
|
|
3303
2955
|
return new Promise((resolve, reject) => {
|
|
3304
2956
|
try {
|
|
@@ -3328,197 +2980,89 @@ var CanvasEditor = ({
|
|
|
3328
2980
|
config,
|
|
3329
2981
|
store: externalStore
|
|
3330
2982
|
}) => {
|
|
3331
|
-
console.log("=== CanvasEditor initializing ===", { hasExternalStore: !!externalStore });
|
|
3332
2983
|
const store = externalStore || createSimpleStore({
|
|
3333
2984
|
name,
|
|
3334
2985
|
width: 800,
|
|
3335
2986
|
height: 600
|
|
3336
2987
|
});
|
|
3337
|
-
const
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
name: "Untitled Design",
|
|
3344
|
-
width: 800,
|
|
3345
|
-
height: 600,
|
|
3346
|
-
pages: [
|
|
3347
|
-
{
|
|
3348
|
-
id: "1",
|
|
3349
|
-
name: "Page 1",
|
|
3350
|
-
elements: [],
|
|
3351
|
-
background: "#ffffff"
|
|
3352
|
-
}
|
|
3353
|
-
],
|
|
3354
|
-
fonts: FONT_FAMILIES,
|
|
3355
|
-
colors: DEFAULT_COLORS
|
|
3356
|
-
};
|
|
3357
|
-
});
|
|
3358
|
-
const [currentPageId, setCurrentPageId] = useState3(() => {
|
|
3359
|
-
if (externalStore?.design.pages && externalStore.design.pages.length > 0) {
|
|
3360
|
-
return externalStore.design.pages[0].id;
|
|
3361
|
-
}
|
|
3362
|
-
if (externalStore?.activePageId) {
|
|
3363
|
-
return externalStore.activePageId;
|
|
3364
|
-
}
|
|
3365
|
-
return "1";
|
|
3366
|
-
});
|
|
3367
|
-
const [selectedId, setSelectedId] = useState3(null);
|
|
3368
|
-
const [selectedIds, setSelectedIds] = useState3([]);
|
|
3369
|
-
const [tool, setTool] = useState3("select");
|
|
3370
|
-
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;
|
|
3371
2994
|
useEffect4(() => {
|
|
3372
2995
|
if (externalStore) {
|
|
3373
|
-
const handleDesignChange = (newDesign) => {
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
};
|
|
3377
|
-
const
|
|
3378
|
-
|
|
3379
|
-
};
|
|
3380
|
-
const
|
|
3381
|
-
setActivePanelId(panelId || "elements");
|
|
3382
|
-
};
|
|
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) => {};
|
|
3383
3004
|
externalStore.on("designChanged", handleDesignChange);
|
|
3384
3005
|
externalStore.on("activePageChanged", handleActivePageChange);
|
|
3385
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);
|
|
3386
3012
|
return () => {
|
|
3387
3013
|
externalStore.off("designChanged");
|
|
3388
3014
|
externalStore.off("activePageChanged");
|
|
3389
3015
|
externalStore.off("activePanelChanged");
|
|
3016
|
+
externalStore.off("selectedIdChanged");
|
|
3017
|
+
externalStore.off("selectedIdsChanged");
|
|
3018
|
+
externalStore.off("toolChanged");
|
|
3019
|
+
externalStore.off("zoomChanged");
|
|
3020
|
+
externalStore.off("selectedShapeChanged");
|
|
3390
3021
|
};
|
|
3391
3022
|
}
|
|
3392
3023
|
}, [externalStore]);
|
|
3393
|
-
const
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
const [selectedShape, setSelectedShape] = useState3("rect");
|
|
3399
|
-
const [history, setHistory] = useState3([]);
|
|
3400
|
-
const [historyIndex, setHistoryIndex] = useState3(-1);
|
|
3401
|
-
const [showInputModal, setShowInputModal] = useState3(false);
|
|
3402
|
-
const [pendingInputs, setPendingInputs] = useState3([]);
|
|
3403
|
-
const stageRef = useRef5(null);
|
|
3404
|
-
const fileInputRef = useRef5(null);
|
|
3405
|
-
const jsonInputRef = useRef5(null);
|
|
3406
|
-
const containerRef = useRef5(null);
|
|
3407
|
-
const currentPage = design.pages.find((p) => p.id === currentPageId) || design.pages[0] || null;
|
|
3408
|
-
const selectedElement = currentPage?.elements.find((el) => el.id === selectedId) || null;
|
|
3409
|
-
const saveToHistory = useCallback4((newDesign) => {
|
|
3410
|
-
const newHistory = history.slice(0, historyIndex + 1);
|
|
3411
|
-
newHistory.push(JSON.parse(JSON.stringify(newDesign)));
|
|
3412
|
-
setHistory(newHistory);
|
|
3413
|
-
setHistoryIndex(newHistory.length - 1);
|
|
3414
|
-
}, [history, historyIndex]);
|
|
3415
|
-
const undo = useCallback4(() => {
|
|
3416
|
-
if (historyIndex > 0) {
|
|
3417
|
-
setHistoryIndex(historyIndex - 1);
|
|
3418
|
-
setDesign(JSON.parse(JSON.stringify(history[historyIndex - 1])));
|
|
3419
|
-
}
|
|
3420
|
-
}, [history, historyIndex]);
|
|
3421
|
-
const redo = useCallback4(() => {
|
|
3422
|
-
if (historyIndex < history.length - 1) {
|
|
3423
|
-
setHistoryIndex(historyIndex + 1);
|
|
3424
|
-
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([]);
|
|
3425
3029
|
}
|
|
3426
|
-
}, [
|
|
3030
|
+
}, [store]);
|
|
3427
3031
|
const addText = useCallback4(() => {
|
|
3428
|
-
|
|
3429
|
-
|
|
3032
|
+
if (!store.activePage)
|
|
3033
|
+
return;
|
|
3034
|
+
store.activePage.addElement({
|
|
3430
3035
|
type: "text",
|
|
3431
|
-
|
|
3432
|
-
x: design.width / 2 - 50,
|
|
3433
|
-
y: design.height / 2 -
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
text: "Click to edit text",
|
|
3439
|
-
fontSize: 24,
|
|
3440
|
-
fontFamily: "Arial",
|
|
3441
|
-
fill: "#000000",
|
|
3442
|
-
align: "left",
|
|
3443
|
-
lineHeight: 1.2,
|
|
3444
|
-
letterSpacing: 0,
|
|
3445
|
-
textCase: "none",
|
|
3446
|
-
strikethrough: false
|
|
3447
|
-
};
|
|
3448
|
-
const newDesign = {
|
|
3449
|
-
...design,
|
|
3450
|
-
pages: design.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
|
|
3451
|
-
};
|
|
3452
|
-
setDesign(newDesign);
|
|
3453
|
-
saveToHistory(newDesign);
|
|
3454
|
-
if (externalStore) {
|
|
3455
|
-
externalStore.setDesign(newDesign);
|
|
3456
|
-
}
|
|
3457
|
-
setSelectedId(newElement.id);
|
|
3458
|
-
setTool("select");
|
|
3459
|
-
}, [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]);
|
|
3460
3043
|
const addShape = useCallback4((shapeType) => {
|
|
3461
|
-
|
|
3462
|
-
|
|
3044
|
+
if (!store.activePage)
|
|
3045
|
+
return;
|
|
3046
|
+
store.activePage.addElement({
|
|
3463
3047
|
type: "shape",
|
|
3464
|
-
name: shapeType.charAt(0).toUpperCase() + shapeType.slice(1),
|
|
3465
|
-
x: design.width / 2 - 50,
|
|
3466
|
-
y: design.height / 2 - 50,
|
|
3467
|
-
width: 100,
|
|
3468
|
-
height: 100,
|
|
3469
|
-
rotation: 0,
|
|
3470
|
-
visible: true,
|
|
3471
|
-
locked: false,
|
|
3472
|
-
opacity: 1,
|
|
3473
|
-
fill: "#4299e1",
|
|
3474
|
-
stroke: "#000000",
|
|
3475
|
-
strokeWidth: 0,
|
|
3476
3048
|
shapeType,
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
setDesign((prev) => {
|
|
3482
|
-
const newDesign = {
|
|
3483
|
-
...prev,
|
|
3484
|
-
pages: prev.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
|
|
3485
|
-
};
|
|
3486
|
-
saveToHistory(newDesign);
|
|
3487
|
-
return newDesign;
|
|
3049
|
+
x: store.design.width / 2 - 50,
|
|
3050
|
+
y: store.design.height / 2 - 50,
|
|
3051
|
+
width: 100,
|
|
3052
|
+
height: 100
|
|
3488
3053
|
});
|
|
3489
|
-
|
|
3490
|
-
}, [currentPageId, saveToHistory, design.width, design.height]);
|
|
3491
|
-
const handleStageClick = useCallback4((e) => {
|
|
3492
|
-
const clickedOnEmpty = e.target === e.target.getStage();
|
|
3493
|
-
if (clickedOnEmpty) {
|
|
3494
|
-
setSelectedId(null);
|
|
3495
|
-
setSelectedIds([]);
|
|
3496
|
-
}
|
|
3497
|
-
}, []);
|
|
3054
|
+
}, [store]);
|
|
3498
3055
|
const updateElement = useCallback4((id, attrs) => {
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
pages: prev.pages.map((page) => ({
|
|
3502
|
-
...page,
|
|
3503
|
-
elements: page.elements.map((el) => el.id === id ? { ...el, ...attrs } : el)
|
|
3504
|
-
}))
|
|
3505
|
-
}));
|
|
3506
|
-
}, []);
|
|
3056
|
+
store.updateElement(id, attrs);
|
|
3057
|
+
}, [store]);
|
|
3507
3058
|
const deleteSelected = useCallback4(() => {
|
|
3508
|
-
if (selectedId || selectedIds.length > 0) {
|
|
3509
|
-
const idsToDelete = selectedIds.length > 0 ? selectedIds : [selectedId];
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
...page,
|
|
3514
|
-
elements: page.elements.filter((el) => !idsToDelete.includes(el.id))
|
|
3515
|
-
}))
|
|
3516
|
-
}));
|
|
3517
|
-
setSelectedId(null);
|
|
3518
|
-
setSelectedIds([]);
|
|
3519
|
-
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([]);
|
|
3520
3064
|
}
|
|
3521
|
-
}, [
|
|
3065
|
+
}, [store]);
|
|
3522
3066
|
const duplicateSelected = useCallback4(() => {
|
|
3523
3067
|
if (selectedElement) {
|
|
3524
3068
|
const newElement = {
|
|
@@ -3528,634 +3072,254 @@ var CanvasEditor = ({
|
|
|
3528
3072
|
x: selectedElement.x + 20,
|
|
3529
3073
|
y: selectedElement.y + 20
|
|
3530
3074
|
};
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
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
|
+
}
|
|
3538
3112
|
});
|
|
3539
|
-
setSelectedId(newElement.id);
|
|
3540
3113
|
}
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
const index = page.elements.findIndex((el) => el.id === id);
|
|
3548
|
-
if (index < page.elements.length - 1) {
|
|
3549
|
-
const newElements = [...page.elements];
|
|
3550
|
-
[newElements[index], newElements[index + 1]] = [
|
|
3551
|
-
newElements[index + 1],
|
|
3552
|
-
newElements[index]
|
|
3553
|
-
];
|
|
3554
|
-
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]);
|
|
3555
3120
|
}
|
|
3121
|
+
} else {
|
|
3122
|
+
orderedConfigs.push(mergedConfigs[panelConfig.id]);
|
|
3556
3123
|
}
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
}, [
|
|
3561
|
-
const
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
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);
|
|
3575
3163
|
}
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
}));
|
|
3579
|
-
}, [currentPageId]);
|
|
3580
|
-
const addPage = useCallback4(() => {
|
|
3581
|
-
const newPage = {
|
|
3582
|
-
id: Date.now().toString(),
|
|
3583
|
-
name: `Page ${design.pages.length + 1}`,
|
|
3584
|
-
elements: [],
|
|
3585
|
-
background: "#ffffff",
|
|
3586
|
-
backgroundImageObject: undefined
|
|
3587
|
-
};
|
|
3588
|
-
setDesign((prev) => ({
|
|
3589
|
-
...prev,
|
|
3590
|
-
pages: [...prev.pages, newPage]
|
|
3591
|
-
}));
|
|
3592
|
-
setCurrentPageId(newPage.id);
|
|
3593
|
-
}, [design.pages.length]);
|
|
3594
|
-
const deletePage = useCallback4((pageId) => {
|
|
3595
|
-
if (design.pages.length > 1) {
|
|
3596
|
-
setDesign((prev) => ({
|
|
3597
|
-
...prev,
|
|
3598
|
-
pages: prev.pages.filter((p) => p.id !== pageId)
|
|
3599
|
-
}));
|
|
3600
|
-
if (currentPageId === pageId) {
|
|
3601
|
-
setCurrentPageId(design.pages[0].id);
|
|
3602
|
-
}
|
|
3164
|
+
};
|
|
3165
|
+
reader.readAsText(file);
|
|
3603
3166
|
}
|
|
3604
|
-
}, [
|
|
3167
|
+
}, [store]);
|
|
3605
3168
|
const handleImageUpload = useCallback4((e) => {
|
|
3606
3169
|
const file = e.target.files?.[0];
|
|
3607
3170
|
if (file) {
|
|
3608
3171
|
const reader = new FileReader;
|
|
3609
3172
|
reader.onload = (event) => {
|
|
3610
3173
|
const img = new window.Image;
|
|
3611
|
-
img.src = event.target?.result;
|
|
3612
3174
|
img.onload = () => {
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
locked: false,
|
|
3624
|
-
opacity: 1,
|
|
3625
|
-
src: event.target?.result,
|
|
3626
|
-
cropX: 0,
|
|
3627
|
-
cropY: 0,
|
|
3628
|
-
cropWidth: img.naturalWidth,
|
|
3629
|
-
cropHeight: img.naturalHeight,
|
|
3630
|
-
mask: undefined
|
|
3631
|
-
};
|
|
3632
|
-
setDesign((prev) => ({
|
|
3633
|
-
...prev,
|
|
3634
|
-
pages: prev.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
|
|
3635
|
-
}));
|
|
3636
|
-
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
|
+
}
|
|
3637
3185
|
};
|
|
3186
|
+
img.src = event.target?.result;
|
|
3638
3187
|
};
|
|
3639
3188
|
reader.readAsDataURL(file);
|
|
3640
3189
|
}
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
},
|
|
3645
|
-
const searchUnsplash = useCallback4(async () => {
|
|
3646
|
-
if (!unsplashQuery)
|
|
3647
|
-
return;
|
|
3648
|
-
if (UNSPLASH_ACCESS_KEY === "YOUR_UNSPLASH_ACCESS_KEY_HERE" || !UNSPLASH_ACCESS_KEY) {
|
|
3649
|
-
console.warn("Unsplash API key is not configured. Please set UNSPLASH_ACCESS_KEY in src/config.ts");
|
|
3650
|
-
const mockResults = Array(9).fill(null).map((_, i) => ({
|
|
3651
|
-
id: `unsplash-mock-${i}`,
|
|
3652
|
-
urls: {
|
|
3653
|
-
regular: `https://source.unsplash.com/400x300/?${unsplashQuery}&sig=${i}`,
|
|
3654
|
-
thumb: `https://source.unsplash.com/200x150/?${unsplashQuery}&sig=${i}`
|
|
3655
|
-
},
|
|
3656
|
-
user: { name: "Mock User" }
|
|
3657
|
-
}));
|
|
3658
|
-
setUnsplashResults(mockResults);
|
|
3659
|
-
return;
|
|
3660
|
-
}
|
|
3661
|
-
try {
|
|
3662
|
-
const response = await fetch(`https://api.unsplash.com/search/photos?query=${encodeURIComponent(unsplashQuery)}&per_page=9`, {
|
|
3663
|
-
headers: {
|
|
3664
|
-
Authorization: `Client-ID ${UNSPLASH_ACCESS_KEY}`
|
|
3665
|
-
}
|
|
3666
|
-
});
|
|
3667
|
-
if (!response.ok) {
|
|
3668
|
-
console.error("Failed to fetch from Unsplash:", response.statusText);
|
|
3669
|
-
setUnsplashResults([]);
|
|
3670
|
-
return;
|
|
3671
|
-
}
|
|
3672
|
-
const data = await response.json();
|
|
3673
|
-
setUnsplashResults(data.results.map((img) => ({
|
|
3674
|
-
id: img.id,
|
|
3675
|
-
urls: { regular: img.urls.regular, thumb: img.urls.thumb },
|
|
3676
|
-
user: { name: img.user.name }
|
|
3677
|
-
})));
|
|
3678
|
-
} catch (error) {
|
|
3679
|
-
console.error("Error searching Unsplash:", error);
|
|
3680
|
-
setUnsplashResults([]);
|
|
3681
|
-
}
|
|
3682
|
-
}, [unsplashQuery]);
|
|
3683
|
-
const addUnsplashImage = useCallback4((imageUrl) => {
|
|
3684
|
-
if (unsplashMode === "element") {
|
|
3685
|
-
const img = new window.Image;
|
|
3686
|
-
img.crossOrigin = "anonymous";
|
|
3687
|
-
img.src = imageUrl;
|
|
3688
|
-
img.onload = () => {
|
|
3689
|
-
const newElement = {
|
|
3690
|
-
id: Date.now().toString(),
|
|
3691
|
-
type: "image",
|
|
3692
|
-
name: "Unsplash Image",
|
|
3693
|
-
x: 100,
|
|
3694
|
-
y: 100,
|
|
3695
|
-
width: img.naturalWidth,
|
|
3696
|
-
height: img.naturalHeight,
|
|
3697
|
-
rotation: 0,
|
|
3698
|
-
visible: true,
|
|
3699
|
-
locked: false,
|
|
3700
|
-
opacity: 1,
|
|
3701
|
-
src: imageUrl,
|
|
3702
|
-
cropX: 0,
|
|
3703
|
-
cropY: 0,
|
|
3704
|
-
cropWidth: img.naturalWidth,
|
|
3705
|
-
cropHeight: img.naturalHeight,
|
|
3706
|
-
mask: undefined
|
|
3707
|
-
};
|
|
3708
|
-
setDesign((prev) => ({
|
|
3709
|
-
...prev,
|
|
3710
|
-
pages: prev.pages.map((page) => page.id === currentPageId ? { ...page, elements: [...page.elements, newElement] } : page)
|
|
3711
|
-
}));
|
|
3712
|
-
saveToHistory(design);
|
|
3713
|
-
};
|
|
3714
|
-
} else if (unsplashMode === "background") {
|
|
3715
|
-
const bgImg = new window.Image;
|
|
3716
|
-
bgImg.crossOrigin = "anonymous";
|
|
3717
|
-
bgImg.src = imageUrl;
|
|
3718
|
-
bgImg.onload = () => {
|
|
3719
|
-
setDesign((prev) => ({
|
|
3720
|
-
...prev,
|
|
3721
|
-
pages: prev.pages.map((p) => p.id === currentPageId ? {
|
|
3722
|
-
...p,
|
|
3723
|
-
background: `url(${imageUrl})`,
|
|
3724
|
-
backgroundImageObject: bgImg
|
|
3725
|
-
} : p)
|
|
3726
|
-
}));
|
|
3727
|
-
saveToHistory(design);
|
|
3728
|
-
};
|
|
3729
|
-
}
|
|
3730
|
-
setShowUnsplash(false);
|
|
3731
|
-
setUnsplashQuery("");
|
|
3732
|
-
setUnsplashResults([]);
|
|
3733
|
-
setUnsplashMode("element");
|
|
3734
|
-
}, [currentPageId, saveToHistory, unsplashMode]);
|
|
3735
|
-
const handleImportJSON = (event) => {
|
|
3736
|
-
importFromJSON(event, (newDesign) => {
|
|
3737
|
-
if (newDesign && newDesign.pages && newDesign.pages.length > 0) {
|
|
3738
|
-
setDesign(newDesign);
|
|
3739
|
-
setSelectedId(null);
|
|
3740
|
-
setSelectedIds([]);
|
|
3741
|
-
const firstPageId = newDesign.pages[0]?.id;
|
|
3742
|
-
setCurrentPageId(firstPageId || "1");
|
|
3743
|
-
saveToHistory(newDesign);
|
|
3744
|
-
} else {
|
|
3745
|
-
alert("Invalid design structure in JSON file. Could not load.");
|
|
3746
|
-
}
|
|
3747
|
-
}, (errorMessage) => {
|
|
3748
|
-
alert(`Error importing JSON: ${errorMessage}`);
|
|
3749
|
-
}, (inputs, onComplete) => {
|
|
3750
|
-
setPendingInputs(inputs);
|
|
3751
|
-
setShowInputModal(true);
|
|
3752
|
-
window.__pendingImportComplete = onComplete;
|
|
3753
|
-
});
|
|
3754
|
-
if (jsonInputRef.current) {
|
|
3755
|
-
jsonInputRef.current.value = "";
|
|
3756
|
-
}
|
|
3757
|
-
};
|
|
3758
|
-
const handleInputModalComplete = (values) => {
|
|
3759
|
-
setShowInputModal(false);
|
|
3760
|
-
const onComplete = window.__pendingImportComplete;
|
|
3761
|
-
if (onComplete) {
|
|
3762
|
-
onComplete(values);
|
|
3763
|
-
delete window.__pendingImportComplete;
|
|
3764
|
-
}
|
|
3765
|
-
setPendingInputs([]);
|
|
3766
|
-
};
|
|
3767
|
-
const handleInputModalCancel = () => {
|
|
3768
|
-
setShowInputModal(false);
|
|
3769
|
-
setPendingInputs([]);
|
|
3770
|
-
delete window.__pendingImportComplete;
|
|
3771
|
-
};
|
|
3772
|
-
const panelConfigs = useMemo(() => {
|
|
3773
|
-
const builtInConfigs = {
|
|
3774
|
-
elements: {
|
|
3775
|
-
id: "elements",
|
|
3776
|
-
title: "Elements",
|
|
3777
|
-
component: ElementPanel_default,
|
|
3778
|
-
props: { onAddShape: addShape, store }
|
|
3779
|
-
},
|
|
3780
|
-
text: {
|
|
3781
|
-
id: "text",
|
|
3782
|
-
title: "Text",
|
|
3783
|
-
component: TextPanel_default,
|
|
3784
|
-
props: {
|
|
3785
|
-
selectedElement,
|
|
3786
|
-
updateElement,
|
|
3787
|
-
setTool,
|
|
3788
|
-
onAddText: addText,
|
|
3789
|
-
store
|
|
3790
|
-
}
|
|
3791
|
-
},
|
|
3792
|
-
image: {
|
|
3793
|
-
id: "image",
|
|
3794
|
-
title: "Images",
|
|
3795
|
-
component: ImagePanel_default,
|
|
3796
|
-
props: {
|
|
3797
|
-
selectedElement,
|
|
3798
|
-
updateElement,
|
|
3799
|
-
onUploadClick: () => fileInputRef.current?.click(),
|
|
3800
|
-
onUnsplashClick: () => {
|
|
3801
|
-
setShowUnsplash(true);
|
|
3802
|
-
setUnsplashMode("element");
|
|
3803
|
-
},
|
|
3804
|
-
canvasWidth: design.width,
|
|
3805
|
-
canvasHeight: design.height,
|
|
3806
|
-
store
|
|
3807
|
-
}
|
|
3808
|
-
},
|
|
3809
|
-
design: {
|
|
3810
|
-
id: "design",
|
|
3811
|
-
title: "Design",
|
|
3812
|
-
component: DesignPanel_default,
|
|
3813
|
-
props: {
|
|
3814
|
-
design,
|
|
3815
|
-
currentPage,
|
|
3816
|
-
selectedElement,
|
|
3817
|
-
setDesign,
|
|
3818
|
-
updateElement,
|
|
3819
|
-
onSetUnsplashBackground: () => {
|
|
3820
|
-
setShowUnsplash(true);
|
|
3821
|
-
setUnsplashMode("background");
|
|
3822
|
-
},
|
|
3823
|
-
config,
|
|
3824
|
-
store
|
|
3825
|
-
}
|
|
3826
|
-
},
|
|
3827
|
-
background: {
|
|
3828
|
-
id: "background",
|
|
3829
|
-
title: "Background",
|
|
3830
|
-
component: BackgroundPanel_default,
|
|
3831
|
-
props: {
|
|
3832
|
-
design,
|
|
3833
|
-
currentPage,
|
|
3834
|
-
setDesign,
|
|
3835
|
-
onSetUnsplashBackground: () => {
|
|
3836
|
-
setShowUnsplash(true);
|
|
3837
|
-
setUnsplashMode("background");
|
|
3838
|
-
},
|
|
3839
|
-
store
|
|
3840
|
-
}
|
|
3841
|
-
},
|
|
3842
|
-
...config?.variables ? {
|
|
3843
|
-
variables: {
|
|
3844
|
-
id: "variables",
|
|
3845
|
-
title: "Variables",
|
|
3846
|
-
component: VariablesPanel_default,
|
|
3847
|
-
props: {
|
|
3848
|
-
config,
|
|
3849
|
-
design,
|
|
3850
|
-
setDesign,
|
|
3851
|
-
store
|
|
3852
|
-
}
|
|
3853
|
-
}
|
|
3854
|
-
} : {},
|
|
3855
|
-
...config?.export ? {
|
|
3856
|
-
export: {
|
|
3857
|
-
id: "export",
|
|
3858
|
-
title: "Export",
|
|
3859
|
-
component: ExportPanel_default,
|
|
3860
|
-
props: {
|
|
3861
|
-
onExportToPNG: config.export?.png ? () => {
|
|
3862
|
-
if (stageRef.current)
|
|
3863
|
-
exportToPNG(stageRef.current, design);
|
|
3864
|
-
} : undefined,
|
|
3865
|
-
onExportToJPG: config.export?.jpg ? () => {
|
|
3866
|
-
if (stageRef.current)
|
|
3867
|
-
exportToJPG(stageRef.current, design);
|
|
3868
|
-
} : undefined,
|
|
3869
|
-
onExportToJSON: config.export?.json ? () => exportToJSON(design) : undefined,
|
|
3870
|
-
onImportJSON: () => jsonInputRef.current?.click(),
|
|
3871
|
-
store
|
|
3872
|
-
}
|
|
3873
|
-
}
|
|
3874
|
-
} : {}
|
|
3875
|
-
};
|
|
3876
|
-
if (!config?.panels || config.panels.length === 0) {
|
|
3877
|
-
return [
|
|
3878
|
-
"text",
|
|
3879
|
-
"elements",
|
|
3880
|
-
"image",
|
|
3881
|
-
"design",
|
|
3882
|
-
"background",
|
|
3883
|
-
...config?.variables ? ["variables"] : [],
|
|
3884
|
-
...config?.export ? ["export"] : []
|
|
3885
|
-
].filter((id) => builtInConfigs[id]).map((id) => builtInConfigs[id]);
|
|
3886
|
-
}
|
|
3887
|
-
const ordered = [];
|
|
3888
|
-
for (const panel of config.panels) {
|
|
3889
|
-
if (typeof panel === "string") {
|
|
3890
|
-
const config2 = builtInConfigs[panel];
|
|
3891
|
-
if (config2) {
|
|
3892
|
-
ordered.push(config2);
|
|
3893
|
-
}
|
|
3894
|
-
} else {
|
|
3895
|
-
ordered.push({
|
|
3896
|
-
id: panel.id,
|
|
3897
|
-
title: panel.title,
|
|
3898
|
-
component: panel.component,
|
|
3899
|
-
props: { ...panel.props, store }
|
|
3900
|
-
});
|
|
3901
|
-
}
|
|
3902
|
-
}
|
|
3903
|
-
return ordered;
|
|
3904
|
-
}, [
|
|
3905
|
-
addShape,
|
|
3906
|
-
addText,
|
|
3907
|
-
config,
|
|
3908
|
-
currentPage,
|
|
3909
|
-
design,
|
|
3910
|
-
selectedElement,
|
|
3911
|
-
setTool,
|
|
3912
|
-
updateElement,
|
|
3913
|
-
store
|
|
3914
|
-
]);
|
|
3915
|
-
const DynamicPanelRenderer = () => {
|
|
3916
|
-
const activePanelConfig = panelConfigs.find((p) => p.id === activePanelId);
|
|
3917
|
-
if (!activePanelConfig) {
|
|
3918
|
-
return /* @__PURE__ */ React18.createElement("div", {
|
|
3919
|
-
className: "text-white"
|
|
3920
|
-
}, "Panel not found");
|
|
3921
|
-
}
|
|
3922
|
-
const PanelComponent = activePanelConfig.component;
|
|
3923
|
-
return /* @__PURE__ */ React18.createElement(PanelComponent, {
|
|
3924
|
-
...activePanelConfig.props
|
|
3925
|
-
});
|
|
3926
|
-
};
|
|
3927
|
-
useEffect4(() => {
|
|
3928
|
-
const handleKeyDown = (e) => {
|
|
3929
|
-
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement)
|
|
3930
|
-
return;
|
|
3931
|
-
if (e.metaKey || e.ctrlKey) {
|
|
3932
|
-
switch (e.key) {
|
|
3933
|
-
case "z":
|
|
3934
|
-
if (e.shiftKey) {
|
|
3935
|
-
redo();
|
|
3936
|
-
} else {
|
|
3937
|
-
undo();
|
|
3938
|
-
}
|
|
3939
|
-
e.preventDefault();
|
|
3940
|
-
break;
|
|
3941
|
-
case "c":
|
|
3942
|
-
break;
|
|
3943
|
-
case "v":
|
|
3944
|
-
break;
|
|
3945
|
-
case "d":
|
|
3946
|
-
duplicateSelected();
|
|
3947
|
-
e.preventDefault();
|
|
3948
|
-
break;
|
|
3949
|
-
case "s":
|
|
3950
|
-
exportToJSON(design);
|
|
3951
|
-
e.preventDefault();
|
|
3952
|
-
break;
|
|
3953
|
-
}
|
|
3954
|
-
} else {
|
|
3955
|
-
switch (e.key) {
|
|
3956
|
-
case "Delete":
|
|
3957
|
-
case "Backspace":
|
|
3958
|
-
deleteSelected();
|
|
3959
|
-
break;
|
|
3960
|
-
case "Escape":
|
|
3961
|
-
setSelectedId(null);
|
|
3962
|
-
setSelectedIds([]);
|
|
3963
|
-
break;
|
|
3964
|
-
}
|
|
3965
|
-
}
|
|
3966
|
-
};
|
|
3967
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
3968
|
-
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
3969
|
-
}, [deleteSelected, duplicateSelected, exportToJSON, undo, redo]);
|
|
3970
|
-
useEffect4(() => {
|
|
3971
|
-
if (history.length === 0) {
|
|
3972
|
-
setHistory([JSON.parse(JSON.stringify(design))]);
|
|
3973
|
-
setHistoryIndex(0);
|
|
3974
|
-
}
|
|
3975
|
-
}, []);
|
|
3976
|
-
return /* @__PURE__ */ React18.createElement("div", {
|
|
3977
|
-
className: "h-screen flex flex-col bg-gray-900"
|
|
3978
|
-
}, /* @__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, {
|
|
3979
3194
|
name,
|
|
3980
|
-
zoom,
|
|
3981
|
-
historyIndex,
|
|
3982
|
-
historyLength:
|
|
3983
|
-
onUndo:
|
|
3984
|
-
onRedo:
|
|
3985
|
-
onZoomIn: () => setZoom(Math.min(3, zoom + 0.1)),
|
|
3986
|
-
onZoomOut: () => setZoom(Math.max(0.1, zoom - 0.1)),
|
|
3987
|
-
onZoomReset: () => setZoom(1),
|
|
3988
|
-
onSetActivePanel:
|
|
3989
|
-
}), /* @__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", {
|
|
3990
3205
|
className: "flex-1 flex overflow-hidden"
|
|
3991
|
-
}, /* @__PURE__ */
|
|
3206
|
+
}, /* @__PURE__ */ React17.createElement("div", {
|
|
3992
3207
|
className: "w-80 bg-gray-800 border-r border-gray-700 flex"
|
|
3993
|
-
}, /* @__PURE__ */
|
|
3994
|
-
tool,
|
|
3995
|
-
activePanel: activePanelId,
|
|
3996
|
-
onSetTool: setTool,
|
|
3997
|
-
onSetActivePanel:
|
|
3208
|
+
}, /* @__PURE__ */ React17.createElement(LeftMenu_default, {
|
|
3209
|
+
tool: store.tool,
|
|
3210
|
+
activePanel: store.activePanelId || "elements",
|
|
3211
|
+
onSetTool: store.setTool,
|
|
3212
|
+
onSetActivePanel: store.openSidePanel,
|
|
3998
3213
|
config
|
|
3999
|
-
}), /* @__PURE__ */
|
|
3214
|
+
}), /* @__PURE__ */ React17.createElement("div", {
|
|
4000
3215
|
className: "flex-1 p-4 overflow-y-auto"
|
|
4001
|
-
}, /* @__PURE__ */
|
|
3216
|
+
}, /* @__PURE__ */ React17.createElement(DynamicPanelRenderer, null))), /* @__PURE__ */ React17.createElement("div", {
|
|
4002
3217
|
className: "flex-1 bg-gray-700 overflow-hidden relative",
|
|
4003
3218
|
ref: containerRef
|
|
4004
|
-
}, !currentPage ? /* @__PURE__ */
|
|
3219
|
+
}, !currentPage ? /* @__PURE__ */ React17.createElement("div", {
|
|
4005
3220
|
className: "absolute inset-0 flex items-center justify-center text-gray-400"
|
|
4006
|
-
}, /* @__PURE__ */
|
|
3221
|
+
}, /* @__PURE__ */ React17.createElement("div", {
|
|
4007
3222
|
className: "text-center"
|
|
4008
|
-
}, /* @__PURE__ */
|
|
3223
|
+
}, /* @__PURE__ */ React17.createElement("p", {
|
|
4009
3224
|
className: "mb-4"
|
|
4010
|
-
}, "No pages available"), /* @__PURE__ */
|
|
3225
|
+
}, "No pages available"), /* @__PURE__ */ React17.createElement("button", {
|
|
4011
3226
|
onClick: () => store.addPage(),
|
|
4012
3227
|
className: "px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
|
4013
|
-
}, "Add Page"))) : /* @__PURE__ */
|
|
3228
|
+
}, "Add Page"))) : /* @__PURE__ */ React17.createElement("div", {
|
|
4014
3229
|
className: "absolute inset-0 flex items-center justify-center"
|
|
4015
|
-
}, /* @__PURE__ */
|
|
3230
|
+
}, /* @__PURE__ */ React17.createElement("div", {
|
|
4016
3231
|
className: "bg-white shadow-2xl",
|
|
4017
3232
|
style: {
|
|
4018
|
-
transform: `scale(${zoom})`,
|
|
3233
|
+
transform: `scale(${store.zoom})`,
|
|
4019
3234
|
transformOrigin: "center center"
|
|
4020
3235
|
}
|
|
4021
|
-
}, /* @__PURE__ */
|
|
3236
|
+
}, /* @__PURE__ */ React17.createElement(Stage, {
|
|
4022
3237
|
ref: stageRef,
|
|
4023
|
-
width: design.width,
|
|
4024
|
-
height: design.height,
|
|
3238
|
+
width: store.design.width,
|
|
3239
|
+
height: store.design.height,
|
|
4025
3240
|
onClick: handleStageClick,
|
|
4026
3241
|
onTap: handleStageClick
|
|
4027
|
-
}, /* @__PURE__ */
|
|
3242
|
+
}, /* @__PURE__ */ React17.createElement(Layer, null, /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement(Rect2, {
|
|
4028
3243
|
x: 0,
|
|
4029
3244
|
y: 0,
|
|
4030
|
-
width: design.width,
|
|
4031
|
-
height: design.height,
|
|
3245
|
+
width: store.design.width,
|
|
3246
|
+
height: store.design.height,
|
|
4032
3247
|
fill: currentPage.backgroundImageObject ? undefined : currentPage.background,
|
|
4033
3248
|
fillPatternImage: currentPage.backgroundImageObject,
|
|
4034
3249
|
fillPatternRepeat: "no-repeat"
|
|
4035
3250
|
}), currentPage.elements.map((element) => {
|
|
4036
3251
|
switch (element.type) {
|
|
4037
3252
|
case "text":
|
|
4038
|
-
return /* @__PURE__ */
|
|
3253
|
+
return /* @__PURE__ */ React17.createElement(EditableTextElement, {
|
|
4039
3254
|
key: element.id,
|
|
4040
3255
|
element,
|
|
4041
|
-
isSelected: element.id === selectedId,
|
|
3256
|
+
isSelected: element.id === store.selectedId,
|
|
4042
3257
|
onSelect: () => {
|
|
4043
|
-
setSelectedId(element.id);
|
|
4044
|
-
setSelectedIds([]);
|
|
3258
|
+
store.setSelectedId(element.id);
|
|
3259
|
+
store.setSelectedIds([]);
|
|
4045
3260
|
},
|
|
4046
3261
|
onChange: (attrs) => updateElement(element.id, attrs)
|
|
4047
3262
|
});
|
|
4048
3263
|
case "image":
|
|
4049
|
-
return /* @__PURE__ */
|
|
3264
|
+
return /* @__PURE__ */ React17.createElement(UrlImageElement, {
|
|
4050
3265
|
key: element.id,
|
|
4051
3266
|
element,
|
|
4052
|
-
isSelected: element.id === selectedId,
|
|
3267
|
+
isSelected: element.id === store.selectedId,
|
|
4053
3268
|
onSelect: () => {
|
|
4054
|
-
setSelectedId(element.id);
|
|
4055
|
-
setSelectedIds([]);
|
|
3269
|
+
store.setSelectedId(element.id);
|
|
3270
|
+
store.setSelectedIds([]);
|
|
4056
3271
|
},
|
|
4057
3272
|
onChange: (attrs) => updateElement(element.id, attrs)
|
|
4058
3273
|
});
|
|
4059
3274
|
case "shape":
|
|
4060
|
-
return /* @__PURE__ */
|
|
3275
|
+
return /* @__PURE__ */ React17.createElement(ShapeElement, {
|
|
4061
3276
|
key: element.id,
|
|
4062
3277
|
element,
|
|
4063
|
-
isSelected: element.id === selectedId,
|
|
3278
|
+
isSelected: element.id === store.selectedId,
|
|
4064
3279
|
onSelect: () => {
|
|
4065
|
-
setSelectedId(element.id);
|
|
4066
|
-
setSelectedIds([]);
|
|
3280
|
+
store.setSelectedId(element.id);
|
|
3281
|
+
store.setSelectedIds([]);
|
|
4067
3282
|
},
|
|
4068
3283
|
onChange: (attrs) => updateElement(element.id, attrs)
|
|
4069
3284
|
});
|
|
4070
3285
|
default:
|
|
4071
3286
|
return null;
|
|
4072
3287
|
}
|
|
4073
|
-
})))))),
|
|
3288
|
+
})))))), config?.multiPage && /* @__PURE__ */ React17.createElement("div", {
|
|
4074
3289
|
className: "absolute bottom-4 left-4 flex items-center space-x-2"
|
|
4075
|
-
}, design.pages.map((page, index) => /* @__PURE__ */
|
|
3290
|
+
}, store.design.pages.map((page, index) => /* @__PURE__ */ React17.createElement("button", {
|
|
4076
3291
|
key: page.id,
|
|
4077
|
-
onClick: () =>
|
|
4078
|
-
className: `px-3 py-1 rounded text-sm ${page.id ===
|
|
4079
|
-
}, "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", {
|
|
4080
3295
|
onClick: addPage,
|
|
4081
|
-
className: "
|
|
3296
|
+
className: "px-3 py-1 rounded text-sm bg-gray-800 text-gray-300 hover:bg-gray-700",
|
|
4082
3297
|
title: "Add Page"
|
|
4083
|
-
}, /* @__PURE__ */
|
|
3298
|
+
}, /* @__PURE__ */ React17.createElement(PlusCircle, {
|
|
4084
3299
|
className: "w-4 h-4"
|
|
4085
|
-
})))), /* @__PURE__ */
|
|
3300
|
+
})))), /* @__PURE__ */ React17.createElement(RightSidebar_default, {
|
|
4086
3301
|
currentPageElements: currentPage?.elements || [],
|
|
4087
3302
|
selectedElement,
|
|
4088
|
-
selectedId,
|
|
4089
|
-
onSelectElement: setSelectedId,
|
|
3303
|
+
selectedId: store.selectedId,
|
|
3304
|
+
onSelectElement: store.setSelectedId,
|
|
4090
3305
|
onUpdateElement: updateElement,
|
|
4091
3306
|
onDuplicateSelected: duplicateSelected,
|
|
4092
3307
|
onMoveElementUp: moveElementUp,
|
|
4093
3308
|
onMoveElementDown: moveElementDown,
|
|
4094
3309
|
onDeleteSelected: deleteSelected
|
|
4095
|
-
})), /* @__PURE__ */
|
|
3310
|
+
})), /* @__PURE__ */ React17.createElement("input", {
|
|
4096
3311
|
ref: fileInputRef,
|
|
4097
3312
|
type: "file",
|
|
4098
3313
|
accept: "image/*",
|
|
4099
3314
|
onChange: handleImageUpload,
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
}), /* @__PURE__ */ React18.createElement("input", {
|
|
3315
|
+
style: { display: "none" }
|
|
3316
|
+
}), /* @__PURE__ */ React17.createElement("input", {
|
|
4103
3317
|
ref: jsonInputRef,
|
|
4104
3318
|
type: "file",
|
|
4105
3319
|
accept: ".json",
|
|
4106
3320
|
onChange: handleImportJSON,
|
|
4107
|
-
|
|
4108
|
-
})
|
|
4109
|
-
inputs: pendingInputs,
|
|
4110
|
-
onComplete: handleInputModalComplete,
|
|
4111
|
-
onCancel: handleInputModalCancel
|
|
4112
|
-
}), showUnsplash && /* @__PURE__ */ React18.createElement("div", {
|
|
4113
|
-
className: "fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 p-8"
|
|
4114
|
-
}, /* @__PURE__ */ React18.createElement("div", {
|
|
4115
|
-
className: "bg-gray-800 rounded-lg w-full max-w-4xl max-h-full overflow-hidden flex flex-col"
|
|
4116
|
-
}, /* @__PURE__ */ React18.createElement("div", {
|
|
4117
|
-
className: "p-6 border-b border-gray-700"
|
|
4118
|
-
}, /* @__PURE__ */ React18.createElement("h3", {
|
|
4119
|
-
className: "text-xl font-semibold text-white mb-4"
|
|
4120
|
-
}, "Search Unsplash"), /* @__PURE__ */ React18.createElement("div", {
|
|
4121
|
-
className: "flex space-x-4"
|
|
4122
|
-
}, /* @__PURE__ */ React18.createElement("input", {
|
|
4123
|
-
type: "text",
|
|
4124
|
-
value: unsplashQuery,
|
|
4125
|
-
onChange: (e) => setUnsplashQuery(e.target.value),
|
|
4126
|
-
onKeyDown: (e) => e.key === "Enter" && searchUnsplash(),
|
|
4127
|
-
placeholder: "Search for images...",
|
|
4128
|
-
className: "flex-1 bg-gray-700 text-white border border-gray-600 rounded px-4 py-2 focus:border-blue-500 focus:outline-none",
|
|
4129
|
-
autoFocus: true
|
|
4130
|
-
}), /* @__PURE__ */ React18.createElement("button", {
|
|
4131
|
-
onClick: searchUnsplash,
|
|
4132
|
-
className: "px-6 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
|
4133
|
-
}, "Search"), /* @__PURE__ */ React18.createElement("button", {
|
|
4134
|
-
onClick: () => {
|
|
4135
|
-
setShowUnsplash(false);
|
|
4136
|
-
setUnsplashQuery("");
|
|
4137
|
-
setUnsplashResults([]);
|
|
4138
|
-
},
|
|
4139
|
-
className: "px-6 py-2 bg-gray-700 text-white rounded hover:bg-gray-600"
|
|
4140
|
-
}, "Cancel"))), /* @__PURE__ */ React18.createElement("div", {
|
|
4141
|
-
className: "flex-1 overflow-y-auto p-6"
|
|
4142
|
-
}, unsplashResults.length > 0 ? /* @__PURE__ */ React18.createElement("div", {
|
|
4143
|
-
className: "grid grid-cols-3 gap-4"
|
|
4144
|
-
}, unsplashResults.map((result) => /* @__PURE__ */ React18.createElement("button", {
|
|
4145
|
-
key: result.id,
|
|
4146
|
-
onClick: () => addUnsplashImage(result.urls.regular),
|
|
4147
|
-
className: "relative group overflow-hidden rounded-lg aspect-square"
|
|
4148
|
-
}, /* @__PURE__ */ React18.createElement("img", {
|
|
4149
|
-
src: result.urls.thumb,
|
|
4150
|
-
alt: "",
|
|
4151
|
-
className: "w-full h-full object-cover group-hover:scale-110 transition-transform duration-200"
|
|
4152
|
-
}), /* @__PURE__ */ React18.createElement("div", {
|
|
4153
|
-
className: "absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-50 transition-opacity duration-200 flex items-center justify-center"
|
|
4154
|
-
}, /* @__PURE__ */ React18.createElement(PlusCircle, {
|
|
4155
|
-
className: "w-8 h-8 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-200"
|
|
4156
|
-
}))))) : /* @__PURE__ */ React18.createElement("div", {
|
|
4157
|
-
className: "text-center text-gray-400 py-12"
|
|
4158
|
-
}, "Enter a search term to find images")))));
|
|
3321
|
+
style: { display: "none" }
|
|
3322
|
+
}));
|
|
4159
3323
|
};
|
|
4160
3324
|
var CanvasEditor_default = CanvasEditor;
|
|
4161
3325
|
// src/context/CanvasStoreContext.tsx
|
|
@@ -4168,6 +3332,14 @@ var useCanvasStore = () => {
|
|
|
4168
3332
|
}
|
|
4169
3333
|
return store;
|
|
4170
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
|
+
}
|
|
4171
3343
|
|
|
4172
3344
|
// src/lib/index.ts
|
|
4173
3345
|
initJsxCompat();
|