diff --git a/package-lock.json b/package-lock.json
index 62927b4..d4d19ba 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -31,6 +31,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-dropzone": "^14.3.5",
+ "react-icons": "^5.4.0",
"react-image-file-resizer": "^0.4.8",
"react-rnd": "^10.4.13",
"react-window": "^1.8.10",
@@ -7128,6 +7129,15 @@
"react": ">= 16.8 || 18.0.0"
}
},
+ "node_modules/react-icons": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.4.0.tgz",
+ "integrity": "sha512-7eltJxgVt7X64oHh6wSWNwwbKTCtMfK35hcjvJS0yxEAhPM8oUKdS3+kqaW1vicIltw+kR2unHaa12S9pPALoQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-image-file-resizer": {
"version": "0.4.8",
"resolved": "https://registry.npmjs.org/react-image-file-resizer/-/react-image-file-resizer-0.4.8.tgz",
diff --git a/package.json b/package.json
index fbb6e1e..b4403e6 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-dropzone": "^14.3.5",
+ "react-icons": "^5.4.0",
"react-image-file-resizer": "^0.4.8",
"react-rnd": "^10.4.13",
"react-window": "^1.8.10",
diff --git a/src/App.jsx b/src/App.jsx
index e12cd48..d878806 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,19 +1,20 @@
-import { useContext, useEffect, useState } from "react";
+import { useContext, useEffect } from "react";
import "./App.css";
// import Canvas from "./components/Canvas";
import WebFont from "webfontloader";
-import Header from "./components/Layouts/Header";
-import SheetRightPanel from "./components/Layouts/SheetRightPanel";
-import SheetLeftPanel from "./components/Layouts/SheetLeftPanel";
-import CanvasCapture from "./components/CanvasCapture";
-import { Toaster } from "./components/ui/toaster";
+// import Header from "./components/Layouts/Header";
+// import SheetRightPanel from "./components/Layouts/SheetRightPanel";
+// import SheetLeftPanel from "./components/Layouts/SheetLeftPanel";
+// import CanvasCapture from "./components/CanvasCapture";
+// import { Toaster } from "./components/ui/toaster";
import { Sidebar } from "./components/Layouts/LeftSidebar";
-import { Canvas } from "./components/Panel/Canvas";
-import TextPanel from "./components/Panel/TextPanel";
+// import TextPanel from "./components/Panel/TextPanel";
import { TopBar } from "./components/Panel/TopBar";
import { ActionButtons } from "./components/ActionButtons";
import EditorPanel from "./components/Panel/EditorPanel";
import CanvasContext from "./components/Context/canvasContext/CanvasContext";
+import Canvas from "./components/Canvas/Canvas";
+import ActiveObjectContext from "./components/Context/activeObject/ObjectContext";
function App() {
useEffect(() => {
@@ -75,7 +76,7 @@ function App() {
}, []);
const { selectedPanel } = useContext(CanvasContext);
- const [hasSelectedObject, setHasSelectedObject] = useState(true);
+ const { activeObject } = useContext(ActiveObjectContext);
return (
//
@@ -96,7 +97,7 @@ function App() {
{selectedPanel !== "" &&
}
diff --git a/src/components/Panel/Canvas.jsx b/src/components/Canvas/Canvas.jsx
similarity index 77%
rename from src/components/Panel/Canvas.jsx
rename to src/components/Canvas/Canvas.jsx
index 283448e..c2993a3 100644
--- a/src/components/Panel/Canvas.jsx
+++ b/src/components/Canvas/Canvas.jsx
@@ -3,8 +3,9 @@ import { AspectRatio } from "@/components/ui/aspect-ratio";
import OpenContext from "../Context/openContext/OpenContext";
import CanvasContext from "../Context/canvasContext/CanvasContext";
import { Card, CardContent } from "../ui/card";
+import ActiveObjectContext from "../Context/activeObject/ObjectContext";
-export function Canvas() {
+export default function Canvas() {
const {
setLeftPanelOpen,
setRightPanelOpen,
@@ -24,6 +25,36 @@ export function Canvas() {
setScreenWidth,
} = useContext(CanvasContext);
+ const { activeObject, setActiveObject } = useContext(ActiveObjectContext);
+
+ useEffect(() => {
+ if (!canvas) return; // Ensure canvas is available
+
+ // Event handler for mouse down
+ const handleMouseDown = (event) => {
+ const target = event.target; // Get the clicked target
+ const activeObject = canvas.getActiveObject(); // Get the active object
+
+ if (target) {
+ if (target.type === "group") {
+ setActiveObject(activeObject);
+ } else {
+ setActiveObject(activeObject);
+ }
+ } else {
+ setActiveObject(activeObject);
+ }
+ };
+
+ // Attach the event listener
+ canvas.on("mouse:down", handleMouseDown);
+
+ // Cleanup function to remove the event listener
+ return () => {
+ canvas.off("mouse:down", handleMouseDown); // Remove the listener on unmount
+ };
+ }, [canvas, setActiveObject]);
+
useEffect(() => {
import("fabric").then((fabricModule) => {
window.fabric = fabricModule.fabric;
@@ -127,7 +158,11 @@ export function Canvas() {
}, []);
return (
-
+
{
- const [activeObject, setActiveObject] = useState(null);
- return (
-
- {children}
-
- )
-}
+const ObjectProvider = ({ children }) => {
+ const [activeObject, setActiveObject] = useState(null);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default ObjectProvider;
diff --git a/src/components/Context/canvasContext/CanvasContextProvider.jsx b/src/components/Context/canvasContext/CanvasContextProvider.jsx
index 6d7ef57..f808269 100644
--- a/src/components/Context/canvasContext/CanvasContextProvider.jsx
+++ b/src/components/Context/canvasContext/CanvasContextProvider.jsx
@@ -9,6 +9,7 @@ const CanvasContextProvider = ({ children }) => {
const [screenWidth, setScreenWidth] = useState(0);
const [canvasRatio, setCanvasRatio] = useState("4:3");
const [selectedPanel, setSelectedPanel] = useState("");
+ const [textColor, setTextColor] = useState(null);
const fabricCanvasRef = useRef(null);
return (
@@ -21,6 +22,8 @@ const CanvasContextProvider = ({ children }) => {
canvasHeight,
canvasRatio,
setCanvasRatio,
+ textColor,
+ setTextColor,
selectedPanel,
setSelectedPanel,
setCanvasHeight,
diff --git a/src/components/EachComponent/ApplyColor.jsx b/src/components/EachComponent/ApplyColor.jsx
index c16e48f..662b25c 100644
--- a/src/components/EachComponent/ApplyColor.jsx
+++ b/src/components/EachComponent/ApplyColor.jsx
@@ -1,289 +1,358 @@
-import { useContext, useEffect, useState } from 'react'
-import ActiveObjectContext from '../Context/activeObject/ObjectContext';
-import CanvasContext from '../Context/canvasContext/CanvasContext';
-import { fabric } from 'fabric';
-import { debounce } from "lodash";
-import { Separator } from '../ui/separator';
-import { Label } from '../ui/label';
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select';
-import { Input } from '../ui/input';
-import { Card } from '../ui/card';
-import { Tabs, TabsContent, TabsList, TabsTrigger } from '../ui/tabs';
-import { Button } from '../ui/button';
-import CollapsibleComponent from './Customization/CollapsibleComponent';
+import { useCallback, useContext, useEffect, useState } from "react";
+import ActiveObjectContext from "../Context/activeObject/ObjectContext";
+import CanvasContext from "../Context/canvasContext/CanvasContext";
+import { fabric } from "fabric";
+import { Separator } from "../ui/separator";
+import { Label } from "../ui/label";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "../ui/select";
+import { Input } from "../ui/input";
+import { Card } from "../ui/card";
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
+import CollapsibleComponent from "./Customization/CollapsibleComponent";
const ApplyColor = () => {
- const [colorField, setColorField] = useState("fill");
- const [fillColor, setFillColor] = useState("");
- const [backgroundColor, setBackgroundColor] = useState("");
- const [gradientFillColors, setGradientFillColors] = useState({
- color1: "#f97316",
- color2: "#e26286",
- });
- const [colorType, setColorType] = useState("color"); // 'color' or 'gradient'
- const [gradientDirection, setGradientDirection] = useState("top-to-bottom");
- // get values from context
- const { activeObject } = useContext(ActiveObjectContext);
- const { canvas } = useContext(CanvasContext);
+ const [colorField, setColorField] = useState("fill");
+ const [fillColor, setFillColor] = useState("");
+ const [backgroundColor, setBackgroundColor] = useState("");
+ const [gradientFillColors, setGradientFillColors] = useState({
+ color1: "#f97316",
+ color2: "#e26286",
+ });
+ const [colorType, setColorType] = useState("color"); // 'color' or 'gradient'
+ const [gradientDirection, setGradientDirection] = useState("top-to-bottom");
- // to get previous values from active object
- useEffect(() => {
- const handleObjectStyle = (object) => {
- if (object.fill) {
- if (typeof object.fill === "string") {
- setColorType("color");
- } else if (object.fill instanceof fabric.Gradient) {
- setColorType("gradient");
- }
- }
+ // Get values from context
+ const { activeObject, setActiveObject } = useContext(ActiveObjectContext);
+ const { canvas, setTextColor } = useContext(CanvasContext);
- // Handle solid colors
- if (object.fill && !object.fill.colorStops) {
- setFillColor(object.fill); // Solid fill
- }
- if (object.backgroundColor) {
- setBackgroundColor(object.backgroundColor); // Solid background color
- }
-
- // Handle gradients
- if (object.fill?.colorStops) {
- setGradientFillColors({
- color1: object.fill.colorStops[0]?.color || "",
- color2: object.fill.colorStops[1]?.color || "",
- });
- }
- };
-
- const processGroupObjects = (group) => {
- group._objects.forEach((obj) => {
- if (obj.type === "group") {
- processGroupObjects(obj); // Recursively handle nested groups
- } else {
- handleObjectStyle(obj); // Apply styles to child objects
- }
- });
- };
-
- if (activeObject) {
- if (activeObject.type === "group") {
- processGroupObjects(activeObject); // Process all objects in the group
- } else {
- handleObjectStyle(activeObject); // Handle single object
- }
+ // To get previous values from active object
+ useEffect(() => {
+ const handleObjectStyle = (object) => {
+ if (object.fill) {
+ if (typeof object.fill === "string") {
+ setColorType("color");
+ } else if (object.fill instanceof fabric.Gradient) {
+ setColorType("gradient");
}
- }, [activeObject, colorField]);
+ }
- const handleSolidColorChange = debounce((newColor) => {
- if (colorField === "fill") {
- setFillColor(newColor)
- }
- else {
- setBackgroundColor(newColor)
- }
- }, 100);
+ // Handle solid colors
+ if (object.fill && !object.fill.colorStops) {
+ setFillColor(object.fill); // Solid fill
+ }
+ if (object.backgroundColor) {
+ setBackgroundColor(object.backgroundColor); // Solid background color
+ }
- // Common debounce handler for updating colors
- const debouncedSetGradientColors = debounce((key, value) => {
- if (colorField === "fill") {
- setGradientFillColors((prev) => ({
- ...prev,
- [key]: value,
- }))
- }
- }, 300); // Adjust debounce delay as needed
-
- const handleColorChange = (key) => (e) => {
- const newColor = e.target.value;
- debouncedSetGradientColors(key, newColor);
+ // Handle gradients
+ if (object.fill?.colorStops) {
+ setGradientFillColors({
+ color1: object.fill.colorStops[0]?.color || "",
+ color2: object.fill.colorStops[1]?.color || "",
+ });
+ }
};
- // Apply color/gradient style to the selected object on the canvas
- const applyColor = () => {
- const applyStyleToObject = (object, style) => {
- if (colorType === "color") {
- if (colorField === "fill" && object.fill !== style.fill) {
- object.set("fill", style.fill);
- }
+ const processGroupObjects = (group) => {
+ group._objects.forEach((obj) => {
+ if (obj.type === "group") {
+ processGroupObjects(obj); // Recursively handle nested groups
+ } else {
+ handleObjectStyle(obj); // Apply styles to child objects
+ }
+ });
+ };
- if (colorField === "background" && object.backgroundColor !== style.backgroundColor) {
- object.set("backgroundColor", style.backgroundColor);
- }
- }
-
- if (colorType === "gradient" && colorField === "fill") {
- const width = object?.width || 0;
- const height = object?.height || 0;
-
- const coords = {
- "top-to-bottom": { x1: 0, y1: 0, x2: 0, y2: height },
- "bottom-to-top": { x1: 0, y1: height, x2: 0, y2: 0 },
- "left-to-right": { x1: 0, y1: 0, x2: width, y2: 0 },
- "right-to-left": { x1: width, y1: 0, x2: 0, y2: 0 },
- };
-
- const directionCoords = coords[gradientDirection];
- const gradient = new fabric.Gradient({
- type: "linear",
- gradientUnits: "pixels",
- coords: directionCoords,
- colorStops: [
- { offset: 0, color: gradientFillColors.color1 },
- { offset: 1, color: gradientFillColors.color2 },
- ],
- });
-
- object.set("fill", gradient);
- }
- };
-
- const applyStyleRecursively = (object, style) => {
- if (object.type === "group" && object._objects) {
- // If the object is a group, iterate through its children
- object._objects.forEach((child) => applyStyleRecursively(child, style));
- } else {
- // If the object is not a group, apply the style directly
- applyStyleToObject(object, style);
- }
- };
-
- const style = {
- fill: fillColor,
- backgroundColor: backgroundColor,
- };
-
- applyStyleRecursively(activeObject, style);
-
- // Trigger re-render for the canvas
- canvas.renderAll();
+ if (activeObject) {
+ if (activeObject.type === "group") {
+ processGroupObjects(activeObject); // Process all objects in the group
+ } else {
+ handleObjectStyle(activeObject); // Handle single object
+ }
}
+ }, [activeObject, colorField]);
- const content = () => {
- return (
-
-
-
-
-
-
-
+ // Apply color/gradient style to the selected object on the canvas
+ const applyColor = useCallback(() => {
+ const applyStyleToObject = (object, style) => {
+ if (colorType === "color") {
+ if (colorField === "fill" && object.fill !== style.fill) {
+ object.set("fill", style.fill);
+ }
-
setColorType(value)}>
-
- Solid Color
- Gradient
-
+ if (
+ colorField === "background" &&
+ object.backgroundColor !== style.backgroundColor
+ ) {
+ object.set("backgroundColor", style.backgroundColor);
+ }
+ }
-
-
+ if (colorType === "gradient" && colorField === "fill") {
+ const width = object?.width || 0;
+ const height = object?.height || 0;
-
-
+ const coords = {
+ "top-to-bottom": { x1: 0, y1: 0, x2: 0, y2: height },
+ "bottom-to-top": { x1: 0, y1: height, x2: 0, y2: 0 },
+ "left-to-right": { x1: 0, y1: 0, x2: width, y2: 0 },
+ "right-to-left": { x1: width, y1: 0, x2: 0, y2: 0 },
+ };
-
-
-
-
-
-
-
-
-
-
-
+ const directionCoords = coords[gradientDirection];
+ const gradient = new fabric.Gradient({
+ type: "linear",
+ gradientUnits: "pixels",
+ coords: directionCoords,
+ colorStops: [
+ { offset: 0, color: gradientFillColors.color1 },
+ { offset: 1, color: gradientFillColors.color2 },
+ ],
+ });
-
-
-
- )
+ object.set("fill", gradient);
+ }
+ };
+
+ const applyStyleRecursively = (object, style) => {
+ if (object.type === "group" && object._objects) {
+ // If the object is a group, iterate through its children
+ object._objects.forEach((child) => applyStyleRecursively(child, style));
+ } else {
+ // If the object is not a group, apply the style directly
+ applyStyleToObject(object, style);
+ }
+ };
+
+ const style = {
+ fill: fillColor,
+ backgroundColor: backgroundColor,
+ };
+
+ if (activeObject) {
+ applyStyleRecursively(activeObject, style);
+ setActiveObject(activeObject);
+ setTextColor(style);
+ canvas.renderAll();
}
+ }, [
+ activeObject,
+ fillColor,
+ backgroundColor,
+ gradientFillColors,
+ colorType,
+ gradientDirection,
+ setActiveObject,
+ canvas,
+ colorField,
+ setTextColor,
+ ]);
+ // Watch for changes in color-related states and apply them instantly
+ useEffect(() => {
+ applyColor();
+ }, [
+ applyColor, // Now included in dependencies
+ fillColor,
+ backgroundColor,
+ gradientFillColors,
+ colorType,
+ gradientDirection,
+ ]);
+
+ const handleSolidColorChange = (newColor) => {
+ if (colorField === "fill") {
+ setFillColor(newColor);
+ } else {
+ setBackgroundColor(newColor);
+ }
+ };
+
+ const handleGradientColorChange = (key, value) => {
+ setGradientFillColors((prev) => ({
+ ...prev,
+ [key]: value,
+ }));
+ };
+
+ const content = () => {
return (
-
-
-
- {content()}
-
-
-
-
- )
-}
+
+
+
+
+
+
+
-export default ApplyColor
\ No newline at end of file
+
setColorType(value)}
+ >
+
+ Solid Color
+
+ Gradient
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ };
+
+ return (
+
+
+
+ {content()}
+
+
+
+
+ );
+};
+
+export default ApplyColor;
diff --git a/src/components/EachComponent/Customization/CollapsibleComponent.jsx b/src/components/EachComponent/Customization/CollapsibleComponent.jsx
index edd626a..180835f 100644
--- a/src/components/EachComponent/Customization/CollapsibleComponent.jsx
+++ b/src/components/EachComponent/Customization/CollapsibleComponent.jsx
@@ -18,7 +18,7 @@ const CollapsibleComponent = ({ children, text }) => {
}, [text]);
return (
-
+
{
const { canvas } = useContext(CanvasContext);
@@ -51,8 +50,7 @@ const LockObject = () => {
};
return (
-
- {!isLocked ? "Lock" : "Unlock"} Object
+
-
+
);
};
diff --git a/src/components/EachComponent/Customization/OpacityCustomization.jsx b/src/components/EachComponent/Customization/OpacityCustomization.jsx
index e8d3c04..a1d2e84 100644
--- a/src/components/EachComponent/Customization/OpacityCustomization.jsx
+++ b/src/components/EachComponent/Customization/OpacityCustomization.jsx
@@ -1,46 +1,61 @@
-import ActiveObjectContext from '@/components/Context/activeObject/ObjectContext';
-import CanvasContext from '@/components/Context/canvasContext/CanvasContext';
-import { Label } from '@/components/ui/label';
-import { Slider } from '@/components/ui/slider';
-import { useContext, useEffect, useState } from 'react'
+import ActiveObjectContext from "@/components/Context/activeObject/ObjectContext";
+import CanvasContext from "@/components/Context/canvasContext/CanvasContext";
+import { Label } from "@/components/ui/label";
+import { Slider } from "@/components/ui/slider";
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui/popover";
+import { useContext, useEffect, useState } from "react";
+import { BsTransparency } from "react-icons/bs";
+import { Button } from "@/components/ui/button";
const OpacityCustomization = () => {
- const { activeObject } = useContext(ActiveObjectContext);
- const { canvas } = useContext(CanvasContext);
+ const { activeObject } = useContext(ActiveObjectContext);
+ const { canvas } = useContext(CanvasContext);
+ const [opacity, setOpacity] = useState(0);
- const [opacity, setOpacity] = useState(0);
+ useEffect(() => {
+ if (activeObject) {
+ setOpacity(activeObject?.opacity);
+ }
+ }, [activeObject]);
- useEffect(() => {
- if (activeObject) {
- setOpacity(activeObject?.opacity);
- }
- }, [activeObject])
+ const adjustBackgroundOpacity = (newOpacity) => {
+ setOpacity(newOpacity);
+ if (activeObject) {
+ activeObject.set("opacity", newOpacity);
+ canvas.renderAll();
+ }
+ };
- const adjustBackgroundOpacity = (value) => {
- setOpacity(value);
- if (activeObject) {
- activeObject.set("opacity", opacity); // Update the opacity
- canvas.renderAll(); // Re-render the canvas
- }
- };
-
- return (
-
-
-
{
- const newOpacity = value[0]; // Extract slider value
- adjustBackgroundOpacity(newOpacity); // Adjust Fabric.js background opacity
- }}
- />
+ return (
+
+
+
+
+
+
+
+
+
+ {Math.round(opacity * 100)}%
+
+
+
adjustBackgroundOpacity(value[0])}
+ />
- )
-}
+
+
+ );
+};
-export default OpacityCustomization
\ No newline at end of file
+export default OpacityCustomization;
diff --git a/src/components/EachComponent/Customization/StrokeCustomization.jsx b/src/components/EachComponent/Customization/StrokeCustomization.jsx
index cfd73e8..ccef96c 100644
--- a/src/components/EachComponent/Customization/StrokeCustomization.jsx
+++ b/src/components/EachComponent/Customization/StrokeCustomization.jsx
@@ -47,7 +47,7 @@ const StrokeCustomization = () => {
}
}
if (object.strokeWidth) {
- setStrokeWidth(object.strokeWidth || 0);
+ setStrokeWidth(0);
}
};
diff --git a/src/components/EachComponent/Customization/TextCustomization.jsx b/src/components/EachComponent/Customization/TextCustomization.jsx
index 354c2fd..c0f545c 100644
--- a/src/components/EachComponent/Customization/TextCustomization.jsx
+++ b/src/components/EachComponent/Customization/TextCustomization.jsx
@@ -1,7 +1,7 @@
import ActiveObjectContext from "@/components/Context/activeObject/ObjectContext";
import CanvasContext from "@/components/Context/canvasContext/CanvasContext";
import { Button } from "@/components/ui/button";
-import { Card, CardContent } from "@/components/ui/card";
+
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
@@ -12,9 +12,12 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
-import { Slider } from "@/components/ui/slider";
-import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
-import { useContext, useEffect, useState } from "react";
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui/popover";
+import { useCallback, useContext, useEffect, useState } from "react";
import {
AlignLeft,
AlignCenter,
@@ -23,8 +26,11 @@ import {
Italic,
Underline,
Strikethrough,
+ Minus,
+ Plus,
} from "lucide-react";
-import CollapsibleComponent from "./CollapsibleComponent";
+import { RiLineHeight } from "react-icons/ri";
+import { Slider } from "@/components/ui/slider";
const fonts = [
"Roboto",
@@ -79,9 +85,8 @@ const fonts = [
];
const TextCustomization = () => {
- // get values from context
const { activeObject } = useContext(ActiveObjectContext);
- const { canvas } = useContext(CanvasContext);
+ const { canvas, setSelectedPanel, textColor } = useContext(CanvasContext);
const [text, setText] = useState("");
const [fontFamily, setFontFamily] = useState("Arial");
@@ -93,7 +98,7 @@ const TextCustomization = () => {
const [underline, setUnderline] = useState(false);
const [linethrough, setLinethrough] = useState(false);
const [textAlign, setTextAlign] = useState("left");
- const [previewText, setPreviewText] = useState("");
+ const [fillColor, setFillColor] = useState("black");
useEffect(() => {
if (activeObject?.type === "i-text") {
@@ -107,18 +112,21 @@ const TextCustomization = () => {
setUnderline(activeObject?.underline || false);
setLinethrough(activeObject?.linethrough || false);
setTextAlign(activeObject?.textAlign || "left");
- setPreviewText(activeObject?.text || "");
+ setFillColor(textColor?.fill || "black");
}
- }, [activeObject]);
+ }, [activeObject, textColor]);
- const updateActiveObject = (properties) => {
- if (activeObject?.type === "i-text") {
- activeObject.set(properties);
- canvas?.renderAll();
- }
- };
+ const updateActiveObject = useCallback(
+ (properties) => {
+ if (activeObject?.type === "i-text") {
+ activeObject.set(properties);
+ canvas?.renderAll();
+ }
+ },
+ [activeObject, canvas]
+ ); // Add dependencies
- const applyChanges = () => {
+ const applyChanges = useCallback(() => {
updateActiveObject({
text,
fontFamily,
@@ -131,12 +139,29 @@ const TextCustomization = () => {
linethrough,
textAlign,
});
- };
+ }, [
+ text,
+ fontFamily,
+ fontSize,
+ fontStyle,
+ fontWeight,
+ lineHeight,
+ charSpacing,
+ underline,
+ linethrough,
+ textAlign,
+ updateActiveObject, // Add this dependency
+ ]);
- const handleTextChange = (newText) => {
- setText(newText);
- setPreviewText(newText);
- };
+ // Automatically apply changes when state updates
+ useEffect(() => {
+ if (activeObject?.type === "i-text") {
+ applyChanges();
+ }
+ }, [
+ applyChanges, // Now included in dependencies
+ activeObject?.type, // Track active object type
+ ]);
const handleFontFamilyChange = (newFontFamily) => {
setFontFamily(newFontFamily);
@@ -151,204 +176,217 @@ const TextCustomization = () => {
};
const handleFontStyleChange = () => {
- const newFontStyle = fontStyle === "normal" ? "italic" : "normal";
- setFontStyle(newFontStyle);
+ setFontStyle(fontStyle === "normal" ? "italic" : "normal");
};
const handleFontWeightChange = () => {
- const newFontWeight = fontWeight === "normal" ? "bold" : "normal";
- setFontWeight(newFontWeight);
+ setFontWeight(fontWeight === "normal" ? "bold" : "normal");
};
const handleLineHeightChange = (newLineHeight) => {
- setLineHeight(newLineHeight);
+ setLineHeight(parseFloat(newLineHeight));
};
const handleCharSpacingChange = (newCharSpacing) => {
- setCharSpacing(newCharSpacing);
+ setCharSpacing(parseInt(newCharSpacing));
};
const handleUnderlineChange = () => {
- const newUnderline = !underline;
- setUnderline(newUnderline);
+ setUnderline(!underline);
};
const handleLinethroughChange = () => {
- const newLinethrough = !linethrough;
- setLinethrough(newLinethrough);
+ setLinethrough(!linethrough);
};
const content = () => {
if (!(activeObject?.type === "i-text")) {
- return (
-
-
-
-
- Select a text object to customize
-
-
-
-
- );
- } else {
- return (
-
-
-
- Text
- Style
-
-
-
-
-
- handleTextChange(e.target.value)}
- />
-
-
-
-
-
-
-
-
- handleFontSizeChange(value)}
- min={8}
- max={72}
- step={1}
- className="flex-grow"
- />
-
- handleFontSizeChange(parseInt(e.target.value, 10) || 16)
- }
- className="w-16"
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- handleLineHeightChange(value)}
- min={0.5}
- max={3}
- step={0.1}
- />
-
-
-
- handleCharSpacingChange(value)}
- min={-20}
- max={100}
- step={1}
- />
-
-
-
-
- );
+ return ;
}
- };
- return (
-
-
- {content()}
-
-
- {previewText && (
+ return (
+
+ {/* New Toolbar Design */}
+
+ {/* Font Family Select */}
+
+
+ {/* Font Size Controls */}
+
+
+
{
+ const numericValue = e.target.value.replace(/\D/g, "");
+ handleFontSizeChange(parseInt(numericValue) || 12);
+ }}
+ className="w-12 h-8 border-0 text-center"
+ />
+
+
+
+ {/* Vertical Separator */}
+
+
+ {/* Text Formatting Controls */}
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Vertical Separator */}
+
+
+ {/* Spacing Controls */}
+
+
+
+
+
+
+
+
+
+ handleLineHeightChange(value)}
+ min={0.5}
+ max={3}
+ step={0.1}
+ />
+
+
+
+
+
+
+ handleCharSpacingChange(value)
+ }
+ min={-20}
+ max={100}
+ step={1}
+ />
+
+
+
+
+
+
+
+ {/* Text Input */}
+ {/*
+
+ handleTextChange(e.target.value)}
+ />
+
*/}
+
+ {/* Preview */}
+ {/* {previewText && (
- )}
+ )} */}
-
*/}
-
- );
+ );
+ };
+
+ return
{content()}
;
};
export default TextCustomization;
diff --git a/src/components/Panel/ColorPanel.jsx b/src/components/Panel/ColorPanel.jsx
new file mode 100644
index 0000000..e8d7900
--- /dev/null
+++ b/src/components/Panel/ColorPanel.jsx
@@ -0,0 +1,29 @@
+import { useContext } from "react";
+import ApplyColor from "../EachComponent/ApplyColor";
+import { Button } from "../ui/button";
+import CanvasContext from "../Context/canvasContext/CanvasContext";
+import { X } from "lucide-react";
+import { ScrollArea } from "../ui/scroll-area";
+
+const ColorPanel = () => {
+ const { setSelectedPanel } = useContext(CanvasContext);
+ return (
+
+
+
Color
+ setSelectedPanel("")}
+ >
+
+
+
+
+
+
+
+ );
+};
+
+export default ColorPanel;
diff --git a/src/components/Panel/CommonPanel.jsx b/src/components/Panel/CommonPanel.jsx
index 252c0c3..c319a54 100644
--- a/src/components/Panel/CommonPanel.jsx
+++ b/src/components/Panel/CommonPanel.jsx
@@ -5,23 +5,31 @@ import StrokeCustomization from "../EachComponent/Customization/StrokeCustomizat
import PositionCustomization from "../EachComponent/Customization/PositionCustomization";
import { Card } from "../ui/card";
import CollapsibleComponent from "../EachComponent/Customization/CollapsibleComponent";
-import OpacityCustomization from "../EachComponent/Customization/OpacityCustomization";
import FlipCustomization from "../EachComponent/Customization/FlipCustomization";
import RotateCustomization from "../EachComponent/Customization/RotateCustomization";
import SkewCustomization from "../EachComponent/Customization/SkewCustomization";
import ScaleObjects from "../EachComponent/Customization/ScaleObjects";
import ShadowCustomization from "../EachComponent/Customization/ShadowCustomization";
import AddImageIntoShape from "../EachComponent/Customization/AddImageIntoShape";
+import ApplyColor from "../EachComponent/ApplyColor";
const CommonPanel = () => {
const { canvas } = useContext(CanvasContext);
const activeObject = canvas?.getActiveObject();
+ const activeObjectType = activeObject?.type;
+ const hasClipPath = !!activeObject?.clipPath;
const customClipPath = activeObject?.isClipPath;
+
return (
+ {/* Apply fill and background color */}
+ {activeObjectType !== "image" && !hasClipPath && !customClipPath && (
+
+ )}
+
{/* Apply stroke and stroke color */}
{!customClipPath && (
<>
@@ -37,9 +45,8 @@ const CommonPanel = () => {
{/* Controls for opacity, flip, and rotation */}
-
+
-
diff --git a/src/components/Panel/EditorPanel.jsx b/src/components/Panel/EditorPanel.jsx
index ab44e28..d28260b 100644
--- a/src/components/Panel/EditorPanel.jsx
+++ b/src/components/Panel/EditorPanel.jsx
@@ -1,6 +1,7 @@
import { useContext } from "react";
import CanvasContext from "../Context/canvasContext/CanvasContext";
import TextPanel from "./TextPanel";
+import ColorPanel from "./ColorPanel";
const EditorPanel = () => {
const { selectedPanel } = useContext(CanvasContext);
@@ -9,6 +10,8 @@ const EditorPanel = () => {
switch (selectedPanel) {
case "text":
return ;
+ case "color":
+ return ;
default:
return;
}
@@ -17,7 +20,7 @@ const EditorPanel = () => {
return (
<>
{selectedPanel !== "" && (
-
+
{renderPanel()}
)}
diff --git a/src/components/Panel/TextPanel.jsx b/src/components/Panel/TextPanel.jsx
index d375311..cdcc761 100644
--- a/src/components/Panel/TextPanel.jsx
+++ b/src/components/Panel/TextPanel.jsx
@@ -1,21 +1,25 @@
import { Button } from "../ui/Button";
import { X } from "lucide-react";
import { ScrollArea } from "../ui/scroll-area";
-import { useContext } from "react";
+import { useContext, useEffect, useState } from "react";
import CanvasContext from "../Context/canvasContext/CanvasContext";
import ActiveObjectContext from "../Context/activeObject/ObjectContext";
import { fabric } from "fabric";
import CommonPanel from "./CommonPanel";
-import TextCustomization from "../EachComponent/Customization/TextCustomization";
export default function TextPanel() {
- const { canvas } = useContext(CanvasContext);
- const { setActiveObject } = useContext(ActiveObjectContext);
- const activeObject = canvas?.getActiveObject();
- const activeObjectType = activeObject?.type;
- const hasClipPath = !!activeObject?.clipPath;
- const customClipPath = activeObject?.isClipPath;
+ const { canvas, setSelectedPanel } = useContext(CanvasContext);
+ const { activeObject, setActiveObject } = useContext(ActiveObjectContext);
+ const [open, setOpen] = useState(false);
+
+ useEffect(() => {
+ if (activeObject) {
+ setOpen(true);
+ } else {
+ setOpen(false);
+ }
+ }, [activeObject]);
const addText = () => {
if (canvas) {
const text = new fabric.IText("Editable Text", {
@@ -37,12 +41,16 @@ export default function TextPanel() {
Text
-
+ setSelectedPanel("")}
+ >
-
+
{
@@ -77,15 +85,14 @@ export default function TextPanel() {
/>
- {activeObject ? (
-
-
-
-
- ) : (
+ {!open ? (
No active object found
+ ) : (
+
+
+
)}
diff --git a/src/components/Panel/TopBar.jsx b/src/components/Panel/TopBar.jsx
index a5c6b47..b278fad 100644
--- a/src/components/Panel/TopBar.jsx
+++ b/src/components/Panel/TopBar.jsx
@@ -1,13 +1,3 @@
-import {
- AlignCenter,
- AlignLeft,
- AlignRight,
- Bold,
- Italic,
- Lock,
- Underline,
-} from "lucide-react";
-import { Button } from "../ui/Button";
import {
Select,
SelectContent,
@@ -15,87 +5,46 @@ import {
SelectTrigger,
SelectValue,
} from "../ui/Select";
+import TextCustomization from "../EachComponent/Customization/TextCustomization";
+import LockObject from "../EachComponent/Customization/LockObject";
+import { ScrollArea, ScrollBar } from "../ui/scroll-area";
+import OpacityCustomization from "../EachComponent/Customization/OpacityCustomization";
+import CanvasContext from "../Context/canvasContext/CanvasContext";
+import { useContext } from "react";
-export function TopBar({ isVisible = false }) {
- if (!isVisible) return null;
-
+export function TopBar() {
+ const { selectedPanel } = useContext(CanvasContext);
return (
-
-
-
+
+
+
+
+
+
+
+
-
-
- -
-
-
12
-
- +
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
);
}
diff --git a/src/main.jsx b/src/main.jsx
index 7b98f01..9c4bd2b 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -1,13 +1,12 @@
-import { StrictMode } from 'react'
-import { createRoot } from 'react-dom/client'
-import './index.css'
-import App from './App.jsx'
-import CanvasContextProvider from './components/Context/canvasContext/CanvasContextProvider'
-import ColorContextProvider from './components/Context/colorContext/ColorContextProvider'
-import { ObjectProvider } from './components/Context/activeObject/ObjectProvider'
-import OpenContextProvider from './components/Context/openContext/OpenContextProvider'
+import { createRoot } from "react-dom/client";
+import "./index.css";
+import App from "./App.jsx";
+import CanvasContextProvider from "./components/Context/canvasContext/CanvasContextProvider";
+import ColorContextProvider from "./components/Context/colorContext/ColorContextProvider";
+import ObjectProvider from "./components/Context/activeObject/ObjectProvider";
+import OpenContextProvider from "./components/Context/openContext/OpenContextProvider";
-createRoot(document.getElementById('root')).render(
+createRoot(document.getElementById("root")).render(
//
@@ -19,4 +18,4 @@ createRoot(document.getElementById('root')).render(
// ,
-)
+);