feat: implement color playground with interactive picker and info display

Add complete color manipulation interface:

**Color Components:**
- ColorPicker - Interactive hex color picker with text input
  - Uses react-colorful for visual selection
  - Manual input support for any color format
  - Real-time updates

- ColorDisplay - Large color preview swatch
  - Configurable sizes (sm, md, lg, xl)
  - Optional border styling
  - Accessible with ARIA labels

- ColorInfo - Comprehensive color information display
  - Shows all formats: Hex, RGB, HSL, Lab, OkLab
  - Copy to clipboard functionality for each format
  - Displays brightness, luminance, light/dark type
  - Shows named color matches

**API Integration:**
- React Query hooks for all Pastel API endpoints
  - useColorInfo - Get color information
  - useConvertFormat - Format conversion
  - useLighten, useDarken, useSaturate, etc. - Manipulations
  - useGenerateRandom, useGenerateDistinct, useGenerateGradient
  - useNamedColors - Cached named colors list
  - Automatic error handling and loading states

**Playground Page (/playground):**
- Two-column layout: picker + info
- Live color preview with large swatch
- Real-time API integration with loading states
- Error handling with user-friendly messages
- Quick action buttons (ready for implementation)
- Responsive grid layout

**Features:**
- Toast notifications for clipboard copy
- Loading spinners during API calls
- Error display with helpful messages
- Accessible keyboard navigation
- Smooth transitions and animations

Build successful with playground page rendering! Ready for color manipulation actions.

🤖 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 11:05:23 +01:00
parent 6c1ec9b44f
commit 173d81d9d4
5 changed files with 469 additions and 0 deletions

95
app/playground/page.tsx Normal file
View File

@@ -0,0 +1,95 @@
'use client';
import { useState } from 'react';
import { ColorPicker } from '@/components/color/ColorPicker';
import { ColorDisplay } from '@/components/color/ColorDisplay';
import { ColorInfo } from '@/components/color/ColorInfo';
import { Button } from '@/components/ui/button';
import { useColorInfo } from '@/lib/api/queries';
import { Loader2 } from 'lucide-react';
export default function PlaygroundPage() {
const [color, setColor] = useState('#ff0099');
const { data, isLoading, isError, error } = useColorInfo({
colors: [color],
});
const colorInfo = data?.colors[0];
return (
<div className="min-h-screen p-8">
<div className="max-w-7xl mx-auto space-y-8">
<div>
<h1 className="text-4xl font-bold mb-2">Color Playground</h1>
<p className="text-muted-foreground">
Interactive color manipulation and analysis tool
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{/* Left Column: Color Picker and Display */}
<div className="space-y-6">
<div className="p-6 border rounded-lg bg-card">
<h2 className="text-xl font-semibold mb-4">Color Picker</h2>
<ColorPicker color={color} onChange={setColor} />
</div>
<div className="p-6 border rounded-lg bg-card">
<h2 className="text-xl font-semibold mb-4">Preview</h2>
<div className="flex justify-center">
<ColorDisplay color={color} size="xl" />
</div>
</div>
</div>
{/* Right Column: Color Information */}
<div className="space-y-6">
<div className="p-6 border rounded-lg bg-card">
<h2 className="text-xl font-semibold mb-4">Color Information</h2>
{isLoading && (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
)}
{isError && (
<div className="p-4 bg-destructive/10 text-destructive rounded-lg">
<p className="font-medium">Error loading color information</p>
<p className="text-sm mt-1">{error?.message || 'Unknown error'}</p>
</div>
)}
{colorInfo && <ColorInfo info={colorInfo} />}
</div>
<div className="p-6 border rounded-lg bg-card">
<h2 className="text-xl font-semibold mb-4">Quick Actions</h2>
<div className="grid grid-cols-2 gap-3">
<Button variant="outline" className="w-full">
Lighten
</Button>
<Button variant="outline" className="w-full">
Darken
</Button>
<Button variant="outline" className="w-full">
Saturate
</Button>
<Button variant="outline" className="w-full">
Desaturate
</Button>
<Button variant="outline" className="w-full">
Complement
</Button>
<Button variant="outline" className="w-full">
Grayscale
</Button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}