fix: correct API integration and complete missing features

Fix API response format mismatches and implement all remaining features:

**API Integration Fixes:**
- Fix ManipulationPanel to use `colors` instead of `results` from API responses
- Fix gradient endpoint to use `gradient` array from API response
- Fix color blindness simulator to use correct field names (`input`/`output` vs `original`/`simulated`)
- Fix text color optimizer request field (`backgrounds` vs `background_colors`)
- Fix method name casing: `simulateColorBlindness` (capital B)
- Add palette generation endpoint integration

**Type Definition Updates:**
- Update GradientData to match API structure with `gradient` array
- Update ColorBlindnessData to use `colors` with `input`/`output`/`difference_percentage`
- Update TextColorData to use `colors` with `textcolor`/`wcag_aa`/`wcag_aaa` fields
- Add PaletteGenerateRequest and PaletteGenerateData types

**Completed Features:**
- Harmony Palettes: Now uses dedicated `/palettes/generate` API endpoint
  - Simplified from 80 lines of manual color theory to single API call
  - Supports 6 harmony types: monochromatic, analogous, complementary, split-complementary, triadic, tetradic
- Text Color Optimizer: Full implementation with WCAG compliance checking
  - Automatic black/white text color selection
  - Live preview with contrast ratios
  - AA/AAA compliance indicators
- Color Blindness Simulator: Fixed and working
  - Shows difference percentage for each simulation
  - Side-by-side comparison view
- Gradient Creator: Fixed to use correct API response structure
- Batch Operations: Fixed to extract output colors correctly

**UI Improvements:**
- Enable all accessibility tool cards (remove "Coming Soon" badges)
- Enable harmony palettes card
- Add safety check for gradient state to prevent undefined errors

All features now fully functional and properly integrated with Pastel API.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
valknarness
2025-11-07 14:33:38 +01:00
parent cb3fcdd806
commit 93889ab9bd
11 changed files with 314 additions and 112 deletions

View File

@@ -6,7 +6,7 @@ import { PaletteGrid } from '@/components/color/PaletteGrid';
import { ExportMenu } from '@/components/tools/ExportMenu';
import { Button } from '@/components/ui/button';
import { Select } from '@/components/ui/select';
import { useComplement, useRotate } from '@/lib/api/queries';
import { useGeneratePalette } from '@/lib/api/queries';
import { Loader2, Palette } from 'lucide-react';
import { toast } from 'sonner';
@@ -23,83 +23,17 @@ export default function HarmonyPage() {
const [harmonyType, setHarmonyType] = useState<HarmonyType>('complementary');
const [palette, setPalette] = useState<string[]>([]);
const complementMutation = useComplement();
const rotateMutation = useRotate();
const paletteMutation = useGeneratePalette();
const generateHarmony = async () => {
try {
let colors: string[] = [baseColor];
switch (harmonyType) {
case 'monochromatic':
// Base color with lightness variations
colors = [baseColor];
toast.info('Monochromatic harmony uses variations of the base color');
break;
case 'analogous':
// Base + 30° and -30°
const analog1 = await rotateMutation.mutateAsync({
colors: [baseColor],
amount: 30,
});
const analog2 = await rotateMutation.mutateAsync({
colors: [baseColor],
amount: -30,
});
colors = [analog2.colors[0], baseColor, analog1.colors[0]];
break;
case 'complementary':
// Base + opposite (180°)
const complement = await complementMutation.mutateAsync([baseColor]);
colors = [baseColor, complement.colors[0]];
break;
case 'split-complementary':
// Base + 150° and 210° (flanking the complement)
const split1 = await rotateMutation.mutateAsync({
colors: [baseColor],
amount: 150,
});
const split2 = await rotateMutation.mutateAsync({
colors: [baseColor],
amount: 210,
});
colors = [baseColor, split1.colors[0], split2.colors[0]];
break;
case 'triadic':
// Base + 120° and 240° (evenly spaced)
const tri1 = await rotateMutation.mutateAsync({
colors: [baseColor],
amount: 120,
});
const tri2 = await rotateMutation.mutateAsync({
colors: [baseColor],
amount: 240,
});
colors = [baseColor, tri1.colors[0], tri2.colors[0]];
break;
case 'tetradic':
// Base + 90°, 180°, 270° (square)
const tet1 = await rotateMutation.mutateAsync({
colors: [baseColor],
amount: 90,
});
const tet2 = await rotateMutation.mutateAsync({
colors: [baseColor],
amount: 180,
});
const tet3 = await rotateMutation.mutateAsync({
colors: [baseColor],
amount: 270,
});
colors = [baseColor, tet1.colors[0], tet2.colors[0], tet3.colors[0]];
break;
}
const result = await paletteMutation.mutateAsync({
base: baseColor,
scheme: harmonyType,
});
// Combine primary and secondary colors into flat array
const colors = [result.palette.primary, ...result.palette.secondary];
setPalette(colors);
toast.success(`Generated ${harmonyType} harmony palette`);
} catch (error) {
@@ -157,10 +91,10 @@ export default function HarmonyPage() {
<Button
onClick={generateHarmony}
disabled={complementMutation.isPending || rotateMutation.isPending}
disabled={paletteMutation.isPending}
className="w-full"
>
{complementMutation.isPending || rotateMutation.isPending ? (
{paletteMutation.isPending ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Generating...