diff --git a/src/components/DropArea.tsx b/src/components/DropArea.tsx index 8afcb06..1a3a7e3 100644 --- a/src/components/DropArea.tsx +++ b/src/components/DropArea.tsx @@ -1,9 +1,9 @@ 'use client' -import React, { useState, useRef, useCallback } from 'react' +import React, { useState, useRef, useCallback, useEffect } from 'react' import { useDrop } from 'react-dnd' -import { DraggableItem } from './DraggableItem' -import { useElements } from '../context/ElementsContext' +import { DraggableItem } from './DraggableItem'; +import { useElements } from '../context/ElementsContext'; interface Item { id: string @@ -34,11 +34,110 @@ const mergeElements = async (type1: string, type2: string) => { } } -const DropArea: React.FC = () => { +const DropArea = () => { const [items, setItems] = useState([]) const [maxZIndex, setMaxZIndex] = useState(0) const dropAreaRef = useRef(null) - const { addElement } = useElements() + const canvasRef = useRef(null) + + // Canvas animation logic + useEffect(() => { + const canvas = canvasRef.current + if (!canvas) return + + const ctx = canvas.getContext('2d') + if (!ctx) return + + let animationFrameId: number + let width: number + let height: number + + const dots: any[] = [] + const numDots = 150 + const dotSizeRange = { min: 1, max: 3 } + const moveSpeed = 0.15 + + class Dot { + x: number + y: number + size: number + vx: number + vy: number + opacity: number + + constructor() { + this.x = Math.random() * width + this.y = Math.random() * height + this.size = Math.random() * (dotSizeRange.max - dotSizeRange.min) + dotSizeRange.min + this.vx = (Math.random() - 0.5) * moveSpeed + this.vy = (Math.random() - 0.5) * moveSpeed + this.opacity = Math.random() * 0.5 + 0.1 + } + + update() { + this.x += this.vx + this.y += this.vy + + if (this.x < 0 || this.x > width) this.vx *= -1 + if (this.y < 0 || this.y > height) this.vy *= -1 + } + + draw() { + if (!ctx) return + ctx.beginPath() + ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2) + ctx.fillStyle = `rgba(200, 200, 200, ${this.opacity})` + ctx.fill() + } + } + + function initDots() { + const gridSize = Math.sqrt(numDots) + const cellWidth = width / gridSize + const cellHeight = height / gridSize + + for (let i = 0; i < numDots; i++) { + const dot = new Dot() + const gridX = i % gridSize + const gridY = Math.floor(i / gridSize) + + dot.x = (gridX + Math.random()) * cellWidth + dot.y = (gridY + Math.random()) * cellHeight + + dots.push(dot) + } + } + + function resizeCanvas() { + width = window.innerWidth + height = window.innerHeight + canvas.width = width + canvas.height = height + dots.length = 0 + initDots() + } + + function animate() { + ctx.clearRect(0, 0, width, height) + + dots.forEach(dot => { + dot.update() + dot.draw() + }) + + animationFrameId = requestAnimationFrame(animate) + } + + resizeCanvas() + animate() + + window.addEventListener('resize', resizeCanvas) + + return () => { + window.removeEventListener('resize', resizeCanvas) + cancelAnimationFrame(animationFrameId) + } + }, []) const moveItem = useCallback((id: string, left: number, top: number) => { setItems((prevItems) => { @@ -53,15 +152,13 @@ const DropArea: React.FC = () => { const mergeItems = useCallback(async (item1: Item, item2: Item) => { const result = await mergeElements(item1.type, item2.type) if (result) { - // Add the new element type to the sidebar - addElement(result.type, result.emoji) return { ...item1, type: result.type } } return item1 - }, [addElement]) + }, []) const [, drop] = useDrop(() => ({ accept: ['item', 'new-item'], @@ -85,7 +182,6 @@ const DropArea: React.FC = () => { if (targetItem) { const mergedItem = await mergeItems(item, targetItem) setItems(prevItems => { - // Remove both original items and add the merged item const filteredItems = prevItems.filter(i => i.id !== item.id && i.id !== targetItem.id) return [...filteredItems, { ...mergedItem, @@ -118,7 +214,6 @@ const DropArea: React.FC = () => { if (targetItem) { const mergedItem = await mergeItems(newItem, targetItem) setItems(prevItems => { - // Remove the original item and add the merged item const filteredItems = prevItems.filter(i => i.id !== targetItem.id) return [...filteredItems, { ...mergedItem, @@ -137,27 +232,34 @@ const DropArea: React.FC = () => { }), [moveItem, maxZIndex, items, mergeItems]) return ( -
{ - drop(node) - dropAreaRef.current = node - }} - className="w-full h-full relative bg-white" - > - {items.map((item) => ( - - ))} +
+
) } -export default DropArea - +export default DropArea \ No newline at end of file