docs: initial project setup and documentation

Add comprehensive documentation and planning for Pastel UI:
- Complete architecture design using Next.js 16 and Tailwind CSS 4
- Detailed development guide (CLAUDE.md) with all patterns and conventions
- Feature-rich README with keyboard shortcuts and export formats
- Project structure and technology stack decisions

Features planned:
- Color playground with multi-format support
- Palette generation (harmony, distinct, gradient)
- Accessibility tools (WCAG, color blindness simulation)
- Named colors explorer (148 CSS/X11 colors)
- Batch operations with CSV/JSON import/export
- Command palette (Cmd+K) and keyboard shortcuts
- Dark/light mode with system preference detection
- Shareable links with URL state

Tech stack:
- Next.js 16 with App Router and Server Components
- React 19 with latest concurrent features
- Tailwind CSS 4 with CSS-first configuration
- TypeScript strict mode
- React Query for server state
- Zustand for client state
- Framer Motion for animations

Ready for implementation phase.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-07 10:30:29 +01:00
commit c544fbb6f2
5 changed files with 1501 additions and 0 deletions

6
.env.example Normal file
View File

@@ -0,0 +1,6 @@
# Pastel API Configuration
# URL of the Pastel API instance
NEXT_PUBLIC_API_URL=http://localhost:3000
# Application URL (used for sharing and OG images)
NEXT_PUBLIC_APP_URL=http://localhost:3000

57
.gitignore vendored Normal file
View File

@@ -0,0 +1,57 @@
# Dependencies
node_modules/
.pnp/
.pnp.js
# Testing
coverage/
.nyc_output/
playwright-report/
test-results/
# Next.js
.next/
out/
build/
dist/
# Production
*.tsbuildinfo
next-env.d.ts
# Misc
.DS_Store
*.pem
Thumbs.db
# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Local env files
.env
.env*.local
.env.production
# Vercel
.vercel
# TypeScript
*.tsbuildinfo
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# Logs
logs/
*.log
# Turbopack
.turbo/

988
CLAUDE.md Normal file
View File

