diff --git a/src/components/HomePage.jsx b/src/components/HomePage.jsx index 55120fc..239afdb 100644 --- a/src/components/HomePage.jsx +++ b/src/components/HomePage.jsx @@ -158,7 +158,7 @@ const HomePage = () => {
{/* Header */} -
+
{/* Main Content */}
diff --git a/src/components/KonvaDrawingBoard.jsx b/src/components/KonvaDrawingBoard.jsx index 675a4c9..d1bc89a 100644 --- a/src/components/KonvaDrawingBoard.jsx +++ b/src/components/KonvaDrawingBoard.jsx @@ -9,12 +9,19 @@ import { MousePointerClick, Save, } from "lucide-react"; +import PenOptions from "./PenOptions"; -const DEFAULT_STROKE_COLOR = 'white'; +const DEFAULT_STROKE_COLOR = "white"; const DEFAULT_STROKE_WIDTH = 5; const ERASER_STROKE_WIDTH = 20; -function KonvaDrawingBoard({ initialStrokes, onSaveStroke, onSaveAllBoardContent, boardId, onClearAllStrokes }) { +function KonvaDrawingBoard({ + initialStrokes, + onSaveStroke, + onSaveAllBoardContent, + boardId, + onClearAllStrokes, +}) { const stageRef = useRef(null); const containerRef = useRef(null); const [tool, setTool] = useState("pen"); @@ -23,7 +30,9 @@ function KonvaDrawingBoard({ initialStrokes, onSaveStroke, onSaveAllBoardContent const [stagePos, setStagePos] = useState({ x: 0, y: 0 }); const [stageScale, setStageScale] = useState(1); const [containerSize, setContainerSize] = useState({ width: 0, height: 0 }); - + const [toolOptions, setToolOptions] = useState(false); + const [penColor, setPenColor] = useState("white"); + const [penSize, setPenSize] = useState(5); // --- Resizing the Stage when container size changes --- const checkSize = useCallback(() => { if (containerRef.current) { @@ -36,17 +45,17 @@ function KonvaDrawingBoard({ initialStrokes, onSaveStroke, onSaveAllBoardContent useEffect(() => { checkSize(); - window.addEventListener('resize', checkSize); - return () => window.removeEventListener('resize', checkSize); + window.addEventListener("resize", checkSize); + return () => window.removeEventListener("resize", checkSize); }, [checkSize]); // --- Load initial strokes --- useEffect(() => { const loadedLines = (initialStrokes || []) - .filter(s => s.points && s.points.length > 0) - .map(s => ({ + .filter((s) => s.points && s.points.length > 0) + .map((s) => ({ id: s.id, - points: typeof s.points === 'string' ? JSON.parse(s.points) : s.points, + points: typeof s.points === "string" ? JSON.parse(s.points) : s.points, tool: s.tool || "pen", color: s.color || DEFAULT_STROKE_COLOR, strokeWidth: s.strokeWidth || DEFAULT_STROKE_WIDTH, @@ -55,46 +64,55 @@ function KonvaDrawingBoard({ initialStrokes, onSaveStroke, onSaveAllBoardContent }, [initialStrokes]); // --- Drawing Event Handlers --- - const handleMouseDown = useCallback((e) => { - if (tool === "pan" || tool === "pointer") return; - setIsDrawing(true); - const stage = e.target.getStage(); - const pos = stage.getPointerPosition(); - - //convert screen coordinates into stage coordinates - const transform = stage.getAbsoluteTransform().copy(); - transform.invert(); - const relativePos = transform.point(pos); - setLines((prevLines) => [ - ...prevLines, - { - tool, - color: tool === "eraser" ? "black" : DEFAULT_STROKE_COLOR, - strokeWidth: tool === "eraser" ? ERASER_STROKE_WIDTH : DEFAULT_STROKE_WIDTH, - points: [relativePos.x, relativePos.y], - id: Date.now() + Math.random(), - }, - ]); - }, [tool]); - - const handleMouseMove = useCallback((e) => { - if (!isDrawing || tool === "pan" || tool === "pointer") return; - const stage = stageRef.current; - const point = stage.getPointerPosition(); - - //convert screen coordinates into stage coordinates - const transform = stage.getAbsoluteTransform().copy(); - transform.invert(); - const relativePos = transform.point(point); - - setLines((prevLines) => { - const lastLine = { ...prevLines[prevLines.length - 1] }; - lastLine.points = lastLine.points.concat([relativePos.x, relativePos.y]); - const newLines = [...prevLines]; - newLines[newLines.length - 1] = lastLine; - return newLines; - }); - }, [isDrawing, tool]); + const handleMouseDown = useCallback( + (e) => { + if (tool === "pan" || tool === "pointer") return; + setIsDrawing(true); + const stage = e.target.getStage(); + const pos = stage.getPointerPosition(); + + //convert screen coordinates into stage coordinates + const transform = stage.getAbsoluteTransform().copy(); + transform.invert(); + const relativePos = transform.point(pos); + setLines((prevLines) => [ + ...prevLines, + { + tool, + color: tool === "eraser" ? "black" : penColor, + strokeWidth: tool === "eraser" ? ERASER_STROKE_WIDTH : penSize, + points: [relativePos.x, relativePos.y], + id: Date.now() + Math.random(), + }, + ]); + }, + [tool] + ); + + const handleMouseMove = useCallback( + (e) => { + if (!isDrawing || tool === "pan" || tool === "pointer") return; + const stage = stageRef.current; + const point = stage.getPointerPosition(); + + //convert screen coordinates into stage coordinates + const transform = stage.getAbsoluteTransform().copy(); + transform.invert(); + const relativePos = transform.point(point); + + setLines((prevLines) => { + const lastLine = { ...prevLines[prevLines.length - 1] }; + lastLine.points = lastLine.points.concat([ + relativePos.x, + relativePos.y, + ]); + const newLines = [...prevLines]; + newLines[newLines.length - 1] = lastLine; + return newLines; + }); + }, + [isDrawing, tool] + ); const handleMouseUp = useCallback(async () => { setIsDrawing(false); @@ -114,17 +132,21 @@ function KonvaDrawingBoard({ initialStrokes, onSaveStroke, onSaveAllBoardContent // --- Explicit Save Handler --- const handleExplicitSave = useCallback(() => { - if (onSaveAllBoardContent) { - onSaveAllBoardContent(boardId, lines); - alert("All changes saved!"); - } else { - alert("Save feature not fully connected. Check console."); - } + if (onSaveAllBoardContent) { + onSaveAllBoardContent(boardId, lines); + alert("All changes saved!"); + } else { + alert("Save feature not fully connected. Check console."); + } }, [onSaveAllBoardContent, boardId, lines]); // --- Clear Canvas Function --- const clearCanvas = useCallback(async () => { - if (window.confirm("Are you sure you want to clear the entire canvas? This action cannot be undone.")) { + if ( + window.confirm( + "Are you sure you want to clear the entire canvas? This action cannot be undone." + ) + ) { setLines([]); // Clear locally first for immediate feedback await onClearAllStrokes(boardId); alert("Canvas cleared permanently!"); @@ -132,7 +154,8 @@ function KonvaDrawingBoard({ initialStrokes, onSaveStroke, onSaveAllBoardContent }, [boardId, onClearAllStrokes]); // --- View Control Handlers (MOVED HERE) --- - const handleWheel = useCallback((e) => { // <--- MOVED AND WRAPPED IN useCallback + const handleWheel = useCallback((e) => { + // <--- MOVED AND WRAPPED IN useCallback e.evt.preventDefault(); const stage = stageRef.current; if (!stage) return; @@ -157,31 +180,84 @@ function KonvaDrawingBoard({ initialStrokes, onSaveStroke, onSaveAllBoardContent }); }, []); // No external dependencies, stageRef is ref - const handleDragEnd = useCallback((e) => { // <--- MOVED AND WRAPPED IN useCallback + const handleDragEnd = useCallback((e) => { + // <--- MOVED AND WRAPPED IN useCallback setStagePos({ x: e.target.x(), y: e.target.y(), }); }, []); - const resetView = useCallback(() => { // <--- MOVED AND WRAPPED IN useCallback + const resetView = useCallback(() => { + // <--- MOVED AND WRAPPED IN useCallback setStagePos({ x: 0, y: 0 }); setStageScale(1); }, []); + const handleToolClick = (toolName) => { + if (tool !== toolName) { + setTool(toolName); + setToolOptions(false); + } else if (tool === toolName) { + setToolOptions(!toolOptions); + } + }; return (
{/* Toolbar */}
- - - - + + + +
- +
- +
+ {toolOptions && tool == "pen" && ( +
+ +
+ )} + {/* Canvas Area */}
{lines.map((line) => ( @@ -238,4 +333,4 @@ function KonvaDrawingBoard({ initialStrokes, onSaveStroke, onSaveAllBoardContent ); } -export default KonvaDrawingBoard; \ No newline at end of file +export default KonvaDrawingBoard; diff --git a/src/components/PenOptions.jsx b/src/components/PenOptions.jsx new file mode 100644 index 0000000..39fd6ba --- /dev/null +++ b/src/components/PenOptions.jsx @@ -0,0 +1,93 @@ + // src/components/KonvaDrawingBoard.jsx + import React, { useState, useRef, useEffect, useCallback } from "react"; + import { Stage, Layer, Line, Rect } from "react-konva"; + import { + Pencil, + Eraser, + Move, + RotateCcw, + MousePointerClick, + Save, + } from "lucide-react"; + + function PenOptions({currentColor, currentSize, onColorChange, onSizeChange}) { + const colors = [ + { name: "White", value: "#ffffff" }, + { name: "Black", value: "#000000" }, + { name: "Red", value: "#ef4444" }, + { name: "Blue", value: "#3b82f6" }, + { name: "Green", value: "#22c55e" }, + { name: "Yellow", value: "#eab308" }, + { name: "Purple", value: "#a855f7" }, + { name: "Orange", value: "#f97316" }, + { name: "Pink", value: "#ec4899" }, + { name: "Cyan", value: "#06b6d4" }, + ]; + + const brushSizes = [ + { name: "Extra Small", value: 2 }, + { name: "Small", value: 5 }, + { name: "Medium", value: 10 }, + { name: "Large", value: 15 }, + { name: "Extra Large", value: 20 }, + { name: "Huge", value: 30 }, + ]; + + return ( +
+

Pen Options

+ + {/* Color Selection */} +
+

Color:

+
+ {colors.map(color => ( +
+
+ + {/* Brush Size Selection */} +
+

Brush Size:

+
+ {brushSizes.map(size => ( + + ))} +
+
+
+ ); + } + + export default PenOptions;