Create all components
This commit is contained in:
@@ -15,30 +15,6 @@ const EditorSidebar = () => {
|
|||||||
setTool(selectedTool);
|
setTool(selectedTool);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const file = e.target.files?.[0];
|
|
||||||
if (!file) return;
|
|
||||||
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = (event) => {
|
|
||||||
const imageUrl = event.target?.result as string;
|
|
||||||
const img = new Image();
|
|
||||||
img.onload = () => {
|
|
||||||
const newImage = {
|
|
||||||
id: `image-${Date.now()}`,
|
|
||||||
type: "image" as ToolType,
|
|
||||||
x: 100,
|
|
||||||
y: 100,
|
|
||||||
width: img.width,
|
|
||||||
height: img.height,
|
|
||||||
imageUrl,
|
|
||||||
};
|
|
||||||
useEditorStore.getState().addObject(newImage);
|
|
||||||
};
|
|
||||||
img.src = imageUrl;
|
|
||||||
};
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -72,7 +48,7 @@ const EditorSidebar = () => {
|
|||||||
onDelete={deleteObject}
|
onDelete={deleteObject}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ToolInstructions tool={tool} onImageUpload={handleImageUpload} />
|
<ToolInstructions tool={tool} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
LinkSettings,
|
LinkSettings,
|
||||||
VideoSettings,
|
VideoSettings,
|
||||||
TransformSettings,
|
TransformSettings,
|
||||||
|
GridSettings,
|
||||||
} from "./settings";
|
} from "./settings";
|
||||||
|
|
||||||
type ObjectSettingsProps = {
|
type ObjectSettingsProps = {
|
||||||
@@ -60,6 +61,10 @@ const ObjectSettings = ({ selectedObject, onUpdate, onDelete }: ObjectSettingsPr
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{selectedObject.type === "grid" && (
|
||||||
|
<GridSettings selectedObject={selectedObject} onUpdate={onUpdate} />
|
||||||
|
)}
|
||||||
|
|
||||||
<TransformSettings selectedObject={selectedObject} onUpdate={onUpdate} />
|
<TransformSettings selectedObject={selectedObject} onUpdate={onUpdate} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,14 +1,53 @@
|
|||||||
import type { ToolType } from "../../store/editorStore";
|
import { useEditorStore, type ToolType } from "../../store/editorStore";
|
||||||
import { ImageUpload, DocumentUpload, VideoInput, LinkInput, SimpleInstruction } from "./instructions";
|
import {
|
||||||
|
ImageUpload,
|
||||||
|
DocumentUpload,
|
||||||
|
VideoInput,
|
||||||
|
LinkInput,
|
||||||
|
SelectInstruction,
|
||||||
|
RectangleInstruction,
|
||||||
|
CircleInstruction,
|
||||||
|
TextInstruction,
|
||||||
|
LineInstruction,
|
||||||
|
ArrowInstruction,
|
||||||
|
StickerInstruction,
|
||||||
|
GridInstruction,
|
||||||
|
} from "./instructions";
|
||||||
|
|
||||||
type ToolInstructionsProps = {
|
type ToolInstructionsProps = {
|
||||||
tool: ToolType;
|
tool: ToolType;
|
||||||
onImageUpload: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ToolInstructions = ({ tool, onImageUpload }: ToolInstructionsProps) => {
|
const ToolInstructions = ({ tool }: ToolInstructionsProps) => {
|
||||||
|
const { addObject } = useEditorStore();
|
||||||
|
|
||||||
|
const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const file = e.target.files?.[0];
|
||||||
|
if (file) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (event) => {
|
||||||
|
const imageUrl = event.target?.result as string;
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
const newImage = {
|
||||||
|
id: `image-${Date.now()}`,
|
||||||
|
type: "image" as ToolType,
|
||||||
|
x: 100,
|
||||||
|
y: 100,
|
||||||
|
width: img.width,
|
||||||
|
height: img.height,
|
||||||
|
imageUrl,
|
||||||
|
};
|
||||||
|
addObject(newImage);
|
||||||
|
};
|
||||||
|
img.src = imageUrl;
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (tool === "image") {
|
if (tool === "image") {
|
||||||
return <ImageUpload onImageUpload={onImageUpload} />;
|
return <ImageUpload onImageUpload={handleImageUpload} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tool === "document") {
|
if (tool === "document") {
|
||||||
@@ -23,7 +62,18 @@ const ToolInstructions = ({ tool, onImageUpload }: ToolInstructionsProps) => {
|
|||||||
return <LinkInput />;
|
return <LinkInput />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <SimpleInstruction tool={tool} />;
|
const simpleInstructions: Partial<Record<ToolType, React.ReactElement>> = {
|
||||||
|
select: <SelectInstruction />,
|
||||||
|
rectangle: <RectangleInstruction />,
|
||||||
|
circle: <CircleInstruction />,
|
||||||
|
text: <TextInstruction />,
|
||||||
|
line: <LineInstruction />,
|
||||||
|
arrow: <ArrowInstruction />,
|
||||||
|
sticker: <StickerInstruction />,
|
||||||
|
grid: <GridInstruction />,
|
||||||
|
};
|
||||||
|
|
||||||
|
return simpleInstructions[tool] ?? null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ToolInstructions;
|
export default ToolInstructions;
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const ArrowInstruction = () => (
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
<p>برای رسم پیکان، روی کانوس کلیک کرده و بکشید</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default ArrowInstruction;
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const CircleInstruction = () => (
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
<p>برای رسم دایره، روی کانوس کلیک کرده و بکشید</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default CircleInstruction;
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const GridInstruction = () => (
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
<p>برای افزودن گرید، روی کانوس کلیک کنید</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default GridInstruction;
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const LineInstruction = () => (
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
<p>برای رسم خط، روی کانوس کلیک کرده و بکشید</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default LineInstruction;
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const RectangleInstruction = () => (
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
<p>برای رسم مستطیل، روی کانوس کلیک کرده و بکشید</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default RectangleInstruction;
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const SelectInstruction = () => (
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
<p>برای انتخاب و جابجایی اشیاء، روی آنها کلیک کنید</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default SelectInstruction;
|
||||||
|
|
||||||
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import type { ToolType } from "../../../store/editorStore";
|
|
||||||
|
|
||||||
type SimpleInstructionProps = {
|
|
||||||
tool: ToolType;
|
|
||||||
};
|
|
||||||
|
|
||||||
const SimpleInstruction = ({ tool }: SimpleInstructionProps) => {
|
|
||||||
const instructions: Record<ToolType, string> = {
|
|
||||||
select: "برای انتخاب و جابجایی اشیاء، روی آنها کلیک کنید",
|
|
||||||
rectangle: "برای رسم مستطیل، روی کانوس کلیک کرده و بکشید",
|
|
||||||
circle: "برای رسم دایره، روی کانوس کلیک کرده و بکشید",
|
|
||||||
text: "برای افزودن متن، روی کانوس کلیک کنید",
|
|
||||||
line: "برای رسم خط، روی کانوس کلیک کرده و بکشید",
|
|
||||||
arrow: "برای رسم پیکان، روی کانوس کلیک کرده و بکشید",
|
|
||||||
sticker: "برای افزودن استیکر، روی کانوس کلیک کنید",
|
|
||||||
grid: "برای افزودن گرید، روی کانوس کلیک کنید",
|
|
||||||
image: "",
|
|
||||||
document: "",
|
|
||||||
video: "",
|
|
||||||
link: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="text-sm text-gray-600">
|
|
||||||
<p>{instructions[tool]}</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SimpleInstruction;
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const StickerInstruction = () => (
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
<p>برای افزودن استیکر، روی کانوس کلیک کنید</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default StickerInstruction;
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const TextInstruction = () => (
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
<p>برای افزودن متن، روی کانوس کلیک کنید</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default TextInstruction;
|
||||||
|
|
||||||
|
|
||||||
@@ -2,5 +2,12 @@ export { default as ImageUpload } from "./ImageUpload";
|
|||||||
export { default as DocumentUpload } from "./DocumentUpload";
|
export { default as DocumentUpload } from "./DocumentUpload";
|
||||||
export { default as VideoInput } from "./VideoInput";
|
export { default as VideoInput } from "./VideoInput";
|
||||||
export { default as LinkInput } from "./LinkInput";
|
export { default as LinkInput } from "./LinkInput";
|
||||||
export { default as SimpleInstruction } from "./SimpleInstruction";
|
export { default as SelectInstruction } from "./SelectInstruction";
|
||||||
|
export { default as RectangleInstruction } from "./RectangleInstruction";
|
||||||
|
export { default as CircleInstruction } from "./CircleInstruction";
|
||||||
|
export { default as TextInstruction } from "./TextInstruction";
|
||||||
|
export { default as LineInstruction } from "./LineInstruction";
|
||||||
|
export { default as ArrowInstruction } from "./ArrowInstruction";
|
||||||
|
export { default as StickerInstruction } from "./StickerInstruction";
|
||||||
|
export { default as GridInstruction } from "./GridInstruction";
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import type { EditorObject } from "../../../store/editorStore";
|
||||||
|
import Input from "@/components/Input";
|
||||||
|
|
||||||
|
type GridSettingsProps = {
|
||||||
|
selectedObject: EditorObject;
|
||||||
|
onUpdate: (id: string, updates: Partial<EditorObject>) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const GridSettings = ({ selectedObject, onUpdate }: GridSettingsProps) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Input
|
||||||
|
label="عرض"
|
||||||
|
type="number"
|
||||||
|
value={selectedObject.width || 200}
|
||||||
|
onChange={(e) =>
|
||||||
|
onUpdate(selectedObject.id, {
|
||||||
|
width: parseInt(e.target.value) || 200,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
label="ارتفاع"
|
||||||
|
type="number"
|
||||||
|
value={selectedObject.height || 200}
|
||||||
|
onChange={(e) =>
|
||||||
|
onUpdate(selectedObject.id, {
|
||||||
|
height: parseInt(e.target.value) || 200,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GridSettings;
|
||||||
|
|
||||||
@@ -5,4 +5,5 @@ export { default as SizeSettings } from "./SizeSettings";
|
|||||||
export { default as LinkSettings } from "./LinkSettings";
|
export { default as LinkSettings } from "./LinkSettings";
|
||||||
export { default as VideoSettings } from "./VideoSettings";
|
export { default as VideoSettings } from "./VideoSettings";
|
||||||
export { default as TransformSettings } from "./TransformSettings";
|
export { default as TransformSettings } from "./TransformSettings";
|
||||||
|
export { default as GridSettings } from "./GridSettings";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Konva from "konva";
|
import Konva from "konva";
|
||||||
import { EditorObject } from "../../store/editorStore";
|
import type { EditorObject } from "../../store/editorStore";
|
||||||
|
|
||||||
export type ShapeProps = {
|
export type ShapeProps = {
|
||||||
obj: EditorObject;
|
obj: EditorObject;
|
||||||
|
|||||||
Reference in New Issue
Block a user