import React, { useEffect, useRef } from 'react'; const WaveCanvas = () => { const canvasRef = useRef(null); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; let animationFrameId; // Set canvas size const setCanvasSize = () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }; // Initial setup setCanvasSize(); // Wave parameters const waves = [ { amplitude: 120, frequency: 0.001, speed: 0.0005, phase: 0 }, { amplitude: 80, frequency: 0.002, speed: 0.0004, phase: 2 } ]; // Get theme colors const getColors = () => { const isDarkTheme = document.body.getAttribute('data-theme') === 'dark'; return { firstWave: isDarkTheme ? { r: 147, g: 51, b: 234 } // Purple for dark theme : { r: 18, g: 163, b: 176 }, // #12A3B0 Bright teal secondWave: isDarkTheme ? { r: 59, g: 130, b: 246 } // Blue for dark theme : { r: 1, g: 73, b: 81 } // #014951 Medium teal }; }; // Draw function const draw = () => { ctx.clearRect(0, 0, canvas.width, canvas.height); // Center the waves vertically const centerY = canvas.height * 0.5; const colors = getColors(); waves.forEach((wave, index) => { // Update wave phase wave.phase += wave.speed; // Create gradient with theme-aware colors const gradient = ctx.createLinearGradient(0, centerY - wave.amplitude, 0, centerY + wave.amplitude); const color = index === 0 ? colors.firstWave : colors.secondWave; if (document.body.getAttribute('data-theme') === 'dark') { gradient.addColorStop(0, `rgba(${color.r}, ${color.g}, ${color.b}, 0)`); gradient.addColorStop(0.5, `rgba(${color.r}, ${color.g}, ${color.b}, 0.8)`); gradient.addColorStop(1, `rgba(${color.r}, ${color.g}, ${color.b}, 0)`); } else { // Light theme gradient with additional color stops gradient.addColorStop(0, `rgba(${color.r}, ${color.g}, ${color.b}, 0)`); gradient.addColorStop(0.2, `rgba(1, 49, 53, 0.4)`); // #013135 gradient.addColorStop(0.5, `rgba(${color.r}, ${color.g}, ${color.b}, 0.8)`); gradient.addColorStop(0.8, `rgba(175, 221, 229, 0.4)`); // #AFDDE5 gradient.addColorStop(1, `rgba(${color.r}, ${color.g}, ${color.b}, 0)`); } // Begin drawing wave ctx.beginPath(); // Start from bottom left ctx.moveTo(0, canvas.height); ctx.lineTo(0, centerY); // Draw wave path for (let x = 0; x <= canvas.width; x++) { const y = centerY + Math.sin(x * wave.frequency + wave.phase) * wave.amplitude; ctx.lineTo(x, y); } // Complete the path to bottom right ctx.lineTo(canvas.width, centerY); ctx.lineTo(canvas.width, canvas.height); ctx.closePath(); // Fill with gradient ctx.fillStyle = gradient; ctx.fill(); }); animationFrameId = requestAnimationFrame(draw); }; // Start animation draw(); // Handle resize and theme changes const handleResize = () => { setCanvasSize(); }; window.addEventListener('resize', handleResize); // Watch for theme changes const observer = new MutationObserver(() => { draw(); // Redraw when theme changes }); observer.observe(document.body, { attributes: true, attributeFilter: ['data-theme'] }); // Cleanup return () => { window.removeEventListener('resize', handleResize); cancelAnimationFrame(animationFrameId); observer.disconnect(); }; }, []); return ; }; export default WaveCanvas;