costum shape
This commit is contained in:
@@ -4,6 +4,7 @@ import TextInstruction from "./instructions/TextInstruction";
|
||||
import {
|
||||
AlignmentSettings,
|
||||
AudioSettings,
|
||||
CustomShapeSettings,
|
||||
EntranceAnimationSettings,
|
||||
GridSettings,
|
||||
LineSettings,
|
||||
@@ -97,6 +98,10 @@ const ObjectSettings = ({ selectedObject, pageWidth, pageHeight, onUpdate, onDel
|
||||
|
||||
{roundedSelectedObject.type === "grid" && <GridSettings selectedObject={roundedSelectedObject} onUpdate={handleRoundedUpdate} />}
|
||||
|
||||
{roundedSelectedObject.type === "custom-shape" && (
|
||||
<CustomShapeSettings selectedObject={roundedSelectedObject} onUpdate={handleRoundedUpdate} />
|
||||
)}
|
||||
|
||||
<EntranceAnimationSettings selectedObject={roundedSelectedObject} onUpdate={handleRoundedUpdate} />
|
||||
|
||||
<TransformSettings selectedObject={roundedSelectedObject} onUpdate={handleRoundedUpdate} />
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
ArrowInstruction,
|
||||
StickerInstruction,
|
||||
GridInstruction,
|
||||
CustomShapeInstruction,
|
||||
} from "./instructions";
|
||||
|
||||
type ToolInstructionsProps = {
|
||||
@@ -42,6 +43,7 @@ const ToolInstructions = ({ tool }: ToolInstructionsProps) => {
|
||||
arrow: <ArrowInstruction />,
|
||||
sticker: <StickerInstruction />,
|
||||
grid: <GridInstruction />,
|
||||
"custom-shape": <CustomShapeInstruction />,
|
||||
};
|
||||
|
||||
return simpleInstructions[tool] ?? null;
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
Music,
|
||||
Minus,
|
||||
Link2,
|
||||
Magicpen,
|
||||
} from "iconsax-react";
|
||||
import type { ToolType } from "../../store/editorStore";
|
||||
|
||||
@@ -26,6 +27,7 @@ const tools: Array<{ icon: (color: string, variant?: "Bold" | "Outline" | "Broke
|
||||
{ icon: (color, variant) => <ArrowLeft size={20} color={color} variant={variant} />, tool: "arrow", label: "پیکان" },
|
||||
{ icon: (color, variant) => <Minus size={20} color={color} variant={variant} />, tool: "line", label: "خط" },
|
||||
{ icon: (color, variant) => <Sticker size={20} color={color} variant={variant} />, tool: "sticker", label: "استیکر" },
|
||||
{ icon: (color, variant) => <Magicpen size={20} color={color} variant={variant} />, tool: "custom-shape", label: "شکل سفارشی" },
|
||||
];
|
||||
|
||||
type ToolsBarProps = {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
const CustomShapeInstruction = () => (
|
||||
<div className="space-y-2 text-sm text-gray-600">
|
||||
<p className="font-medium text-gray-700">رسم شکل سفارشی</p>
|
||||
<ul className="space-y-1">
|
||||
<li>• روی کانوس کلیک کنید تا نقاط اضافه شود</li>
|
||||
<li>• روی نقطه اول کلیک کنید تا شکل بسته شود</li>
|
||||
<li>• دوبار کلیک کنید تا شکل تکمیل شود</li>
|
||||
<li>• Escape را بزنید تا لغو شود</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default CustomShapeInstruction;
|
||||
@@ -12,3 +12,4 @@ export { default as LineInstruction } from "./LineInstruction";
|
||||
export { default as ArrowInstruction } from "./ArrowInstruction";
|
||||
export { default as StickerInstruction } from "./StickerInstruction";
|
||||
export { default as GridInstruction } from "./GridInstruction";
|
||||
export { default as CustomShapeInstruction } from "./CustomShapeInstruction";
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
import ColorPicker from "@/components/ColorPicker";
|
||||
import Input from "@/components/Input";
|
||||
import type { EditorObject } from "@/pages/editor/store/editorStore";
|
||||
|
||||
type CustomShapeSettingsProps = {
|
||||
selectedObject: EditorObject;
|
||||
onUpdate: (id: string, updates: Partial<EditorObject>) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sidebar settings panel for a completed custom-shape polygon.
|
||||
* Supports solid fill, gradient fill, stroke colour, and stroke width.
|
||||
* Mirrors the visual and UX conventions of ShapeSettings.
|
||||
*/
|
||||
const CustomShapeSettings = ({ selectedObject, onUpdate }: CustomShapeSettingsProps) => {
|
||||
const fill = selectedObject.fill ?? "#3b82f6";
|
||||
const fillType = selectedObject.fillType ?? "solid";
|
||||
const gradient = selectedObject.gradient ?? {
|
||||
from: "#3b82f6",
|
||||
to: "#1d4ed8",
|
||||
angle: 135,
|
||||
};
|
||||
const stroke = selectedObject.stroke ?? "#1e40af";
|
||||
const strokeWidth = selectedObject.strokeWidth ?? 2;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<ColorPicker
|
||||
label="رنگ پر"
|
||||
value={fill}
|
||||
readOnly={fillType === "gradient"}
|
||||
onChange={(value) => onUpdate(selectedObject.id, { fill: value })}
|
||||
/>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm">نوع Fill</label>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onUpdate(selectedObject.id, { fillType: "solid" })}
|
||||
className={`px-3 py-1.5 rounded-lg border text-xs ${
|
||||
fillType === "solid"
|
||||
? "border-gray-800 text-gray-900"
|
||||
: "border-border text-gray-500"
|
||||
}`}
|
||||
>
|
||||
رنگ ساده
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
onUpdate(selectedObject.id, {
|
||||
fillType: "gradient",
|
||||
gradient: selectedObject.gradient ?? gradient,
|
||||
})
|
||||
}
|
||||
className={`px-3 py-1.5 rounded-lg border text-xs ${
|
||||
fillType === "gradient"
|
||||
? "border-gray-800 text-gray-900"
|
||||
: "border-border text-gray-500"
|
||||
}`}
|
||||
>
|
||||
گرادیانت
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{fillType === "gradient" && (
|
||||
<div className="space-y-3 border border-border rounded-xl p-3">
|
||||
<ColorPicker
|
||||
label="رنگ شروع"
|
||||
value={gradient.from}
|
||||
onChange={(value) =>
|
||||
onUpdate(selectedObject.id, { gradient: { ...gradient, from: value } })
|
||||
}
|
||||
/>
|
||||
<ColorPicker
|
||||
label="رنگ پایان"
|
||||
value={gradient.to}
|
||||
onChange={(value) =>
|
||||
onUpdate(selectedObject.id, { gradient: { ...gradient, to: value } })
|
||||
}
|
||||
/>
|
||||
<div className="space-y-1">
|
||||
<label className="text-sm">زاویه گرادیانت</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
min={0}
|
||||
max={360}
|
||||
value={gradient.angle}
|
||||
onChange={(e) =>
|
||||
onUpdate(selectedObject.id, {
|
||||
gradient: { ...gradient, angle: Number(e.target.value) },
|
||||
})
|
||||
}
|
||||
className="w-full"
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
min={0}
|
||||
max={360}
|
||||
value={gradient.angle}
|
||||
onChange={(e) =>
|
||||
onUpdate(selectedObject.id, {
|
||||
gradient: { ...gradient, angle: Number(e.target.value) || 0 },
|
||||
})
|
||||
}
|
||||
className="w-16 h-9 rounded-lg border border-border px-2 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ColorPicker
|
||||
label="رنگ خط"
|
||||
value={stroke}
|
||||
onChange={(value) => onUpdate(selectedObject.id, { stroke: value })}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="ضخامت خط"
|
||||
type="number"
|
||||
value={strokeWidth}
|
||||
min={0}
|
||||
onChange={(e) =>
|
||||
onUpdate(selectedObject.id, {
|
||||
strokeWidth: parseInt(e.target.value) || 0,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomShapeSettings;
|
||||
@@ -1,4 +1,5 @@
|
||||
export { default as TextSettings } from "./TextSettings";
|
||||
export { default as CustomShapeSettings } from "./CustomShapeSettings";
|
||||
export { default as ShapeSettings } from "./ShapeSettings";
|
||||
export { default as LineSettings } from "./LineSettings";
|
||||
export { default as SizeSettings } from "./SizeSettings";
|
||||
|
||||
Reference in New Issue
Block a user