diff --git a/client/package.json b/client/package.json
index 08a7785..fbd370a 100644
--- a/client/package.json
+++ b/client/package.json
@@ -15,7 +15,8 @@
"react-konva": "^18.2.10",
"konva": "^9.3.18",
"use-image": "^1.1.1",
- "@xenova/transformers": "^2.17.2"
+ "@xenova/transformers": "^2.17.2",
+ "react-filerobot-image-editor": "^4.8.1"
},
"devDependencies": {
"@eslint/js": "^9.39.4",
diff --git a/client/src/components/editor/PhotoPreEditor.jsx b/client/src/components/editor/PhotoPreEditor.jsx
new file mode 100644
index 0000000..7167c41
--- /dev/null
+++ b/client/src/components/editor/PhotoPreEditor.jsx
@@ -0,0 +1,58 @@
+import { useState } from 'react';
+import FilerobotImageEditor from 'react-filerobot-image-editor';
+
+export function PhotoPreEditor({ imageSrc, onComplete, onClose }) {
+ const [saving, setSaving] = useState(false);
+
+ const handleComplete = (editedImageObject, designState) => {
+ setSaving(true);
+
+ // Export the edited image
+ editedImageObject.exportAsync({
+ quality: 1,
+ mimeType: 'image/png',
+ }).then((blob) => {
+ const url = URL.createObjectURL(blob);
+ setSaving(false);
+ onComplete(url);
+ }).catch((error) => {
+ console.error('Export failed:', error);
+ setSaving(false);
+ onClose();
+ });
+ };
+
+ return (
+
+ );
+}
diff --git a/client/src/components/editor/index.js b/client/src/components/editor/index.js
new file mode 100644
index 0000000..d18f55a
--- /dev/null
+++ b/client/src/components/editor/index.js
@@ -0,0 +1 @@
+export { PhotoPreEditor } from './PhotoPreEditor';
diff --git a/client/src/components/sidebar/UploadTab.jsx b/client/src/components/sidebar/UploadTab.jsx
index 51325eb..4dbab0c 100644
--- a/client/src/components/sidebar/UploadTab.jsx
+++ b/client/src/components/sidebar/UploadTab.jsx
@@ -1,9 +1,11 @@
-import { useRef, useState } from 'react';
+import { useState } from 'react';
+import { PhotoPreEditor } from '../editor/PhotoPreEditor';
export function UploadTab({ onUpload }) {
- const fileInputRef = useRef(null);
+ const fileInputRef = useState(null)[0];
const [isDragging, setIsDragging] = useState(false);
const [uploading, setUploading] = useState(false);
+ const [editingImage, setEditingImage] = useState(null);
const handleFile = async (file) => {
if (!file || !file.type.startsWith('image/')) return;
@@ -20,7 +22,8 @@ export function UploadTab({ onUpload }) {
if (response.ok) {
const data = await response.json();
- onUpload(data);
+ // Open photo editor with uploaded image
+ setEditingImage(data.original.url);
}
} catch (error) {
console.error('Upload failed:', error);
@@ -45,6 +48,25 @@ export function UploadTab({ onUpload }) {
setIsDragging(false);
};
+ const handleEditorComplete = (editedImageUrl) => {
+ onUpload({ preview: { url: editedImageUrl } });
+ setEditingImage(null);
+ };
+
+ const handleEditorClose = () => {
+ setEditingImage(null);
+ };
+
+ if (editingImage) {
+ return (
+
+ );
+ }
+
return (
Upload Image
@@ -53,7 +75,7 @@ export function UploadTab({ onUpload }) {
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
- onClick={() => fileInputRef.current?.click()}
+ onClick={() => fileInputRef?.click()}
>
{uploading ? (
@@ -65,6 +87,9 @@ export function UploadTab({ onUpload }) {
📁
Drop image here or click to upload
PNG, JPG, WEBP up to 20MB
+
+ Edit with crop, filters, and effects before adding to design
+
>
)}