feat: implement Phase 10 - Shape Tools

Add comprehensive shape drawing system with support for 7 shape types:
rectangle, ellipse, line, arrow, polygon, star, and triangle.

Features:
- Created types/shape.ts with ShapeType and ShapeSettings interfaces
- Implemented lib/shape-utils.ts with drawing algorithms for all shapes:
  * Rectangle with optional corner radius
  * Ellipse with independent x/y radii
  * Line with stroke support
  * Arrow with configurable head size and angle
  * Polygon with adjustable sides (3-20)
  * Star with points and inner radius control
  * Triangle (equilateral style)
- Created store/shape-store.ts for shape state management
- Implemented tools/shape-tool.ts as unified tool handling all shapes
- Built components/shapes/shape-panel.tsx with comprehensive UI:
  * Grid selector for all 7 shape types
  * Fill/stroke toggles with color pickers
  * Dynamic properties panel (corner radius, sides, inner radius, etc.)
  * Real-time stroke width adjustment
- Integrated ShapeTool into canvas-with-tools.tsx
- Added ShapePanel to editor-layout.tsx sidebar
- Removed duplicate ShapeType/ShapeSettings from types/tool.ts

All shapes support:
- Fill with color selection
- Stroke with color and width controls
- Shape-specific properties (corners, sides, arrow heads, etc.)
- Undo/redo via DrawCommand integration

Build Status: ✓ Successful (1290ms)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-21 02:43:15 +01:00
parent 1d82f60182
commit 89a845feb3
12 changed files with 866 additions and 26 deletions

View File

@@ -19,6 +19,7 @@ import {
MagicWandTool,
MoveTool,
FreeTransformTool,
ShapeTool,
type BaseTool,
} from '@/tools';
import type { PointerState } from '@/types';
@@ -38,6 +39,7 @@ const tools: Record<string, BaseTool> = {
'magic-wand': new MagicWandTool(),
move: new MoveTool(),
transform: new FreeTransformTool(),
shape: new ShapeTool(),
};
export function CanvasWithTools() {
@@ -224,7 +226,7 @@ export function CanvasWithTools() {
}
// Drawing tools
if (e.button === 0 && !e.shiftKey && ['pencil', 'brush', 'eraser', 'fill', 'eyedropper'].includes(activeTool)) {
if (e.button === 0 && !e.shiftKey && ['pencil', 'brush', 'eraser', 'fill', 'eyedropper', 'shape'].includes(activeTool)) {
const activeLayer = getActiveLayer();
if (!activeLayer || !activeLayer.canvas || activeLayer.locked) return;
@@ -267,7 +269,7 @@ export function CanvasWithTools() {
}
// Drawing
if (pointer.isDown && ['pencil', 'brush', 'eraser', 'eyedropper'].includes(activeTool)) {
if (pointer.isDown && ['pencil', 'brush', 'eraser', 'eyedropper', 'shape'].includes(activeTool)) {
const activeLayer = getActiveLayer();
if (!activeLayer || !activeLayer.canvas) return;
@@ -294,7 +296,7 @@ export function CanvasWithTools() {
return;
}
if (pointer.isDown && ['pencil', 'brush', 'eraser', 'fill', 'eyedropper'].includes(activeTool)) {
if (pointer.isDown && ['pencil', 'brush', 'eraser', 'fill', 'eyedropper', 'shape'].includes(activeTool)) {
const activeLayer = getActiveLayer();
if (!activeLayer || !activeLayer.canvas) return;