An interactive canvas where users can draw, express, and bring their ideas to life with every stroke.
import React from "react";
import { FaBrush, FaEraser, FaUndo, FaMinus, FaPlus } from "react-icons/fa";
interface ToolBarProps {
activeTool: "draw" | "erase";
onToolClick: (tool: "draw" | "erase") => void;
onClear: () => void;
brushSize: number;
onBrushSizeChange: (size: number) => void;
}
export const ToolBar: React.FC<ToolBarProps> = ({
activeTool,
onToolClick,
onClear,
brushSize,
onBrushSizeChange
}) => {
return (
<div className="bg-gray-50 rounded-xl p-4 space-y-4 border border-gray-200">
<h3 className="font-semibold text-gray-800 text-center mb-4 -ml-6">��️ Tools</h3>
<div className="space-y-2">
<button
onClick={() => onToolClick("draw")}
className={`w-full flex items-center justify-center gap-2 h-12 px-4 rounded-lg border
${activeTool === "draw" ? "bg-blue-500 text-white" : "bg-white
text-gray-700 border-gray-300 hover:bg-gray-100"}`}>
<FaBrush />
Brush
</button>
<button
onClick={() => onToolClick("erase")}
className={`w-full flex items-center justify-center gap-2 h-12 px-4 rounded-lg border
${activeTool === "erase" ? "bg-blue-500 text-white" : "bg-white text-gray-700
border-gray-300 hover:bg-gray-100"}`}>
<FaEraser />
Eraser
</button>
</div>
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm font-medium text-gray-700">Brush Size</span>
<span className="text-sm text-gray-500">{brushSize}px</span>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => onBrushSizeChange(Math.max(1, brushSize - 1))}
disabled={brushSize <= 1}
className="p-2 rounded-lg border bg-gray-200 hover:bg-gray-300
disabled:opacity-50">
<FaMinus />
</button>
<input
type="range"
value={brushSize}
onChange={(e) => onBrushSizeChange(parseInt(e.target.value))}
min={1}
max={20}
step={1}
className="flex-1"/>
<button
onClick={() => onBrushSizeChange(Math.min(20, brushSize + 1))}
disabled={brushSize >= 20}
className="p-2 rounded-lg border bg-gray-200 hover:bg-gray-3 disabled:opacity-50">
<FaPlus />
</button>
</div>
</div>
<button
onClick={onClear}
className="w-full flex items-center justify-center gap-3 h-12 px-2
rounded-lg bg-red-500 text-white hover:bg-red-600">
<FaUndo />
Clear Canvas
</button>
</div>
);
};
import { useState } from "react";
interface ColorPickerProps {
color: string;
onChange: (color: string) => void;
}
export const ColorPicker: React.FC<ColorPickerProps> = ({ color, onChange }) => {
const [customColor, setCustomColor] = useState<string>(color);
const predefinedColors: string[] = [
"#000000",
"#FF0000",
"#00FF00",
"#0000FF",
"#FFFF00",
"#FF00FF",
"#00FFFF",
"#FFA500",
"#800080",
"#FFC0CB",
"#A52A2A",
"#808080",
"#FFE4E1",
"#98FB98",
"#87CEEB",
"#DDA0DD",
];
const handleColorClick = (selectedColor: string) => {
onChange(selectedColor);
setCustomColor(selectedColor);
};
const handleCustomColorChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newColor = e.target.value;
setCustomColor(newColor);
onChange(newColor);
};
return (
<div className="bg-gray-50 rounded-xl p-4 border
border-gray-200 sm:p-3 sm:rounded-lg sm:max-w-xs sm:mx-auto">
<h3 className="font-semibold text-gray-800 text-center mb-4 sm:text-base -ml-6">�� Colors</h3>
<div className="mb-4 text-center">
<div
className="w-12 h-12 rounded-full border-4 border-white shadow-lg mx-auto mb-2"
style={{ backgroundColor: color }}/>
<span className="text-sm text-gray-600">Current Color</span>
</div>
<div className="grid grid-cols-4 gap-2 mb-4 sm:gap-1 justify-items-center">
{predefinedColors.map((predefinedColor) => (
<button
key={predefinedColor}
onClick={() => handleColorClick(predefinedColor)}
className={`w-12 h-12 sm:w-9 sm:h-9 rounded-lg border-2 transition-all hover:scale-110
${color === predefinedColor ? "border-gray-800 shadow-lg" : "border-gray-300
hover:border-gray-500"}`}
style={{ backgroundColor: predefinedColor }}/>
))}
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700 ml-2">Custom Color</label>
<div className="flex justify-evenly gap-2 mt-1">
<input
type="color"
value={customColor}
onChange={handleCustomColorChange}
className="w-12 h-10 rounded-md border border-gray-300 p-1"/>
<input
type="text"
value={customColor}
onChange={handleCustomColorChange}
placeholder="#FFFFFF"
className="h-10 text-sm border border-gray-300 rounded-md px-2 w-[120px]"/>
</div>
</div>
</div>
);
};
App.jsx