From c544fbb6f2cb0f210efbb77cbb23364f362f95d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Fri, 7 Nov 2025 10:30:29 +0100 Subject: [PATCH] docs: initial project setup and documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .env.example | 6 + .gitignore | 57 +++ CLAUDE.md | 988 +++++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE | 21 ++ README.md | 429 ++++++++++++++++++++++ 5 files changed, 1501 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 CLAUDE.md create mode 100644 LICENSE create mode 100644 README.md diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4640766 --- /dev/null +++ b/.env.example @@ -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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2357719 --- /dev/null +++ b/.gitignore @@ -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/ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..957e5ba --- /dev/null +++ b/CLAUDE.md @@ -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 { + 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 ( + + + ); +} +``` + +## 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(); + const swatch = screen.getByRole('button'); + expect(swatch).toHaveStyle({ backgroundColor: '#ff0099' }); + }); + + it('should call onClick when clicked', async () => { + const onClick = vi.fn(); + render(); + + 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('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()( + 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 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c7dba8d --- /dev/null +++ b/LICENSE @@ -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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..df5d174 --- /dev/null +++ b/README.md @@ -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