revert: restore button-based manipulation controls
Revert to the original button-based approach for color manipulation. The reactive slider implementation was causing infinite loops and page reloads. Buttons provide stable, predictable behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { Slider } from '@/components/ui/slider';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
@@ -19,11 +19,11 @@ interface ManipulationPanelProps {
|
||||
}
|
||||
|
||||
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 [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();
|
||||
@@ -32,101 +32,80 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
||||
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);
|
||||
const handleLighten = async () => {
|
||||
try {
|
||||
const result = await lightenMutation.mutateAsync({
|
||||
colors: [color],
|
||||
amount: lightenAmount,
|
||||
});
|
||||
if (result.colors[0]) {
|
||||
onColorChange(result.colors[0].output);
|
||||
toast.success(`Lightened by ${(lightenAmount * 100).toFixed(0)}%`);
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error('Failed to lighten color');
|
||||
}
|
||||
}, [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;
|
||||
const handleDarken = async () => {
|
||||
try {
|
||||
const result = await darkenMutation.mutateAsync({
|
||||
colors: [color],
|
||||
amount: darkenAmount,
|
||||
});
|
||||
if (result.colors[0]) {
|
||||
onColorChange(result.colors[0].output);
|
||||
toast.success(`Darkened by ${(darkenAmount * 100).toFixed(0)}%`);
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error('Failed to darken color');
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
const handleSaturate = async () => {
|
||||
try {
|
||||
const result = await saturateMutation.mutateAsync({
|
||||
colors: [color],
|
||||
amount: saturateAmount,
|
||||
});
|
||||
if (result.colors[0]) {
|
||||
onColorChange(result.colors[0].output);
|
||||
toast.success(`Saturated by ${(saturateAmount * 100).toFixed(0)}%`);
|
||||
}
|
||||
}, 300);
|
||||
} catch (error) {
|
||||
toast.error('Failed to saturate color');
|
||||
}
|
||||
};
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [lightenAmount, darkenAmount, saturateAmount, desaturateAmount, rotateAmount]);
|
||||
const handleDesaturate = async () => {
|
||||
try {
|
||||
const result = await desaturateMutation.mutateAsync({
|
||||
colors: [color],
|
||||
amount: desaturateAmount,
|
||||
});
|
||||
if (result.colors[0]) {
|
||||
onColorChange(result.colors[0].output);
|
||||
toast.success(`Desaturated by ${(desaturateAmount * 100).toFixed(0)}%`);
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error('Failed to desaturate color');
|
||||
}
|
||||
};
|
||||
|
||||
const handleRotate = async () => {
|
||||
try {
|
||||
const result = await rotateMutation.mutateAsync({
|
||||
colors: [color],
|
||||
amount: rotateAmount,
|
||||
});
|
||||
if (result.colors[0]) {
|
||||
onColorChange(result.colors[0].output);
|
||||
toast.success(`Rotated hue by ${rotateAmount}°`);
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error('Failed to rotate hue');
|
||||
}
|
||||
};
|
||||
|
||||
const handleComplement = async () => {
|
||||
try {
|
||||
@@ -151,7 +130,7 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Lighten */}
|
||||
<div>
|
||||
<div className="space-y-3">
|
||||
<Slider
|
||||
label="Lighten"
|
||||
min={0}
|
||||
@@ -162,10 +141,13 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
||||
suffix="%"
|
||||
showValue
|
||||
/>
|
||||
<Button onClick={handleLighten} disabled={isLoading} className="w-full">
|
||||
Apply Lighten
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Darken */}
|
||||
<div>
|
||||
<div className="space-y-3">
|
||||
<Slider
|
||||
label="Darken"
|
||||
min={0}
|
||||
@@ -176,10 +158,13 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
||||
suffix="%"
|
||||
showValue
|
||||
/>
|
||||
<Button onClick={handleDarken} disabled={isLoading} className="w-full">
|
||||
Apply Darken
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Saturate */}
|
||||
<div>
|
||||
<div className="space-y-3">
|
||||
<Slider
|
||||
label="Saturate"
|
||||
min={0}
|
||||
@@ -190,10 +175,13 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
||||
suffix="%"
|
||||
showValue
|
||||
/>
|
||||
<Button onClick={handleSaturate} disabled={isLoading} className="w-full">
|
||||
Apply Saturate
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Desaturate */}
|
||||
<div>
|
||||
<div className="space-y-3">
|
||||
<Slider
|
||||
label="Desaturate"
|
||||
min={0}
|
||||
@@ -204,10 +192,13 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
||||
suffix="%"
|
||||
showValue
|
||||
/>
|
||||
<Button onClick={handleDesaturate} disabled={isLoading} className="w-full">
|
||||
Apply Desaturate
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Rotate Hue */}
|
||||
<div>
|
||||
<div className="space-y-3">
|
||||
<Slider
|
||||
label="Rotate Hue"
|
||||
min={-180}
|
||||
@@ -218,6 +209,9 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
||||
suffix="°"
|
||||
showValue
|
||||
/>
|
||||
<Button onClick={handleRotate} disabled={isLoading} className="w-full">
|
||||
Apply Rotation
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Quick Actions */}
|
||||
|
||||
Reference in New Issue
Block a user