'use client'; import { useState, useEffect, useRef, useCallback } from 'react'; import { Slider } from '@/components/ui/slider'; import { Button } from '@/components/ui/button'; import { useLighten, useDarken, useSaturate, useDesaturate, useRotate, useComplement } from '@/lib/api/queries'; import { toast } from 'sonner'; interface ManipulationPanelProps { color: string; onColorChange: (color: string) => void; } export function ManipulationPanel({ color, onColorChange }: ManipulationPanelProps) { const [lightenAmount, setLightenAmount] = useState(0); const [darkenAmount, setDarkenAmount] = useState(0); const [saturateAmount, setSaturateAmount] = useState(0); const [desaturateAmount, setDesaturateAmount] = useState(0); const [rotateAmount, setRotateAmount] = useState(0); const lightenMutation = useLighten(); const darkenMutation = useDarken(); const saturateMutation = useSaturate(); const desaturateMutation = useDesaturate(); const rotateMutation = useRotate(); const complementMutation = useComplement(); // Track if we're applying our own changes to prevent feedback loop const isApplyingRef = useRef(false); const baseColorRef = useRef(color); // Update base color only when not applying our own changes useEffect(() => { if (!isApplyingRef.current) { baseColorRef.current = color; // Reset sliders when color changes externally setLightenAmount(0); setDarkenAmount(0); setSaturateAmount(0); setDesaturateAmount(0); setRotateAmount(0); } }, [color]); // Debounced effect to apply manipulations useEffect(() => { const timer = setTimeout(async () => { // Skip if all sliders are at neutral position if (lightenAmount === 0 && darkenAmount === 0 && saturateAmount === 0 && desaturateAmount === 0 && rotateAmount === 0) { return; } isApplyingRef.current = true; let currentColor = baseColorRef.current; try { // Apply lighten if (lightenAmount > 0) { const result = await lightenMutation.mutateAsync({ colors: [currentColor], amount: lightenAmount, }); if (result.colors[0]) { currentColor = result.colors[0].output; } } // Apply darken if (darkenAmount > 0) { const result = await darkenMutation.mutateAsync({ colors: [currentColor], amount: darkenAmount, }); if (result.colors[0]) { currentColor = result.colors[0].output; } } // Apply saturate if (saturateAmount > 0) { const result = await saturateMutation.mutateAsync({ colors: [currentColor], amount: saturateAmount, }); if (result.colors[0]) { currentColor = result.colors[0].output; } } // Apply desaturate if (desaturateAmount > 0) { const result = await desaturateMutation.mutateAsync({ colors: [currentColor], amount: desaturateAmount, }); if (result.colors[0]) { currentColor = result.colors[0].output; } } // Apply rotate if (rotateAmount !== 0) { const result = await rotateMutation.mutateAsync({ colors: [currentColor], amount: rotateAmount, }); if (result.colors[0]) { currentColor = result.colors[0].output; } } onColorChange(currentColor); } catch (error) { // Silent error during manipulation } finally { isApplyingRef.current = false; } }, 300); return () => clearTimeout(timer); }, [lightenAmount, darkenAmount, saturateAmount, desaturateAmount, rotateAmount]); const handleComplement = async () => { try { const result = await complementMutation.mutateAsync([color]); if (result.colors[0]) { onColorChange(result.colors[0].output); toast.success('Generated complementary color'); } } catch (error) { toast.error('Failed to generate complement'); } }; const isLoading = lightenMutation.isPending || darkenMutation.isPending || saturateMutation.isPending || desaturateMutation.isPending || rotateMutation.isPending || complementMutation.isPending; return (
{/* Lighten */}
setLightenAmount(parseFloat(e.target.value))} suffix="%" showValue />
{/* Darken */}
setDarkenAmount(parseFloat(e.target.value))} suffix="%" showValue />
{/* Saturate */}
setSaturateAmount(parseFloat(e.target.value))} suffix="%" showValue />
{/* Desaturate */}
setDesaturateAmount(parseFloat(e.target.value))} suffix="%" showValue />
{/* Rotate Hue */}
setRotateAmount(parseInt(e.target.value))} suffix="°" showValue />
{/* Quick Actions */}

Quick Actions

); }