@@ -0,0 +1,988 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Overview
**Pastel UI** is a modern, interactive web application for color manipulation, palette generation, and accessibility analysis. Built with Next.js 16 and Tailwind CSS 4, it provides a beautiful interface for all features of the [Pastel API](https://github.com/valknarness/pastel-api).
**Technology Stack:**
- **Framework**: Next.js 16 (App Router, React 19)
- **Styling**: Tailwind CSS 4 (CSS-first configuration)
- **Language**: TypeScript (strict mode)
- **State Management**:
- `@tanstack/react-query` (server state)
- `zustand` (client state)
- **Animation**: `framer-motion`
- **Icons**: `lucide-react`
- **UI Components**: Custom components + shadcn/ui patterns
- **API Client**: Type-safe Pastel API integration
## Project Structure
```
pastel-ui/
├── app/ # Next.js 16 App Router
│ ├── layout.tsx # Root layout with providers
│ ├── page.tsx # Home/main playground
│ ├── globals.css # Tailwind CSS imports
│ ├── playground/ # Main color manipulation tool
│ │ └── page.tsx
│ ├── palettes/ # Palette generation tools
│ │ ├── page.tsx # Palette dashboard
│ │ ├── harmony/page.tsx # Harmony-based palettes
│ │ ├── distinct/page.tsx # Distinct colors generator
│ │ └── gradient/page.tsx # Gradient creator
│ ├── accessibility/ # Accessibility tools
│ │ ├── page.tsx # A11y dashboard
│ │ ├── contrast/page.tsx # Contrast checker
│ │ └── colorblind/page.tsx # Colorblindness simulator
│ ├── names/ # Named colors explorer
│ │ └── page.tsx
│ ├── batch/ # Batch operations
│ │ └── page.tsx
│ ├── docs/ # Documentation
│ │ └── page.tsx
│ └── api/ # API route handlers (proxy)
│ └── proxy/[...path]/route.ts
├── components/
│ ├── ui/ # Base UI components (shadcn/ui style)
│ │ ├── button.tsx
│ │ ├── input.tsx
│ │ ├── slider.tsx
│ │ ├── tabs.tsx
│ │ ├── dialog.tsx
│ │ ├── dropdown-menu.tsx
│ │ ├── command.tsx
│ │ ├── toast.tsx
│ │ └── ...
│ ├── color/ # Color-specific components
│ │ ├── ColorPicker.tsx # Main color input
│ │ ├── ColorDisplay.tsx # Large preview swatch
│ │ ├── ColorInfo.tsx # Detailed color information
│ │ ├── FormatConverter.tsx # Format conversion tabs
│ │ ├── ColorSwatch.tsx # Small color preview
│ │ └── ColorInput.tsx # Text input with validation
│ ├── tools/ # Tool-specific components
│ │ ├── ManipulationPanel.tsx # Lighten/darken/etc controls
│ │ ├── PaletteGenerator.tsx # Palette creation UI
│ │ ├── AccessibilityChecker.tsx # Contrast/WCAG analysis
│ │ ├── GradientCreator.tsx # Gradient builder
│ │ ├── ColorBlindSimulator.tsx # Colorblindness preview
│ │ └── DistinctGenerator.tsx # Distinct colors UI
│ ├── layout/ # Layout components
│ │ ├── Navbar.tsx # Top navigation
│ │ ├── Sidebar.tsx # Side navigation
│ │ ├── Footer.tsx # Footer
│ │ ├── ThemeToggle.tsx # Dark/light mode
│ │ └── CommandPalette.tsx # Cmd+K interface
│ └── providers/ # Context providers
│ ├── Providers.tsx # Root provider wrapper
│ ├── ThemeProvider.tsx # Theme context
│ └── QueryProvider.tsx # React Query provider
├── lib/
│ ├── api/ # API client
│ │ ├── client.ts # PastelAPIClient class
│ │ ├── types.ts # API type definitions
│ │ ├── endpoints.ts # Endpoint definitions
│ │ └── queries.ts # React Query hooks
│ ├── utils/ # Utilities
│ │ ├── color.ts # Color helpers
│ │ ├── format.ts # Format converters
│ │ ├── export.ts # Export utilities (CSS, JSON, etc.)
│ │ ├── validation.ts # Input validation
│ │ └── cn.ts # Class name utility
│ ├── hooks/ # Custom React hooks
│ │ ├── useColor.ts # Color state management
│ │ ├── usePalette.ts # Palette state
│ │ ├── useColorHistory.ts # History tracking
│ │ ├── useKeyboard.ts # Keyboard shortcuts
│ │ └── useClipboard.ts # Copy to clipboard
│ ├── stores/ # Zustand stores
│ │ ├── colorStore.ts # Color state
│ │ ├── historyStore.ts # Color history
│ │ └── preferencesStore.ts # User preferences
│ └── constants/ # Constants
│ ├── colors.ts # Named colors
│ ├── shortcuts.ts # Keyboard shortcuts
│ └── exports.ts # Export templates
├── styles/
│ └── globals.css # Global styles + Tailwind
├── public/
│ ├── favicon.ico
│ ├── og-image.png
│ └── icons/
├── tests/
│ ├── unit/ # Vitest unit tests
│ │ ├── utils/
│ │ └── components/
│ └── e2e/ # Playwright E2E tests
│ ├── playground.spec.ts
│ └── palettes.spec.ts
├── .github/
│ └── workflows/
│ └── ci.yml # CI/CD pipeline
├── package.json
├── tsconfig.json
├── tailwind.config.ts # Tailwind CSS 4 config
├── next.config.ts # Next.js 16 config
├── vitest.config.ts # Vitest config
├── playwright.config.ts # Playwright config
├── .env.example
├── .env.local # Local environment variables
├── .gitignore
├── .eslintrc.json
├── .prettierrc
├── CLAUDE.md # This file
└── README.md # Project overview
```
## Key Features
### 1. Color Playground
**Location**: `/` or `/playground`
Interactive color manipulation interface with:
- Real-time color picker
- Support for all input formats (hex, rgb, hsl, hsv, lab, oklab, lch, oklch, cmyk, gray, named)
- Live color information display (all format representations)
- Format conversion with copy-to-clipboard
- Color manipulation controls (lighten, darken, saturate, desaturate, rotate, complement, grayscale)
- Color mixing with ratio slider
- Visual preview with large swatch
**Key Components**:
- `ColorPicker` - Main input component
- `ColorDisplay` - Large preview area
- `ColorInfo` - Tabbed format information
- `ManipulationPanel` - Slider controls for adjustments
### 2. Palette Generation
**Location**: `/palettes/*`
Multiple palette generation tools:
**a) Harmony Palettes** (`/palettes/harmony`)
- Monochromatic (1 base color)
- Analogous (3 adjacent colors)
- Complementary (2 opposite colors)
- Split-complementary (3 colors)
- Triadic (3 evenly spaced colors)
- Tetradic (4 colors in rectangle)
- Custom harmony angles
**b) Distinct Colors** (`/palettes/distinct`)
- Generate N visually distinct colors
- Configurable count (2-100)
- Distance metric selection (CIE76, CIEDE2000)
- Optional fixed colors to include
- Progress indicator (can take 2-5 minutes)
**c) Gradient Creator** (`/palettes/gradient`)
- Multiple color stops
- Configurable step count
- Color space selection (RGB, HSL, Lab, LCH, OkLab, OkLCH)
- Live preview
- Export as CSS gradient or color array
**Key Components**:
- `PaletteGenerator` - Main palette UI
- `GradientCreator` - Gradient builder
- `DistinctGenerator` - Distinct colors with progress
- `PaletteGrid` - Visual palette display
- `ExportMenu` - Export in multiple formats
### 3. Accessibility Tools
**Location**: `/accessibility/*`
**a) Contrast Checker** (`/accessibility/contrast`)
- WCAG 2.1 compliance analysis
- AA/AAA ratings for normal and large text
- Foreground/background color inputs
- Contrast ratio calculation
- Recommendations for improvement
**b) Color Blindness Simulator** (`/accessibility/colorblind`)
- Simulate protanopia (red-blind)
- Simulate deuteranopia (green-blind)
- Simulate tritanopia (blue-blind)
- Side-by-side comparison
- Batch simulation for palettes
**c) Text Color Optimizer**
- Find optimal text color for background
- WCAG compliance guarantee
- Light/dark text selection
**Key Components**:
- `AccessibilityChecker` - Main A11y interface
- `ContrastAnalyzer` - WCAG contrast checker
- `ColorBlindSimulator` - Simulation previews
- `ComplianceBadge` - AA/AAA status indicators
### 4. Named Colors Explorer
**Location**: `/names`
Browse and search 148 CSS/X11 named colors:
- Searchable grid of color swatches
- Filter by name, hex value
- Sort by hue, brightness, saturation, name
- Click to use in playground
- Find nearest named color for any input
**Key Components**:
- `NamedColorsGrid` - Visual grid display
- `ColorSearch` - Search and filter
- `NearestColorFinder` - Find closest named color
### 5. Batch Operations
**Location**: `/batch`
Process multiple colors at once:
- Upload CSV/JSON files with color lists
- Apply operations to all colors (lighten, darken, etc.)
- Bulk format conversion
- Download results in multiple formats
- Visual preview of batch results
**Key Components**:
- `BatchUploader` - File upload interface
- `BatchOperations` - Operation selection
- `BatchPreview` - Results preview
- `BatchExporter` - Download results
## Architecture Patterns
### Server vs Client Components
**Server Components** (default):
- Page layouts
- Static content
- Data fetching (when possible)
- SEO-critical content
**Client Components** (use 'use client'):
- Interactive UI (color pickers, sliders)
- State management components
- Animation/transition components
- Browser API usage (localStorage, clipboard)
### State Management Strategy
**Server State** (React Query):
- API responses from Pastel API
- Cached color operations
- Automatic refetching and caching
**Client State** (Zustand):
- Current selected colors
- Color history (session)
- User preferences (theme, shortcuts)
- UI state (sidebar open/closed)
**Persistent State** (LocalStorage/IndexedDB):
- Saved palettes
- Long-term color history
- User settings
### API Integration
**Type-Safe Client**:
```typescript
// lib/api/client.ts
export class PastelAPIClient {
private baseURL: string;
constructor(baseURL: string = process.env.NEXT_PUBLIC_API_URL!) {
this.baseURL = baseURL;
}
async getColorInfo(colors: string[]): Promise<ColorInfoResponse> {
const response = await fetch(`${this.baseURL}/api/v1/colors/info`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ colors }),
});
if (!response.ok) throw new Error('API request failed');
return response.json();
}
// ... all 21 endpoints
}
export const pastelAPI = new PastelAPIClient();
```
**React Query Hooks**:
```typescript
// lib/api/queries.ts
export const useColorInfo = (colors: string[]) => {
return useQuery({
queryKey: ['colorInfo', colors],
queryFn: () => pastelAPI.getColorInfo(colors),
enabled: colors.length > 0,
});
};
export const useDistinctColors = () => {
return useMutation({
mutationFn: (params: DistinctColorsParams) =>
pastelAPI.generateDistinct(params.count, params.metric),
});
};
```
### Routing Strategy
**Next.js 16 App Router**:
- File-based routing in `app/` directory
- Server Components by default
- Nested layouts for shared UI
- Loading states with `loading.tsx`
- Error boundaries with `error.tsx`
- Metadata API for SEO
**Example Route Structure**:
```
app/
├── layout.tsx # Root layout (navbar, providers)
├── page.tsx # Home page
├── playground/
│ ├── layout.tsx # Playground layout (sidebar)
│ └── page.tsx # Playground content
└── palettes/
├── layout.tsx # Shared palette layout
├── page.tsx # Palette dashboard
└── harmony/
└── page.tsx # Harmony palettes
```
## Development
### Setup
```bash
# Clone repository
git clone git@github.com:valknarness/pastel-ui.git
cd pastel-ui
# Install dependencies (requires Node.js 18+)
pnpm install
# Set up environment variables
cp .env.example .env.local
# Edit .env.local with your Pastel API URL
# Run development server
pnpm dev
# Open http://localhost:3000
```
### Environment Variables
```bash
# .env.local
NEXT_PUBLIC_API_URL=http://localhost:3000 # Pastel API URL
NEXT_PUBLIC_APP_URL=http://localhost:3000 # This app URL
```
### Available Scripts
```bash
# Development
pnpm dev # Start dev server (localhost:3000)
pnpm dev:turbo # Start with Turbopack
# Building
pnpm build # Production build
pnpm start # Start production server
# Code Quality
pnpm lint # ESLint
pnpm lint:fix # Fix ESLint issues
pnpm format # Prettier formatting
pnpm type-check # TypeScript check
# Testing
pnpm test # Run Vitest unit tests
pnpm test:ui # Vitest UI mode
pnpm test:e2e # Playwright E2E tests
pnpm test:e2e:ui # Playwright UI mode
# Analysis
pnpm analyze # Bundle size analysis
```
### Code Style
**TypeScript**:
- Strict mode enabled
- No `any` types (use `unknown` if needed)
- Explicit return types for functions
- Interface over type for object shapes
**React**:
- Functional components only
- Custom hooks for reusable logic
- Proper dependency arrays in hooks
- Descriptive prop names
**Naming Conventions**:
- Components: `PascalCase` (e.g., `ColorPicker.tsx`)
- Hooks: `camelCase` with `use` prefix (e.g., `useColor.ts`)
- Utilities: `camelCase` (e.g., `formatColor.ts`)
- Constants: `SCREAMING_SNAKE_CASE` (e.g., `MAX_COLORS`)
- Types/Interfaces: `PascalCase` (e.g., `ColorInfo`)
**File Organization**:
- One component per file
- Co-locate types with components
- Group related utilities
- Barrel exports (`index.ts`) for public APIs
## Tailwind CSS 4 Usage
### Configuration
```typescript
// tailwind.config.ts
import type { Config } from 'tailwindcss';
const config: Config = {
content: [
'./app/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
colors: {
// Custom color palette
primary: 'oklch(var(--primary))',
secondary: 'oklch(var(--secondary))',
// ... using CSS variables for theming
},
animation: {
// Custom animations
'fade-in': 'fadeIn 0.2s ease-in',
'slide-up': 'slideUp 0.3s ease-out',
},
},
},
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
],
};
export default config;
```
### CSS-First Configuration (Tailwind 4)
```css
/* app/globals.css */
@import "tailwindcss";
@theme {
/* Custom design tokens */
--color-primary: oklch(0.7 0.15 250);
--color-secondary: oklch(0.6 0.12 180);
/* Spacing scale */
--spacing-xs: 0.5rem;
--spacing-sm: 0.75rem;
--spacing-md: 1rem;
/* Animations */
--transition-fast: 150ms;
--transition-normal: 300ms;
}
/* Dark mode overrides */
@media (prefers-color-scheme: dark) {
@theme {
--color-primary: oklch(0.8 0.15 250);
--color-secondary: oklch(0.7 0.12 180);
}
}
```
### Component Styling Pattern
```tsx
// components/color/ColorSwatch.tsx
import { cn } from '@/lib/utils/cn';
interface ColorSwatchProps {
color: string;
size?: 'sm' | 'md' | 'lg';
onClick?: () => void;
}
export function ColorSwatch({ color, size = 'md', onClick }: ColorSwatchProps) {
return (
<button
className={cn(
'rounded-lg border-2 border-gray-300 transition-all hover:scale-110',
'focus:outline-none focus:ring-2 focus:ring-primary',
{
'h-8 w-8': size === 'sm',
'h-12 w-12': size === 'md',
'h-16 w-16': size === 'lg',
}
)}
style={{ backgroundColor: color }}
onClick={onClick}
aria-label={`Color swatch: ${color}`}
/>
);
}
```
## Performance Optimization
### Code Splitting
```tsx
// Lazy load heavy components
import dynamic from 'next/dynamic';
const DistinctGenerator = dynamic(
() => import('@/components/tools/DistinctGenerator'),
{
loading: () => <LoadingSpinner />,
ssr: false, // Client-only component
}
);
```
### Image Optimization
```tsx
import Image from 'next/image';
<Image
src="/og-image.png"
alt="Pastel UI"
width={1200}
height={630}
priority // Load eagerly for above-fold images
/>
```
### API Call Optimization
```tsx
// Debounce API calls during slider interactions
import { useDebouncedValue } from '@/lib/hooks/useDebouncedValue';
const [lightness, setLightness] = useState(0.5);
const debouncedLightness = useDebouncedValue(lightness, 300);
const { data } = useColorInfo([color], {
enabled: !!color && debouncedLightness !== lightness,
});
```
### Bundle Size Management
- Keep initial bundle < 200KB
- Use dynamic imports for route-specific code
- Analyze bundle with `pnpm analyze`
- Tree-shake unused dependencies
## Accessibility
### WCAG Compliance
- **AA** minimum for all UI elements
- **AAA** target for text content
- Color contrast checker built into design system
- Never rely on color alone for information
### Keyboard Navigation
```tsx
// All interactive elements must be keyboard accessible
<div
role="button"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleClick();
}
}}
onClick={handleClick}
>
Click me
</div>
```
### ARIA Labels
```tsx
<input
type="text"
value={color}
onChange={(e) => setColor(e.target.value)}
aria-label="Color input (hex, rgb, hsl, etc.)"
aria-describedby="color-format-hint"
/>
<span id="color-format-hint" className="sr-only">
Enter a color in any format: hex, rgb, hsl, or named color
</span>
```
### Focus Management
```tsx
import { useEffect, useRef } from 'react';
function Dialog({ isOpen, onClose }: DialogProps) {
const closeButtonRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
if (isOpen) {
closeButtonRef.current?.focus();
}
}, [isOpen]);
return (
<div role="dialog" aria-modal="true">
{/* Dialog content */}
<button ref={closeButtonRef} onClick={onClose}>
Close
</button>
</div>
);
}
```
## Testing Strategy
### Unit Tests (Vitest)
```typescript
// tests/unit/utils/color.test.ts
import { describe, it, expect } from 'vitest';
import { parseColor, formatColor } from '@/lib/utils/color';
describe('color utilities', () => {
it('should parse hex colors', () => {
expect(parseColor('#ff0099')).toEqual({
r: 255,
g: 0,
b: 153,
});
});
it('should format RGB to hex', () => {
expect(formatColor({ r: 255, g: 0, b: 153 }, 'hex'))
.toBe('#ff0099');
});
});
```
### Component Tests
```typescript
// tests/unit/components/ColorSwatch.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ColorSwatch } from '@/components/color/ColorSwatch';
describe('ColorSwatch', () => {
it('should render with correct background color', () => {
render(<ColorSwatch color="#ff0099" />);
const swatch = screen.getByRole('button');
expect(swatch).toHaveStyle({ backgroundColor: '#ff0099' });
});
it('should call onClick when clicked', async () => {
const onClick = vi.fn();
render(<ColorSwatch color="#ff0099" onClick={onClick} />);
await userEvent.click(screen.getByRole('button'));
expect(onClick).toHaveBeenCalledOnce();
});
});
```
### E2E Tests (Playwright)
```typescript
// tests/e2e/playground.spec.ts
import { test, expect } from '@playwright/test';
test('color manipulation workflow', async ({ page }) => {
await page.goto('/playground');
// Enter a color
await page.fill('[aria-label="Color input"]', '#ff0099');
// Verify color info is displayed
await expect(page.locator('text=rgb(255, 0, 153)')).toBeVisible();
// Adjust lightness
await page.locator('[aria-label="Lightness slider"]').fill('0.7');
// Verify updated color
await expect(page.locator('.color-display')).toHaveCSS(
'background-color',
/rgb\(255, \d+, \d+\)/
);
});
```
## Deployment
### Vercel (Recommended)
```bash
# Install Vercel CLI
pnpm add -g vercel
# Deploy
vercel
# Production deployment
vercel --prod
```
### Environment Variables (Production)
```bash
# Vercel dashboard or .env.production
NEXT_PUBLIC_API_URL=https://api.pastel.example.com
NEXT_PUBLIC_APP_URL=https://pastel.example.com
```
### Build Optimization
```typescript
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
// Enable React Compiler (Next.js 16)
experimental: {
reactCompiler: true,
},
// Image optimization
images: {
formats: ['image/avif', 'image/webp'],
},
// Bundle analyzer (conditional)
...(process.env.ANALYZE === 'true' && {
webpack(config) {
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
config.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
})
);
return config;
},
}),
};
export default nextConfig;
```
### CI/CD Pipeline
```yaml
# .github/workflows/ci.yml
name: CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install
- run: pnpm lint
- run: pnpm type-check
- run: pnpm test
- run: pnpm build
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4
- run: pnpm install
- run: pnpm build
- run: pnpm test:e2e
deploy:
needs: [test, e2e]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'
```
## Common Patterns
### Custom Hook Example
```typescript
// lib/hooks/useColor.ts
import { useState, useCallback } from 'use';
import { useColorInfo } from '@/lib/api/queries';
import { parseColor } from '@/lib/utils/color';
export function useColor(initialColor?: string) {
const [color, setColor] = useState(initialColor ?? '#000000');
const [format, setFormat] = useState<ColorFormat>('hex');
const { data: colorInfo, isLoading } = useColorInfo([color]);
const updateColor = useCallback((newColor: string) => {
try {
const parsed = parseColor(newColor);
if (parsed) {
setColor(newColor);
}
} catch (error) {
console.error('Invalid color:', error);
}
}, []);
return {
color,
colorInfo: colorInfo?.data.colors[0],
format,
setFormat,
updateColor,
isLoading,
};
}
```
### Zustand Store Example
```typescript
// lib/stores/historyStore.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface ColorHistoryState {
history: string[];
addColor: (color: string) => void;
clearHistory: () => void;
}
export const useColorHistory = create<ColorHistoryState>()(
persist(
(set) => ({
history: [],
addColor: (color) => set((state) => ({
history: [color, ...state.history.filter(c => c !== color)].slice(0, 50),
})),
clearHistory: () => set({ history: [] }),
}),
{
name: 'color-history',
storage: createJSONStorage(() => localStorage),
}
)
);
```
## Troubleshooting
### Common Issues
**Issue**: API calls failing with CORS errors
**Solution**: Ensure `NEXT_PUBLIC_API_URL` is set correctly and the Pastel API has CORS enabled
**Issue**: Tailwind classes not applying
**Solution**: Check `content` paths in `tailwind.config.ts` include all component files
**Issue**: Hydration errors
**Solution**: Ensure client components using browser APIs have proper checks:
```tsx
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
```
**Issue**: Large bundle size
**Solution**: Use dynamic imports for heavy components and run `pnpm analyze`
## Resources
### Documentation
- [Next.js 16 Docs](https://nextjs.org/docs)
- [React 19 Docs](https://react.dev)
- [Tailwind CSS 4 Docs](https://tailwindcss.com/docs)
- [React Query Docs](https://tanstack.com/query/latest)
- [Pastel API Docs](https://github.com/valknarness/pastel-api)
### Color Science
- [OkLab Color Space](https://bottosson.github.io/posts/oklab/)
- [WCAG Contrast Guidelines](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html)
- [Color Blindness Simulation](https://www.color-blindness.com/coblis-color-blindness-simulator/)
### Tools
- [Figma](https://www.figma.com) - Design mockups
- [Playwright](https://playwright.dev) - E2E testing
- [Vitest](https://vitest.dev) - Unit testing
## Contributing
### PR Checklist
- [ ] Tests pass (`pnpm test`)
- [ ] E2E tests pass (`pnpm test:e2e`)
- [ ] No ESLint errors (`pnpm lint`)
- [ ] No TypeScript errors (`pnpm type-check`)
- [ ] Code formatted (`pnpm format`)
- [ ] Documentation updated (if needed)
- [ ] Accessibility tested (keyboard, screen reader)
- [ ] Performance checked (bundle size)
### Code Review Guidelines
- All interactive elements must be keyboard accessible
- All images must have alt text
- Color contrast must meet WCAG AA
- No console.log in production code
- Meaningful variable/function names
- Comments for complex logic only
---
**Project Status**: Design phase complete, ready for implementation
**Last Updated**: 2025-11-07

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Valknarness
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

429
README.md Normal file
View File

@@ -0,0 +1,429 @@
# Pastel UI
> A modern, interactive web application for color manipulation, palette generation, and accessibility analysis.
[![Next.js](https://img.shields.io/badge/Next.js-16-black?logo=next.js)](https://nextjs.org)
[![React](https://img.shields.io/badge/React-19-blue?logo=react)](https://react.dev)
[![Tailwind CSS](https://img.shields.io/badge/Tailwind-4-38bdf8?logo=tailwind-css)](https://tailwindcss.com)
[![TypeScript](https://img.shields.io/badge/TypeScript-5-3178c6?logo=typescript)](https://www.typescriptlang.org)
[![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
Pastel UI is a beautiful, feature-rich interface for the [Pastel API](https://github.com/valknarness/pastel-api), providing intuitive tools for color manipulation, palette generation, and accessibility testing.
## Features
### 🎨 Color Playground
- **Interactive Color Picker** - Real-time color selection with live preview
- **Multi-Format Support** - Hex, RGB, HSL, HSV, Lab, OkLab, LCH, OkLCH, CMYK, Gray, and 148 named colors
- **Color Manipulation** - Lighten, darken, saturate, desaturate, rotate, complement, mix, grayscale
- **Format Conversion** - Convert between any color format with one click
- **Copy to Clipboard** - Quick copy for all formats
### 🎭 Palette Generation
- **Harmony Palettes** - Monochromatic, analogous, complementary, split-complementary, triadic, tetradic
- **Distinct Colors** - Generate visually distinct colors using simulated annealing algorithm
- **Gradient Creator** - Multi-stop gradients with color space selection (RGB, HSL, Lab, LCH, OkLab, OkLCH)
- **Export Options** - CSS, JSON, Tailwind config, SCSS, SVG, PNG
### ♿ Accessibility Tools
- **WCAG Contrast Checker** - AA/AAA compliance analysis for text and backgrounds
- **Color Blindness Simulator** - Protanopia, deuteranopia, tritanopia simulation
- **Text Color Optimizer** - Find optimal text color for any background
- **Batch Accessibility Testing** - Test entire palettes at once
### 🔍 Color Analysis
- **Perceptual Distance** - CIE76 and CIEDE2000 metrics
- **Color Sorting** - Sort by hue, brightness, luminance, chroma
- **Named Color Search** - Find nearest named color for any input
- **Color Information** - Comprehensive color data in all formats
### ⚡ Advanced Features
- **Batch Operations** - Upload CSV/JSON, process multiple colors, download results
- **Color History** - Track all colors used in your session
- **Saved Palettes** - Persistent storage of your favorite palettes
- **Command Palette** - Keyboard shortcuts (Cmd+K) for power users
- **Dark/Light Mode** - System preference + manual toggle
- **Shareable Links** - Share colors and palettes via URL
## Tech Stack
- **[Next.js 16](https://nextjs.org)** - React framework with App Router and Server Components
- **[React 19](https://react.dev)** - Latest React with improved concurrent features
- **[Tailwind CSS 4](https://tailwindcss.com)** - CSS-first utility framework with modern color spaces
- **[TypeScript](https://www.typescriptlang.org)** - Strict type safety throughout
- **[React Query](https://tanstack.com/query)** - Server state management and caching
- **[Zustand](https://github.com/pmndrs/zustand)** - Client state management
- **[Framer Motion](https://www.framer.com/motion/)** - Smooth animations and transitions
- **[Lucide React](https://lucide.dev)** - Beautiful icon set
## Quick Start
### Prerequisites
- **Node.js** 18+ (20+ recommended)
- **pnpm** 9+ (or npm/yarn)
- **Pastel API** running locally or remotely
### Installation
```bash
# Clone the repository
git clone git@github.com:valknarness/pastel-ui.git
cd pastel-ui
# Install dependencies
pnpm install
# Set up environment variables
cp .env.example .env.local
# Edit .env.local with your Pastel API URL
# Run development server
pnpm dev
```
Open [http://localhost:3000](http://localhost:3000) in your browser.
### Environment Variables
```bash
# .env.local
NEXT_PUBLIC_API_URL=http://localhost:3000 # Your Pastel API URL
NEXT_PUBLIC_APP_URL=http://localhost:3000 # This app's URL (for sharing)
```
## Development
### Available Commands
```bash
# Development
pnpm dev # Start dev server (http://localhost:3000)
pnpm dev:turbo # Start with Turbopack (faster)
# Building
pnpm build # Production build
pnpm start # Start production server
# Code Quality
pnpm lint # Run ESLint
pnpm lint:fix # Fix ESLint issues automatically
pnpm format # Format code with Prettier
pnpm type-check # TypeScript type checking
# Testing
pnpm test # Run unit tests (Vitest)
pnpm test:ui # Vitest UI mode
pnpm test:e2e # Run E2E tests (Playwright)
pnpm test:e2e:ui # Playwright UI mode
# Analysis
pnpm analyze # Analyze bundle size
```
### Project Structure
```
pastel-ui/
├── app/ # Next.js App Router
│ ├── playground/ # Color manipulation tool
│ ├── palettes/ # Palette generation
│ ├── accessibility/ # Accessibility tools
│ ├── names/ # Named colors explorer
│ └── batch/ # Batch operations
├── components/
│ ├── ui/ # Base UI components
│ ├── color/ # Color-specific components
│ ├── tools/ # Tool components
│ └── layout/ # Layout components
├── lib/
│ ├── api/ # API client and queries
│ ├── utils/ # Utility functions
│ ├── hooks/ # Custom React hooks
│ └── stores/ # Zustand stores
└── tests/ # Unit and E2E tests
```
See [CLAUDE.md](CLAUDE.md) for detailed architecture documentation.
## Features Overview
### Color Playground (`/`)
The main interface for color manipulation:
- Input colors in any format
- View comprehensive color information
- Manipulate colors with intuitive controls
- Convert between formats instantly
- Copy values with one click
### Palette Generation (`/palettes`)
Create beautiful color palettes:
#### Harmony Palettes (`/palettes/harmony`)
Generate palettes based on color theory:
- **Monochromatic** - Variations of a single hue
- **Analogous** - Adjacent colors on the wheel
- **Complementary** - Opposite colors
- **Split-complementary** - Base + two adjacent to complement
- **Triadic** - Three evenly spaced colors
- **Tetradic** - Four colors in a rectangle
#### Distinct Colors (`/palettes/distinct`)
Generate visually distinct colors using advanced algorithms:
- Configurable count (2-100 colors)
- Distance metric selection (CIE76, CIEDE2000)
- Optional fixed colors to include
- Real-time progress indicator
#### Gradient Creator (`/palettes/gradient`)
Create smooth color gradients:
- Multiple color stops
- Configurable step count
- Color space selection for interpolation
- Live preview
- Export as CSS or color array
### Accessibility Tools (`/accessibility`)
Ensure your colors are accessible:
#### Contrast Checker (`/accessibility/contrast`)
- WCAG 2.1 compliance testing
- AA/AAA ratings for normal and large text
- Contrast ratio calculation
- Improvement recommendations
#### Color Blindness Simulator (`/accessibility/colorblind`)
- Simulate protanopia (red-blind)
- Simulate deuteranopia (green-blind)
- Simulate tritanopia (blue-blind)
- Side-by-side comparison
- Batch palette testing
### Named Colors Explorer (`/names`)
Browse and search 148 CSS/X11 named colors:
- Visual grid display
- Search by name or hex value
- Sort by hue, brightness, saturation, name
- Find nearest named color for any input
- Click to use in playground
### Batch Operations (`/batch`)
Process multiple colors efficiently:
- Upload CSV/JSON files
- Apply operations to all colors
- Bulk format conversion
- Visual preview of results
- Download in multiple formats
## Export Formats
Export your colors and palettes in various formats:
### CSS Variables
```css
:root {
--color-primary: #ff0099;
--color-secondary: #00ccff;
--color-accent: #ffcc00;
}
```
### Tailwind Config
```javascript
module.exports = {
theme: {
extend: {
colors: {
primary: '#ff0099',
secondary: '#00ccff',
accent: '#ffcc00',
}
}
}
}
```
### JSON
```json
{
"colors": [
{ "name": "primary", "hex": "#ff0099" },
{ "name": "secondary", "hex": "#00ccff" },
{ "name": "accent", "hex": "#ffcc00" }
]
}
```
### SCSS
```scss
$color-primary: #ff0099;
$color-secondary: #00ccff;
$color-accent: #ffcc00;
```
## Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
| `Cmd/Ctrl + K` | Open command palette |
| `Cmd/Ctrl + C` | Copy current color (hex) |
| `Cmd/Ctrl + V` | Paste color from clipboard |
| `Cmd/Ctrl + Z` | Undo color change |
| `Cmd/Ctrl + Shift + Z` | Redo color change |
| `Cmd/Ctrl + D` | Toggle dark/light mode |
| `Cmd/Ctrl + /` | Show keyboard shortcuts |
| `Esc` | Close modals/dialogs |
| `Arrow Keys` | Navigate color history |
| `Space` | Toggle color picker |
## API Integration
Pastel UI communicates with the [Pastel API](https://github.com/valknarness/pastel-api) for all color operations. The API client is type-safe and includes automatic retries, caching, and error handling.
### Example API Usage
```typescript
import { pastelAPI } from '@/lib/api/client';
// Get color information
const info = await pastelAPI.getColorInfo(['#ff0099']);
// Generate distinct colors
const distinct = await pastelAPI.generateDistinct(8, 'ciede2000');
// Create gradient
const gradient = await pastelAPI.generateGradient({
stops: ['#ff0000', '#0000ff'],
count: 10,
colorspace: 'lch'
});
```
See [CLAUDE.md](CLAUDE.md) for detailed API integration documentation.
## Performance
Pastel UI is optimized for performance:
- **Fast Initial Load** - < 200KB initial bundle
- **Code Splitting** - Route-based automatic splitting
- **Image Optimization** - Next.js Image with AVIF/WebP
- **API Caching** - React Query with smart cache invalidation
- **Debounced Updates** - Smooth slider interactions
- **Web Workers** - Heavy calculations off main thread
## Accessibility
Pastel UI meets WCAG 2.1 Level AAA standards:
- **Keyboard Navigation** - Full keyboard support
- **Screen Reader Support** - Comprehensive ARIA labels
- **Focus Management** - Logical focus order
- **Color Contrast** - AAA contrast throughout
- **Reduced Motion** - Respects user preferences
- **Semantic HTML** - Proper HTML structure
## Browser Support
- **Chrome/Edge** 90+
- **Firefox** 88+
- **Safari** 14+
- **Mobile Safari** 14+
- **Chrome Android** 90+
## Deployment
### Vercel (Recommended)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/valknarness/pastel-ui)
```bash
# Install Vercel CLI
pnpm add -g vercel
# Deploy
vercel
# Production deployment
vercel --prod
```
### Docker
```bash
# Build
docker build -t pastel-ui .
# Run
docker run -p 3000:3000 -e NEXT_PUBLIC_API_URL=https://api.pastel.com pastel-ui
```
### Static Export
```bash
# Build static export
pnpm build
# Output in out/ directory
# Deploy to any static hosting (Netlify, Cloudflare Pages, etc.)
```
## Contributing
Contributions are welcome! Please read [CLAUDE.md](CLAUDE.md) for development guidelines.
### Development Workflow
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes
4. Run tests (`pnpm test`)
5. Commit your changes (`git commit -m 'Add amazing feature'`)
6. Push to the branch (`git push origin feature/amazing-feature`)
7. Open a Pull Request
### PR Checklist
- [ ] Tests pass (`pnpm test` and `pnpm test:e2e`)
- [ ] No linting errors (`pnpm lint`)
- [ ] No TypeScript errors (`pnpm type-check`)
- [ ] Code formatted (`pnpm format`)
- [ ] Documentation updated (if needed)
- [ ] Accessibility tested (keyboard, screen reader)
- [ ] Performance checked (`pnpm analyze`)
## Related Projects
- **[Pastel API](https://github.com/valknarness/pastel-api)** - REST API for color manipulation
- **[Pastel CLI](https://github.com/sharkdp/pastel)** - Original command-line tool by David Peter
## License
MIT License - see [LICENSE](LICENSE) file for details.
## Acknowledgments
- **[David Peter](https://github.com/sharkdp)** - Creator of the original [Pastel CLI](https://github.com/sharkdp/pastel)
- **[Vercel](https://vercel.com)** - Next.js framework and hosting platform
- **[Tailwind Labs](https://tailwindcss.com)** - Tailwind CSS framework
- Color science resources from [OkLab](https://bottosson.github.io/posts/oklab/) and [W3C](https://www.w3.org/WAI/WCAG21/)
## Support
- **Documentation**: [CLAUDE.md](CLAUDE.md)
- **API Docs**: [Pastel API](https://github.com/valknarness/pastel-api)
- **Issues**: [GitHub Issues](https://github.com/valknarness/pastel-ui/issues)
- **Discussions**: [GitHub Discussions](https://github.com/valknarness/pastel-ui/discussions)
---
**Built with** ❤️ **using** [Next.js](https://nextjs.org), [React](https://react.dev), and [Tailwind CSS](https://tailwindcss.com)
**Project Status**: Design phase complete, ready for implementation
**Last Updated**: 2025-11-07