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';
|
'use client';
|
||||||
|
|
||||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
import { useState } from 'react';
|
||||||
import { Slider } from '@/components/ui/slider';
|
import { Slider } from '@/components/ui/slider';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
@@ -19,11 +19,11 @@ interface ManipulationPanelProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ManipulationPanel({ color, onColorChange }: ManipulationPanelProps) {
|
export function ManipulationPanel({ color, onColorChange }: ManipulationPanelProps) {
|
||||||
const [lightenAmount, setLightenAmount] = useState(0);
|
const [lightenAmount, setLightenAmount] = useState(0.2);
|
||||||
const [darkenAmount, setDarkenAmount] = useState(0);
|
const [darkenAmount, setDarkenAmount] = useState(0.2);
|
||||||
const [saturateAmount, setSaturateAmount] = useState(0);
|
const [saturateAmount, setSaturateAmount] = useState(0.2);
|
||||||
const [desaturateAmount, setDesaturateAmount] = useState(0);
|
const [desaturateAmount, setDesaturateAmount] = useState(0.2);
|
||||||
const [rotateAmount, setRotateAmount] = useState(0);
|
const [rotateAmount, setRotateAmount] = useState(30);
|
||||||
|
|
||||||
const lightenMutation = useLighten();
|
const lightenMutation = useLighten();
|
||||||
const darkenMutation = useDarken();
|
const darkenMutation = useDarken();
|
||||||
@@ -32,101 +32,80 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
|||||||
const rotateMutation = useRotate();
|
const rotateMutation = useRotate();
|
||||||
const complementMutation = useComplement();
|
const complementMutation = useComplement();
|
||||||
|
|
||||||
// Track if we're applying our own changes to prevent feedback loop
|
const handleLighten = async () => {
|
||||||
const isApplyingRef = useRef(false);
|
try {
|
||||||
const baseColorRef = useRef(color);
|
const result = await lightenMutation.mutateAsync({
|
||||||
|
colors: [color],
|
||||||
// Update base color only when not applying our own changes
|
amount: lightenAmount,
|
||||||
useEffect(() => {
|
});
|
||||||
if (!isApplyingRef.current) {
|
if (result.colors[0]) {
|
||||||
baseColorRef.current = color;
|
onColorChange(result.colors[0].output);
|
||||||
// Reset sliders when color changes externally
|
toast.success(`Lightened by ${(lightenAmount * 100).toFixed(0)}%`);
|
||||||
setLightenAmount(0);
|
}
|
||||||
setDarkenAmount(0);
|
} catch (error) {
|
||||||
setSaturateAmount(0);
|
toast.error('Failed to lighten color');
|
||||||
setDesaturateAmount(0);
|
|
||||||
setRotateAmount(0);
|
|
||||||
}
|
}
|
||||||
}, [color]);
|
};
|
||||||
|
|
||||||
// Debounced effect to apply manipulations
|
const handleDarken = async () => {
|
||||||
useEffect(() => {
|
try {
|
||||||
const timer = setTimeout(async () => {
|
const result = await darkenMutation.mutateAsync({
|
||||||
// Skip if all sliders are at neutral position
|
colors: [color],
|
||||||
if (lightenAmount === 0 && darkenAmount === 0 && saturateAmount === 0 &&
|
amount: darkenAmount,
|
||||||
desaturateAmount === 0 && rotateAmount === 0) {
|
});
|
||||||
return;
|
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;
|
const handleSaturate = async () => {
|
||||||
let currentColor = baseColorRef.current;
|
try {
|
||||||
|
const result = await saturateMutation.mutateAsync({
|
||||||
try {
|
colors: [color],
|
||||||
// Apply lighten
|
amount: saturateAmount,
|
||||||
if (lightenAmount > 0) {
|
});
|
||||||
const result = await lightenMutation.mutateAsync({
|
if (result.colors[0]) {
|
||||||
colors: [currentColor],
|
onColorChange(result.colors[0].output);
|
||||||
amount: lightenAmount,
|
toast.success(`Saturated by ${(saturateAmount * 100).toFixed(0)}%`);
|
||||||
});
|
|
||||||
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);
|
} catch (error) {
|
||||||
|
toast.error('Failed to saturate color');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return () => clearTimeout(timer);
|
const handleDesaturate = async () => {
|
||||||
}, [lightenAmount, darkenAmount, saturateAmount, desaturateAmount, rotateAmount]);
|
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 () => {
|
const handleComplement = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -151,7 +130,7 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
|||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Lighten */}
|
{/* Lighten */}
|
||||||
<div>
|
<div className="space-y-3">
|
||||||
<Slider
|
<Slider
|
||||||
label="Lighten"
|
label="Lighten"
|
||||||
min={0}
|
min={0}
|
||||||
@@ -162,10 +141,13 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
|||||||
suffix="%"
|
suffix="%"
|
||||||
showValue
|
showValue
|
||||||
/>
|
/>
|
||||||
|
<Button onClick={handleLighten} disabled={isLoading} className="w-full">
|
||||||
|
Apply Lighten
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Darken */}
|
{/* Darken */}
|
||||||
<div>
|
<div className="space-y-3">
|
||||||
<Slider
|
<Slider
|
||||||
label="Darken"
|
label="Darken"
|
||||||
min={0}
|
min={0}
|
||||||
@@ -176,10 +158,13 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
|||||||
suffix="%"
|
suffix="%"
|
||||||
showValue
|
showValue
|
||||||
/>
|
/>
|
||||||
|
<Button onClick={handleDarken} disabled={isLoading} className="w-full">
|
||||||
|
Apply Darken
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Saturate */}
|
{/* Saturate */}
|
||||||
<div>
|
<div className="space-y-3">
|
||||||
<Slider
|
<Slider
|
||||||
label="Saturate"
|
label="Saturate"
|
||||||
min={0}
|
min={0}
|
||||||
@@ -190,10 +175,13 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
|||||||
suffix="%"
|
suffix="%"
|
||||||
showValue
|
showValue
|
||||||
/>
|
/>
|
||||||
|
<Button onClick={handleSaturate} disabled={isLoading} className="w-full">
|
||||||
|
Apply Saturate
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Desaturate */}
|
{/* Desaturate */}
|
||||||
<div>
|
<div className="space-y-3">
|
||||||
<Slider
|
<Slider
|
||||||
label="Desaturate"
|
label="Desaturate"
|
||||||
min={0}
|
min={0}
|
||||||
@@ -204,10 +192,13 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
|||||||
suffix="%"
|
suffix="%"
|
||||||
showValue
|
showValue
|
||||||
/>
|
/>
|
||||||
|
<Button onClick={handleDesaturate} disabled={isLoading} className="w-full">
|
||||||
|
Apply Desaturate
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Rotate Hue */}
|
{/* Rotate Hue */}
|
||||||
<div>
|
<div className="space-y-3">
|
||||||
<Slider
|
<Slider
|
||||||
label="Rotate Hue"
|
label="Rotate Hue"
|
||||||
min={-180}
|
min={-180}
|
||||||
@@ -218,6 +209,9 @@ export function ManipulationPanel({ color, onColorChange }: ManipulationPanelPro
|
|||||||
suffix="°"
|
suffix="°"
|
||||||
showValue
|
showValue
|
||||||
/>
|
/>
|
||||||
|
<Button onClick={handleRotate} disabled={isLoading} className="w-full">
|
||||||
|
Apply Rotation
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Quick Actions */}
|
{/* Quick Actions */}
|
||||||
|
|||||||
Reference in New Issue
Block a user