'use client'; import { useState } from 'react'; import { Slider } from '@/components/ui/slider'; import { useLighten, useDarken, useSaturate, useDesaturate, useRotate, useComplement, } from '@/lib/color/api/queries'; import { toast } from 'sonner'; import { Sun, Moon, Droplets, Droplet, RotateCcw, ArrowLeftRight } from 'lucide-react'; import { cn } from '@/lib/utils/cn'; interface ManipulationPanelProps { color: string; onColorChange: (color: string) => void; } const actionBtn = 'shrink-0 px-3 py-1 text-[10px] font-mono glass rounded-md border border-border/30 text-muted-foreground hover:text-primary hover:border-primary/30 hover:bg-primary/10 transition-all disabled:opacity-40 disabled:cursor-not-allowed'; export function ManipulationPanel({ color, onColorChange }: ManipulationPanelProps) { const [lightenAmount, setLightenAmount] = useState(0.2); const [darkenAmount, setDarkenAmount] = useState(0.2); const [saturateAmount, setSaturateAmount] = useState(0.2); const [desaturateAmount, setDesaturateAmount] = useState(0.2); const [rotateAmount, setRotateAmount] = useState(30); const lightenMutation = useLighten(); const darkenMutation = useDarken(); const saturateMutation = useSaturate(); const desaturateMutation = useDesaturate(); const rotateMutation = useRotate(); const complementMutation = useComplement(); const isLoading = lightenMutation.isPending || darkenMutation.isPending || saturateMutation.isPending || desaturateMutation.isPending || rotateMutation.isPending || complementMutation.isPending; const applyMutation = async ( // eslint-disable-next-line @typescript-eslint/no-explicit-any mutationFn: (p: any) => Promise<{ colors: { output: string }[] }>, // eslint-disable-next-line @typescript-eslint/no-explicit-any params: any, msg: string ) => { try { const result = await mutationFn(params); if (result.colors[0]) { onColorChange(result.colors[0].output); toast.success(msg); } } catch { toast.error('Failed to apply'); } }; const rows = [ { label: 'Lighten', icon: , value: lightenAmount, setValue: setLightenAmount, display: `${(lightenAmount * 100).toFixed(0)}%`, min: 0, max: 1, step: 0.05, onApply: () => applyMutation(lightenMutation.mutateAsync, { colors: [color], amount: lightenAmount }, `Lightened ${(lightenAmount * 100).toFixed(0)}%`), }, { label: 'Darken', icon: , value: darkenAmount, setValue: setDarkenAmount, display: `${(darkenAmount * 100).toFixed(0)}%`, min: 0, max: 1, step: 0.05, onApply: () => applyMutation(darkenMutation.mutateAsync, { colors: [color], amount: darkenAmount }, `Darkened ${(darkenAmount * 100).toFixed(0)}%`), }, { label: 'Saturate', icon: , value: saturateAmount, setValue: setSaturateAmount, display: `${(saturateAmount * 100).toFixed(0)}%`, min: 0, max: 1, step: 0.05, onApply: () => applyMutation(saturateMutation.mutateAsync, { colors: [color], amount: saturateAmount }, `Saturated ${(saturateAmount * 100).toFixed(0)}%`), }, { label: 'Desaturate', icon: , value: desaturateAmount, setValue: setDesaturateAmount, display: `${(desaturateAmount * 100).toFixed(0)}%`, min: 0, max: 1, step: 0.05, onApply: () => applyMutation(desaturateMutation.mutateAsync, { colors: [color], amount: desaturateAmount }, `Desaturated ${(desaturateAmount * 100).toFixed(0)}%`), }, { label: 'Rotate Hue', icon: , value: rotateAmount, setValue: setRotateAmount, display: `${rotateAmount}°`, min: -180, max: 180, step: 5, onApply: () => applyMutation(rotateMutation.mutateAsync, { colors: [color], amount: rotateAmount }, `Rotated ${rotateAmount}°`), }, ]; return (
{rows.map((row) => (
{row.icon} {row.label}
{row.display}
row.setValue(vals[0])} className="flex-1" />
))}
); }