import React, { useState, useEffect, useRef } from 'react'; import { Palette, Eraser, Trash2, Download, Users } from 'lucide-react'; export default function CollaborativeWhiteboard() { const canvasRef = useRef(null); const [isDrawing, setIsDrawing] = useState(false); const [color, setColor] = useState('#000000'); const [brushSize, setBrushSize] = useState(3); const [tool, setTool] = useState('pen'); const [activeUsers, setActiveUsers] = useState(1); const [loading, setLoading] = useState(true); const colors = ['#000000', '#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#FF00FF', '#00FFFF', '#FFA500']; useEffect(() => { loadCanvas(); const interval = setInterval(loadCanvas, 1000); return () => clearInterval(interval); }, []); const loadCanvas = async () => { try { const result = await window.storage.get('whiteboard-data', true); if (result && result.value) { const data = JSON.parse(result.value); const canvas = canvasRef.current; const ctx = canvas.getContext('2d'); const img = new Image(); img.onload = () => { ctx.drawImage(img, 0, 0); setLoading(false); }; img.src = data.imageData; if (data.userCount) { setActiveUsers(data.userCount); } } else { setLoading(false); } } catch (error) { setLoading(false); } }; const saveCanvas = async () => { try { const canvas = canvasRef.current; const imageData = canvas.toDataURL(); const timestamp = Date.now(); await window.storage.set('whiteboard-data', JSON.stringify({ imageData, timestamp, userCount: activeUsers }), true); } catch (error) { console.error('Save failed:', error); } }; const getCoordinates = (e) => { const canvas = canvasRef.current; const rect = canvas.getBoundingClientRect(); const scaleX = canvas.width / rect.width; const scaleY = canvas.height / rect.height; if (e.touches) { return { x: (e.touches[0].clientX - rect.left) * scaleX, y: (e.touches[0].clientY - rect.top) * scaleY }; } return { x: (e.clientX - rect.left) * scaleX, y: (e.clientY - rect.top) * scaleY }; }; const startDrawing = (e) => { e.preventDefault(); setIsDrawing(true); const { x, y } = getCoordinates(e); const ctx = canvasRef.current.getContext('2d'); ctx.beginPath(); ctx.moveTo(x, y); }; const draw = (e) => { if (!isDrawing) return; e.preventDefault(); const { x, y } = getCoordinates(e); const ctx = canvasRef.current.getContext('2d'); ctx.lineWidth = brushSize; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; if (tool === 'eraser') { ctx.globalCompositeOperation = 'destination-out'; ctx.strokeStyle = 'rgba(0,0,0,1)'; } else { ctx.globalCompositeOperation = 'source-over'; ctx.strokeStyle = color; } ctx.lineTo(x, y); ctx.stroke(); ctx.beginPath(); ctx.moveTo(x, y); }; const stopDrawing = () => { if (isDrawing) { setIsDrawing(false); saveCanvas(); } }; const clearCanvas = async () => { const ctx = canvasRef.current.getContext('2d'); ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height); await saveCanvas(); }; const downloadCanvas = () => { const canvas = canvasRef.current; const link = document.createElement('a'); link.download = 'whiteboard.png'; link.href = canvas.toDataURL(); link.click(); }; useEffect(() => { const canvas = canvasRef.current; canvas.width = 1200; canvas.height = 700; const ctx = canvas.getContext('2d'); ctx.fillStyle = 'white'; ctx.fillRect(0, 0, canvas.width, canvas.height); }, []); return (
{/* Header */}

Live Collaborative Whiteboard

Draw together in real-time with anyone!

{activeUsers} active
{/* Toolbar */}
{/* Tool Selection */}
{/* Color Palette */}
{colors.map((c) => (
{/* Brush Size */}
setBrushSize(Number(e.target.value))} className="w-24" /> {brushSize}px
{/* Actions */}
{/* Canvas */}
{loading && (

Loading canvas...

)}
{/* Info */}

✨ Your drawings are automatically saved and synced with all users!

Changes appear within 1 second for everyone viewing this board

); }