diff --git a/src/components/AspectCanvas.jsx b/src/components/AspectCanvas.jsx index 6786892..74c4b15 100644 --- a/src/components/AspectCanvas.jsx +++ b/src/components/AspectCanvas.jsx @@ -8,6 +8,7 @@ import { Card, CardContent } from './ui/card'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './ui/tooltip'; import { Button } from './ui/button'; import { Separator } from './ui/separator'; +import { ObjectShortcut } from './ObjectShortcut'; const aspectRatios = [ { value: "1:1", label: "Square (1:1)" }, @@ -28,10 +29,10 @@ const aspectRatios = [ ]; export function AspectCanvas() { - const { setLeftPanelOpen, setRightPanelOpen, setOpenPanel, setCaptureOpen, setOpenSetting, openObjectPanel, setOpenObjectPanel, rightPanelOpen } = useContext(OpenContext); + const { setLeftPanelOpen, setRightPanelOpen, setOpenPanel, setCaptureOpen, setOpenSetting, setOpenObjectPanel, rightPanelOpen } = useContext(OpenContext); const [selectedRatio, setSelectedRatio] = useState("4:3"); - const { canvasRef, canvas, setCanvas, fabricCanvasRef, setCanvasHeight, setCanvasWidth } = useContext(CanvasContext); + const { canvasRef, canvas, setCanvas, fabricCanvasRef, setCanvasHeight, setCanvasWidth, setScreenWidth } = useContext(CanvasContext); useEffect(() => { import('fabric').then((fabricModule) => { @@ -80,6 +81,8 @@ export function AspectCanvas() { } } + setScreenWidth(document.getElementById("root").offsetWidth); + // Handle responsive behavior for panels if (document.getElementById("root").offsetWidth <= 640) { setLeftPanelOpen(false); @@ -87,9 +90,9 @@ export function AspectCanvas() { } if (document.getElementById("root").offsetWidth > 640) { setOpenObjectPanel(false); + setOpenSetting(false); } }; - // Initial setup updateCanvasSize(); @@ -98,18 +101,7 @@ export function AspectCanvas() { // Cleanup listener on unmount return () => window.removeEventListener('resize', updateCanvasSize); - }, [ - setCanvasWidth, - setCanvasHeight, - selectedRatio, - canvasRef, - canvas, - openObjectPanel, - setLeftPanelOpen, - setOpenObjectPanel, - setRightPanelOpen, - rightPanelOpen - ]); + }, [setCanvasWidth, setCanvasHeight, selectedRatio, canvasRef, canvas, setLeftPanelOpen, setOpenObjectPanel, setRightPanelOpen, rightPanelOpen, setScreenWidth, setOpenSetting]); useEffect(() => { if (window.fabric) { @@ -138,10 +130,10 @@ export function AspectCanvas() { return ( - -
+ +
-
+
@@ -155,19 +147,22 @@ export function AspectCanvas() { -
- - - - - - -

Open Settings

-
-
-
+
+
+ + + + + + +

Open Settings

+
+
+
+
+ @@ -180,6 +175,7 @@ export function AspectCanvas() { + @@ -201,12 +197,12 @@ export function AspectCanvas() {
+
- {backgroundType === "color" ? ( + {previewBackgroundType === "color" ? (
applySolidColor(e.target.value)} + value={previewSolidColor} + onChange={(e) => setPreviewSolidColor(e.target.value)} />
- ) : backgroundType === "gradient" ? ( + ) : previewBackgroundType === "gradient" ? (
-
+
-
+
- setGradientColors((prev) => ({ + setPreviewGradientColors((prev) => ({ ...prev, color1: e.target.value, }))} />
-
+
- setGradientColors((prev) => ({ + setPreviewGradientColors((prev) => ({ ...prev, color2: e.target.value, }))} @@ -168,27 +196,27 @@ const ColorComponent = () => {
) : ( -
-
+
+
- setGradientColors((prev) => ({ + setPreviewGradientColors((prev) => ({ ...prev, color1: e.target.value, }))} />
-
+
- setGradientColors((prev) => ({ + setPreviewGradientColors((prev) => ({ ...prev, color2: e.target.value, }))} @@ -196,8 +224,21 @@ const ColorComponent = () => {
)} -
- ); -}; -export default ColorComponent; +
+ +
+
+ + +
+ ) +} + +export default ColorComponent + diff --git a/src/components/Context/canvasContext/CanvasContextProvider.jsx b/src/components/Context/canvasContext/CanvasContextProvider.jsx index 8bc708e..ac5a125 100644 --- a/src/components/Context/canvasContext/CanvasContextProvider.jsx +++ b/src/components/Context/canvasContext/CanvasContextProvider.jsx @@ -6,10 +6,11 @@ const CanvasContextProvider = ({ children }) => { const [canvas, setCanvas] = useState(null); const [canvasHeight, setCanvasHeight] = useState(0); const [canvasWidth, setCanvasWidth] = useState(0); + const [screenWidth, setScreenWidth] = useState(0); const fabricCanvasRef = useRef(null); return ( - + {children} ) diff --git a/src/components/Context/colorContext/ColorContextProvider.jsx b/src/components/Context/colorContext/ColorContextProvider.jsx index 9fc8567..ef4ae2e 100644 --- a/src/components/Context/colorContext/ColorContextProvider.jsx +++ b/src/components/Context/colorContext/ColorContextProvider.jsx @@ -3,7 +3,7 @@ import ColorContext from './ColorContext' const ColorContextProvider = ({ children }) => { const [backgroundType, setBackgroundType] = useState("color"); // 'color' or 'gradient' - const [solidColor, setSolidColor] = useState("#ffffff"); + const [solidColor, setSolidColor] = useState("#FFA500"); const [gradientColors, setGradientColors] = useState({ color1: "#ffffff", color2: "#e26286", diff --git a/src/components/EachComponent/Customization/CollapsibleComponent.jsx b/src/components/EachComponent/Customization/CollapsibleComponent.jsx index 43a48eb..80e6c60 100644 --- a/src/components/EachComponent/Customization/CollapsibleComponent.jsx +++ b/src/components/EachComponent/Customization/CollapsibleComponent.jsx @@ -1,10 +1,21 @@ import { Button } from "@/components/ui/button"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; import { ChevronUp, ChevronDown } from "lucide-react"; -import { useState } from "react"; +import { useEffect, useState } from "react"; const CollapsibleComponent = ({ children, text }) => { - const [isOpen, setIsOpen] = useState(true); + const [isOpen, setIsOpen] = useState(null); + + useEffect(() => { + // Check if the text prop is "Canvas Setting" and set isOpen to false + if (text === "Canvas Setting") { + setIsOpen(false); + } + else { + setIsOpen(true) + } + }, [text]) + return ( diff --git a/src/components/EachComponent/Icons/AllIcons.jsx b/src/components/EachComponent/Icons/AllIcons.jsx index ae7d45f..c08e5d6 100644 --- a/src/components/EachComponent/Icons/AllIcons.jsx +++ b/src/components/EachComponent/Icons/AllIcons.jsx @@ -114,11 +114,11 @@ const AllIconsPage = () => { onChange={handleSearch} className="border p-2 mb-0 w-full" /> - + { - const activeObjects = canvas.getActiveObjects(); // Get selected objects - if (activeObjects.length > 1) { - - canvas.discardActiveObject(); - - const group = new fabric.Group(activeObjects, { - left: canvas?.width / 2, - top: canvas?.height / 2, - originX: "center", - originY: "center", - selectable: true, // Allow group selection - subTargetCheck: true, // Allow individual object selection - hasControls: true, // Enable resizing/movement of the group - }) - canvas.remove(...activeObjects); - canvas.add(group); - canvas.setActiveObject(group); - setActiveObject(group); - canvas.renderAll(); - } else { - console.log("Select at least two objects") - } - }; - - const ungroupSelectedObjects = () => { - const activeObject = canvas.getActiveObject(); - if (activeObject && activeObject.type === "group") { - // Get the group - const group = activeObject; - canvas.discardActiveObject(); - // Remove the group from the canvas - canvas.remove(group); - setActiveObject(null); - - // Iterate through each object in the group - group._objects.forEach((object) => { - // Calculate the absolute position based on the group's transformation - const objLeft = object.left * group.scaleX + group.left; - const objTop = object.top * group.scaleY + group.top; - - // Reset transformations and positions - object.set({ - left: objLeft, - top: objTop, - scaleX: object.scaleX * group.scaleX, // Adjust scale based on group - scaleY: object.scaleY * group.scaleY, // Adjust scale based on group - angle: object.angle + group.angle, // Adjust rotation - hasControls: true, // Allow resizing - selectable: true, // Make selectable - group: null, // Remove group reference - originX: "center", - originY: "center", - }); - - // Update coordinates - object.setCoords(); - - // Add the object back to the canvas - canvas.add(object); - }); - - // Clear the selection - canvas.discardActiveObject(); - - // Render the canvas to reflect changes - canvas.renderAll(); - } - }; - - // Bring Selected Object to Front - const bringToFront = () => { - if (activeObject) { - activeObject.bringToFront(); - canvas.renderAll(); - } - }; - - // Remove Selected Element - const removeSelected = useCallback(() => { - const activeObject = canvas?.getActiveObject(); - - const allObjects = canvas?.getObjects(); - - const textObjects = allObjects.filter((obj) => obj.type === 'textbox' || obj.type === 'text' || - obj.type === 'i-text'); - - if (activeObject) { - canvas.remove(activeObject); - setActiveObject(null); - } - if (activeObject && textObjects?.length === 1) { - canvas.remove(activeObject); - setActiveObject(null); - } - if (activeObject.length > 1) { - canvas.remove(...activeObject); - setActiveObject(null); - } - }, [canvas, setActiveObject]); + const { setActiveObject } = useContext(ActiveObjectContext); const saveCanvasState = () => { // Get the JSON representation of all objects @@ -155,17 +55,6 @@ export function EditPanel() { // loadCanvasState(canvasState); }; - // duplicating current objects - const duplicating = () => { - // Clone the active object to create a true deep copy - activeObject.clone((clonedObject) => { - // Add the cloned object to the canvas - clonedObject.set("left", clonedObject?.left + 30) - canvas.add(clonedObject); - canvas.renderAll(); - }); - } - // for clear canvas const clearCanvas = () => { canvas.clear(); @@ -227,57 +116,7 @@ export function EditPanel() { - -
- } - label="Group" - onClick={groupSelectedObjects} - tooltipContent={ -
-

Group selected objects

-

To select multiple objects:

-
    -
  1. Hold down the Shift key
  2. -
  3. Click and drag with the left mouse button to select objects
  4. -
  5. Release the Shift key and mouse button
  6. -
-

Then click this button to group the selected objects.

-
- } - /> - } - label="Ungroup" - onClick={ungroupSelectedObjects} - tooltipContent="Ungroup selected objects" - /> - } - label="Duplicate" - onClick={duplicating} - tooltipContent="Duplicate selected objects" - /> - } - label="To Front" - onClick={bringToFront} - tooltipContent="Bring selected objects to front" - /> - } - label="Move" - onClick={() => { }} - tooltipContent="Move selected objects" - /> - } - label="Remove" - onClick={removeSelected} - tooltipContent="Remove selected objects" - /> -
-
+
@@ -343,12 +182,14 @@ export function EditPanel() { onClick={saveCanvasState} tooltipContent="Save current canvas state" /> - } - label="Settings" - onClick={() => setOpenSetting(true)} - tooltipContent="Open canvas settings" - /> +
+ } + label="Settings" + onClick={() => setOpenSetting(true)} + tooltipContent="Open canvas settings" + /> +
} label="Clear" diff --git a/src/components/Layouts/RndComponent.jsx b/src/components/Layouts/RndComponent.jsx index 4e7f609..6b15cc7 100644 --- a/src/components/Layouts/RndComponent.jsx +++ b/src/components/Layouts/RndComponent.jsx @@ -10,7 +10,7 @@ const RndComponent = ({ children, value }) => { x: valueX, y: valueY, width: width, - height: 'auto', + height: height, }} minWidth={minWidth} maxWidth={maxWidth} diff --git a/src/components/Layouts/SheetLeftPanel.jsx b/src/components/Layouts/SheetLeftPanel.jsx index 3d8dadc..63d09ce 100644 --- a/src/components/Layouts/SheetLeftPanel.jsx +++ b/src/components/Layouts/SheetLeftPanel.jsx @@ -59,7 +59,7 @@ const SheetLeftPanel = () => { - + @@ -67,7 +67,7 @@ const SheetLeftPanel = () => { - + diff --git a/src/components/Layouts/SheetRightPanel.jsx b/src/components/Layouts/SheetRightPanel.jsx index ed89a59..9615e2e 100644 --- a/src/components/Layouts/SheetRightPanel.jsx +++ b/src/components/Layouts/SheetRightPanel.jsx @@ -12,6 +12,9 @@ import { X } from "lucide-react"; import { useContext, useEffect, useState } from "react"; import ActiveObjectContext from "../Context/activeObject/ObjectContext"; import OpenContext from "../Context/openContext/OpenContext"; +import CanvasSetting from "../CanvasSetting"; +import CollapsibleComponent from "../EachComponent/Customization/CollapsibleComponent"; +import { Card } from "../ui/card"; const SheetRightPanel = () => { const { rightPanelOpen, setRightPanelOpen } = useContext(OpenContext) @@ -43,7 +46,7 @@ const SheetRightPanel = () => { return ( - + Edit Customization @@ -52,16 +55,30 @@ const SheetRightPanel = () => { - + Customize each shapes, and text as per your choice. -
- - { - open ? :

No active object found

- } + + + +
+
+ + +
+ +
+
+
+
+
+ + { + open ? :

No active object found

+ } +
diff --git a/src/components/ObjectPanel.jsx b/src/components/ObjectPanel.jsx index 92114fe..782b4f4 100644 --- a/src/components/ObjectPanel.jsx +++ b/src/components/ObjectPanel.jsx @@ -22,7 +22,7 @@ const ObjectPanel = () => { valueY: 20, width: 250, height: 0, - minWidth: 250, + minWidth: 280, maxWidth: 300, minHeight: 0, maxHeight: 500, @@ -31,7 +31,7 @@ const ObjectPanel = () => { return ( - +
@@ -48,7 +48,7 @@ const ObjectPanel = () => { - +
setTabValue(value)} // Sync tab state with context @@ -101,18 +101,18 @@ const ObjectPanel = () => { {/* All shapes */} - +
Shapes - +
{/* Upload images */} - +
Upload @@ -120,23 +120,23 @@ const ObjectPanel = () => { - +
{/* Customization */} - +
Object customization - +
- +
diff --git a/src/components/ObjectShortcut.jsx b/src/components/ObjectShortcut.jsx new file mode 100644 index 0000000..e879438 --- /dev/null +++ b/src/components/ObjectShortcut.jsx @@ -0,0 +1,211 @@ +import { useCallback, useContext } from 'react' +import CanvasContext from './Context/canvasContext/CanvasContext'; +import ActiveObjectContext from './Context/activeObject/ObjectContext'; +import { fabric } from 'fabric'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './ui/tooltip'; +import { Button } from './ui/button'; +import { BringToFront, CopyPlus, GroupIcon, SquareX, Trash2, UngroupIcon } from 'lucide-react'; + +export const ObjectShortcut = ({ value }) => { + const { canvas } = useContext(CanvasContext); + const { setActiveObject, activeObject } = useContext(ActiveObjectContext); + + const groupSelectedObjects = () => { + const activeObjects = canvas.getActiveObjects(); // Get selected objects + if (activeObjects.length > 1) { + + canvas.discardActiveObject(); + + const group = new fabric.Group(activeObjects, { + left: canvas?.width / 2, + top: canvas?.height / 2, + originX: "center", + originY: "center", + selectable: true, // Allow group selection + subTargetCheck: true, // Allow individual object selection + hasControls: true, // Enable resizing/movement of the group + }) + canvas.remove(...activeObjects); + canvas.add(group); + canvas.setActiveObject(group); + setActiveObject(group); + canvas.renderAll(); + } else { + console.log("Select at least two objects") + } + }; + + const ungroupSelectedObjects = () => { + const activeObject = canvas.getActiveObject(); + if (activeObject && activeObject.type === "group") { + // Get the group + const group = activeObject; + canvas.discardActiveObject(); + // Remove the group from the canvas + canvas.remove(group); + setActiveObject(null); + + // Iterate through each object in the group + group._objects.forEach((object) => { + // Calculate the absolute position based on the group's transformation + const objLeft = object.left * group.scaleX + group.left; + const objTop = object.top * group.scaleY + group.top; + + // Reset transformations and positions + object.set({ + left: objLeft, + top: objTop, + scaleX: object.scaleX * group.scaleX, // Adjust scale based on group + scaleY: object.scaleY * group.scaleY, // Adjust scale based on group + angle: object.angle + group.angle, // Adjust rotation + hasControls: true, // Allow resizing + selectable: true, // Make selectable + group: null, // Remove group reference + originX: "center", + originY: "center", + }); + + // Update coordinates + object.setCoords(); + + // Add the object back to the canvas + canvas.add(object); + }); + + // Clear the selection + canvas.discardActiveObject(); + + // Render the canvas to reflect changes + canvas.renderAll(); + } + }; + + // Bring Selected Object to Front + const bringToFront = () => { + if (activeObject) { + activeObject.bringToFront(); + canvas.renderAll(); + } + }; + + // Remove Selected Element + const removeSelected = useCallback(() => { + const activeObject = canvas?.getActiveObject(); + + const allObjects = canvas?.getObjects(); + + const textObjects = allObjects.filter((obj) => obj.type === 'textbox' || obj.type === 'text' || + obj.type === 'i-text'); + + if (activeObject) { + canvas.remove(activeObject); + setActiveObject(null); + } + if (activeObject && textObjects?.length === 1) { + canvas.remove(activeObject); + setActiveObject(null); + } + if (activeObject.length > 1) { + canvas.remove(...activeObject); + setActiveObject(null); + } + }, [canvas, setActiveObject]); + + // duplicating current objects + const duplicating = () => { + // Clone the active object to create a true deep copy + activeObject.clone((clonedObject) => { + // Add the cloned object to the canvas + clonedObject.set("left", clonedObject?.left + 30) + canvas.add(clonedObject); + canvas.renderAll(); + }); + } + + // for clear canvas + const clearCanvas = () => { + canvas.clear(); + canvas.renderAll(); + setActiveObject(null); + } + + return ( +
+ +
+ } + label="Group" + onClick={groupSelectedObjects} + tooltipContent={ +
+

Group selected objects

+

To select multiple objects:

+
    +
  1. Hold down the Shift key
  2. +
  3. Click and drag with the left mouse button to select objects
  4. +
  5. Release the Shift key and mouse button
  6. +
+

Then click this button to group the selected objects.

+
+ } + /> + + } + label="Ungroup" + onClick={ungroupSelectedObjects} + tooltipContent="Ungroup selected objects" + /> + + } + label="Duplicate" + onClick={duplicating} + tooltipContent="Duplicate selected objects" + /> + + } + label="To Front" + onClick={bringToFront} + tooltipContent="Bring selected objects to front" + /> + + } + label="Remove" + onClick={removeSelected} + tooltipContent="Remove selected objects" + /> + + } + label="Clear" + onClick={clearCanvas} + tooltipContent="Clear entire canvas" + /> +
+
+
+ ) +} + + +function ActionButton({ icon, label, onClick, tooltipContent }) { + return ( + + + + + +

{tooltipContent}

+
+
+ ) +}