From 1b1dcc91a814206c17a88bbd36963a0ebb989ee1 Mon Sep 17 00:00:00 2001 From: John Crafts <5889731+Artsen@users.noreply.github.com> Date: Sat, 25 Jul 2026 03:21:06 -0400 Subject: [PATCH 1/2] Prepare ColorCraft for dashboard discovery --- .github/workflows/ci.yml | 53 + .gitignore | 5 + README.md | 1100 +---------------- app-manifest.json | 25 + backend/accessibility.py | 122 +- backend/color_extractor.py | 21 +- backend/color_suggestions.py | 619 +++++----- backend/color_theory.py | 52 +- backend/config.py | 14 +- backend/main.py | 62 +- backend/models.py | 20 +- backend/requirements-dev.txt | 3 + check.cmd | 17 + check.py | 118 ++ dev.py | 18 +- docs/README.md | 15 + docs/api.md | 49 + docs/architecture.md | 26 + docs/assets/screenshots/create-light.png | Bin 0 -> 137039 bytes docs/assets/screenshots/library-dark.png | Bin 0 -> 47157 bytes docs/assets/screenshots/mobile-create.png | Bin 0 -> 55961 bytes docs/assets/screenshots/review-dark.png | Bin 0 -> 157352 bytes docs/brand-system.md | 8 +- docs/dashboard-manifest.md | 23 + docs/getting-started.md | 49 + docs/persistence-and-privacy.md | 30 + docs/runtime-configuration.md | 30 + docs/screenshot-review.md | 16 + docs/testing.md | 46 + docs/troubleshooting.md | 46 + docs/user-workflow.md | 36 + frontend/.prettierignore | 6 + frontend/.prettierrc.json | 5 + frontend/e2e/capture-screenshots.mjs | 23 + frontend/e2e/screenshot-review.spec.ts | 179 +++ frontend/e2e/workflow.spec.ts | 86 ++ frontend/eslint.config.js | 41 + frontend/index.html | 6 +- frontend/package.json | 18 + frontend/playwright.config.ts | 49 + frontend/pnpm-lock.yaml | 986 +++++++++++++++ frontend/pnpm-workspace.yaml | 2 +- frontend/postcss.config.js | 1 - frontend/public/app-manifest.json | 25 + frontend/public/colorcraft-mark.svg | 7 + frontend/src/App.test.tsx | 162 ++- frontend/src/App.tsx | 450 ++++++- frontend/src/api/client.test.ts | 13 +- frontend/src/api/client.ts | 4 +- frontend/src/api/errors.ts | 5 +- .../src/components/AnalysisResults.test.tsx | 4 +- frontend/src/components/AnalysisResults.tsx | 114 +- frontend/src/components/AppShell.test.tsx | 34 +- frontend/src/components/AppShell.tsx | 52 +- .../src/components/ColorSuggestions.test.tsx | 35 +- frontend/src/components/ColorSuggestions.tsx | 122 +- frontend/src/components/ColorWheel.tsx | 14 +- .../src/components/ExportWorkspace.test.tsx | 20 +- frontend/src/components/ExportWorkspace.tsx | 45 +- .../src/components/ImageColorPicker.test.tsx | 4 +- frontend/src/components/ImageColorPicker.tsx | 45 +- frontend/src/components/ImageUpload.test.tsx | 26 +- frontend/src/components/ImageUpload.tsx | 21 +- frontend/src/components/MiniColorWheel.tsx | 18 +- frontend/src/components/PaletteItem.tsx | 40 +- .../src/components/PaletteLibrary.test.tsx | 91 ++ frontend/src/components/PaletteLibrary.tsx | 199 +++ .../src/components/ReviewWorkspace.test.tsx | 95 +- frontend/src/components/ReviewWorkspace.tsx | 314 ++++- frontend/src/components/ui/Dialog.tsx | 6 +- frontend/src/components/ui/Field.tsx | 10 +- frontend/src/components/ui/IconButton.tsx | 9 +- frontend/src/components/ui/Notice.tsx | 7 +- frontend/src/components/ui/Panel.tsx | 5 +- frontend/src/components/ui/StatusBadge.tsx | 3 +- frontend/src/components/ui/Tabs.tsx | 4 +- frontend/src/components/ui/ThemeControl.tsx | 11 +- .../src/components/ui/primitives.test.tsx | 39 +- frontend/src/contrast.test.ts | 23 +- frontend/src/contrast.ts | 67 +- frontend/src/exporters.test.ts | 2 +- frontend/src/exporters.ts | 90 +- frontend/src/main.tsx | 1 - frontend/src/persistence.test.ts | 69 ++ frontend/src/persistence.ts | 205 +++ frontend/src/styles/components.css | 243 +++- frontend/src/styles/features.css | 1022 ++++++++++++--- frontend/src/styles/foundation.test.ts | 10 +- frontend/src/styles/foundations.css | 41 +- frontend/src/styles/layout.css | 128 +- frontend/src/styles/responsive.css | 246 +++- frontend/src/styles/tokens.css | 67 +- frontend/src/test/setup.ts | 9 +- frontend/src/theme.test.tsx | 18 +- frontend/src/theme.ts | 4 +- frontend/src/workspace.test.ts | 9 +- frontend/src/workspace.ts | 37 +- frontend/tailwind.config.js | 6 +- frontend/tsconfig.json | 1 - frontend/tsconfig.node.json | 1 - frontend/vite.config.ts | 15 +- frontend/vitest.config.ts | 13 + pyproject.toml | 19 + tests/conftest.py | 3 +- tests/test_accessibility.py | 1 - tests/test_api.py | 62 +- tests/test_check.py | 28 + tests/test_color_extractor.py | 14 +- tests/test_color_theory.py | 22 +- tests/test_docs.py | 42 + tests/test_manifest.py | 26 + tests/test_runtime.py | 4 +- 112 files changed, 6299 insertions(+), 2327 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 app-manifest.json create mode 100644 check.cmd create mode 100644 check.py create mode 100644 docs/README.md create mode 100644 docs/api.md create mode 100644 docs/architecture.md create mode 100644 docs/assets/screenshots/create-light.png create mode 100644 docs/assets/screenshots/library-dark.png create mode 100644 docs/assets/screenshots/mobile-create.png create mode 100644 docs/assets/screenshots/review-dark.png create mode 100644 docs/dashboard-manifest.md create mode 100644 docs/getting-started.md create mode 100644 docs/persistence-and-privacy.md create mode 100644 docs/runtime-configuration.md create mode 100644 docs/screenshot-review.md create mode 100644 docs/testing.md create mode 100644 docs/troubleshooting.md create mode 100644 docs/user-workflow.md create mode 100644 frontend/.prettierignore create mode 100644 frontend/.prettierrc.json create mode 100644 frontend/e2e/capture-screenshots.mjs create mode 100644 frontend/e2e/screenshot-review.spec.ts create mode 100644 frontend/e2e/workflow.spec.ts create mode 100644 frontend/eslint.config.js create mode 100644 frontend/playwright.config.ts create mode 100644 frontend/public/app-manifest.json create mode 100644 frontend/public/colorcraft-mark.svg create mode 100644 frontend/src/components/PaletteLibrary.test.tsx create mode 100644 frontend/src/components/PaletteLibrary.tsx create mode 100644 frontend/src/persistence.test.ts create mode 100644 frontend/src/persistence.ts create mode 100644 pyproject.toml create mode 100644 tests/test_check.py create mode 100644 tests/test_docs.py create mode 100644 tests/test_manifest.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f17874e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,53 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: pip + cache-dependency-path: backend/requirements-dev.txt + + - uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Enable Corepack + run: corepack enable + + - name: Install backend dependencies + run: python -m pip install -r backend/requirements-dev.txt + + - name: Install frontend dependencies + working-directory: frontend + run: corepack pnpm@9.15.9 install --frozen-lockfile + + - name: Install Playwright browser + working-directory: frontend + run: corepack pnpm@9.15.9 exec playwright install --with-deps chromium + + - name: Run complete validation + run: python check.py + + - name: Upload browser diagnostics + if: failure() + uses: actions/upload-artifact@v4 + with: + name: playwright-diagnostics + path: | + frontend/playwright-report + frontend/test-results + if-no-files-found: ignore diff --git a/.gitignore b/.gitignore index c7a33a9..6b7ed02 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ venv/ .venv*/ ENV/ *.egg-info/ +.coverage dist/ build/ *.log @@ -24,6 +25,10 @@ pnpm-debug.log* # Frontend build frontend/dist/ frontend/.vite/ +frontend/coverage/ +frontend/playwright-report/ +frontend/test-results/ +.tmp/ # IDE .vscode/ diff --git a/README.md b/README.md index c222e5c..ac51c85 100644 --- a/README.md +++ b/README.md @@ -1,1085 +1,87 @@ # ColorCraft -![ColorCraft Banner](./colorcraft-banner.png) +

+ ColorCraft mark +

-[![ColorCraft Badge](https://img.shields.io/badge/ColorCraft-Color_Theory_Analysis-purple?style=for-the-badge)](https://github.com/Artsen/ColorCraft) +

A local-first workspace for extracting, refining, reviewing, saving, and exporting color palettes.

-ColorCraft is an intelligent visual design companion that transforms images into actionable color insights. Upload a photo, extract dominant colors using perceptual clustering, and analyze geometric color relationships and WCAG contrast. Relationship fit describes angular structure; it is not an objective judgment of aesthetic quality. +

+ CI + MIT license + Local-first +

-## Table of Contents -- [Overview](#overview) -- [What's New](#whats-new) -- [Plain-English Tour](#plain-english-tour) -- [Repository Layout](#repository-layout) -- [Key Capabilities](#key-capabilities) - - [Backend](#backend) - - [Frontend](#frontend) -- [Architecture](#architecture) -- [Prerequisites](#prerequisites) -- [Environment Setup](#environment-setup) -- [Backend Setup](#backend-setup) -- [Frontend Setup](#frontend-setup) -- [Running the Stack](#running-the-stack) -- [Using ColorCraft](#using-colorcraft) - - [Workflow Options](#workflow-options) - - [Controls Reference](#controls-reference) - - [Exploration Tips](#exploration-tips) -- [Color Extraction Algorithm](#color-extraction-algorithm) -- [Color Theory Engine](#color-theory-engine) -- [Accessibility Analysis](#accessibility-analysis) -- [API Endpoints](#api-endpoints) -- [Data Flow & Processing](#data-flow--processing) -- [Troubleshooting](#troubleshooting) -- [Roadmap & Next Steps](#roadmap--next-steps) -- [Contributing](#contributing) -- [License](#license) -- [Mermaid Diagrams](#mermaid-diagrams) +![ColorCraft review workspace](./docs/assets/screenshots/review-dark.png) -## Overview +ColorCraft turns an image or a hand-built set of colors into practical design evidence. It extracts representative colors, detects geometric harmony relationships, checks WCAG contrast, suggests additions, and exports reusable values. Saved palettes stay in the current browser. Uploaded source images are processed for the active session and are not placed in persistent browser storage. -ColorCraft bridges the gap between subjective color choices and objective color science. Instead of manually checking contrast ratios or guessing at harmony relationships, you upload an image or build a palette manually, and ColorCraft does the heavy lifting: perceptual color extraction in LAB space, multi-dimensional harmony detection (complementary, triadic, analogous, split-complementary, tetradic, monochromatic), WCAG 2.1 accessibility validation, and interactive D3.js visualization showing exactly how your colors relate on the color wheel. +## Quick start -## What's New +Use Python 3.11 and Node.js 20 or newer. From the repository root: -- **Windows compatibility fix**: Removed UMAP dependency to eliminate numba/coverage conflicts on Windows systems -- **Manual-only workflow**: Skip image upload entirely and start with custom colors using the "Skip & Add Colors Manually" button -- **IPv4 proxy fix**: Explicit 127.0.0.1 targeting for Windows Node.js compatibility -- **Start Over functionality**: Reset and try different images or workflows without page reload -- **LAB color space clustering**: Deterministic clustering with a seeded sample and processed-sample medoid representatives -- **Default starter palette**: Beautiful gradient colors (#667eea, #764ba2, #f093fb) when skipping upload -- **Enhanced UX flow**: Seamless transitions between upload and manual workflows - -## Plain-English Tour - -Think of ColorCraft as your color theory assistant. Here's the journey without jargon: - -1. **Choose your starting point.** Upload an image to extract its colors, or skip and add colors manually. -2. **Extract dominant colors.** If you uploaded an image, select how many colors (3-10) you want to extract. ColorCraft analyzes the image in perceptual LAB color space and finds the most representative colors using KMeans clustering. -3. **Refine your palette.** Add, remove, or edit colors. Click any color swatch to change it with the color picker, or type HEX values directly. -4. **Analyze color relationships.** Click "Apply Color Theory" and ColorCraft examines your palette for: - - **Harmony patterns**: Complementary pairs, triadic triangles, analogous neighbors, split-complementary schemes, tetradic squares, and monochromatic variations - - **Temperature balance**: Warm vs. cool color distribution - - **Accessibility**: WCAG AA/AAA contrast ratios for every color pair - - **Palette metrics**: Circular hue diversity, average saturation, and lightness range -5. **Explore the color wheel.** See every palette color and detected geometric relationship. The center displays relationship fit (0-100), not an aesthetic rating. -6. **Review detailed insights.** Scroll down to see harmony tags, temperature analysis, accessibility warnings, and a complete contrast ratio table. - -If you remember only one thing: ColorCraft turns subjective color choices into objective, measurable insights. - -## Repository Layout - -```text -. -├── README.md # This guide -├── LICENSE # MIT License -├── CONTRIBUTING.md # Contribution guidelines -├── backend/ # Python FastAPI backend -│ ├── main.py # FastAPI application entry point -│ ├── color_extractor.py # KMeans clustering in LAB color space -│ ├── color_theory.py # Harmony detection algorithms -│ ├── accessibility.py # WCAG 2.1 contrast calculations -│ └── requirements.txt # Python dependencies -├── frontend/ # React + TypeScript frontend -│ ├── src/ -│ │ ├── components/ # React components -│ │ │ ├── ImageUpload.tsx # File upload and extraction UI -│ │ │ ├── ColorPalette.tsx # Color grid with editing -│ │ │ ├── ColorWheel.tsx # D3.js visualization -│ │ │ └── AnalysisResults.tsx # Harmony and accessibility display -│ │ ├── App.tsx # Main application component -│ │ ├── main.tsx # React entry point -│ │ └── index.css # Global styles with Tailwind -│ ├── package.json # Frontend dependencies -│ ├── vite.config.ts # Vite configuration -│ ├── tailwind.config.js # Tailwind CSS configuration -│ └── tsconfig.json # TypeScript configuration -└── .gitignore # Git ignore patterns -``` - -## Key Capabilities - -### Backend - -- **Perceptual color extraction**: Converts RGB to LAB color space for human-vision-aligned clustering -- **KMeans clustering**: Seeded clustering and sampling with an effective cluster count based on usable unique pixels -- **LAB ↔ RGB conversion**: High-precision color space transformations with D65 white point -- **Color theory engine**: Hue angle mathematics for harmony detection with configurable tolerance -- **Harmony detection**: Complementary (180°), analogous (30-60°), triadic (120°), tetradic (90°), split-complementary, and monochromatic patterns -- **Temperature analysis**: Warm vs. cool color classification and ratio calculation -- **WCAG 2.1 compliance**: Relative luminance calculation and contrast ratio formulas -- **Accessibility validation**: AA/AAA compliance checking for normal and large text -- **Relationship fit**: Explainable 0-100 fit based on measured angular deviation, confidence, and meaningful-hue coverage -- **FastAPI framework**: RESTful API with automatic OpenAPI documentation -- **CORS support**: Configured for local development and production deployment - -### Frontend - -- **Dual workflow support**: Image upload with extraction OR manual color creation -- **Interactive color editing**: Click-to-edit swatches with native color picker -- **HEX input validation**: Real-time validation and RGB/HSL conversion -- **D3.js color wheel**: Interactive visualization with harmony connections and hover effects -- **Harmony visualization**: Pattern-distinguished geometry for every detected relationship type, with an accessible text summary -- **Relationship fit**: Compact geometric-fit display with contributing factors and an explicit non-aesthetic disclaimer -- **Responsive design**: Tailwind CSS with mobile-first approach -- **State management**: React hooks for efficient re-rendering -- **Color format conversion**: Seamless HEX ↔ RGB ↔ HSL transformations -- **Accessibility-first UI**: High contrast, semantic HTML, keyboard navigation -- **TypeScript safety**: Full type coverage for color objects and API responses - -## Architecture - -ColorCraft follows a clean client-server architecture: - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Frontend (React) │ -│ ┌────────────┐ ┌────────────┐ ┌──────────────────────┐ │ -│ │ Image │ │ Color │ │ Color Wheel │ │ -│ │ Upload │→ │ Palette │→ │ Visualization │ │ -│ └────────────┘ └────────────┘ └──────────────────────┘ │ -│ │ │ ↑ │ -│ └───────────────┴─────────────────────┘ │ -│ │ │ -│ API Calls (REST) │ -└─────────────────────────┼───────────────────────────────────┘ - │ - ↓ -┌─────────────────────────────────────────────────────────────┐ -│ Backend (FastAPI) │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │ -│ │ Color │ │ Color │ │ Accessibility │ │ -│ │ Extractor │ │ Theory │ │ Engine │ │ -│ │ (LAB+KMeans)│ │ Engine │ │ (WCAG 2.1) │ │ -│ └──────────────┘ └──────────────┘ └──────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ -``` - -## Prerequisites - -- **Python 3.11+** (3.11 recommended for best compatibility) -- **Node.js 18+** (LTS version recommended) -- **Corepack** (included with supported Node.js releases) -- **pip** (Python package installer) - -**Platform Support:** -- ✅ Windows 10/11 -- ✅ macOS 11+ -- ✅ Linux (Ubuntu 20.04+, Debian 11+) - -## Environment Setup - -### Windows - -```powershell -# Check Python version -python --version # Should be 3.11+ - -# Check Node version -node --version # Should be 18+ - -# Upgrade pip -python -m pip install --upgrade pip -``` - -### macOS / Linux - -```bash -# Check Python version -python3 --version # Should be 3.11+ - -# Check Node version -node --version # Should be 18+ - -# Upgrade pip -python3 -m pip install --upgrade pip -``` - -## Backend Setup - -### Option A: Virtual Environment (Recommended) - -**Windows:** ```powershell -cd backend -py -3.11 -m venv .venv311 -.\.venv311\Scripts\python.exe -m pip install -r requirements-dev.txt -``` - -**macOS / Linux:** -```bash -cd backend -python3.11 -m venv .venv -.venv/bin/python -m pip install -r requirements-dev.txt -``` - -### Option B: Global Installation - -```bash -cd backend -pip install -r requirements.txt -``` - -### Dependencies Installed - -- **fastapi** (0.104.1): Modern web framework for building APIs -- **uvicorn** (0.24.0): ASGI server for FastAPI -- **python-multipart** (0.0.6): File upload support -- **pillow** (10.1.0): Image processing library -- **numpy** (1.26.2): Numerical computing -- **scikit-learn** (1.3.2): KMeans clustering and metrics -- **pydantic** (2.5.0): Data validation and settings management - -## Frontend Setup - -```bash +py -3.11 -m venv backend\.venv311 +.\backend\.venv311\Scripts\python.exe -m pip install -r backend\requirements-dev.txt cd frontend corepack pnpm@9.15.9 install +cd .. +.\backend\.venv311\Scripts\python.exe dev.py ``` -### Dependencies Installed - -- **react** (18.3.1): UI component library -- **react-dom** (18.3.1): React DOM rendering -- **typescript** (5.9.3): Type-safe JavaScript -- **vite** (5.4.20): Fast build tool and dev server -- **tailwindcss** (3.4.18): Utility-first CSS framework -- **d3** (7.9.0): Data visualization library -- **zod** (3.25): Runtime validation for API contracts - -## Running the Stack - -### One terminal (recommended) - -**Windows:** -```powershell -cd D:\path\to\ColorCraft -.\dev.cmd -``` - -**macOS / Linux:** -```bash -cd /path/to/ColorCraft -backend/.venv/bin/python dev.py -``` - -The launcher finds the backend virtual environment, starts FastAPI and Vite, -checks for obvious port conflicts, waits for API readiness, and keeps both -services attached to the same terminal. If either service exits unexpectedly, -the launcher stops the sibling process and returns a nonzero exit status. -Press `Ctrl+C` to stop both. - -- App: http://127.0.0.1:5174 -- API: http://127.0.0.1:4100 -- Health: http://127.0.0.1:4100/health -- Readiness: http://127.0.0.1:4100/ready - -These defaults do not conflict with Web Video Optimizer, which uses ports 5173 -and 4000. - -### Runtime configuration - -ColorCraft binds only to the local loopback interface by default. The launcher, -API, and Vite read these environment variables: - -| Variable | Default | Purpose | -| --- | --- | --- | -| `COLORCRAFT_WEB_HOST` | `127.0.0.1` | Vite bind host | -| `COLORCRAFT_WEB_PORT` | `5174` | Vite port | -| `COLORCRAFT_API_HOST` | `127.0.0.1` | FastAPI bind host | -| `COLORCRAFT_API_PORT` | `4100` | FastAPI port | -| `COLORCRAFT_ALLOW_LAN_ACCESS` | `false` | Explicitly permits non-loopback binding and LAN CORS origins | -| `COLORCRAFT_ALLOWED_ORIGINS` | Resolved frontend origin | Comma-separated exact CORS origins | -| `VITE_COLORCRAFT_API_URL` | Resolved API origin | Optional direct frontend API origin | - -Vite uses `strictPort`, so startup fails instead of silently moving to another -port. Non-loopback hosts and LAN origins are rejected unless -`COLORCRAFT_ALLOW_LAN_ACCESS=true`. - -Trusted LAN example: - -```powershell -$env:COLORCRAFT_ALLOW_LAN_ACCESS = "true" -$env:COLORCRAFT_WEB_HOST = "0.0.0.0" -$env:COLORCRAFT_API_HOST = "0.0.0.0" -$env:COLORCRAFT_ALLOWED_ORIGINS = "http://192.168.1.20:5174" -.\dev.cmd -``` - -Replace the example address with the host computer's LAN address. ColorCraft -has no authentication and is intended only for trusted local or explicitly -enabled trusted LAN use, not public hosting. - -### Two terminals (manual alternative) - -#### Terminal 1: Backend - -**Windows:** -```powershell -cd backend -.\.venv311\Scripts\python.exe -m uvicorn main:app --host 127.0.0.1 --port 4100 -``` - -**macOS / Linux:** -```bash -cd backend -./.venv/bin/python -m uvicorn main:app --host 127.0.0.1 --port 4100 -``` - -**Expected output:** -``` -INFO: Started server process [XXXX] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: Uvicorn running on http://127.0.0.1:4100 (Press CTRL+C to quit) -``` - -**Verify:** Visit http://127.0.0.1:4100/ready and confirm the status is -`ready`. - -#### Terminal 2: Frontend - -```powershell -cd frontend -corepack pnpm@9.15.9 dev -``` - -**Expected output:** -``` - VITE v5.4.20 ready in XXX ms - - ➜ Local: http://127.0.0.1:5174/ - ➜ Network: use --host to expose - ➜ press h + enter to show help -``` - -**Access:** Open http://127.0.0.1:5174 in your browser - -## Using ColorCraft - -### Workflow Options - -#### Option 1: Image Upload & Extraction - -1. **Upload an image**: Click the upload area or drag and drop a JPG, PNG, or WebP file -2. **Select color count**: Use the slider to choose 3-10 colors -3. **Extract colors**: Click "Find Colors" button -4. **Wait for processing**: Typically 1-2 seconds for standard images -5. **Review extracted colors**: See swatches with HEX, RGB, and HSL values -6. **Optional refinement**: Add, remove, or edit colors manually -7. **Analyze**: Click "Apply Color Theory" to see harmony and accessibility analysis - -#### Option 2: Manual Color Creation +On macOS or Linux, create `backend/.venv`, install the same requirements, then run `backend/.venv/bin/python dev.py`. One launcher starts both services and opens the app: -1. **Skip upload**: Click "Skip & Add Colors Manually" button -2. **Start with defaults**: Begin with 3 gradient colors -3. **Edit colors**: Click any swatch to open color picker -4. **Type HEX values**: Edit HEX codes directly in the input field -5. **Add more colors**: Click the "+" button to add additional colors -6. **Remove colors**: Click the "×" button on any color to remove it -7. **Analyze**: Click "Apply Color Theory" when you have 2+ colors +- Web: `http://127.0.0.1:5174` +- API: `http://127.0.0.1:4100` +- Runtime metadata: `http://127.0.0.1:4100/metadata` -### Controls Reference - -| Control | Action | Location | -|---------|--------|----------| -| **Upload Area** | Click or drag-drop to select image | Top of page | -| **Color Slider** | Adjust number of colors to extract (3-10) | Below upload area | -| **Find Colors** | Extract colors from uploaded image | Below slider | -| **Skip & Add Manually** | Bypass upload and start with default colors | Below upload area | -| **Color Swatch** | Click to open color picker | Color palette grid | -| **HEX Input** | Type HEX code directly | Below each swatch | -| **+ Button** | Add new color to palette | End of color grid | -| **× Button** | Remove color from palette | Top-right of each swatch | -| **Apply Color Theory** | Analyze color relationships | Below color palette | -| **Start Over** | Reset and return to upload screen | Top-right of palette | - -### Exploration Tips - -- **Minimum colors**: You need at least 2 colors for analysis -- **Optimal range**: 3-7 colors typically produce the clearest harmony patterns -- **Image selection**: Photos with distinct color regions work best for extraction -- **Manual refinement**: Extracted colors can be edited after extraction -- **Harmony connections**: Look for colored lines on the color wheel showing detected relationships -- **Accessibility focus**: Red ✗ marks in the contrast table indicate potential issues -- **Temperature balance**: Check if your palette skews warm, cool, or balanced -- **Relationship fit**: Higher values mean detected hue geometry more closely matches the documented structures; this is not an aesthetic rating - -## Color Extraction Algorithm - -ColorCraft uses a sophisticated perceptual color extraction pipeline: - -### Step 1: Image Preprocessing -```python -# Resize to max 400px for performance -# Ignore fully transparent pixels; composite partial alpha over white -# Sample up to 10,000 pixels with a seeded generator -``` - -### Step 2: RGB → LAB Conversion -```python -# LAB color space is perceptually uniform -# Distances in LAB space match human vision -# Uses D65 white point (standard daylight) -# Gamma correction for sRGB → linear RGB -# XYZ intermediate transformation -``` - -### Step 3: KMeans Clustering -```python -# Effective clusters = min(requested colors, usable unique sampled pixels) -# Seeded initialization for deterministic output -# 300 max iterations for convergence -# Clusters directly in LAB space -# No dimensionality reduction needed -``` - -### Step 4: Representative Selection -```python -# Select the sampled RGB pixel nearest each LAB cluster center (a medoid) -# Sort representatives by sampled population, largest first -# Report population ratio and sampled pixel count -``` +See [Getting started](./docs/getting-started.md) for setup and recovery details. -### Step 5: Output Validation +## Product workflow -Representatives are processed-sample RGB values, so conversion cannot create -NaN-derived or malformed HEX values. The API returns the actual number of -colors found, which can be lower than the requested maximum. - -**Why LAB instead of RGB?** -- RGB distances don't match perceived color differences -- LAB is designed for human vision (CIE 1976) -- Equal distances in LAB = equal perceptual differences -- Better clustering results for color palettes - -## Color Theory Engine - -ColorCraft detects multiple harmony patterns using hue angle mathematics: - -### Harmony Detection Methods - -| Harmony Type | Hue Relationship | Tolerance | Visual Pattern | -|--------------|------------------|-----------|----------------| -| **Complementary** | 180° apart | ±12° | Opposite sides of wheel | -| **Analogous** | 30° apart | ±15° | Adjacent neighbors | -| **Triadic** | Three 120° gaps | ±12° per gap | Equilateral triangle | -| **Tetradic** | Four 90° gaps | ±10° per gap | Square | -| **Split-Complementary** | 150°, 150°, and 60° | ±12° | Y-shape pattern | -| **Monochromatic** | Same meaningful hue, varied S/L | ±10° hue | Single color family | - -### Temperature Analysis - -**Warm Colors** (0-60°, 300-360°): -- Reds, oranges, yellows -- Associated with energy, passion, warmth - -**Cool Colors** (120-300°): -- Greens, blues, purples -- Associated with calm, professionalism, nature - -**Neutral** (60-120°): -- Yellow-greens, chartreuse -- Transitional colors - -### Geometric relationship fit - -Relationship fit combines the best measured confidence for each detected -relationship type with the share of meaningful, chromatic hues involved. -Every relationship reports expected angles, measured angles, deviation, and -confidence. Colors below 10% saturation do not count as hue evidence, and -duplicate hues cannot manufacture a relationship. This metric describes -geometry only—not whether a palette is attractive or suitable for a design. - -## Accessibility Analysis - -ColorCraft implements full WCAG 2.1 contrast ratio calculations: - -### Contrast Ratio Formula - -```python -# 1. Calculate relative luminance for each color -L = 0.2126 * R + 0.7152 * G + 0.0722 * B -# (where R, G, B are gamma-corrected) - -# 2. Compute contrast ratio -ratio = (lighter_L + 0.05) / (darker_L + 0.05) -# Range: 1:1 (no contrast) to 21:1 (black on white) -``` - -### WCAG Compliance Levels - -| Level | Normal Text | Large Text | Use Case | -|-------|-------------|------------|----------| -| **AA** | 4.5:1 | 3:1 | Minimum for body text | -| **AAA** | 7:1 | 4.5:1 | Enhanced accessibility | - -**Large Text Definition:** -- 18pt+ regular weight -- 14pt+ bold weight - -### Accessibility Features - -- ✅ Pairwise contrast analysis for all color combinations -- ✅ AA/AAA compliance badges for normal and large text -- ✅ Automatic issue flagging with severity levels -- ✅ Visual indicators (✓/✗) in contrast table -- ✅ Summary statistics (total pairs, compliant count) -- ✅ Specific warnings with color pairs and ratios - -## API Endpoints - -### Service Metadata -```http -GET / -``` -**Response:** -```json -{ - "status": "ok", - "service": "colorcraft-api", - "version": "1.0.0" -} -``` - -### Health and Readiness - -```http -GET /health -GET /ready -``` - -`/health` indicates that the API process is alive. `/ready` returns `ready` -after color extraction, palette analysis, and color suggestions have -initialized. The single-terminal launcher waits for this readiness response. - -Request and response validation details, including the canonical color-input -strategy, are documented in [API Contracts](docs/api-contracts.md). - -### Extract Colors -```http -POST /api/extract-colors?n_colors=5 -Content-Type: multipart/form-data - -file: -``` -**Parameters:** -- `n_colors` (query): Maximum number of colors to extract (3-10) -- `file` (form): Image file (JPG, PNG, WebP), up to 10 MB and 40 million decoded pixels - -**Response:** -```json -{ - "success": true, - "colors": [ - { - "hex": "#667eea", - "rgb": {"r": 102, "g": 126, "b": 234}, - "hsl": {"h": 229, "s": 75, "l": 66}, - "population": 0.52, - "pixelCount": 5200 - }, - { - "hex": "#f093fb", - "rgb": {"r": 240, "g": 147, "b": 251}, - "hsl": {"h": 294, "s": 92, "l": 78}, - "population": 0.31, - "pixelCount": 3100 - }, - { - "hex": "#764ba2", - "rgb": {"r": 118, "g": 75, "b": 162}, - "hsl": {"h": 270, "s": 37, "l": 46}, - "population": 0.17, - "pixelCount": 1700 - } - ], - "count": 3 -} -``` - -### Analyze Colors -```http -POST /api/analyze-colors -Content-Type: application/json - -{ - "colors": [ - { - "hex": "#667eea", - "rgb": {"r": 102, "g": 126, "b": 234}, - "hsl": {"h": 229, "s": 75, "l": 66} - }, - { - "hex": "#f093fb", - "rgb": {"r": 240, "g": 147, "b": 251}, - "hsl": {"h": 294, "s": 92, "l": 78} - } - ] -} -``` - -**Response:** -```json -{ - "success": true, - "analysis": { - "colorTheory": { - "harmonies": { - "complementary": [{ - "type": "complementary", - "colorIndexes": [0, 1], - "expectedAngles": [180.0], - "measuredAngles": [178.0], - "deviation": 2.0, - "confidence": 0.889 - }], - "triadic": [], - "analogous": [], - "tetradic": [], - "splitComplementary": [], - "monochromatic": [] - }, - "temperatureBalance": { - "balance": "cool", - "warmCount": 1, - "coolCount": 4, - "warmRatio": 0.2, - "coolRatio": 0.8 - }, - "relationshipFit": 75, - "relationshipSummary": "Strong geometric relationship", - "relationshipFactors": ["Best complementary pair deviation: 2.0 degrees."], - "tags": [ - "Complementary Harmony Detected", - "Triadic Harmony Detected", - "Cool Color Palette", - "Balanced Saturation" - ], - "metrics": { - "hueDiversity": 45.2, - "saturationAvg": 68.4, - "lightnessRange": 42 - } - }, - "accessibility": { - "pairs": [ - { - "color1": "#667eea", - "color2": "#ffffff", - "ratio": 4.52, - "aaNormal": true, - "aaLarge": true, - "aaaNormal": false, - "aaaLarge": true - } - ], - "issues": [ - { - "type": "low_contrast", - "message": "Low contrast detected between #f1f1f1 and #aaaaaa (ratio: 2.1)", - "severity": "warning", - "color1": "#f1f1f1", - "color2": "#aaaaaa", - "ratio": 2.1 - } - ], - "summary": { - "totalPairs": 10, - "aaNormalPasses": 7, - "aaLargePasses": 8, - "aaaNormalPasses": 3, - "aaaLargePasses": 7 - } - } - } -} -``` - -## Data Flow & Processing - -### Image Upload Flow ```mermaid -graph TD - A[User Uploads Image] --> B[Frontend: File Validation] - B --> C[API: POST /extract-colors] - C --> D[Backend: Load Image with Pillow] - D --> E[Resize to 400px max] - E --> F[Sample up to 10k pixels] - F --> G[Convert RGB → LAB] - G --> H[KMeans Clustering 20 inits] - H --> I[Select Median Colors] - I --> J[Convert LAB → RGB/HEX/HSL] - J --> K[Return Color Array] - K --> L[Frontend: Display Color Palette] +flowchart LR + Start[Upload image or start manually] --> Edit[Refine palette] + Edit --> Save[Save locally] + Save --> Review[Review harmony and contrast] + Review --> Export[Copy or download exports] + Save --> Library[Search, reopen, rename, duplicate, or delete] ``` -### Color Analysis Flow -```mermaid -graph TD - A[User Clicks Apply Color Theory] --> B[Frontend: Validate 2+ Colors] - B --> C[API: POST /analyze-colors] - C --> D[Backend: Extract Hues] - D --> E[Detect Complementary 180°] - D --> F[Detect Triadic 120°] - D --> G[Detect Analogous 30-60°] - D --> H[Detect Tetradic 90°] - D --> I[Detect Split-Complementary] - D --> J[Detect Monochromatic] - E --> K[Calculate Temperature Balance] - F --> K - G --> K - H --> K - I --> K - J --> K - K --> L[Compute Relationship Fit] - L --> M[Calculate WCAG Ratios] - M --> N[Generate Tags & Metrics] - N --> O[Return Analysis Object] - O --> P[Frontend: Render Visualizations] -``` +The application makes state explicit: **Unsaved** means no local record exists, **Saved** means the open palette matches its record, and **Modified** means local edits need **Save changes**. Starting another palette or opening a saved palette prompts before meaningful unsaved work is discarded. -### Color Wheel Rendering -```mermaid -graph LR - A[Analysis Results] --> B[D3.js Initialize SVG] - B --> C[Draw 360° Color Wheel] - C --> D[Plot Color Points by Hue] - D --> E[Draw Harmony Connections] - E --> F[Add Hover Interactions] - F --> G[Display Relationship Fit] - G --> H[Render Complete Wheel] -``` - -## Troubleshooting - -### Backend Issues +## Capabilities -**Problem: `ModuleNotFoundError: No module named 'fastapi'`** -```bash -# Solution: Install dependencies -cd backend -pip install -r requirements.txt -``` +- Deterministic LAB-space image color extraction +- Manual palette creation and direct HEX editing +- Harmony visualization and explainable relationship fit +- WCAG contrast-role review and color suggestions +- CSS, JSON, Tailwind, and token export +- IndexedDB palette library with search and recent items +- Light, dark, and system themes with responsive navigation +- Dashboard discovery through a static manifest and runtime metadata endpoint -**Problem: `Address already in use` (port 4100)** -```bash -# Windows: Find and kill process -netstat -ano | findstr :4100 -taskkill /PID /F +## Validation -# macOS/Linux: Find and kill process -lsof -ti:4100 | xargs kill -9 -``` +After installing the development dependencies and Playwright Chromium: -**Problem: `ImportError: DLL load failed` (Windows)** -```bash -# Solution: Reinstall numpy with proper binaries -pip uninstall numpy -pip install numpy==1.26.2 -``` - -### Frontend Issues - -**Problem: `ECONNREFUSED 127.0.0.1:4100`** -```bash -# Solution 1: Ensure backend is running -cd backend -python -m uvicorn main:app --host 127.0.0.1 --port 4100 - -# Solution 2: Restart frontend after backend starts -cd frontend -# Press Ctrl+C to stop -corepack pnpm@9.15.9 dev -``` - -**Problem: `pnpm: command not found`** -```bash -# Solution: Run pnpm through Corepack -corepack pnpm@9.15.9 install -``` - -**Problem: Frontend won't start after `git pull`** -```bash -# Solution: Clean reinstall +```powershell cd frontend -rm -rf node_modules pnpm-lock.yaml -corepack pnpm@9.15.9 install -corepack pnpm@9.15.9 dev +corepack pnpm@9.15.9 exec playwright install chromium +cd .. +.\backend\.venv311\Scripts\python.exe check.py ``` -### Image Upload Issues - -**Problem: "Invalid file type" error** -- **Solution**: Ensure file is JPG, PNG, or WebP format -- Check file extension matches actual format - -**Problem: Colors extraction takes too long** -- **Solution**: Image is likely very large -- Try resizing image to under 2000px before upload -- App auto-resizes to 400px but large images take time to load +`check.py` runs formatting, linting, frontend and backend typing, unit and integration coverage, production build, Playwright workflow coverage, and automated accessibility checks. CI runs the same command. See [Testing](./docs/testing.md). -**Problem: Extracted colors don't match image** -- **Solution**: Image may have too many similar colors -- Try increasing number of colors to extract (up to 10) -- Or manually adjust colors after extraction +## Documentation -### Analysis Issues +The [documentation index](./docs/README.md) links setup, workflow, runtime configuration, architecture, API, persistence and privacy, dashboard manifest, brand, testing, screenshot review, and troubleshooting guides. -**Problem: "Please add at least 2 colors to analyze"** -- **Solution**: Add more colors using the "+" button -- Or extract colors from an image first +## Privacy and security -**Problem: Low relationship fit despite a good-looking palette** -- **Explanation**: Relationship fit measures angular geometry, not aesthetics -- Beautiful palettes may intentionally avoid strict geometric relationships -- Treat the measured factors, accessibility, and intended use as separate evidence - -**Problem: All contrast ratios fail AA/AAA** -- **Solution**: Your colors may be too similar in lightness -- Add darker or lighter colors for better contrast -- Use the contrast table to identify which pairs need adjustment - -## Roadmap & Next Steps - -### Planned Features (Post-MVP) - -- [ ] **Palette Export**: Save palettes as .ASE, .JSON, .SVG, .PNG -- [ ] **AI Palette Naming**: Generate descriptive names like "Autumn Glow" or "Ocean Breeze" -- [ ] **Batch Analysis**: Upload multiple images and compare color consistency -- [ ] **Color Blindness Simulation**: Preview palette for deuteranopia, protanopia, tritanopia -- [ ] **Gradient Generator**: Create smooth gradients between selected colors -- [ ] **Palette History**: Save and revisit previous analyses -- [ ] **Shareable Links**: Generate URLs to share palettes with collaborators -- [ ] **Plugin Integration**: Figma, Photoshop, Canva plugins -- [ ] **API Key System**: Rate limiting and usage tracking -- [ ] **Advanced Clustering**: DBSCAN, hierarchical clustering options -- [ ] **Color Mood Analysis**: Emotional associations and psychological impact -- [ ] **Brand Palette Validation**: Upload brand guidelines and validate compliance - -### Technical Improvements - -- [ ] **Database Integration**: PostgreSQL for multi-user support -- [ ] **Caching Layer**: Redis for frequently extracted color palettes -- [ ] **WebSocket Support**: Real-time progress updates during extraction -- [ ] **Docker Deployment**: Containerized stack for easy deployment -- [ ] **CI/CD Pipeline**: Automated testing and deployment -- [ ] **Performance Monitoring**: Sentry integration for error tracking -- [ ] **API Documentation**: Interactive Swagger UI -- [ ] **Unit Tests**: Comprehensive test coverage for backend and frontend -- [ ] **E2E Tests**: Playwright or Cypress for user flow testing - -## Contributing - -Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines. - -### Quick Start for Contributors - -1. **Fork the repository** -2. **Clone your fork**: `git clone https://github.com/YOUR_USERNAME/ColorCraft.git` -3. **Create a branch**: `git checkout -b feature/your-feature-name` -4. **Make changes** and test thoroughly -5. **Commit**: `git commit -m "Add your feature"` -6. **Push**: `git push origin feature/your-feature-name` -7. **Create Pull Request** on GitHub - -### Development Guidelines - -- **Backend**: Follow PEP 8, use type hints, add docstrings -- **Frontend**: Use TypeScript, follow React best practices, use functional components -- **Commits**: Use conventional commits (feat:, fix:, docs:, etc.) -- **Testing**: Add tests for new features -- **Documentation**: Update README and inline comments +ColorCraft binds to loopback addresses by default. Palette records are stored in the browser's IndexedDB database; theme preference is the only application preference stored in LocalStorage. Source images are sent to the local API for extraction but are not retained by ColorCraft after processing. Clearing site data removes saved palettes. Read [Persistence and privacy](./docs/persistence-and-privacy.md) before enabling LAN access. ## License -MIT License - See [LICENSE](LICENSE) file for details. - -Copyright (c) 2025 ColorCraft - -## Mermaid Diagrams - -### System Architecture - -```mermaid -graph TB - subgraph Frontend["Frontend (React + TypeScript)"] - UI[User Interface] - Upload[ImageUpload Component] - Palette[ColorPalette Component] - Wheel[ColorWheel Component D3.js] - Results[AnalysisResults Component] - end - - subgraph Backend["Backend (Python FastAPI)"] - API[FastAPI Router] - Extractor[Color Extractor
LAB + KMeans] - Theory[Color Theory Engine
Harmony Detection] - Access[Accessibility Engine
WCAG 2.1] - end - - subgraph Processing["Processing Pipeline"] - LAB[RGB → LAB Conversion] - KMeans[KMeans Clustering
20 Initializations] - Median[Median Selection] - RGB[LAB → RGB/HEX/HSL] - end - - UI --> Upload - UI --> Palette - Upload -->|Image File| API - Palette -->|Color Array| API - - API --> Extractor - API --> Theory - API --> Access - - Extractor --> LAB - LAB --> KMeans - KMeans --> Median - Median --> RGB - RGB -->|Colors| Palette - - Theory -->|Harmonies| Results - Access -->|WCAG Ratios| Results - Results --> Wheel -``` - -### Color Extraction Pipeline - -```mermaid -sequenceDiagram - autonumber - actor User - participant UI as ImageUpload UI - participant API as FastAPI /extract-colors - participant Img as Image Processor - participant LAB as LAB Converter - participant KM as KMeans Clusterer - participant Conv as Color Converter - - User->>UI: Upload image (JPG/PNG/WebP) - UI->>UI: Validate file type - UI->>API: POST /extract-colors?n_colors=5 - API->>Img: Load image with Pillow - Img->>Img: Convert to RGB if needed - Img->>Img: Resize to max 400px - Img->>Img: Extract pixel array - Img->>Img: Sample 10k pixels if large - - Img->>LAB: Convert RGB pixels → LAB - LAB->>LAB: Gamma correction - LAB->>LAB: RGB → XYZ → LAB (D65) - LAB-->>KM: LAB pixel array - - KM->>KM: KMeans fit (20 inits, 300 iters) - KM->>KM: Assign cluster labels - KM->>KM: Select nearest sampled RGB medoid - KM-->>Conv: LAB cluster colors - - Conv->>Conv: LAB → XYZ → RGB - Conv->>Conv: Gamma inverse correction - Conv->>Conv: Clip to [0, 255] - Conv->>Conv: RGB → HEX - Conv->>Conv: RGB → HSL - Conv-->>API: Color array (HEX, RGB, HSL) - - API-->>UI: JSON response with colors - UI-->>User: Display color palette -``` - -### Color Analysis Pipeline - -```mermaid -sequenceDiagram - autonumber - actor User - participant UI as App UI - participant API as FastAPI /analyze-colors - participant Theory as Color Theory Engine - participant Access as Accessibility Engine - participant Wheel as D3.js Color Wheel - - User->>UI: Click "Apply Color Theory" - UI->>UI: Validate 2+ colors - UI->>API: POST /analyze-colors {colors} - - API->>Theory: Extract hue angles - Theory->>Theory: Detect complementary (180°±30°) - Theory->>Theory: Detect triadic (120°±30°) - Theory->>Theory: Detect analogous (30-60°±30°) - Theory->>Theory: Detect tetradic (90°±30°) - Theory->>Theory: Detect split-complementary - Theory->>Theory: Detect monochromatic (±15° hue) - Theory->>Theory: Analyze temperature (warm/cool) - Theory->>Theory: Calculate geometric relationship fit (0-100) - Theory->>Theory: Generate harmony tags - Theory-->>API: Color theory analysis - - API->>Access: Calculate pairwise contrasts - Access->>Access: Compute relative luminance - Access->>Access: Calculate contrast ratios - Access->>Access: Check AA/AAA compliance - Access->>Access: Flag accessibility issues - Access-->>API: Accessibility analysis - - API-->>UI: Combined analysis JSON - UI->>Wheel: Render color wheel - Wheel->>Wheel: Draw 360° wheel background - Wheel->>Wheel: Plot colors by hue angle - Wheel->>Wheel: Draw harmony connections - Wheel->>Wheel: Add compact relationship-fit annotation - Wheel-->>UI: Interactive visualization - - UI-->>User: Display analysis results -``` - -### Data Model - -```mermaid -erDiagram - COLOR { - string hex PK - object rgb - object hsl - } - - HARMONY_ANALYSIS { - uuid id PK - array complementary_pairs - array triadic_groups - array analogous_groups - array tetradic_groups - array split_complementary - boolean monochromatic - object temperature_balance - int relationship_fit - array tags - object metrics - } - - ACCESSIBILITY_ANALYSIS { - uuid id PK - array contrast_pairs - array issues - object summary - } - - CONTRAST_PAIR { - string color1 FK - string color2 FK - float ratio - boolean aa_normal - boolean aa_large - boolean aaa_normal - boolean aaa_large - } - - COLOR ||--o{ CONTRAST_PAIR : "participates in" - HARMONY_ANALYSIS ||--o{ COLOR : "analyzes" - ACCESSIBILITY_ANALYSIS ||--o{ CONTRAST_PAIR : "contains" -``` - ---- - -**Built with ❤️ for designers, developers, and artists who care about color.** - +[MIT](./LICENSE) diff --git a/app-manifest.json b/app-manifest.json new file mode 100644 index 0000000..092843c --- /dev/null +++ b/app-manifest.json @@ -0,0 +1,25 @@ +{ + "schemaVersion": 1, + "id": "colorcraft", + "name": "ColorCraft", + "descriptor": "Local color utility", + "version": "1.0.0", + "icon": "/colorcraft-mark.svg", + "defaults": { + "webAddress": "http://127.0.0.1:5174", + "apiAddress": "http://127.0.0.1:4100" + }, + "endpoints": { + "metadata": "/metadata", + "health": "/health", + "readiness": "/ready" + }, + "capabilities": [ + "image-color-extraction", + "palette-editing", + "harmony-analysis", + "contrast-review", + "palette-export", + "local-palette-library" + ] +} diff --git a/backend/accessibility.py b/backend/accessibility.py index 34f926d..c28cf1e 100644 --- a/backend/accessibility.py +++ b/backend/accessibility.py @@ -8,18 +8,19 @@ def hex_to_rgb(hex_color): """Convert hex color to RGB.""" - hex_color = hex_color.lstrip('#') - return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4)) + hex_color = hex_color.lstrip("#") + return tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4)) def relative_luminance(rgb): """Calculate relative luminance using the current sRGB breakpoint.""" + def adjust(channel): channel = channel / 255.0 if channel <= 0.04045: return channel / 12.92 return ((channel + 0.055) / 1.055) ** 2.4 - + r, g, b = [adjust(c) for c in rgb] return 0.2126 * r + 0.7152 * g + 0.0722 * b @@ -27,11 +28,11 @@ def adjust(channel): def contrast_ratio(color1, color2): """ Calculate WCAG contrast ratio between two colors. - + Args: color1: RGB tuple or hex string color2: RGB tuple or hex string - + Returns: Contrast ratio (1-21) """ @@ -39,95 +40,96 @@ def contrast_ratio(color1, color2): color1 = hex_to_rgb(color1) if isinstance(color2, str): color2 = hex_to_rgb(color2) - + l1 = relative_luminance(color1) l2 = relative_luminance(color2) - + lighter = max(l1, l2) darker = min(l1, l2) - + return (lighter + 0.05) / (darker + 0.05) def wcag_rating(ratio): """ Get WCAG rating for a contrast ratio. - + Returns: Dictionary with AA and AAA compliance for normal and large text """ return { - 'ratio': round(ratio, 2), - 'aa_normal': ratio >= AA_NORMAL_MINIMUM, - 'aa_large': ratio >= AA_LARGE_MINIMUM, - 'aaa_normal': ratio >= AAA_NORMAL_MINIMUM, - 'aaa_large': ratio >= AAA_LARGE_MINIMUM + "ratio": round(ratio, 2), + "aa_normal": ratio >= AA_NORMAL_MINIMUM, + "aa_large": ratio >= AA_LARGE_MINIMUM, + "aaa_normal": ratio >= AAA_NORMAL_MINIMUM, + "aaa_large": ratio >= AAA_LARGE_MINIMUM, } def analyze_accessibility(colors): """ Analyze accessibility for all color pairs. - + Args: colors: List of color dictionaries with 'hex' key - + Returns: Dictionary with accessibility analysis """ results = { - 'pairs': [], - 'issues': [], - 'summary': { - 'total_pairs': 0, - 'aa_normal_passes': 0, - 'aa_large_passes': 0, - 'aaa_normal_passes': 0, - 'aaa_large_passes': 0 - } + "pairs": [], + "issues": [], + "summary": { + "total_pairs": 0, + "aa_normal_passes": 0, + "aa_large_passes": 0, + "aaa_normal_passes": 0, + "aaa_large_passes": 0, + }, } - + # Analyze all pairs for i, color1 in enumerate(colors): for j, color2 in enumerate(colors): if i >= j: continue - - ratio = contrast_ratio(color1['hex'], color2['hex']) + + ratio = contrast_ratio(color1["hex"], color2["hex"]) rating = wcag_rating(ratio) - + pair_result = { - 'color1': color1['hex'], - 'color2': color2['hex'], - 'ratio': rating['ratio'], - 'aa_normal': rating['aa_normal'], - 'aa_large': rating['aa_large'], - 'aaa_normal': rating['aaa_normal'], - 'aaa_large': rating['aaa_large'] + "color1": color1["hex"], + "color2": color2["hex"], + "ratio": rating["ratio"], + "aa_normal": rating["aa_normal"], + "aa_large": rating["aa_large"], + "aaa_normal": rating["aaa_normal"], + "aaa_large": rating["aaa_large"], } - - results['pairs'].append(pair_result) - results['summary']['total_pairs'] += 1 - - if rating['aa_normal']: - results['summary']['aa_normal_passes'] += 1 - if rating['aa_large']: - results['summary']['aa_large_passes'] += 1 - if rating['aaa_normal']: - results['summary']['aaa_normal_passes'] += 1 - if rating['aaa_large']: - results['summary']['aaa_large_passes'] += 1 - + + results["pairs"].append(pair_result) + results["summary"]["total_pairs"] += 1 + + if rating["aa_normal"]: + results["summary"]["aa_normal_passes"] += 1 + if rating["aa_large"]: + results["summary"]["aa_large_passes"] += 1 + if rating["aaa_normal"]: + results["summary"]["aaa_normal_passes"] += 1 + if rating["aaa_large"]: + results["summary"]["aaa_large_passes"] += 1 + # Flag potential issues - if not rating['aa_large']: - results['issues'].append({ - 'type': 'low_contrast', - 'message': f"Low contrast detected between {color1['hex']} and {color2['hex']} (ratio: {rating['ratio']})", - 'severity': 'warning', - 'color1': color1['hex'], - 'color2': color2['hex'], - 'ratio': rating['ratio'] - }) - - return results + if not rating["aa_large"]: + results["issues"].append( + { + "type": "low_contrast", + "message": f"Low contrast detected between {color1['hex']} and {color2['hex']} (ratio: {rating['ratio']})", + "severity": "warning", + "color1": color1["hex"], + "color2": color2["hex"], + "ratio": rating["ratio"], + } + ) + return results diff --git a/backend/color_extractor.py b/backend/color_extractor.py index de41a5a..6633802 100644 --- a/backend/color_extractor.py +++ b/backend/color_extractor.py @@ -13,7 +13,6 @@ from PIL import Image, UnidentifiedImageError from sklearn.cluster import KMeans - MAX_IMAGE_PIXELS = 40_000_000 MAX_SAMPLE_PIXELS = 10_000 SAMPLE_SEED = 42 @@ -47,11 +46,7 @@ def rgb_to_lab(rgb: list[int] | tuple[int, int, int] | np.ndarray) -> list[float delta = 6 / 29 def transform(value: float) -> float: - return ( - value ** (1 / 3) - if value > delta**3 - else value / (3 * delta**2) + 4 / 29 - ) + return value ** (1 / 3) if value > delta**3 else value / (3 * delta**2) + 4 / 29 fx = transform(x / 95.047) fy = transform(y / 100) @@ -133,6 +128,7 @@ def hsl_to_rgb(hsl: list[int] | tuple[int, int, int]) -> list[int]: if saturation == 0: red = green = blue = lightness else: + def hue_to_rgb(p: float, q: float, value: float) -> float: value %= 1 if value < 1 / 6: @@ -162,9 +158,7 @@ def _visible_rgb_pixels(image: Image.Image) -> np.ndarray: raise NoUsablePixelsError("The image contains no visible pixels.") alpha = visible[:, 3:4].astype(np.float64) / 255.0 - composited = ( - visible[:, :3].astype(np.float64) * alpha + 255.0 * (1.0 - alpha) - ) + composited = visible[:, :3].astype(np.float64) * alpha + 255.0 * (1.0 - alpha) return np.rint(composited).clip(0, 255).astype(np.uint8) @@ -172,9 +166,7 @@ def _sample_pixels(pixels: np.ndarray) -> np.ndarray: if len(pixels) <= MAX_SAMPLE_PIXELS: return pixels generator = np.random.default_rng(SAMPLE_SEED) - indexes = generator.choice( - len(pixels), size=MAX_SAMPLE_PIXELS, replace=False - ) + indexes = generator.choice(len(pixels), size=MAX_SAMPLE_PIXELS, replace=False) return pixels[indexes] @@ -260,6 +252,9 @@ def extract_colors(image_bytes: bytes, n_colors: int = 5) -> list[dict[str, obje ) extracted.sort( - key=lambda color: (-int(color["pixelCount"]), str(color["hex"])) + key=lambda color: ( + -color["pixelCount"] if isinstance(color["pixelCount"], int) else 0, + str(color["hex"]), + ) ) return extracted diff --git a/backend/color_suggestions.py b/backend/color_suggestions.py index 2e0a2fe..0790f70 100644 --- a/backend/color_suggestions.py +++ b/backend/color_suggestions.py @@ -1,8 +1,8 @@ """ Color suggestion engine for generating harmonious color recommendations. """ + from color_extractor import hsl_to_rgb, rgb_to_hsl -import math def normalize_hue(hue): @@ -17,461 +17,475 @@ def normalize_hue(hue): def generate_complementary(base_color): """ Generate complementary color (180° opposite). - + Creates maximum contrast and visual tension. Perfect for call-to-action buttons and emphasis. """ - h, s, l = base_color['hsl']['h'], base_color['hsl']['s'], base_color['hsl']['l'] - + h, s, l = base_color["hsl"]["h"], base_color["hsl"]["s"], base_color["hsl"]["l"] + comp_hue = normalize_hue(h + 180) - + suggestions = [ { - 'hue': comp_hue, - 'saturation': s, - 'lightness': l, - 'name': 'Direct Complement', - 'description': 'Exact opposite on the color wheel' + "hue": comp_hue, + "saturation": s, + "lightness": l, + "name": "Direct Complement", + "description": "Exact opposite on the color wheel", }, { - 'hue': comp_hue, - 'saturation': min(100, s + 15), - 'lightness': max(20, l - 20), - 'name': 'Rich Complement', - 'description': 'More saturated and darker for depth' + "hue": comp_hue, + "saturation": min(100, s + 15), + "lightness": max(20, l - 20), + "name": "Rich Complement", + "description": "More saturated and darker for depth", }, { - 'hue': comp_hue, - 'saturation': max(30, s - 20), - 'lightness': min(90, l + 20), - 'name': 'Soft Complement', - 'description': 'Lighter and less saturated for subtlety' - } + "hue": comp_hue, + "saturation": max(30, s - 20), + "lightness": min(90, l + 20), + "name": "Soft Complement", + "description": "Lighter and less saturated for subtlety", + }, ] - + return { - 'type': 'Complementary', - 'angle': '180°', - 'description': 'Complementary colors sit opposite each other on the color wheel, creating maximum contrast and visual energy.', - 'use_cases': [ - 'Call-to-action buttons that need to stand out', - 'Highlighting important UI elements', - 'Creating vibrant, attention-grabbing designs', - 'Logos that need strong visual impact' + "type": "Complementary", + "angle": "180°", + "description": "Complementary colors sit opposite each other on the color wheel, creating maximum contrast and visual energy.", + "use_cases": [ + "Call-to-action buttons that need to stand out", + "Highlighting important UI elements", + "Creating vibrant, attention-grabbing designs", + "Logos that need strong visual impact", ], - 'mood': 'Energetic, bold, dynamic, attention-grabbing', - 'examples': 'Red & Green, Blue & Orange, Yellow & Purple', - 'suggestions': [convert_hsl_to_color(s) for s in suggestions] + "mood": "Energetic, bold, dynamic, attention-grabbing", + "examples": "Red & Green, Blue & Orange, Yellow & Purple", + "suggestions": [convert_hsl_to_color(s) for s in suggestions], } def generate_triadic(base_color): """ Generate triadic colors (120° apart). - + Creates balanced, vibrant palettes with strong visual interest. """ - h, s, l = base_color['hsl']['h'], base_color['hsl']['s'], base_color['hsl']['l'] - + h, s, l = base_color["hsl"]["h"], base_color["hsl"]["s"], base_color["hsl"]["l"] + suggestions = [] - + # Two triadic partners for offset in [120, 240]: tri_hue = normalize_hue(h + offset) - suggestions.extend([ - { - 'hue': tri_hue, - 'saturation': s, - 'lightness': l, - 'name': f'Triadic Partner {offset}°', - 'description': 'Equal spacing for balance' - }, - { - 'hue': tri_hue, - 'saturation': min(100, s + 10), - 'lightness': l, - 'name': f'Vibrant Triadic {offset}°', - 'description': 'Boosted saturation for impact' - } - ]) - + suggestions.extend( + [ + { + "hue": tri_hue, + "saturation": s, + "lightness": l, + "name": f"Triadic Partner {offset}°", + "description": "Equal spacing for balance", + }, + { + "hue": tri_hue, + "saturation": min(100, s + 10), + "lightness": l, + "name": f"Vibrant Triadic {offset}°", + "description": "Boosted saturation for impact", + }, + ] + ) + return { - 'type': 'Triadic', - 'angle': '120°', - 'description': 'Triadic colors are evenly spaced around the color wheel, forming an equilateral triangle. This creates balanced, vibrant palettes.', - 'use_cases': [ - 'Playful, energetic designs', - 'Children\'s products and educational materials', - 'Brand identities that need to feel dynamic', - 'Infographics and data visualizations' + "type": "Triadic", + "angle": "120°", + "description": "Triadic colors are evenly spaced around the color wheel, forming an equilateral triangle. This creates balanced, vibrant palettes.", + "use_cases": [ + "Playful, energetic designs", + "Children's products and educational materials", + "Brand identities that need to feel dynamic", + "Infographics and data visualizations", ], - 'mood': 'Balanced, vibrant, playful, harmonious', - 'examples': 'Red-Yellow-Blue (primary colors), Orange-Green-Purple (secondary colors)', - 'suggestions': [convert_hsl_to_color(s) for s in suggestions] + "mood": "Balanced, vibrant, playful, harmonious", + "examples": "Red-Yellow-Blue (primary colors), Orange-Green-Purple (secondary colors)", + "suggestions": [convert_hsl_to_color(s) for s in suggestions], } def generate_analogous(base_color): """ Generate analogous colors (30-60° adjacent). - + Creates harmonious, cohesive palettes that feel natural. """ - h, s, l = base_color['hsl']['h'], base_color['hsl']['s'], base_color['hsl']['l'] - + h, s, l = base_color["hsl"]["h"], base_color["hsl"]["s"], base_color["hsl"]["l"] + suggestions = [] - + # Neighbors on both sides for offset in [-60, -30, 30, 60]: ana_hue = normalize_hue(h + offset) - suggestions.append({ - 'hue': ana_hue, - 'saturation': s, - 'lightness': l, - 'name': f'Analogous {abs(offset)}° {"Left" if offset < 0 else "Right"}', - 'description': f'Adjacent color {abs(offset)}° away' - }) - + suggestions.append( + { + "hue": ana_hue, + "saturation": s, + "lightness": l, + "name": f"Analogous {abs(offset)}° {'Left' if offset < 0 else 'Right'}", + "description": f"Adjacent color {abs(offset)}° away", + } + ) + return { - 'type': 'Analogous', - 'angle': '30-60°', - 'description': 'Analogous colors sit next to each other on the color wheel, creating harmonious, cohesive palettes that feel natural and pleasing.', - 'use_cases': [ - 'Backgrounds and gradients', - 'Nature-inspired designs', - 'Calming, serene interfaces', - 'Photography and art portfolios' + "type": "Analogous", + "angle": "30-60°", + "description": "Analogous colors sit next to each other on the color wheel, creating harmonious, cohesive palettes that feel natural and pleasing.", + "use_cases": [ + "Backgrounds and gradients", + "Nature-inspired designs", + "Calming, serene interfaces", + "Photography and art portfolios", ], - 'mood': 'Harmonious, serene, cohesive, natural', - 'examples': 'Blue-Blue/Green-Green, Red-Orange-Yellow', - 'suggestions': [convert_hsl_to_color(s) for s in suggestions] + "mood": "Harmonious, serene, cohesive, natural", + "examples": "Blue-Blue/Green-Green, Red-Orange-Yellow", + "suggestions": [convert_hsl_to_color(s) for s in suggestions], } def generate_split_complementary(base_color): """ Generate split-complementary colors. - + Similar to complementary but with two colors flanking the complement. More nuanced than pure complementary. """ - h, s, l = base_color['hsl']['h'], base_color['hsl']['s'], base_color['hsl']['l'] - + h, s, l = base_color["hsl"]["h"], base_color["hsl"]["s"], base_color["hsl"]["l"] + comp_hue = normalize_hue(h + 180) - + suggestions = [] - + # Split complement: 150° and 210° (or 180° ± 30°) for offset in [-30, 30]: split_hue = normalize_hue(comp_hue + offset) - suggestions.extend([ - { - 'hue': split_hue, - 'saturation': s, - 'lightness': l, - 'name': f'Split Complement {"+30°" if offset > 0 else "-30°"}', - 'description': f'Flanking the complement by {abs(offset)}°' - }, - { - 'hue': split_hue, - 'saturation': max(40, s - 15), - 'lightness': min(85, l + 15), - 'name': f'Soft Split {"+30°" if offset > 0 else "-30°"}', - 'description': 'Muted variation for subtlety' - } - ]) - + suggestions.extend( + [ + { + "hue": split_hue, + "saturation": s, + "lightness": l, + "name": f"Split Complement {'+30°' if offset > 0 else '-30°'}", + "description": f"Flanking the complement by {abs(offset)}°", + }, + { + "hue": split_hue, + "saturation": max(40, s - 15), + "lightness": min(85, l + 15), + "name": f"Soft Split {'+30°' if offset > 0 else '-30°'}", + "description": "Muted variation for subtlety", + }, + ] + ) + return { - 'type': 'Split-Complementary', - 'angle': '150° & 210°', - 'description': 'Split-complementary uses a base color and two colors adjacent to its complement, offering contrast with more nuance than pure complementary.', - 'use_cases': [ - 'Sophisticated brand palettes', - 'Web designs needing contrast without harshness', - 'Editorial layouts and magazines', - 'Product packaging with visual interest' + "type": "Split-Complementary", + "angle": "150° & 210°", + "description": "Split-complementary uses a base color and two colors adjacent to its complement, offering contrast with more nuance than pure complementary.", + "use_cases": [ + "Sophisticated brand palettes", + "Web designs needing contrast without harshness", + "Editorial layouts and magazines", + "Product packaging with visual interest", ], - 'mood': 'Sophisticated, balanced, nuanced, refined', - 'examples': 'Blue with Yellow-Orange and Red-Orange', - 'suggestions': [convert_hsl_to_color(s) for s in suggestions] + "mood": "Sophisticated, balanced, nuanced, refined", + "examples": "Blue with Yellow-Orange and Red-Orange", + "suggestions": [convert_hsl_to_color(s) for s in suggestions], } def generate_tetradic(base_color): """ Generate tetradic/square colors (90° apart). - + Creates rich, complex palettes with four distinct colors. """ - h, s, l = base_color['hsl']['h'], base_color['hsl']['s'], base_color['hsl']['l'] - + h, s, l = base_color["hsl"]["h"], base_color["hsl"]["s"], base_color["hsl"]["l"] + suggestions = [] - + # Three partners at 90°, 180°, 270° for offset in [90, 180, 270]: tet_hue = normalize_hue(h + offset) - suggestions.append({ - 'hue': tet_hue, - 'saturation': s, - 'lightness': l, - 'name': f'Tetradic {offset}°', - 'description': f'Square harmony partner at {offset}°' - }) - + suggestions.append( + { + "hue": tet_hue, + "saturation": s, + "lightness": l, + "name": f"Tetradic {offset}°", + "description": f"Square harmony partner at {offset}°", + } + ) + return { - 'type': 'Tetradic (Square)', - 'angle': '90°', - 'description': 'Tetradic colors form a square on the color wheel, evenly spaced at 90° intervals. This creates rich, complex palettes with maximum variety.', - 'use_cases': [ - 'Complex brand systems with multiple sub-brands', - 'Data visualizations with many categories', - 'Festive, celebratory designs', - 'Gaming interfaces and entertainment' + "type": "Tetradic (Square)", + "angle": "90°", + "description": "Tetradic colors form a square on the color wheel, evenly spaced at 90° intervals. This creates rich, complex palettes with maximum variety.", + "use_cases": [ + "Complex brand systems with multiple sub-brands", + "Data visualizations with many categories", + "Festive, celebratory designs", + "Gaming interfaces and entertainment", ], - 'mood': 'Rich, complex, diverse, energetic', - 'examples': 'Red-Yellow-Green-Blue, Orange-Chartreuse-Cyan-Violet', - 'suggestions': [convert_hsl_to_color(s) for s in suggestions] + "mood": "Rich, complex, diverse, energetic", + "examples": "Red-Yellow-Green-Blue, Orange-Chartreuse-Cyan-Violet", + "suggestions": [convert_hsl_to_color(s) for s in suggestions], } def generate_rectangular(base_color): """ Generate rectangular/compound colors. - + Two complementary pairs that form a rectangle on the wheel. """ - h, s, l = base_color['hsl']['h'], base_color['hsl']['s'], base_color['hsl']['l'] - + h, s, l = base_color["hsl"]["h"], base_color["hsl"]["s"], base_color["hsl"]["l"] + suggestions = [] - + # Rectangular: 60°, 180°, 240° (or other rectangle configurations) for offset in [60, 180, 240]: rect_hue = normalize_hue(h + offset) - suggestions.append({ - 'hue': rect_hue, - 'saturation': s, - 'lightness': l, - 'name': f'Rectangular {offset}°', - 'description': f'Rectangle harmony at {offset}°' - }) - + suggestions.append( + { + "hue": rect_hue, + "saturation": s, + "lightness": l, + "name": f"Rectangular {offset}°", + "description": f"Rectangle harmony at {offset}°", + } + ) + return { - 'type': 'Rectangular (Compound)', - 'angle': '60° & 180°', - 'description': 'Rectangular harmony uses two complementary pairs that form a rectangle on the color wheel, offering rich contrast with balance.', - 'use_cases': [ - 'Editorial designs with multiple sections', - 'Dashboard interfaces with distinct zones', - 'Marketing materials with varied content', - 'Presentation templates' + "type": "Rectangular (Compound)", + "angle": "60° & 180°", + "description": "Rectangular harmony uses two complementary pairs that form a rectangle on the color wheel, offering rich contrast with balance.", + "use_cases": [ + "Editorial designs with multiple sections", + "Dashboard interfaces with distinct zones", + "Marketing materials with varied content", + "Presentation templates", ], - 'mood': 'Balanced, sophisticated, varied, professional', - 'examples': 'Blue-Orange paired with Yellow-Violet', - 'suggestions': [convert_hsl_to_color(s) for s in suggestions] + "mood": "Balanced, sophisticated, varied, professional", + "examples": "Blue-Orange paired with Yellow-Violet", + "suggestions": [convert_hsl_to_color(s) for s in suggestions], } def generate_monochromatic(base_color): """ Generate monochromatic variations (same hue, different S/L). - + Creates cohesive, elegant palettes with subtle variation. """ - h, s, l = base_color['hsl']['h'], base_color['hsl']['s'], base_color['hsl']['l'] - + h, s, l = base_color["hsl"]["h"], base_color["hsl"]["s"], base_color["hsl"]["l"] + suggestions = [ { - 'hue': h, - 'saturation': max(10, s - 30), - 'lightness': min(95, l + 30), - 'name': 'Lighter Tint', - 'description': 'Pastel variation for backgrounds' + "hue": h, + "saturation": max(10, s - 30), + "lightness": min(95, l + 30), + "name": "Lighter Tint", + "description": "Pastel variation for backgrounds", }, { - 'hue': h, - 'saturation': max(5, s - 40), - 'lightness': min(98, l + 40), - 'name': 'Very Light Tint', - 'description': 'Nearly white for subtle accents' + "hue": h, + "saturation": max(5, s - 40), + "lightness": min(98, l + 40), + "name": "Very Light Tint", + "description": "Nearly white for subtle accents", }, { - 'hue': h, - 'saturation': min(100, s + 20), - 'lightness': max(15, l - 30), - 'name': 'Darker Shade', - 'description': 'Rich, deep variation for text' + "hue": h, + "saturation": min(100, s + 20), + "lightness": max(15, l - 30), + "name": "Darker Shade", + "description": "Rich, deep variation for text", }, { - 'hue': h, - 'saturation': min(100, s + 10), - 'lightness': max(10, l - 40), - 'name': 'Very Dark Shade', - 'description': 'Nearly black for strong contrast' + "hue": h, + "saturation": min(100, s + 10), + "lightness": max(10, l - 40), + "name": "Very Dark Shade", + "description": "Nearly black for strong contrast", }, { - 'hue': h, - 'saturation': max(15, s - 25), - 'lightness': l, - 'name': 'Desaturated Tone', - 'description': 'Muted variation for sophistication' + "hue": h, + "saturation": max(15, s - 25), + "lightness": l, + "name": "Desaturated Tone", + "description": "Muted variation for sophistication", }, { - 'hue': h, - 'saturation': min(100, s + 30), - 'lightness': l, - 'name': 'Vibrant Tone', - 'description': 'Boosted saturation for impact' - } + "hue": h, + "saturation": min(100, s + 30), + "lightness": l, + "name": "Vibrant Tone", + "description": "Boosted saturation for impact", + }, ] - + return { - 'type': 'Monochromatic', - 'angle': '0° (same hue)', - 'description': 'Monochromatic palettes use variations of a single hue with different saturation and lightness levels, creating cohesive, elegant designs.', - 'use_cases': [ - 'Minimalist, elegant interfaces', - 'Professional corporate designs', - 'Photography portfolios', - 'Luxury brand materials' + "type": "Monochromatic", + "angle": "0° (same hue)", + "description": "Monochromatic palettes use variations of a single hue with different saturation and lightness levels, creating cohesive, elegant designs.", + "use_cases": [ + "Minimalist, elegant interfaces", + "Professional corporate designs", + "Photography portfolios", + "Luxury brand materials", ], - 'mood': 'Cohesive, elegant, sophisticated, calm', - 'examples': 'Navy-Blue-Sky Blue-Powder Blue, Forest-Sage-Mint Green', - 'suggestions': [convert_hsl_to_color(s) for s in suggestions] + "mood": "Cohesive, elegant, sophisticated, calm", + "examples": "Navy-Blue-Sky Blue-Powder Blue, Forest-Sage-Mint Green", + "suggestions": [convert_hsl_to_color(s) for s in suggestions], } def generate_double_complementary(base_color): """ Generate double-complementary (two sets of complements). - + Also known as tetradic rectangle. """ - h, s, l = base_color['hsl']['h'], base_color['hsl']['s'], base_color['hsl']['l'] - + h, s, l = base_color["hsl"]["h"], base_color["hsl"]["s"], base_color["hsl"]["l"] + suggestions = [] - + # Pick a second base 30° away, then both complements second_base = normalize_hue(h + 30) - + for base_hue in [second_base]: comp_hue = normalize_hue(base_hue + 180) - suggestions.extend([ - { - 'hue': base_hue, - 'saturation': s, - 'lightness': l, - 'name': 'Second Base', - 'description': '30° from original' - }, - { - 'hue': comp_hue, - 'saturation': s, - 'lightness': l, - 'name': 'Second Complement', - 'description': 'Complement of second base' - } - ]) - + suggestions.extend( + [ + { + "hue": base_hue, + "saturation": s, + "lightness": l, + "name": "Second Base", + "description": "30° from original", + }, + { + "hue": comp_hue, + "saturation": s, + "lightness": l, + "name": "Second Complement", + "description": "Complement of second base", + }, + ] + ) + # Original complement - suggestions.append({ - 'hue': normalize_hue(h + 180), - 'saturation': s, - 'lightness': l, - 'name': 'Original Complement', - 'description': 'Complement of base color' - }) - + suggestions.append( + { + "hue": normalize_hue(h + 180), + "saturation": s, + "lightness": l, + "name": "Original Complement", + "description": "Complement of base color", + } + ) + return { - 'type': 'Double-Complementary', - 'angle': 'Two 180° pairs', - 'description': 'Double-complementary uses two pairs of complementary colors, creating rich, dynamic palettes with strong contrast.', - 'use_cases': [ - 'Bold, energetic brand identities', - 'Sports team colors and jerseys', - 'Festival and event materials', - 'Attention-grabbing advertisements' + "type": "Double-Complementary", + "angle": "Two 180° pairs", + "description": "Double-complementary uses two pairs of complementary colors, creating rich, dynamic palettes with strong contrast.", + "use_cases": [ + "Bold, energetic brand identities", + "Sports team colors and jerseys", + "Festival and event materials", + "Attention-grabbing advertisements", ], - 'mood': 'Bold, energetic, dynamic, striking', - 'examples': 'Red-Green paired with Blue-Orange', - 'suggestions': [convert_hsl_to_color(s) for s in suggestions] + "mood": "Bold, energetic, dynamic, striking", + "examples": "Red-Green paired with Blue-Orange", + "suggestions": [convert_hsl_to_color(s) for s in suggestions], } def generate_shades_tints(base_color): """ Generate pure shades (darker) and tints (lighter). - + Essential for creating depth and hierarchy. """ - h, s, l = base_color['hsl']['h'], base_color['hsl']['s'], base_color['hsl']['l'] - + h, s, l = base_color["hsl"]["h"], base_color["hsl"]["s"], base_color["hsl"]["l"] + suggestions = [] - + # Tints (lighter) for i, lightness_offset in enumerate([15, 30, 45], 1): - suggestions.append({ - 'hue': h, - 'saturation': s, - 'lightness': min(98, l + lightness_offset), - 'name': f'Tint {i}', - 'description': f'{lightness_offset}% lighter' - }) - + suggestions.append( + { + "hue": h, + "saturation": s, + "lightness": min(98, l + lightness_offset), + "name": f"Tint {i}", + "description": f"{lightness_offset}% lighter", + } + ) + # Shades (darker) for i, lightness_offset in enumerate([15, 30, 45], 1): - suggestions.append({ - 'hue': h, - 'saturation': s, - 'lightness': max(5, l - lightness_offset), - 'name': f'Shade {i}', - 'description': f'{lightness_offset}% darker' - }) - + suggestions.append( + { + "hue": h, + "saturation": s, + "lightness": max(5, l - lightness_offset), + "name": f"Shade {i}", + "description": f"{lightness_offset}% darker", + } + ) + return { - 'type': 'Shades & Tints', - 'angle': 'Same hue, varied lightness', - 'description': 'Shades (darker) and tints (lighter) of the same color create depth, hierarchy, and visual interest while maintaining color identity.', - 'use_cases': [ - 'UI states (hover, active, disabled)', - 'Text hierarchy (headings, body, captions)', - 'Shadows and highlights', - 'Depth and layering in designs' + "type": "Shades & Tints", + "angle": "Same hue, varied lightness", + "description": "Shades (darker) and tints (lighter) of the same color create depth, hierarchy, and visual interest while maintaining color identity.", + "use_cases": [ + "UI states (hover, active, disabled)", + "Text hierarchy (headings, body, captions)", + "Shadows and highlights", + "Depth and layering in designs", ], - 'mood': 'Structured, hierarchical, organized, clear', - 'examples': 'Light Blue → Blue → Navy, Pink → Red → Maroon', - 'suggestions': [convert_hsl_to_color(s) for s in suggestions] + "mood": "Structured, hierarchical, organized, clear", + "examples": "Light Blue → Blue → Navy, Pink → Red → Maroon", + "suggestions": [convert_hsl_to_color(s) for s in suggestions], } def convert_hsl_to_color(hsl_obj): """Convert HSL suggestion object to full color object.""" - h, s, l = hsl_obj['hue'], hsl_obj['saturation'], hsl_obj['lightness'] + h, s, l = hsl_obj["hue"], hsl_obj["saturation"], hsl_obj["lightness"] rgb = hsl_to_rgb([h, s, l]) canonical_hsl = rgb_to_hsl(rgb) - hex_color = '#{:02x}{:02x}{:02x}'.format(*rgb) - + hex_color = "#{:02x}{:02x}{:02x}".format(*rgb) + return { - 'hex': hex_color, - 'rgb': {'r': rgb[0], 'g': rgb[1], 'b': rgb[2]}, - 'hsl': { - 'h': canonical_hsl[0], - 's': canonical_hsl[1], - 'l': canonical_hsl[2] - }, - 'name': hsl_obj['name'], - 'description': hsl_obj['description'] + "hex": hex_color, + "rgb": {"r": rgb[0], "g": rgb[1], "b": rgb[2]}, + "hsl": {"h": canonical_hsl[0], "s": canonical_hsl[1], "l": canonical_hsl[2]}, + "name": hsl_obj["name"], + "description": hsl_obj["description"], } def generate_all_suggestions(base_color): """ Generate all harmony-based suggestions for a base color. - + Returns a comprehensive list of color suggestions organized by harmony type. """ return { - 'base_color': base_color, - 'harmonies': [ + "base_color": base_color, + "harmonies": [ generate_complementary(base_color), generate_analogous(base_color), generate_triadic(base_color), @@ -480,7 +494,6 @@ def generate_all_suggestions(base_color): generate_rectangular(base_color), generate_monochromatic(base_color), generate_double_complementary(base_color), - generate_shades_tints(base_color) - ] + generate_shades_tints(base_color), + ], } - diff --git a/backend/color_theory.py b/backend/color_theory.py index ccbeeeb..80ee6b8 100644 --- a/backend/color_theory.py +++ b/backend/color_theory.py @@ -2,13 +2,12 @@ from __future__ import annotations -from itertools import combinations import math +from itertools import combinations from typing import Iterable import numpy as np - MIN_MEANINGFUL_SATURATION = 10 COMPLEMENTARY_TOLERANCE = 12.0 ANALOGOUS_EXPECTED_ANGLE = 30.0 @@ -73,8 +72,7 @@ def _relationship( expected_angles = [round(value, 2) for value in expected] measured_angles = [round(value, 2) for value in measured] deviation = max( - abs(actual - target) - for actual, target in zip(measured_angles, expected_angles) + abs(actual - target) for actual, target in zip(measured_angles, expected_angles) ) return { "type": relationship_type, @@ -203,11 +201,7 @@ def detect_split_complementary( relationships = [] seen: set[tuple[int, int, int]] = set() for base_index, base_hue in evidence: - others = [ - (index, hue) - for index, hue in evidence - if index != base_index - ] + others = [(index, hue) for index, hue in evidence if index != base_index] for (first_index, first), (second_index, second) in combinations(others, 2): measured = [ hue_distance(base_hue, first), @@ -216,8 +210,7 @@ def detect_split_complementary( ] expected = [150.0, 150.0, 60.0] deviation = max( - abs(actual - target) - for actual, target in zip(measured, expected) + abs(actual - target) for actual, target in zip(measured, expected) ) key = (base_index, *sorted((first_index, second_index))) if deviation <= tolerance and key not in seen: @@ -250,18 +243,14 @@ def detect_monochromatic( if values[1] < MIN_MEANINGFUL_SATURATION or values in seen: continue seen.add(values) - distinct.append( - (index, {"h": values[0], "s": values[1], "l": values[2]}) - ) + distinct.append((index, {"h": values[0], "s": values[1], "l": values[2]})) if len(distinct) < 2: return [] mean_hue = circular_mean(item["h"] for _, item in distinct) if mean_hue is None: return [] - measured = [ - hue_distance(item["h"], mean_hue) for _, item in distinct - ] + measured = [hue_distance(item["h"], mean_hue) for _, item in distinct] deviation = max(measured) saturation_range = max(item["s"] for _, item in distinct) - min( item["s"] for _, item in distinct @@ -269,10 +258,7 @@ def detect_monochromatic( lightness_range = max(item["l"] for _, item in distinct) - min( item["l"] for _, item in distinct ) - if ( - deviation > tolerance - or (saturation_range <= 10 and lightness_range <= 10) - ): + if deviation > tolerance or (saturation_range <= 10 and lightness_range <= 10): return [] return [ _relationship( @@ -309,13 +295,7 @@ def analyze_warm_cool_balance(colors: list[dict[str, object]]) -> dict[str, obje } warm_ratio = warm_count / categorized cool_ratio = cool_count / categorized - balance = ( - "warm" - if warm_ratio > 0.7 - else "cool" - if cool_ratio > 0.7 - else "balanced" - ) + balance = "warm" if warm_ratio > 0.7 else "cool" if cool_ratio > 0.7 else "balanced" return { "balance": balance, "warm_count": warm_count, @@ -346,11 +326,9 @@ def calculate_relationship_fit( involved: set[int] = set() for relationship in detected: relationship_type = str(relationship["type"]) - if ( - relationship_type not in best_by_type - or float(relationship["confidence"]) - > float(best_by_type[relationship_type]["confidence"]) - ): + if relationship_type not in best_by_type or float( + relationship["confidence"] + ) > float(best_by_type[relationship_type]["confidence"]): best_by_type[relationship_type] = relationship involved.update(int(index) for index in relationship["color_indexes"]) @@ -400,8 +378,8 @@ def analyze_color_theory(colors: list[dict[str, object]]) -> dict[str, object]: "split_complementary": detect_split_complementary(evidence), "monochromatic": detect_monochromatic(colors), } - relationship_fit, relationship_summary, factors = ( - calculate_relationship_fit(harmonies, len(evidence)) + relationship_fit, relationship_summary, factors = calculate_relationship_fit( + harmonies, len(evidence) ) temperature_balance = analyze_warm_cool_balance(colors) @@ -413,9 +391,7 @@ def analyze_color_theory(colors: list[dict[str, object]]) -> dict[str, object]: "split_complementary": "Split-Complementary Relationship Detected", "monochromatic": "Monochromatic Relationship Detected", } - tags = [ - labels[name] for name, relationships in harmonies.items() if relationships - ] + tags = [labels[name] for name, relationships in harmonies.items() if relationships] balance = temperature_balance["balance"] tags.append( "Neutral Palette" diff --git a/backend/config.py b/backend/config.py index 842b94f..da35995 100644 --- a/backend/config.py +++ b/backend/config.py @@ -2,15 +2,14 @@ from __future__ import annotations -from dataclasses import dataclass import ipaddress import json import os +from dataclasses import dataclass from pathlib import Path from typing import Mapping from urllib.parse import urlparse - ROOT = Path(__file__).resolve().parent.parent RUNTIME_CONFIG_PATH = ROOT / "runtime-config.json" @@ -129,12 +128,8 @@ def from_env( if not isinstance(defaults, dict): raise ConfigurationError("runtime-config.json defaults must be an object.") - web_host = env.get( - "COLORCRAFT_WEB_HOST", str(defaults["webHost"]) - ).strip() - api_host = env.get( - "COLORCRAFT_API_HOST", str(defaults["apiHost"]) - ).strip() + web_host = env.get("COLORCRAFT_WEB_HOST", str(defaults["webHost"])).strip() + api_host = env.get("COLORCRAFT_API_HOST", str(defaults["apiHost"])).strip() allow_lan_access = parse_boolean( env.get("COLORCRAFT_ALLOW_LAN_ACCESS"), name="COLORCRAFT_ALLOW_LAN_ACCESS", @@ -149,8 +144,7 @@ def from_env( ): if not is_loopback_host(host): raise ConfigurationError( - f"{name}={host} requires " - "COLORCRAFT_ALLOW_LAN_ACCESS=true." + f"{name}={host} requires COLORCRAFT_ALLOW_LAN_ACCESS=true." ) web_port = parse_port( diff --git a/backend/main.py b/backend/main.py index a51109d..a6f73ab 100644 --- a/backend/main.py +++ b/backend/main.py @@ -5,14 +5,7 @@ from contextlib import asynccontextmanager from typing import Annotated -from fastapi import FastAPI, File, Query, Request, UploadFile -from fastapi.exceptions import RequestValidationError -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import JSONResponse -from PIL import Image, UnidentifiedImageError -from starlette.concurrency import run_in_threadpool import uvicorn - from accessibility import analyze_accessibility from color_extractor import ( ImageDimensionError, @@ -22,10 +15,15 @@ from color_suggestions import generate_all_suggestions from color_theory import analyze_color_theory from config import RuntimeSettings +from fastapi import FastAPI, File, Query, Request, UploadFile +from fastapi.exceptions import RequestValidationError +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import JSONResponse from models import ( - APIError, AnalysisResponse, AnalysisResult, + APIError, + ApplicationMetadata, ErrorResponse, ExtractedColor, ExtractionResponse, @@ -37,14 +35,18 @@ SuggestionResponse, ValidationIssue, ) - +from PIL import Image, UnidentifiedImageError +from starlette.concurrency import run_in_threadpool ALLOWED_IMAGE_TYPES = {"image/jpeg", "image/png", "image/webp"} MAX_UPLOAD_BYTES = 10 * 1024 * 1024 CAPABILITIES = [ - "color extraction", - "palette analysis", - "color suggestions", + "image-color-extraction", + "palette-editing", + "harmony-analysis", + "contrast-review", + "palette-export", + "local-palette-library", ] ColorCount = Annotated[int, Query(ge=3, le=10)] @@ -64,9 +66,7 @@ def error_response( message: str, details: list[ValidationIssue] | None = None, ) -> JSONResponse: - payload = ErrorResponse( - error=APIError(code=code, message=message, details=details) - ) + payload = ErrorResponse(error=APIError(code=code, message=message, details=details)) return JSONResponse( status_code=status_code, content=payload.model_dump(by_alias=True, exclude_none=True), @@ -154,6 +154,22 @@ async def health() -> ServiceResponse: version=runtime.application_version, ) + @application.get("/metadata", response_model=ApplicationMetadata) + async def metadata() -> ApplicationMetadata: + return ApplicationMetadata( + schema_version=1, + id="colorcraft", + name="ColorCraft", + descriptor="Local color utility", + version=runtime.application_version, + icon=f"{runtime.web_url}/colorcraft-mark.svg", + web_url=runtime.web_url, + api_url=runtime.client_api_url, + health_url=f"{runtime.client_api_url}/health", + readiness_url=f"{runtime.client_api_url}/ready", + capabilities=CAPABILITIES, + ) + @application.get("/ready", response_model=ReadinessResponse) async def ready(request: Request) -> ReadinessResponse | JSONResponse: is_ready = bool(request.app.state.ready) @@ -200,9 +216,7 @@ async def extract_uploaded_colors( extracted = await run_in_threadpool( extract_colors, image_bytes, color_count ) - return [ - ExtractedColor.model_validate(color) for color in extracted - ] + return [ExtractedColor.model_validate(color) for color in extracted] except ImageDimensionError: raise APIException( 413, @@ -249,9 +263,7 @@ async def extract_colors_endpoint( ) def analyze_palette(request: PaletteAnalysisRequest) -> AnalysisResult: - colors = [ - color.model_dump(by_alias=False) for color in request.colors - ] + colors = [color.model_dump(by_alias=False) for color in request.colors] return AnalysisResult( color_theory=analyze_color_theory(colors), accessibility=analyze_accessibility(colors), @@ -278,14 +290,10 @@ async def analyze_colors_endpoint( async def suggest_colors_endpoint( request: SuggestionRequest, ) -> SuggestionResponse: - colors = [ - color.model_dump(by_alias=False) for color in request.colors - ] + colors = [color.model_dump(by_alias=False) for color in request.colors] return SuggestionResponse( success=True, - suggestions=[ - generate_all_suggestions(color) for color in colors - ], + suggestions=[generate_all_suggestions(color) for color in colors], ) @application.post( diff --git a/backend/models.py b/backend/models.py index 87611f6..cc46373 100644 --- a/backend/models.py +++ b/backend/models.py @@ -28,6 +28,8 @@ class ContractModel(BaseModel): HexColor = Annotated[str, StringConstraints(pattern=r"^#[0-9A-Fa-f]{6}$")] + + class RGB(ContractModel): r: int = Field(ge=0, le=255) g: int = Field(ge=0, le=255) @@ -68,9 +70,7 @@ def representations_must_agree(self) -> "ColorInput": **dict( zip( ("h", "s", "l"), - rgb_to_hsl( - [expected_rgb.r, expected_rgb.g, expected_rgb.b] - ), + rgb_to_hsl([expected_rgb.r, expected_rgb.g, expected_rgb.b]), ) ) ) @@ -105,6 +105,20 @@ class ReadinessResponse(ContractModel): capabilities: list[str] +class ApplicationMetadata(ContractModel): + schema_version: Literal[1] + id: Literal["colorcraft"] + name: Literal["ColorCraft"] + descriptor: Literal["Local color utility"] + version: str + icon: str + web_url: str + api_url: str + health_url: str + readiness_url: str + capabilities: list[str] + + class ExtractionResponse(ContractModel): success: Literal[True] colors: list[ExtractedColor] = Field(min_length=1, max_length=10) diff --git a/backend/requirements-dev.txt b/backend/requirements-dev.txt index 871467b..3b0f6b4 100644 --- a/backend/requirements-dev.txt +++ b/backend/requirements-dev.txt @@ -1,3 +1,6 @@ -r requirements.txt httpx==0.25.2 pytest==8.3.5 +pytest-cov==6.2.1 +ruff==0.12.5 +mypy==1.17.0 diff --git a/check.cmd b/check.cmd new file mode 100644 index 0000000..19b1325 --- /dev/null +++ b/check.cmd @@ -0,0 +1,17 @@ +@echo off +setlocal +set "COLORCRAFT_ROOT=%~dp0" + +if exist "%COLORCRAFT_ROOT%backend\.venv311\Scripts\python.exe" ( + "%COLORCRAFT_ROOT%backend\.venv311\Scripts\python.exe" "%COLORCRAFT_ROOT%check.py" %* + exit /b %errorlevel% +) + +if exist "%COLORCRAFT_ROOT%backend\.venv\Scripts\python.exe" ( + "%COLORCRAFT_ROOT%backend\.venv\Scripts\python.exe" "%COLORCRAFT_ROOT%check.py" %* + exit /b %errorlevel% +) + +echo ColorCraft could not find a backend development environment. +echo Create one and install backend\requirements-dev.txt, then try again. +exit /b 1 diff --git a/check.py b/check.py new file mode 100644 index 0000000..838f37b --- /dev/null +++ b/check.py @@ -0,0 +1,118 @@ +"""Run ColorCraft's complete repository validation workflow.""" + +from __future__ import annotations + +import argparse +import shutil +import subprocess +import sys +from dataclasses import dataclass +from pathlib import Path + +ROOT = Path(__file__).resolve().parent +FRONTEND = ROOT / "frontend" +BACKEND = ROOT / "backend" + + +@dataclass(frozen=True) +class CheckStep: + label: str + command: tuple[str, ...] + cwd: Path + + +def validation_steps( + python: str, + corepack: str, + *, + include_e2e: bool = True, +) -> tuple[CheckStep, ...]: + pnpm = (corepack, "pnpm@9.15.9") + steps = [ + CheckStep("frontend format", (*pnpm, "format:check"), FRONTEND), + CheckStep("frontend lint", (*pnpm, "lint"), FRONTEND), + CheckStep("frontend typecheck", (*pnpm, "typecheck"), FRONTEND), + CheckStep("frontend coverage", (*pnpm, "test:coverage"), FRONTEND), + CheckStep("frontend build", (*pnpm, "build"), FRONTEND), + CheckStep( + "backend format", + ( + python, + "-m", + "ruff", + "format", + "--check", + "backend", + "tests", + "dev.py", + "check.py", + ), + ROOT, + ), + CheckStep( + "backend lint", + (python, "-m", "ruff", "check", "backend", "tests", "dev.py", "check.py"), + ROOT, + ), + CheckStep( + "backend typecheck", + ( + python, + "-m", + "mypy", + "backend/config.py", + "backend/models.py", + "check.py", + ), + ROOT, + ), + CheckStep( + "backend tests and coverage", + ( + python, + "-m", + "pytest", + "tests", + "--cov=backend", + "--cov=dev", + "--cov-report=term-missing", + "--cov-report=xml:.tmp/backend-coverage.xml", + ), + ROOT, + ), + ] + if include_e2e: + steps.append( + CheckStep("browser E2E and accessibility", (*pnpm, "test:e2e"), FRONTEND) + ) + return tuple(steps) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--skip-e2e", + action="store_true", + help="Run the fast validation layers without Playwright.", + ) + arguments = parser.parse_args() + corepack = shutil.which("corepack.cmd") or shutil.which("corepack") + if not corepack: + print("ColorCraft validation requires Corepack.", file=sys.stderr) + return 1 + + for index, step in enumerate( + validation_steps(sys.executable, corepack, include_e2e=not arguments.skip_e2e), + start=1, + ): + print(f"[{index}] {step.label}") + result = subprocess.run(step.command, cwd=step.cwd, check=False) + if result.returncode: + print(f"Validation stopped: {step.label} failed.", file=sys.stderr) + return result.returncode + print("ColorCraft validation passed.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/dev.py b/dev.py index 6b2eb94..b8c397b 100644 --- a/dev.py +++ b/dev.py @@ -2,21 +2,20 @@ from __future__ import annotations -from dataclasses import dataclass import json import os -from pathlib import Path import shutil import signal import socket import subprocess import sys import time +from dataclasses import dataclass +from pathlib import Path from typing import Callable, Sequence from urllib.error import HTTPError, URLError from urllib.request import urlopen - ROOT = Path(__file__).resolve().parent BACKEND_DIR = ROOT / "backend" FRONTEND_DIR = ROOT / "frontend" @@ -228,6 +227,10 @@ def readiness_url(settings: RuntimeSettings) -> str: return f"{settings.client_api_url}/ready" +def metadata_url(settings: RuntimeSettings) -> str: + return f"{settings.client_api_url}/metadata" + + def wait_for_readiness( settings: RuntimeSettings, processes: Sequence[tuple[ProcessStep, subprocess.Popen[bytes]]], @@ -248,7 +251,13 @@ def wait_for_readiness( if response.status == 200 and payload.get("status") == "ready": return last_error = f"readiness returned status {response.status}" - except (HTTPError, URLError, OSError, TimeoutError, json.JSONDecodeError) as error: + except ( + HTTPError, + URLError, + OSError, + TimeoutError, + json.JSONDecodeError, + ) as error: last_error = str(error) sleep(0.2) @@ -295,6 +304,7 @@ def run_dev_launcher( print(f" API: {runtime.client_api_url}") print(f" Health: {runtime.client_api_url}/health") print(f" Readiness: {readiness_url(runtime)}") + print(f" Metadata: {metadata_url(runtime)}") print("Waiting for API readiness...") for step in plan.steps: diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..e85fa55 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,15 @@ +# ColorCraft documentation + +Start with [Getting started](./getting-started.md), then use the guide that matches your task: + +- [User workflow](./user-workflow.md) — create, save, review, export, and manage palettes. +- [Runtime configuration](./runtime-configuration.md) — ports, hosts, CORS, LAN opt-in, and launcher behavior. +- [Architecture](./architecture.md) — application boundaries and data flow. +- [API](./api.md) — endpoints, request shapes, metadata, readiness, and errors. +- [Persistence and privacy](./persistence-and-privacy.md) — IndexedDB schema, migration, retention, and deletion. +- [Dashboard manifest](./dashboard-manifest.md) — static discovery defaults and runtime resolution. +- [Testing](./testing.md) — local and CI quality gates. +- [Screenshot review](./screenshot-review.md) — deterministic fixtures, temporary output, and curation. +- [Troubleshooting](./troubleshooting.md) — common Python, pnpm, port, and browser failures. +- [Brand system](./brand-system.md) — identity, tokens, themes, and shell conventions. +- [API contract rationale](./api-contracts.md) — compatibility and validation design notes. diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..5977f71 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,49 @@ +# API + +The default base URL is `http://127.0.0.1:4100`. Interactive OpenAPI documentation is available at `/docs`. + +| Method | Path | Purpose | +| --- | --- | --- | +| `GET` | `/` | Service identity | +| `GET` | `/health` | Liveness | +| `GET` | `/ready` | Readiness and capability slugs | +| `GET` | `/metadata` | Runtime-resolved dashboard metadata | +| `POST` | `/api/extract-colors?n_colors=5` | Multipart image extraction | +| `POST` | `/api/analyze-colors` | Analyze 2–10 normalized colors | +| `POST` | `/api/suggest-colors` | Suggest colors for 1–10 normalized colors | +| `POST` | `/api/full-analysis?n_colors=5` | Extract and analyze in one request | + +Analysis and suggestion requests wrap colors in an object: + +```json +{ + "colors": [ + { + "hex": "#6A5BCF", + "rgb": { "r": 106, "g": 91, "b": 207 }, + "hsl": { "h": 248, "s": 53, "l": 58 } + }, + { + "hex": "#F5F0E8", + "rgb": { "r": 245, "g": 240, "b": 232 }, + "hsl": { "h": 37, "s": 39, "l": 94 } + } + ] +} +``` + +Passing a bare array produces `422 validation_error`. Error responses are stable envelopes: + +```json +{ + "error": { + "code": "validation_error", + "message": "Request validation failed.", + "details": [] + } +} +``` + +Extraction accepts JPEG, PNG, and WebP files up to 10 MB, limits decoded dimensions, and ignores fully transparent pixels. `n_colors` must be 3–10. Expected client errors use 413, 415, or 422 rather than an unstructured server exception. + +`/metadata` reports the resolved web, API, health, readiness, icon, version, and capabilities. `/ready` returns `503` with `not_ready` until application startup completes. See [Dashboard manifest](./dashboard-manifest.md). diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..bce7456 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,26 @@ +# Architecture + +```mermaid +flowchart TD + Browser[React + TypeScript browser app] + IDB[(IndexedDB palette records)] + LS[(LocalStorage theme preference)] + API[FastAPI service] + Extract[LAB extraction] + Theory[Harmony and suggestions] + Contrast[WCAG contrast] + Browser <--> IDB + Browser <--> LS + Browser -->|JSON and multipart HTTP| API + API --> Extract + API --> Theory + API --> Contrast +``` + +The frontend owns navigation, transient image preview state, explicit save state, role assignments, exports, and the local palette repository. `persistence.ts` validates every stored record with Zod, migrates legacy version-0 records to schema version 1, and ignores malformed or unknown future records without crashing the Library. + +The backend is stateless. It validates contract models with Pydantic and delegates CPU-heavy extraction to a thread pool. Color extraction uses deterministic sampling, LAB conversion, KMeans clustering, and representative processed pixels. Theory, suggestions, and contrast operate on normalized color contracts. + +`dev.py` is a process supervisor rather than an application server. It resolves configuration once, starts the API and Vite with consistent values, checks `/ready`, optionally opens the browser, and forwards shutdown to both processes. + +Dashboard integration has two layers: the checked-in static manifest advertises stable defaults, while `/metadata` reports the runtime-resolved addresses. See [API](./api.md) and [Persistence and privacy](./persistence-and-privacy.md). diff --git a/docs/assets/screenshots/create-light.png b/docs/assets/screenshots/create-light.png new file mode 100644 index 0000000000000000000000000000000000000000..32c0321d6ebb5809525c4d944990d9d12e373a9b GIT binary patch literal 137039 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ð$d%;Dxg%U~S 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 SOMxeB_tkXo=HGex@_zyG3_0BZ literal 0 HcmV?d00001 diff --git a/docs/assets/screenshots/library-dark.png b/docs/assets/screenshots/library-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..3aa4e1d515e87ad00cdee95dfba7beb97878ce38 GIT binary patch literal 47157 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�)dAt-76{wH&h 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
SkO9SoGMva#$pZ?OWJJs})2bT79-FuK% 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 literal 0 HcmV?d00001 diff --git a/docs/assets/screenshots/mobile-create.png b/docs/assets/screenshots/mobile-create.png new file mode 100644 index 0000000000000000000000000000000000000000..307e0525f0955e0baedb32f32aaad3b778c0aee4 GIT binary patch literal 55961 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 S2p@0+BrYr?R3z}>^Zx=+KWVxE literal 0 HcmV?d00001 diff --git a/docs/assets/screenshots/review-dark.png b/docs/assets/screenshots/review-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..1dea84a0099db4cb91e5a670322f00e03bf921b0 GIT binary patch literal 157352 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 z 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 C0ETw} literal 0 HcmV?d00001 diff --git a/docs/brand-system.md b/docs/brand-system.md index 684bdfc..734cfb5 100644 --- a/docs/brand-system.md +++ b/docs/brand-system.md @@ -8,10 +8,10 @@ compact information density, restrained radii, semantic controls, and a narrow iris-to-ember accent. ColorCraft remains its own product. It does not reuse the Web Video Optimizer monogram, video metaphors, or video-specific navigation. -The product uses the family application-shell grammar for three real workflow -stages: Create, Review, and Export. It remains a focused local utility rather -than a dashboard. Library, recent-palette, account, and persistence surfaces -must not appear until the corresponding product capabilities exist. +The product uses the family application-shell grammar for four real workflow +destinations: Create, Review, Export, and Library. Library and recent-palette +surfaces represent browser-local IndexedDB records. ColorCraft remains a focused +local utility rather than a dashboard and does not imply accounts or cloud sync. ## Voice diff --git a/docs/dashboard-manifest.md b/docs/dashboard-manifest.md new file mode 100644 index 0000000..9452634 --- /dev/null +++ b/docs/dashboard-manifest.md @@ -0,0 +1,23 @@ +# Dashboard manifest + +[`app-manifest.json`](../app-manifest.json) is ColorCraft's static discovery contract. The identical file under `frontend/public` makes it available in the built web application. + +The manifest contains schema version 1, a stable `colorcraft` ID, product name and descriptor, version, icon path, default web/API addresses, health and metadata paths, and machine-readable capability slugs. + +Static addresses are defaults only. Environment variables can change ports or hosts at launch, so a dashboard should: + +1. Discover the application from `app-manifest.json`. +2. Query the manifest's metadata path on the candidate API address. +3. Treat `/metadata` as authoritative for runtime-resolved URLs. +4. Use `/ready` for dependency readiness and `/health` for liveness. + +Current capability slugs are: + +- `image-color-extraction` +- `palette-editing` +- `harmony-analysis` +- `contrast-review` +- `palette-export` +- `local-palette-library` + +The manifest contract and public copy are tested for equality. Runtime tests verify that metadata respects configuration overrides. diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..b4b106d --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,49 @@ +# Getting started + +## Requirements + +- Python 3.11 (recommended; pinned Pillow wheels are not available for every newer Python release) +- Node.js 20 or newer +- Corepack +- Git + +## Windows + +From the repository root: + +```powershell +py -3.11 -m venv backend\.venv311 +.\backend\.venv311\Scripts\python.exe -m pip install --upgrade pip +.\backend\.venv311\Scripts\python.exe -m pip install -r backend\requirements-dev.txt +cd frontend +corepack pnpm@9.15.9 install +cd .. +.\backend\.venv311\Scripts\python.exe dev.py +``` + +The launcher supervises the FastAPI and Vite processes, waits for readiness, prints every URL, and shuts both down when you press `Ctrl+C`. + +## macOS and Linux + +```bash +python3.11 -m venv backend/.venv +backend/.venv/bin/python -m pip install --upgrade pip +backend/.venv/bin/python -m pip install -r backend/requirements-dev.txt +cd frontend +corepack pnpm@9.15.9 install +cd .. +backend/.venv/bin/python dev.py +``` + +If the browser does not open, visit `http://127.0.0.1:5174`. The API docs are at `http://127.0.0.1:4100/docs`. + +## Production build + +```powershell +cd frontend +corepack pnpm@9.15.9 build +``` + +The output is written to `frontend/dist`. This repository's launcher is a development workflow; choose a production web server and API process manager for deployment. + +For configuration overrides, see [Runtime configuration](./runtime-configuration.md). For setup errors, see [Troubleshooting](./troubleshooting.md). diff --git a/docs/persistence-and-privacy.md b/docs/persistence-and-privacy.md new file mode 100644 index 0000000..741a8c8 --- /dev/null +++ b/docs/persistence-and-privacy.md @@ -0,0 +1,30 @@ +# Persistence and privacy + +ColorCraft is local-first, not account-backed. There is no synchronization service or server-side palette database. + +## What is stored + +The `colorcraft` IndexedDB database contains `palettes` records with: + +- schema version, ID, name, and created/updated timestamps +- manual or image source type and an optional source filename +- 1–10 normalized colors with optional population and pixel-count metadata +- semantic contrast-role assignments + +Schema version 1 is validated with Zod whenever records are read. Legacy records with no version or version 0 are migrated in memory and become version 1 when next saved. Corrupt records and unknown future versions are skipped so one bad record cannot prevent the Library from opening. + +LocalStorage contains only the theme preference. Uploaded image bytes, object URLs, analysis responses, and suggestions are not written to LocalStorage or IndexedDB. + +## Image processing + +An uploaded file is previewed in browser memory and sent to the configured FastAPI service. The service reads it for that request and does not write it to disk or a database. If LAN access is enabled, image traffic crosses that network path; use a trusted network or HTTPS termination. + +## Retention and deletion + +Palette records remain until the user deletes them or clears site data for the ColorCraft origin. Library deletion is confirmed and cannot be undone. Different browser profiles, origins, and port combinations have separate browser storage. + +To remove all ColorCraft browser data, use the browser's site-data controls for the web origin. Uninstalling the repository does not necessarily clear browser data. + +## Security posture + +Defaults bind both services to loopback. Non-loopback hosts and CORS origins require explicit `COLORCRAFT_ALLOW_LAN_ACCESS=true`; wildcard CORS is rejected. ColorCraft does not provide authentication, so do not expose it directly to an untrusted network. diff --git a/docs/runtime-configuration.md b/docs/runtime-configuration.md new file mode 100644 index 0000000..e1a4330 --- /dev/null +++ b/docs/runtime-configuration.md @@ -0,0 +1,30 @@ +# Runtime configuration + +ColorCraft defaults to loopback-only services: + +| Variable | Default | Purpose | +| --- | --- | --- | +| `COLORCRAFT_WEB_HOST` | `127.0.0.1` | Vite bind host | +| `COLORCRAFT_WEB_PORT` | `5174` | Web port | +| `COLORCRAFT_API_HOST` | `127.0.0.1` | FastAPI bind host | +| `COLORCRAFT_API_PORT` | `4100` | API port | +| `COLORCRAFT_READINESS_TIMEOUT_SECONDS` | `30` | Launcher startup deadline | +| `COLORCRAFT_ALLOWED_ORIGINS` | resolved web origin | Comma-separated exact CORS origins | +| `VITE_API_URL` | resolved API origin | Browser-visible API base URL | +| `COLORCRAFT_ALLOW_LAN_ACCESS` | `false` | Required opt-in for non-loopback hosts/origins | +| `COLORCRAFT_NO_BROWSER` | `false` | Prevent automatic browser launch | + +Example PowerShell override: + +```powershell +$env:COLORCRAFT_WEB_PORT = "5184" +$env:COLORCRAFT_API_PORT = "4110" +$env:COLORCRAFT_NO_BROWSER = "true" +.\backend\.venv311\Scripts\python.exe dev.py +``` + +Ports must be valid and distinct. The launcher checks availability before starting either child process and reports a focused error if a port is occupied. Wildcard CORS origins are rejected. + +LAN binding expands the trust boundary. Set `COLORCRAFT_ALLOW_LAN_ACCESS=true`, configure explicit hosts and origins, and use a firewall appropriate to the network. Uploaded images traverse the configured network path to the API. + +Static dashboard defaults stay in [`app-manifest.json`](../app-manifest.json). Consumers that need overrides must read `/metadata`; see [Dashboard manifest](./dashboard-manifest.md). diff --git a/docs/screenshot-review.md b/docs/screenshot-review.md new file mode 100644 index 0000000..6be5f32 --- /dev/null +++ b/docs/screenshot-review.md @@ -0,0 +1,16 @@ +# Screenshot review + +Run the deterministic review workflow: + +```powershell +cd frontend +corepack pnpm@9.15.9 review:screenshots +``` + +It creates 16 fixture-driven PNGs under `.tmp/ui-review`: empty Create in both themes, extraction progress, image and manual palettes, selected and modified states, four Review surfaces, Export, Library, two mobile surfaces, and an API error. Network-dependent extraction is mocked; analysis uses fixed palette data. + +`.tmp` is intentionally ignored. Review those files locally for clipping, hierarchy, contrast, focus, error placement, and responsive behavior. Temporary test artifacts must not be linked from documentation. + +When a screenshot is representative and stable, copy only that file to `docs/assets/screenshots`, give it a semantic name, and reference it from documentation. Curated images are reviewable product documentation; the complete temporary set is disposable diagnostic output. + +The current curated set shows light Create, dark Review, dark Library, and mobile Create. Regenerate it only when a deliberate interface change makes the existing image inaccurate. diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 0000000..66567b9 --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,46 @@ +# Testing + +## Complete validation + +Install the browser once: + +```powershell +cd frontend +corepack pnpm@9.15.9 exec playwright install chromium +cd .. +``` + +Then run the same gate used by CI: + +```powershell +.\backend\.venv311\Scripts\python.exe check.py +``` + +On Unix, use the Python executable from `backend/.venv`. `check.cmd` is a Windows convenience wrapper. + +The gate runs: + +1. Prettier format verification +2. ESLint +3. TypeScript checking +4. Vitest unit/integration tests with V8 coverage +5. Vite production build +6. Ruff format and lint checks +7. mypy on stable backend contracts and the validation runner +8. pytest with backend and launcher coverage +9. Playwright Chromium workflow and axe accessibility checks + +Use `python check.py --skip-e2e` for a fast local loop. CI always runs the complete gate. + +## Focused commands + +```powershell +cd frontend +corepack pnpm@9.15.9 test +corepack pnpm@9.15.9 test:e2e +corepack pnpm@9.15.9 review:screenshots +cd .. +.\backend\.venv311\Scripts\python.exe -m pytest tests +``` + +Persistence tests use an in-memory IndexedDB implementation and cover migration, malformed data, identity-preserving save updates, sorting, rename, duplicate, and delete. Browser tests cover create → save → analyze → contrast → export → reopen → delete plus representative accessibility states. Backend tests cover contracts, upload defenses, analysis, suggestions, metadata, readiness, runtime parsing, and launcher supervision. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..2b990e4 --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,46 @@ +# Troubleshooting + +## Pillow fails to install on Python 3.13 + +The pinned Pillow version may not provide a compatible wheel. Install Python 3.11 and create the environment explicitly: + +```powershell +py -3.11 -m venv backend\.venv311 +.\backend\.venv311\Scripts\python.exe -m pip install -r backend\requirements-dev.txt +``` + +If virtual-environment creation reports that `venvlauncher.exe` cannot be copied, close processes using that environment, choose a new directory name, and verify the Python installation outside the Microsoft Store alias. + +## pnpm reports “packages field missing or empty” + +Run pnpm inside `frontend`, not the repository root: + +```powershell +cd frontend +corepack pnpm@9.15.9 install +``` + +The repository pins pnpm 9 for reproducibility. If pnpm blocks an `esbuild` lifecycle script, use the pinned version and the checked-in lockfile rather than approving an unrelated global pnpm policy. + +## A port is already in use + +ColorCraft defaults to 5174/4100. Stop the conflicting process or set `COLORCRAFT_WEB_PORT` and `COLORCRAFT_API_PORT`; see [Runtime configuration](./runtime-configuration.md). The launcher prints which address is occupied. + +## The frontend cannot reach the API + +Check `/ready`, confirm the printed API URL, and ensure `VITE_API_URL` matches the browser-reachable address. Custom web origins must appear exactly in `COLORCRAFT_ALLOWED_ORIGINS`. + +## Saved palettes disappeared + +Palettes are scoped to the exact browser profile and origin. Changing the web port, using private browsing, or clearing site data creates an empty Library. ColorCraft has no cloud recovery. + +## Playwright cannot find Chromium + +```powershell +cd frontend +corepack pnpm@9.15.9 exec playwright install chromium +``` + +## A 422 response appears for analysis or suggestions + +Send `{ "colors": [...] }`, not a bare array, and include consistent HEX, RGB, and HSL values. Read the structured `error.details` entries or use `/docs`. diff --git a/docs/user-workflow.md b/docs/user-workflow.md new file mode 100644 index 0000000..54a197e --- /dev/null +++ b/docs/user-workflow.md @@ -0,0 +1,36 @@ +# User workflow + +## Create and refine + +Choose **Upload image** for PNG, JPEG, or WebP files up to 10 MB, or choose **Start manually**. Extraction returns 3–10 representative colors. Select a palette row, type a six-digit HEX value, use the native picker, duplicate a color, or remove it. + +Uploaded image previews exist only for the active page session. Saving an image-derived palette records its filename, colors, population data, and pixel counts—not the image bytes. + +## Save states + +- **Unsaved**: the open palette has no IndexedDB record. **Save palette** creates one. +- **Saved**: the current palette matches its record. The save action is disabled. +- **Modified**: colors, roles, name, or source metadata differ. **Save changes** updates the same record. + +ColorCraft confirms before opening another record or starting over when doing so would discard meaningful unsaved or modified work. + +## Review + +Choose **Analyze palette** to enter Review: + +- **Overview** summarizes temperature, saturation, lightness, geometric relationships, and next actions. +- **Harmony** explains detected relationships on the color wheel. +- **Contrast** assigns semantic interface roles and reports WCAG ratios. +- **Suggestions** proposes complementary, triadic, analogous, split-complementary, tetradic, monochromatic, or accessibility-oriented colors. + +Relationship fit measures geometric hue structure; it is not a judgment of aesthetic quality. + +## Export + +Export the current palette as CSS custom properties, JSON, Tailwind configuration, or design tokens. Copy uses the Clipboard API; download creates a local file. Export does not upload the palette. + +## Library + +The Library lists browser-local records most recently updated first. Search by palette name or source filename. Open, inline rename, duplicate, or delete a record. Deletion always asks for confirmation; deleting the active record returns to the empty Library state and disables Review and Export until another palette opens. + +The sidebar shows recent palettes only when records exist. Clearing browser site data permanently removes the Library. diff --git a/frontend/.prettierignore b/frontend/.prettierignore new file mode 100644 index 0000000..1ece1a9 --- /dev/null +++ b/frontend/.prettierignore @@ -0,0 +1,6 @@ +coverage +dist +node_modules +playwright-report +test-results +pnpm-lock.yaml diff --git a/frontend/.prettierrc.json b/frontend/.prettierrc.json new file mode 100644 index 0000000..e3b414c --- /dev/null +++ b/frontend/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "semi": false, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/frontend/e2e/capture-screenshots.mjs b/frontend/e2e/capture-screenshots.mjs new file mode 100644 index 0000000..6b6b742 --- /dev/null +++ b/frontend/e2e/capture-screenshots.mjs @@ -0,0 +1,23 @@ +import { rm, mkdir } from 'node:fs/promises' +import path from 'node:path' +import { spawn } from 'node:child_process' + +const frontendRoot = path.resolve(import.meta.dirname, '..') +const outputDirectory = path.resolve(frontendRoot, '..', '.tmp', 'ui-review') +await rm(outputDirectory, { recursive: true, force: true }) +await mkdir(outputDirectory, { recursive: true }) + +const isWindows = process.platform === 'win32' +const executable = isWindows + ? 'corepack pnpm@9.15.9 exec playwright test --grep @screenshots' + : 'corepack' +const arguments_ = isWindows + ? [] + : ['pnpm@9.15.9', 'exec', 'playwright', 'test', '--grep', '@screenshots'] +const child = spawn(executable, arguments_, { + cwd: frontendRoot, + stdio: 'inherit', + env: { ...process.env, COLORCRAFT_SCREENSHOTS: '1' }, + shell: isWindows, +}) +child.on('exit', (code) => process.exit(code ?? 1)) diff --git a/frontend/e2e/screenshot-review.spec.ts b/frontend/e2e/screenshot-review.spec.ts new file mode 100644 index 0000000..417bfc8 --- /dev/null +++ b/frontend/e2e/screenshot-review.spec.ts @@ -0,0 +1,179 @@ +import { expect, test, type Page } from '@playwright/test' +import path from 'node:path' + +test.describe.configure({ mode: 'serial' }) + +const outputDirectory = path.resolve( + import.meta.dirname, + '..', + '..', + '.tmp', + 'ui-review', +) +const png = Buffer.from( + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAARElEQVR4nGP8z8AARLJgFIyCUUBPAAA2QQE/7iZ8GAAAAABJRU5ErkJggg==', + 'base64', +) + +async function capture(page: Page, name: string) { + await page.screenshot({ + path: path.join(outputDirectory, `${name}.png`), + fullPage: true, + animations: 'disabled', + }) +} + +async function setPalette(page: Page) { + await page.getByRole('button', { name: 'Start manually' }).click() + for (let index = 0; index < 4; index += 1) { + await page.getByRole('button', { name: 'Add color' }).click() + } + const colors = ['#6A5BCF', '#F2763F', '#141D29', '#F5F0E8', '#41A37A'] + for (let index = 0; index < colors.length; index += 1) { + const input = page.getByRole('textbox', { + name: `Color ${index + 1}`, + exact: true, + }) + await input.fill(colors[index]) + await input.blur() + } +} + +test('@screenshots fixture-driven UI review', async ({ page }) => { + test.skip( + !process.env.COLORCRAFT_SCREENSHOTS, + 'Run through pnpm review:screenshots.', + ) + await page.goto('/?view=create') + await page.locator('.sidebar-theme select').selectOption('dark') + await capture(page, '01-create-empty-dark') + await page.locator('.sidebar-theme select').selectOption('light') + await capture(page, '02-create-empty-light') + + await page.route('**/api/extract-colors?*', async (route) => { + await new Promise((resolve) => setTimeout(resolve, 700)) + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + success: true, + count: 3, + colors: [ + { + hex: '#6A5BCF', + rgb: { r: 106, g: 91, b: 207 }, + hsl: { h: 248, s: 53, l: 58 }, + population: 0.5, + pixelCount: 50, + }, + { + hex: '#F2763F', + rgb: { r: 242, g: 118, b: 63 }, + hsl: { h: 18, s: 87, l: 60 }, + population: 0.3, + pixelCount: 30, + }, + { + hex: '#141D29', + rgb: { r: 20, g: 29, b: 41 }, + hsl: { h: 214, s: 34, l: 12 }, + population: 0.2, + pixelCount: 20, + }, + ], + }), + }) + }) + await page.locator('#source-image').setInputFiles({ + name: 'fixture-palette.png', + mimeType: 'image/png', + buffer: png, + }) + await expect(page.getByRole('button', { name: /^Extracting/ })).toBeVisible() + await capture(page, '03-extraction-progress') + await expect(page.getByText(/3 distinct colors were/)).toBeVisible() + await capture(page, '04-image-palette-workspace') + await page.locator('[aria-label="Palette color 2"]').click() + await capture(page, '05-selected-palette-color') + + await page.getByRole('button', { name: 'New palette' }).click() + await page.getByRole('button', { name: 'Discard and start new' }).click() + await setPalette(page) + await capture(page, '06-manual-palette-workspace') + await page.getByRole('button', { name: 'Save palette' }).click() + await expect(page.getByText('Saved', { exact: true })).toBeVisible() + const firstColor = page.getByRole('textbox', { + name: 'Color 1', + exact: true, + }) + await firstColor.fill('#725FD6') + await firstColor.blur() + await capture(page, '07-modified-state') + await page.getByRole('button', { name: 'Save changes' }).click() + + await page.getByRole('button', { name: 'Analyze palette' }).click() + await expect(page.getByText('Palette summary')).toBeVisible() + await page.locator('.sidebar-theme select').selectOption('dark') + await capture(page, '08-review-overview') + await page.getByRole('tab', { name: 'Harmony' }).click() + await capture(page, '09-review-harmony') + await page.getByRole('tab', { name: 'Contrast' }).click() + await page.getByLabel('Page background').selectOption('#F5F0E8') + await page.getByLabel('Primary text').selectOption('#141D29') + await capture(page, '10-contrast-roles') + await page.getByRole('tab', { name: 'Suggestions' }).click() + await page.getByRole('button', { name: 'Generate suggestions' }).click() + await expect(page.locator('.compact-suggestion-list')).toBeVisible() + await capture(page, '11-suggestions') + + await page + .getByRole('navigation', { name: 'Primary' }) + .getByRole('button', { name: 'Export' }) + .click() + await capture(page, '12-export') + await page + .getByRole('navigation', { name: 'Primary' }) + .getByRole('button', { name: 'Library' }) + .click() + await capture(page, '13-library') + + await page.setViewportSize({ width: 390, height: 844 }) + await page + .getByRole('navigation', { name: 'Mobile primary' }) + .getByRole('button', { name: 'Create' }) + .click() + await capture(page, '14-mobile-create') + await page + .getByRole('navigation', { name: 'Mobile primary' }) + .getByRole('button', { name: 'Review' }) + .click() + await capture(page, '15-mobile-review') + + await page.setViewportSize({ width: 1440, height: 900 }) + await page.getByRole('button', { name: 'New palette' }).click() + const discardButton = page.getByRole('button', { + name: 'Discard and start new', + }) + if (await discardButton.isVisible()) { + await discardButton.click() + } + await page.unroute('**/api/extract-colors?*') + await page.route('**/api/extract-colors?*', (route) => + route.fulfill({ + status: 500, + contentType: 'application/json', + body: JSON.stringify({ + error: { code: 'fixture_error', message: 'Fixture extraction failed.' }, + }), + }), + ) + await page.locator('#source-image').setInputFiles({ + name: 'fixture-error.png', + mimeType: 'image/png', + buffer: png, + }) + await expect(page.getByRole('alert')).toContainText( + 'Fixture extraction failed.', + ) + await capture(page, '16-error-notice') +}) diff --git a/frontend/e2e/workflow.spec.ts b/frontend/e2e/workflow.spec.ts new file mode 100644 index 0000000..a3cb67d --- /dev/null +++ b/frontend/e2e/workflow.spec.ts @@ -0,0 +1,86 @@ +import AxeBuilder from '@axe-core/playwright' +import { expect, test, type Page } from '@playwright/test' + +async function createManualPalette(page: Page) { + await page.goto('/?view=create') + await page.getByRole('button', { name: 'Start manually' }).click() + await page.getByRole('button', { name: 'Add color' }).click() + await page + .getByRole('textbox', { name: 'Color 1', exact: true }) + .fill('#6A5BCF') + await page.getByRole('textbox', { name: 'Color 1', exact: true }).blur() + await page + .getByRole('textbox', { name: 'Color 2', exact: true }) + .fill('#F5F0E8') + await page.getByRole('textbox', { name: 'Color 2', exact: true }).blur() +} + +test('creation through save, review, export, reopen, and delete', async ({ + page, + context, +}) => { + await context.grantPermissions(['clipboard-read', 'clipboard-write']) + await createManualPalette(page) + await expect(page.getByText('Unsaved')).toBeVisible() + await page.getByRole('button', { name: 'Save palette' }).click() + await expect(page.getByText('Saved', { exact: true })).toBeVisible() + + await page.getByRole('button', { name: 'Analyze palette' }).click() + await expect(page.getByText('Palette summary')).toBeVisible() + await page.getByRole('tab', { name: 'Contrast' }).click() + await page.getByLabel('Page background').selectOption('#F5F0E8') + await page.getByLabel('Primary text').selectOption('#6A5BCF') + await expect(page.getByText('Primary text on page background')).toBeVisible() + + await page + .getByRole('navigation', { name: 'Primary' }) + .getByRole('button', { name: 'Export' }) + .click() + await expect( + page.getByLabel(/Generated CSS custom properties preview/), + ).toContainText('--color-palette-1') + await page.getByRole('button', { name: 'Copy' }).click() + await expect(page.getByText(/copied to the clipboard/)).toBeVisible() + + await page + .getByRole('navigation', { name: 'Primary' }) + .getByRole('button', { name: 'Library' }) + .click() + await expect( + page.getByRole('button', { name: 'Open Untitled palette' }), + ).toBeVisible() + await page.getByRole('button', { name: 'Open Untitled palette' }).click() + await expect(page.locator('input[value="#6A5BCF"]').first()).toBeVisible() + + await page + .getByRole('navigation', { name: 'Primary' }) + .getByRole('button', { name: 'Library' }) + .click() + await page.getByRole('button', { name: 'Delete Untitled palette' }).click() + await page.getByRole('button', { name: 'Delete palette' }).click() + await expect(page.getByText('No saved palettes')).toBeVisible() +}) + +test('representative Create, Review, and Library states have no serious axe violations', async ({ + page, +}) => { + await createManualPalette(page) + for (const destination of ['create', 'review', 'library'] as const) { + if (destination === 'review') { + await page.getByRole('button', { name: 'Analyze palette' }).click() + await expect(page.getByText('Palette summary')).toBeVisible() + } else { + await page + .getByRole('navigation', { name: 'Primary' }) + .getByRole('button', { + name: destination === 'create' ? 'Create' : 'Library', + }) + .click() + } + const results = await new AxeBuilder({ page }).analyze() + const serious = results.violations.filter((violation) => + ['serious', 'critical'].includes(violation.impact ?? ''), + ) + expect(serious).toEqual([]) + } +}) diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js new file mode 100644 index 0000000..416c06c --- /dev/null +++ b/frontend/eslint.config.js @@ -0,0 +1,41 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + { + ignores: [ + 'coverage/**', + 'dist/**', + 'node_modules/**', + 'playwright-report/**', + 'test-results/**', + ], + }, + js.configs.recommended, + ...tseslint.configs.recommended, + { + files: ['*.js', 'e2e/**/*.mjs'], + languageOptions: { globals: globals.node }, + }, + { + files: ['src/**/*.{ts,tsx}', 'e2e/**/*.ts'], + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + 'react-hooks/rules-of-hooks': 'error', + 'react-refresh/only-export-components': 'off', + '@typescript-eslint/no-explicit-any': 'off', + }, + }, +) diff --git a/frontend/index.html b/frontend/index.html index 3e3655f..e333467 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -5,9 +5,10 @@ - diff --git a/frontend/package.json b/frontend/package.json index ebf2321..629e5ef 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,8 +6,15 @@ "scripts": { "dev": "vite", "build": "tsc && vite build", + "format": "prettier --write .", + "format:check": "prettier --check .", + "lint": "eslint . --max-warnings 0", "typecheck": "tsc --noEmit", "test": "vitest run", + "test:coverage": "vitest run --coverage", + "test:e2e": "playwright test --grep-invert @screenshots", + "review:screenshots": "node e2e/capture-screenshots.mjs", + "check": "pnpm format:check && pnpm lint && pnpm typecheck && pnpm test:coverage && pnpm build", "preview": "vite preview" }, "dependencies": { @@ -18,6 +25,9 @@ "zod": "^3.24.2" }, "devDependencies": { + "@axe-core/playwright": "^4.12.1", + "@eslint/js": "^10.0.1", + "@playwright/test": "^1.62.0", "@testing-library/jest-dom": "6.9.1", "@testing-library/react": "^16.2.0", "@types/d3": "^7.4.3", @@ -25,11 +35,19 @@ "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", "@vitejs/plugin-react": "^4.2.1", + "@vitest/coverage-v8": "^2.1.9", "autoprefixer": "^10.4.16", + "eslint": "^10.8.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.3", + "fake-indexeddb": "^6.2.5", + "globals": "^17.7.0", "jsdom": "^26.0.0", "postcss": "^8.4.32", + "prettier": "^3.9.6", "tailwindcss": "^3.4.0", "typescript": "^5.3.3", + "typescript-eslint": "^8.65.0", "vite": "^5.0.8", "vitest": "^2.1.9" } diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts new file mode 100644 index 0000000..a365fa5 --- /dev/null +++ b/frontend/playwright.config.ts @@ -0,0 +1,49 @@ +import { defineConfig, devices } from '@playwright/test' +import path from 'node:path' + +const repositoryRoot = path.resolve(import.meta.dirname, '..') +const windowsPython = path.join( + repositoryRoot, + 'backend', + '.venv311', + 'Scripts', + 'python.exe', +) +const python = + process.env.COLORCRAFT_PYTHON ?? + (process.platform === 'win32' ? `"${windowsPython}"` : 'python3') + +export default defineConfig({ + testDir: './e2e', + fullyParallel: false, + forbidOnly: Boolean(process.env.CI), + retries: process.env.CI ? 1 : 0, + workers: 1, + reporter: [['list'], ['html', { open: 'never' }]], + timeout: 60_000, + expect: { timeout: 10_000 }, + use: { + baseURL: 'http://127.0.0.1:5174', + trace: 'retain-on-failure', + screenshot: 'only-on-failure', + video: 'retain-on-failure', + }, + webServer: { + command: `${python} dev.py`, + cwd: repositoryRoot, + url: 'http://127.0.0.1:5174', + reuseExistingServer: !process.env.CI, + timeout: 60_000, + stdout: 'pipe', + stderr: 'pipe', + }, + projects: [ + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + viewport: { width: 1440, height: 900 }, + }, + }, + ], +}) diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index be56282..f74ff7c 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -24,6 +24,15 @@ importers: specifier: ^3.24.2 version: 3.25.76 devDependencies: + '@axe-core/playwright': + specifier: ^4.12.1 + version: 4.12.1(playwright-core@1.62.0) + '@eslint/js': + specifier: ^10.0.1 + version: 10.0.1(eslint@10.8.0(jiti@1.21.7)) + '@playwright/test': + specifier: ^1.62.0 + version: 1.62.0 '@testing-library/jest-dom': specifier: 6.9.1 version: 6.9.1 @@ -45,21 +54,45 @@ importers: '@vitejs/plugin-react': specifier: ^4.2.1 version: 4.7.0(vite@5.4.20(@types/node@22.20.1)) + '@vitest/coverage-v8': + specifier: ^2.1.9 + version: 2.1.9(vitest@2.1.9(@types/node@22.20.1)(jsdom@26.1.0)) autoprefixer: specifier: ^10.4.16 version: 10.4.21(postcss@8.5.6) + eslint: + specifier: ^10.8.0 + version: 10.8.0(jiti@1.21.7) + eslint-plugin-react-hooks: + specifier: ^7.1.1 + version: 7.1.1(eslint@10.8.0(jiti@1.21.7)) + eslint-plugin-react-refresh: + specifier: ^0.5.3 + version: 0.5.3(eslint@10.8.0(jiti@1.21.7)) + fake-indexeddb: + specifier: ^6.2.5 + version: 6.2.5 + globals: + specifier: ^17.7.0 + version: 17.7.0 jsdom: specifier: ^26.0.0 version: 26.1.0 postcss: specifier: ^8.4.32 version: 8.5.6 + prettier: + specifier: ^3.9.6 + version: 3.9.6 tailwindcss: specifier: ^3.4.0 version: 3.4.18 typescript: specifier: ^5.3.3 version: 5.9.3 + typescript-eslint: + specifier: ^8.65.0 + version: 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) vite: specifier: ^5.0.8 version: 5.4.20(@types/node@22.20.1) @@ -76,9 +109,18 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} + '@axe-core/playwright@4.12.1': + resolution: {integrity: sha512-rMd7xriptqKpP+w5265i4Hdkv2X5kbu6uiBi/B2I7uf3hieRBM3qDCfaKPtxfiYb2mKXfF+yLODJwIx+Jv1GDw==} + peerDependencies: + playwright-core: '>= 1.0.0' + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -121,10 +163,18 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.27.1': resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -138,6 +188,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-transform-react-jsx-self@7.27.1': resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} @@ -166,6 +221,13 @@ packages: resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@csstools/color-helpers@5.1.0': resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} engines: {node: '>=18'} @@ -332,10 +394,73 @@ packages: cpu: [x64] os: [win32] + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/config-helpers@0.7.0': + resolution: {integrity: sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true + + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/plugin-kit@0.7.2': + resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} + engines: {node: '>=8'} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -368,6 +493,11 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@playwright/test@1.62.0': + resolution: {integrity: sha512-9zOJ6ZQRAena31MpOH9VSzIz8Ou3YJ/wtY/eQm5T2uhfhG7/U3COrMS8xOtUrZrp9OgdmzEnIYODye3nY1VqzA==} + engines: {node: '>=20'} + hasBin: true + '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} @@ -612,12 +742,18 @@ packages: '@types/d3@7.4.3': resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/geojson@7946.0.16': resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/node@22.20.1': resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} @@ -632,12 +768,80 @@ packages: '@types/react@18.3.26': resolution: {integrity: sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==} + '@typescript-eslint/eslint-plugin@8.65.0': + resolution: {integrity: sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.65.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.65.0': + resolution: {integrity: sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.65.0': + resolution: {integrity: sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.65.0': + resolution: {integrity: sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.65.0': + resolution: {integrity: sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.65.0': + resolution: {integrity: sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.65.0': + resolution: {integrity: sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.65.0': + resolution: {integrity: sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.65.0': + resolution: {integrity: sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.65.0': + resolution: {integrity: sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@vitejs/plugin-react@4.7.0': resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@vitest/coverage-v8@2.1.9': + resolution: {integrity: sha512-Z2cOr0ksM00MpEfyVE8KXIYPEcBFxdbLSs56L8PO0QQMxt/6bDj45uQfxoc96v05KW3clk7vvgP0qfDit9DmfQ==} + peerDependencies: + '@vitest/browser': 2.1.9 + vitest: 2.1.9 + peerDependenciesMeta: + '@vitest/browser': + optional: true + '@vitest/expect@2.1.9': resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} @@ -667,10 +871,23 @@ packages: '@vitest/utils@2.1.9': resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -719,9 +936,17 @@ packages: peerDependencies: postcss: ^8.1.0 + axe-core@4.12.1: + resolution: {integrity: sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==} + engines: {node: '>=4'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + baseline-browser-mapping@2.8.17: resolution: {integrity: sha512-j5zJcx6golJYTG6c05LUZ3Z8Gi+M62zRT/ycz4Xq4iCOdpcxwg7ngEYD4KA0eWZC7U17qh/Smq8bYbACJ0ipBA==} hasBin: true @@ -733,6 +958,10 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.8: + resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==} + engines: {node: 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -949,6 +1178,9 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + delaunator@5.0.1: resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} @@ -996,24 +1228,118 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + + eslint-plugin-react-refresh@0.5.3: + resolution: {integrity: sha512-5EMmLCV98Pi4o/f/3DP/v/tNqLHMIc9I8LKClNDWhZ9JTho89/kQcitCXQBMG7sAfVRK0Ie3T2EDOzp1YXYiVA==} + peerDependencies: + eslint: ^9 || ^10 + + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@10.8.0: + resolution: {integrity: sha512-nuKKvN+oIBO0koN7Tm7dlkmnkc21mtt0QJLwAKzjLq14y6lRTdVG36MZHJ8eQHwdJMwZbQNMlPOYedMq/oVJvQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + expect-type@1.4.0: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} + fake-indexeddb@6.2.5: + resolution: {integrity: sha512-CGnyrvbhPlWYMngksqrSSUT1BAVP49dZocrHuK0SvtR0D5TMs5wP0o3j7jexDJW01KSadjBp1M/71o/KR3nD1w==} + engines: {node: '>=18'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.4.3: + resolution: {integrity: sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==} + foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} @@ -1021,6 +1347,11 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1045,14 +1376,31 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true + globals@17.7.0: + resolution: {integrity: sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==} + engines: {node: '>=18'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} @@ -1065,6 +1413,18 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.6: + resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} + engines: {node: '>= 4'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} @@ -1103,6 +1463,22 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} @@ -1127,11 +1503,27 @@ packages: engines: {node: '>=6'} hasBin: true + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -1139,6 +1531,10 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -1164,6 +1560,13 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1176,6 +1579,10 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -1195,6 +1602,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-releases@2.0.25: resolution: {integrity: sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==} @@ -1217,12 +1627,28 @@ packages: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1248,6 +1674,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -1256,6 +1686,16 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + playwright-core@1.62.0: + resolution: {integrity: sha512-nsNRyq0r2zsG8AcRHWknc9QRA5XCueC7gWMrs+Gx2tlZn9hcl8zudfh00lhJPY1DE7NmZ6bDsT9g2yey8mXljA==} + engines: {node: '>=20'} + hasBin: true + + playwright@1.62.0: + resolution: {integrity: sha512-Z14dG305dgaLu6foB1TXQagFiW8JfSUIUaUuPaKQ6NtBPKF1P/qXcqfh6c6K/icPqdy37JmjbiBXf6JNg6Sylw==} + engines: {node: '>=20'} + hasBin: true + postcss-import@15.1.0: resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -1303,6 +1743,15 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.9.6: + resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} + engines: {node: '>=14'} + hasBin: true + pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -1381,6 +1830,11 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1431,6 +1885,10 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -1443,6 +1901,10 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + test-exclude@7.0.2: + resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==} + engines: {node: '>=18'} + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -1456,6 +1918,10 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + tinypool@1.1.1: resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1487,9 +1953,26 @@ packages: resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} engines: {node: '>=18'} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typescript-eslint@8.65.0: + resolution: {integrity: sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -1504,6 +1987,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -1599,6 +2085,10 @@ packages: engines: {node: '>=8'} hasBin: true + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -1629,6 +2119,16 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} @@ -1638,6 +2138,11 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@asamuzakjp/css-color@3.2.0': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -1646,6 +2151,11 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 lru-cache: 10.4.3 + '@axe-core/playwright@4.12.1(playwright-core@1.62.0)': + dependencies: + axe-core: 4.12.1 + playwright-core: 1.62.0 + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -1712,8 +2222,12 @@ snapshots: '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} + '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.29.7': {} + '@babel/helper-validator-option@7.27.1': {} '@babel/helpers@7.28.4': @@ -1725,6 +2239,10 @@ snapshots: dependencies: '@babel/types': 7.28.4 + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 @@ -1760,6 +2278,13 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@bcoe/v8-coverage@0.2.3': {} + '@csstools/color-helpers@5.1.0': {} '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': @@ -1849,6 +2374,56 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true + '@eslint-community/eslint-utils@4.10.1(eslint@10.8.0(jiti@1.21.7))': + dependencies: + eslint: 10.8.0(jiti@1.21.7) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.23.5': + dependencies: + '@eslint/object-schema': 3.0.5 + debug: 4.4.3 + minimatch: 10.2.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.7.0': + dependencies: + '@eslint/core': 1.2.1 + + '@eslint/core@1.2.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/js@10.0.1(eslint@10.8.0(jiti@1.21.7))': + optionalDependencies: + eslint: 10.8.0(jiti@1.21.7) + + '@eslint/object-schema@3.0.5': {} + + '@eslint/plugin-kit@0.7.2': + dependencies: + '@eslint/core': 1.2.1 + levn: 0.4.1 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -1858,6 +2433,8 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@istanbuljs/schema@0.1.6': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -1892,6 +2469,10 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@playwright/test@1.62.0': + dependencies: + playwright: 1.62.0 + '@rolldown/pluginutils@1.0.0-beta.27': {} '@rollup/rollup-android-arm-eabi@4.52.4': @@ -2130,10 +2711,14 @@ snapshots: '@types/d3-transition': 3.0.9 '@types/d3-zoom': 3.0.8 + '@types/esrecurse@4.3.1': {} + '@types/estree@1.0.8': {} '@types/geojson@7946.0.16': {} + '@types/json-schema@7.0.15': {} + '@types/node@22.20.1': dependencies: undici-types: 6.21.0 @@ -2149,6 +2734,97 @@ snapshots: '@types/prop-types': 15.7.15 csstype: 3.1.3 + '@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.65.0 + '@typescript-eslint/type-utils': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.65.0 + eslint: 10.8.0(jiti@1.21.7) + ignore: 7.0.6 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.65.0 + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.65.0 + debug: 4.4.3 + eslint: 10.8.0(jiti@1.21.7) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.65.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3) + '@typescript-eslint/types': 8.65.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.65.0': + dependencies: + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/visitor-keys': 8.65.0 + + '@typescript-eslint/tsconfig-utils@8.65.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + debug: 4.4.3 + eslint: 10.8.0(jiti@1.21.7) + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.65.0': {} + + '@typescript-eslint/typescript-estree@8.65.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.65.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/visitor-keys': 8.65.0 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.0(jiti@1.21.7)) + '@typescript-eslint/scope-manager': 8.65.0 + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) + eslint: 10.8.0(jiti@1.21.7) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.65.0': + dependencies: + '@typescript-eslint/types': 8.65.0 + eslint-visitor-keys: 5.0.1 + '@vitejs/plugin-react@4.7.0(vite@5.4.20(@types/node@22.20.1))': dependencies: '@babel/core': 7.28.4 @@ -2161,6 +2837,24 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitest/coverage-v8@2.1.9(vitest@2.1.9(@types/node@22.20.1)(jsdom@26.1.0))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 0.2.3 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magic-string: 0.30.21 + magicast: 0.3.5 + std-env: 3.10.0 + test-exclude: 7.0.2 + tinyrainbow: 1.2.0 + vitest: 2.1.9(@types/node@22.20.1)(jsdom@26.1.0) + transitivePeerDependencies: + - supports-color + '@vitest/expect@2.1.9': dependencies: '@vitest/spy': 2.1.9 @@ -2201,8 +2895,21 @@ snapshots: loupe: 3.2.1 tinyrainbow: 1.2.0 + acorn-jsx@5.3.2(acorn@8.17.0): + dependencies: + acorn: 8.17.0 + + acorn@8.17.0: {} + agent-base@7.1.4: {} + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -2242,8 +2949,12 @@ snapshots: postcss: 8.5.6 postcss-value-parser: 4.2.0 + axe-core@4.12.1: {} + balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + baseline-browser-mapping@2.8.17: {} binary-extensions@2.3.0: {} @@ -2252,6 +2963,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.8: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -2486,6 +3201,8 @@ snapshots: deep-eql@5.0.2: {} + deep-is@0.1.4: {} + delaunator@5.0.1: dependencies: robust-predicates: 3.0.2 @@ -2540,12 +3257,99 @@ snapshots: escalade@3.2.0: {} + escape-string-regexp@4.0.0: {} + + eslint-plugin-react-hooks@7.1.1(eslint@10.8.0(jiti@1.21.7)): + dependencies: + '@babel/core': 7.28.4 + '@babel/parser': 7.28.4 + eslint: 10.8.0(jiti@1.21.7) + hermes-parser: 0.25.1 + zod: 3.25.76 + zod-validation-error: 4.0.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-refresh@0.5.3(eslint@10.8.0(jiti@1.21.7)): + dependencies: + eslint: 10.8.0(jiti@1.21.7) + + eslint-scope@9.1.2: + dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.8 + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@10.8.0(jiti@1.21.7): + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.0(jiti@1.21.7)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.7.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.2 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.15.0 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 1.21.7 + transitivePeerDependencies: + - supports-color + + espree@11.2.0: + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + eslint-visitor-keys: 5.0.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.8 + esutils@2.0.3: {} + expect-type@1.4.0: {} + fake-indexeddb@6.2.5: {} + + fast-deep-equal@3.1.3: {} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2554,14 +3358,38 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + fastq@1.19.1: dependencies: reusify: 1.1.0 + fdir@6.5.0(picomatch@4.0.5): + optionalDependencies: + picomatch: 4.0.5 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.3 + keyv: 4.5.4 + + flatted@3.4.3: {} + foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 @@ -2569,6 +3397,9 @@ snapshots: fraction.js@4.3.7: {} + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -2593,14 +3424,26 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + globals@17.7.0: {} + + has-flag@4.0.0: {} + hasown@2.0.2: dependencies: function-bind: 1.1.2 + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 + html-escaper@2.0.2: {} + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -2619,6 +3462,12 @@ snapshots: dependencies: safer-buffer: 2.1.2 + ignore@5.3.2: {} + + ignore@7.0.6: {} + + imurmurhash@0.1.4: {} + indent-string@4.0.0: {} internmap@2.0.3: {} @@ -2645,6 +3494,27 @@ snapshots: isexe@2.0.0: {} + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 @@ -2684,12 +3554,31 @@ snapshots: jsesc@3.1.0: {} + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + json5@2.2.3: {} + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -2712,6 +3601,16 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + magicast@0.3.5: + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.8.5 + merge2@1.4.1: {} micromatch@4.0.8: @@ -2721,6 +3620,10 @@ snapshots: min-indent@1.0.1: {} + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.8 + minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 @@ -2737,6 +3640,8 @@ snapshots: nanoid@3.3.11: {} + natural-compare@1.4.0: {} + node-releases@2.0.25: {} normalize-path@3.0.0: {} @@ -2749,12 +3654,31 @@ snapshots: object-hash@3.0.0: {} + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + package-json-from-dist@1.0.1: {} parse5@7.3.0: dependencies: entities: 6.0.1 + path-exists@4.0.0: {} + path-key@3.1.1: {} path-parse@1.0.7: {} @@ -2772,10 +3696,20 @@ snapshots: picomatch@2.3.1: {} + picomatch@4.0.5: {} + pify@2.3.0: {} pirates@4.0.7: {} + playwright-core@1.62.0: {} + + playwright@1.62.0: + dependencies: + playwright-core: 1.62.0 + optionalDependencies: + fsevents: 2.3.2 + postcss-import@15.1.0(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -2813,6 +3747,10 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + prelude-ls@1.2.1: {} + + prettier@3.9.6: {} + pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 @@ -2908,6 +3846,8 @@ snapshots: semver@6.3.1: {} + semver@7.8.5: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -2958,6 +3898,10 @@ snapshots: pirates: 4.0.7 ts-interface-checker: 0.1.13 + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} symbol-tree@3.2.4: {} @@ -2990,6 +3934,12 @@ snapshots: - tsx - yaml + test-exclude@7.0.2: + dependencies: + '@istanbuljs/schema': 0.1.6 + glob: 10.4.5 + minimatch: 10.2.5 + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -3002,6 +3952,11 @@ snapshots: tinyexec@0.3.2: {} + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + tinypool@1.1.1: {} tinyrainbow@1.2.0: {} @@ -3026,8 +3981,27 @@ snapshots: dependencies: punycode: 2.3.1 + ts-api-utils@2.5.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + ts-interface-checker@0.1.13: {} + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typescript-eslint@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.65.0(@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + eslint: 10.8.0(jiti@1.21.7) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + typescript@5.9.3: {} undici-types@6.21.0: {} @@ -3038,6 +4012,10 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + util-deprecate@1.0.2: {} vite-node@2.1.9(@types/node@22.20.1): @@ -3129,6 +4107,8 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + word-wrap@1.2.5: {} + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -3149,4 +4129,10 @@ snapshots: yallist@3.1.1: {} + yocto-queue@0.1.0: {} + + zod-validation-error@4.0.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + zod@3.25.76: {} diff --git a/frontend/pnpm-workspace.yaml b/frontend/pnpm-workspace.yaml index 9af1dfc..7f5dfdd 100644 --- a/frontend/pnpm-workspace.yaml +++ b/frontend/pnpm-workspace.yaml @@ -1,5 +1,5 @@ packages: - - "." + - '.' allowBuilds: esbuild: true diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js index b4a6220..2e7af2b 100644 --- a/frontend/postcss.config.js +++ b/frontend/postcss.config.js @@ -4,4 +4,3 @@ export default { autoprefixer: {}, }, } - diff --git a/frontend/public/app-manifest.json b/frontend/public/app-manifest.json new file mode 100644 index 0000000..092843c --- /dev/null +++ b/frontend/public/app-manifest.json @@ -0,0 +1,25 @@ +{ + "schemaVersion": 1, + "id": "colorcraft", + "name": "ColorCraft", + "descriptor": "Local color utility", + "version": "1.0.0", + "icon": "/colorcraft-mark.svg", + "defaults": { + "webAddress": "http://127.0.0.1:5174", + "apiAddress": "http://127.0.0.1:4100" + }, + "endpoints": { + "metadata": "/metadata", + "health": "/health", + "readiness": "/ready" + }, + "capabilities": [ + "image-color-extraction", + "palette-editing", + "harmony-analysis", + "contrast-review", + "palette-export", + "local-palette-library" + ] +} diff --git a/frontend/public/colorcraft-mark.svg b/frontend/public/colorcraft-mark.svg new file mode 100644 index 0000000..c9cf12e --- /dev/null +++ b/frontend/public/colorcraft-mark.svg @@ -0,0 +1,7 @@ + + ColorCraft + + + + + diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 055c86e..4ec035c 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -1,7 +1,15 @@ -import { act, fireEvent, render, screen, waitFor, within } from '@testing-library/react' +import { + act, + fireEvent, + render, + screen, + waitFor, + within, +} from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import { analyzeColors, extractColors, suggestColors } from './api/client' import { analysis, red } from './test/fixtures' +import { savePalette } from './persistence' import App from './App' vi.mock('./api/client', () => ({ @@ -18,12 +26,15 @@ describe('ColorCraft workspace', () => { beforeEach(() => { window.history.replaceState({}, '', '/?view=create') localStorage.clear() - vi.stubGlobal('matchMedia', vi.fn(() => ({ - matches: false, - media: '(prefers-color-scheme: dark)', - addEventListener: vi.fn(), - removeEventListener: vi.fn(), - }))) + vi.stubGlobal( + 'matchMedia', + vi.fn(() => ({ + matches: false, + media: '(prefers-color-scheme: dark)', + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + })), + ) Object.defineProperty(URL, 'createObjectURL', { configurable: true, value: vi.fn(() => 'blob:source'), @@ -36,30 +47,47 @@ describe('ColorCraft workspace', () => { vi.mocked(analyzeColors).mockReset() vi.mocked(suggestColors).mockReset() vi.mocked(analyzeColors).mockResolvedValue({ success: true, analysis }) - vi.mocked(suggestColors).mockResolvedValue({ success: true, suggestions: [] }) + vi.mocked(suggestColors).mockResolvedValue({ + success: true, + suggestions: [], + }) }) it('enables views from real palette prerequisites and writes URL state', async () => { render() - expect(within(desktopNavigation()).getByRole('button', { name: 'Review' })).toBeDisabled() - expect(within(desktopNavigation()).getByRole('button', { name: 'Export' })).toBeDisabled() + expect( + within(desktopNavigation()).getByRole('button', { name: 'Review' }), + ).toBeDisabled() + expect( + within(desktopNavigation()).getByRole('button', { name: 'Export' }), + ).toBeDisabled() fireEvent.click(screen.getByRole('button', { name: 'Start manually' })) - expect(within(desktopNavigation()).getByRole('button', { name: 'Export' })).toBeEnabled() - expect(within(desktopNavigation()).getByRole('button', { name: 'Review' })).toBeDisabled() + expect( + within(desktopNavigation()).getByRole('button', { name: 'Export' }), + ).toBeEnabled() + expect( + within(desktopNavigation()).getByRole('button', { name: 'Review' }), + ).toBeDisabled() fireEvent.click(screen.getByRole('button', { name: 'Add color' })) - const review = within(desktopNavigation()).getByRole('button', { name: 'Review' }) + const review = within(desktopNavigation()).getByRole('button', { + name: 'Review', + }) expect(review).toBeEnabled() fireEvent.click(review) expect(window.location.search).toBe('?view=review&review=overview') expect(screen.getByText('Analyze this palette')).toBeInTheDocument() - fireEvent.click(within(desktopNavigation()).getByRole('button', { name: 'Create' })) + fireEvent.click( + within(desktopNavigation()).getByRole('button', { name: 'Create' }), + ) expect(screen.getByText('Palette')).toBeInTheDocument() act(() => window.history.back()) - await waitFor(() => expect(window.location.search).toBe('?view=review&review=overview')) + await waitFor(() => + expect(window.location.search).toBe('?view=review&review=overview'), + ) expect(screen.getByText('Analyze this palette')).toBeInTheDocument() act(() => window.history.forward()) @@ -71,12 +99,16 @@ describe('ColorCraft workspace', () => { render() fireEvent.click(screen.getByRole('button', { name: 'Start manually' })) fireEvent.click(screen.getByRole('button', { name: 'New palette' })) - expect(screen.getByRole('dialog', { name: 'Start a new palette?' })).toBeInTheDocument() + expect( + screen.getByRole('dialog', { name: 'Start a new palette?' }), + ).toBeInTheDocument() fireEvent.click(screen.getByRole('button', { name: 'Keep working' })) expect(screen.getByText('Untitled palette')).toBeInTheDocument() fireEvent.click(screen.getByRole('button', { name: 'New palette' })) - fireEvent.click(screen.getByRole('button', { name: 'Discard and start new' })) + fireEvent.click( + screen.getByRole('button', { name: 'Discard and start new' }), + ) expect(screen.getByText('Create a palette')).toBeInTheDocument() }) @@ -89,13 +121,19 @@ describe('ColorCraft workspace', () => { const { container } = render() const input = container.querySelector('#source-image')! fireEvent.change(input, { - target: { files: [new File(['image'], 'sample.png', { type: 'image/png' })] }, + target: { + files: [new File(['image'], 'sample.png', { type: 'image/png' })], + }, }) expect((await screen.findAllByText('sample.png')).length).toBeGreaterThan(0) fireEvent.click(screen.getByRole('button', { name: 'New palette' })) - fireEvent.click(screen.getByRole('button', { name: 'Discard and start new' })) - await waitFor(() => expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:source')) + fireEvent.click( + screen.getByRole('button', { name: 'Discard and start new' }), + ) + await waitFor(() => + expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:source'), + ) }) it('restores an unavailable refreshed view to Create', async () => { @@ -111,10 +149,9 @@ describe('ColorCraft workspace', () => { fireEvent.click(screen.getByRole('button', { name: 'Add color' })) window.history.pushState({}, '', '/?view=review&review=contrast') act(() => window.dispatchEvent(new PopStateEvent('popstate'))) - expect(await screen.findByRole('tab', { name: 'Contrast' })).toHaveAttribute( - 'aria-selected', - 'true', - ) + expect( + await screen.findByRole('tab', { name: 'Contrast' }), + ).toHaveAttribute('aria-selected', 'true') }) it('withholds stale analysis after the palette changes', async () => { @@ -123,12 +160,83 @@ describe('ColorCraft workspace', () => { fireEvent.click(screen.getByRole('button', { name: 'Add color' })) fireEvent.click(screen.getByRole('button', { name: 'Analyze palette' })) expect(await screen.findByText('Palette summary')).toBeInTheDocument() - fireEvent.click(within(desktopNavigation()).getByRole('button', { name: 'Create' })) + fireEvent.click( + within(desktopNavigation()).getByRole('button', { name: 'Create' }), + ) const input = screen.getByLabelText('Color 1') fireEvent.change(input, { target: { value: '#121212' } }) fireEvent.blur(input) - fireEvent.click(within(desktopNavigation()).getByRole('button', { name: 'Review' })) - expect(screen.getByText('Analysis is stale because the palette changed.')).toBeInTheDocument() + fireEvent.click( + within(desktopNavigation()).getByRole('button', { name: 'Review' }), + ) + expect( + screen.getByText('Analysis is stale because the palette changed.'), + ).toBeInTheDocument() expect(screen.queryByText('Palette summary')).not.toBeInTheDocument() }) + + it('shows unsaved, saved, and modified states around explicit saves', async () => { + render() + fireEvent.click(screen.getByRole('button', { name: 'Start manually' })) + expect(screen.getByText('Unsaved')).toBeInTheDocument() + fireEvent.click(screen.getByRole('button', { name: 'Save palette' })) + expect(await screen.findByText('Saved')).toBeInTheDocument() + + const input = screen.getByLabelText('Color 1') + fireEvent.change(input, { target: { value: '#121212' } }) + fireEvent.blur(input) + expect(screen.getByText('Modified')).toBeInTheDocument() + fireEvent.click(screen.getByRole('button', { name: 'Save changes' })) + await waitFor(() => expect(screen.getByText('Saved')).toBeInTheDocument()) + }) + + it('opens a saved palette and confirms before discarding another unsaved palette', async () => { + await savePalette({ + name: 'Stored palette', + sourceType: 'manual', + colors: [red], + roles: {}, + }) + render() + fireEvent.click(screen.getByRole('button', { name: 'Start manually' })) + fireEvent.click( + within(desktopNavigation()).getByRole('button', { name: 'Library' }), + ) + fireEvent.click( + await screen.findByRole('button', { name: 'Open Stored palette' }), + ) + expect( + screen.getByRole('dialog', { name: 'Open another palette?' }), + ).toBeInTheDocument() + fireEvent.click( + screen.getByRole('button', { name: 'Discard changes and open' }), + ) + expect(await screen.findByDisplayValue('#FF0000')).toBeInTheDocument() + expect(screen.getByText('Saved')).toBeInTheDocument() + }) + + it('leaves a predictable empty Library after deleting the active palette', async () => { + await savePalette({ + name: 'Delete me', + sourceType: 'manual', + colors: [red], + roles: {}, + }) + render() + fireEvent.click( + within(desktopNavigation()).getByRole('button', { name: 'Library' }), + ) + fireEvent.click( + await screen.findByRole('button', { name: 'Open Delete me' }), + ) + fireEvent.click( + within(desktopNavigation()).getByRole('button', { name: 'Library' }), + ) + fireEvent.click(screen.getByRole('button', { name: 'Delete Delete me' })) + fireEvent.click(screen.getByRole('button', { name: 'Delete palette' })) + expect(await screen.findByText('No saved palettes')).toBeInTheDocument() + expect( + within(desktopNavigation()).getByRole('button', { name: 'Review' }), + ).toBeDisabled() + }) }) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 997855a..fc132c6 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,11 @@ -import { Pipette, RefreshCw, Upload } from 'lucide-react' +import { + CheckCircle2, + CircleDotDashed, + Pipette, + RefreshCw, + Save, + Upload, +} from 'lucide-react' import { useEffect, useRef, useState } from 'react' import { analyzeColors, extractColors } from './api/client' import type { Analysis, Color } from './api/contracts' @@ -9,14 +16,26 @@ import ExportWorkspace from './components/ExportWorkspace' import ImageColorPicker from './components/ImageColorPicker' import ImageUpload, { validateImageFile } from './components/ImageUpload' import InlineNotice, { type NoticeState } from './components/InlineNotice' +import PaletteLibrary from './components/PaletteLibrary' import ReviewWorkspace from './components/ReviewWorkspace' import Button from './components/ui/Button' import Dialog from './components/ui/Dialog' +import StatusBadge from './components/ui/StatusBadge' import { pruneRoleAssignments, type PaletteRole, type RoleAssignments, } from './contrast' +import { + deleteSavedPalette, + duplicateSavedPalette, + listSavedPalettes, + paletteSnapshotFingerprint, + renameSavedPalette, + savePalette, + type PaletteDraft, + type SavedPalette, +} from './persistence' import { colorFromHex, type PaletteColor, @@ -45,6 +64,10 @@ function App() { const [view, setView] = useState(() => viewFromLocation()) const [source, setSource] = useState(null) const [manualPalette, setManualPalette] = useState(false) + const [paletteSourceType, setPaletteSourceType] = useState< + 'image' | 'manual' | null + >(null) + const [sourceFilename, setSourceFilename] = useState() const [colors, setColors] = useState([]) const [selectedIndex, setSelectedIndex] = useState(null) const [requestedColors, setRequestedColors] = useState(6) @@ -55,9 +78,18 @@ function App() { const [notice, setNotice] = useState(null) const [confirmNewPalette, setConfirmNewPalette] = useState(false) const [pickerTarget, setPickerTarget] = useState(null) - const [reviewTab, setReviewTab] = useState(() => reviewFromLocation()) + const [reviewTab, setReviewTab] = useState(() => + reviewFromLocation(), + ) const [roles, setRoles] = useState({}) const [paletteName, setPaletteName] = useState('Untitled palette') + const [savedPalettes, setSavedPalettes] = useState([]) + const [libraryLoading, setLibraryLoading] = useState(true) + const [activePaletteId, setActivePaletteId] = useState(null) + const [savedFingerprint, setSavedFingerprint] = useState(null) + const [pendingOpenPalette, setPendingOpenPalette] = + useState(null) + const [deleteTarget, setDeleteTarget] = useState(null) const changeImageInputRef = useRef(null) const sourceUrlRef = useRef(null) const analysisRequestRef = useRef(0) @@ -67,11 +99,32 @@ function App() { const reviewAvailable = colors.length >= 2 const exportAvailable = colors.length >= 1 - const hasUnsavedWork = Boolean(source || manualPalette || colors.length) const paletteActive = Boolean(source || manualPalette) + const paletteDraft: PaletteDraft | null = + paletteActive && colors.length && paletteSourceType + ? { + name: paletteName, + sourceType: paletteSourceType, + ...(sourceFilename ? { sourceFilename } : {}), + colors, + roles, + } + : null + const currentFingerprint = paletteDraft + ? paletteSnapshotFingerprint(paletteDraft) + : null + const saveState = !paletteDraft + ? null + : !activePaletteId + ? 'unsaved' + : currentFingerprint === savedFingerprint + ? 'saved' + : 'modified' + const hasPendingChanges = saveState === 'unsaved' || saveState === 'modified' const canOpenView = (target: WorkspaceView) => target === 'create' || + target === 'library' || (target === 'review' && reviewAvailable) || (target === 'export' && exportAvailable) @@ -81,14 +134,22 @@ function App() { ) => { if (!canOpenView(target)) return const method = options.replace ? 'replaceState' : 'pushState' - const url = target === 'review' ? urlForReview(reviewTab) : urlForView(target) + const url = + target === 'review' ? urlForReview(reviewTab) : urlForView(target) window.history[method]({ view: target, review: reviewTab }, '', url) setView(target) } - const navigateReview = (target: ReviewView, options: { replace?: boolean } = {}) => { + const navigateReview = ( + target: ReviewView, + options: { replace?: boolean } = {}, + ) => { const method = options.replace ? 'replaceState' : 'pushState' - window.history[method]({ view: 'review', review: target }, '', urlForReview(target)) + window.history[method]( + { view: 'review', review: target }, + '', + urlForReview(target), + ) setReviewTab(target) setView('review') } @@ -111,8 +172,7 @@ function App() { if (canOpenView(target)) { setView(target) setReviewTab(targetReview) - } - else navigate('create', { replace: true }) + } else navigate('create', { replace: true }) } window.addEventListener('popstate', onPopState) return () => window.removeEventListener('popstate', onPopState) @@ -126,6 +186,24 @@ function App() { setRoles((current) => pruneRoleAssignments(current, colors)) }, [colors]) + const refreshLibrary = async () => { + try { + setSavedPalettes(await listSavedPalettes()) + } catch (error) { + console.error('Could not load saved palettes:', error) + setNotice({ + variant: 'error', + message: 'Saved palettes could not be read from this browser.', + }) + } finally { + setLibraryLoading(false) + } + } + + useEffect(() => { + void refreshLibrary() + }, []) + useEffect( () => () => { analysisControllerRef.current?.abort() @@ -190,6 +268,10 @@ function App() { setSource({ file, previewUrl, width: null, height: null }) setPaletteName(file.name.replace(/\.[^.]+$/, '') || 'Untitled palette') setManualPalette(false) + setPaletteSourceType('image') + setSourceFilename(file.name) + setActivePaletteId(null) + setSavedFingerprint(null) setColors([]) setSelectedIndex(null) setAnalysis(null) @@ -202,6 +284,10 @@ function App() { revokeSource() setSource(null) setManualPalette(true) + setPaletteSourceType('manual') + setSourceFilename(undefined) + setActivePaletteId(null) + setSavedFingerprint(null) setColors([manualStarter]) setSelectedIndex(0) setAnalysis(null) @@ -210,7 +296,7 @@ function App() { navigate('create') } - const resetPalette = () => { + const resetPalette = (target: WorkspaceView = 'create') => { analysisRequestRef.current += 1 extractionRequestRef.current += 1 analysisControllerRef.current?.abort() @@ -220,35 +306,42 @@ function App() { revokeSource() setSource(null) setManualPalette(false) + setPaletteSourceType(null) + setSourceFilename(undefined) setColors([]) setSelectedIndex(null) setAnalysis(null) setAnalysisStale(false) setRoles({}) setPaletteName('Untitled palette') + setActivePaletteId(null) + setSavedFingerprint(null) setAnalyzing(false) setExtracting(false) setNotice(null) setPickerTarget(null) setConfirmNewPalette(false) - navigate('create') + navigate(target) } const requestNewPalette = () => { - if (hasUnsavedWork) setConfirmNewPalette(true) + if (hasPendingChanges) setConfirmNewPalette(true) else resetPalette() } const updateColor = (index: number, color: Color) => { - setColors((current) => current.map((item, itemIndex) => ( - itemIndex === index ? color : item - ))) + setColors((current) => + current.map((item, itemIndex) => (itemIndex === index ? color : item)), + ) invalidateAnalysis() } const addColor = (color: Color = manualStarter) => { if (colors.length >= 10) { - setNotice({ variant: 'warning', message: 'A palette can contain at most 10 colors.' }) + setNotice({ + variant: 'warning', + message: 'A palette can contain at most 10 colors.', + }) return } setColors((current) => [...current, color]) @@ -260,7 +353,10 @@ function App() { const sourceColor = colors[index] if (!sourceColor || colors.length >= 10) { if (colors.length >= 10) { - setNotice({ variant: 'warning', message: 'A palette can contain at most 10 colors.' }) + setNotice({ + variant: 'warning', + message: 'A palette can contain at most 10 colors.', + }) } return } @@ -279,7 +375,9 @@ function App() { } const removeColor = (index: number) => { - setColors((current) => current.filter((_, itemIndex) => itemIndex !== index)) + setColors((current) => + current.filter((_, itemIndex) => itemIndex !== index), + ) setSelectedIndex((current) => { if (current === null) return null if (colors.length <= 1) return null @@ -334,22 +432,144 @@ function App() { void beginImagePalette(file) } - const headerTitle = paletteActive ? 'Current palette' : 'ColorCraft' - const headerSource = source - ? source.file.name - : manualPalette - ? 'Untitled palette' - : 'Local color utility' - const headerSummary = source - ? `${colorCountLabel(colors.length)} · extracted from image` - : manualPalette - ? `${colorCountLabel(colors.length)} · created manually` - : 'Extract, refine, and validate color palettes from images.' + const openPalette = (palette: SavedPalette) => { + analysisRequestRef.current += 1 + extractionRequestRef.current += 1 + analysisControllerRef.current?.abort() + extractionControllerRef.current?.abort() + revokeSource() + setSource(null) + setManualPalette(true) + setPaletteSourceType(palette.sourceType) + setSourceFilename(palette.sourceFilename) + setPaletteName(palette.name) + setColors(palette.colors) + setRoles(palette.roles) + setSelectedIndex(palette.colors.length ? 0 : null) + setAnalysis(null) + setAnalysisStale(false) + setActivePaletteId(palette.id) + setSavedFingerprint(paletteSnapshotFingerprint(palette)) + setNotice(null) + setPendingOpenPalette(null) + navigate('create') + } + + const requestOpenPalette = (palette: SavedPalette) => { + if (hasPendingChanges && palette.id !== activePaletteId) { + setPendingOpenPalette(palette) + } else { + openPalette(palette) + } + } + + const saveCurrentPalette = async () => { + if (!paletteDraft) return + try { + const existing = activePaletteId + ? savedPalettes.find((palette) => palette.id === activePaletteId) + : undefined + const saved = await savePalette(paletteDraft, existing) + setActivePaletteId(saved.id) + setPaletteName(saved.name) + setSavedFingerprint(paletteSnapshotFingerprint(saved)) + await refreshLibrary() + setNotice({ + variant: 'success', + message: existing + ? 'Palette changes saved locally.' + : 'Palette saved locally.', + }) + } catch (error) { + console.error('Could not save palette:', error) + setNotice({ + variant: 'error', + message: 'The palette could not be saved in this browser.', + retry: () => void saveCurrentPalette(), + }) + } + } + + const handleRenamePalette = async (palette: SavedPalette, name: string) => { + try { + const renamed = await renameSavedPalette(palette.id, name) + if (palette.id === activePaletteId) { + setPaletteName(renamed.name) + setSavedFingerprint(paletteSnapshotFingerprint(renamed)) + } + await refreshLibrary() + } catch (error) { + console.error('Could not rename palette:', error) + setNotice({ + variant: 'error', + message: 'The saved palette could not be renamed.', + }) + } + } + + const handleDuplicatePalette = async (palette: SavedPalette) => { + try { + await duplicateSavedPalette(palette) + await refreshLibrary() + setNotice({ + variant: 'success', + message: `${palette.name} was duplicated.`, + }) + } catch (error) { + console.error('Could not duplicate palette:', error) + setNotice({ + variant: 'error', + message: 'The saved palette could not be duplicated.', + }) + } + } + + const confirmDeletePalette = async () => { + if (!deleteTarget) return + const palette = deleteTarget + try { + await deleteSavedPalette(palette.id) + setDeleteTarget(null) + if (palette.id === activePaletteId) resetPalette('library') + await refreshLibrary() + setNotice({ variant: 'success', message: `${palette.name} was deleted.` }) + } catch (error) { + console.error('Could not delete palette:', error) + setNotice({ + variant: 'error', + message: 'The saved palette could not be deleted.', + }) + } + } + + const headerTitle = + view === 'library' + ? 'Palette Library' + : paletteActive + ? 'Current palette' + : 'ColorCraft' + const headerSource = + view === 'library' + ? 'Local palette storage' + : paletteActive + ? paletteName + : 'Local color utility' + const headerSummary = + view === 'library' + ? `${savedPalettes.length} saved ${savedPalettes.length === 1 ? 'palette' : 'palettes'} · stored in this browser` + : paletteActive + ? `${colorCountLabel(colors.length)} · ${paletteSourceType === 'image' ? 'created from an image' : 'created manually'}` + : 'Extract, refine, and validate color palettes from images.' const createView = !paletteActive ? ( - + ) : ( -
+
{source && (
@@ -380,19 +600,35 @@ function App() { alt={`Source ${source.file.name}`} onLoad={(event) => { const image = event.currentTarget - setSource((current) => current && current.previewUrl === source.previewUrl - ? { ...current, width: image.naturalWidth, height: image.naturalHeight } - : current) + setSource((current) => + current && current.previewUrl === source.previewUrl + ? { + ...current, + width: image.naturalWidth, + height: image.naturalHeight, + } + : current, + ) }} />
-
File
{source.file.name}
+
+
File
+
{source.file.name}
+
Dimensions
-
{source.width && source.height ? `${source.width} × ${source.height}` : 'Reading…'}
+
+ {source.width && source.height + ? `${source.width} × ${source.height}` + : 'Reading…'} +
+
+
+
Size
+
{(source.file.size / 1024 / 1024).toFixed(2)} MB
-
Size
{(source.file.size / 1024 / 1024).toFixed(2)} MB
)} @@ -400,7 +636,13 @@ function App() {
-

{source ? 'Extracted palette' : 'Manual palette'}

+

+ {source + ? 'Extracted palette' + : paletteSourceType === 'image' + ? 'Saved image palette' + : 'Manual palette'} +

Palette

{source && ( @@ -415,6 +657,13 @@ function App() { )}
+ {!source && paletteSourceType === 'image' && ( +

+ Source: {sourceFilename ?? 'image'} · The source image itself was + not retained. +

+ )} + {source && (
@@ -424,11 +673,14 @@ function App() { min="3" max="10" value={requestedColors} - onChange={(event) => setRequestedColors(Number(event.target.value))} + onChange={(event) => + setRequestedColors(Number(event.target.value)) + } /> {requestedColors} - Actual returned: {colors.length} · Distinct colors may be fewer than requested. + Actual returned: {colors.length} · Distinct colors may be fewer + than requested.
)} @@ -453,7 +705,9 @@ function App() { > {analyzing ? 'Analyzing…' : 'Analyze palette'} - {!reviewAvailable && Add one more valid color to enable analysis.} + {!reviewAvailable && ( + Add one more valid color to enable analysis. + )}
@@ -490,6 +744,52 @@ function App() { /> ) + const libraryView = ( + void handleRenamePalette(palette, name)} + onDuplicate={(palette) => void handleDuplicatePalette(palette)} + onDelete={setDeleteTarget} + /> + ) + + const headerActions = paletteDraft ? ( +
+ + {saveState === 'saved' ? ( + + +
+ ) : undefined + return ( <> ({ id, name }))} + onOpenRecent={(id) => { + const palette = savedPalettes.find((item) => item.id === id) + if (palette) requestOpenPalette(palette) + }} + headerActions={headerActions} > {notice && ( setNotice(null)} /> @@ -516,9 +822,12 @@ function App() { {view === 'create' && createView} {view === 'review' && reviewView} {view === 'export' && exportView} + {view === 'library' && libraryView} - + setConfirmNewPalette(false)} > -

Your current unsaved palette will be cleared from this browser session.

+

+ Your current {saveState === 'modified' ? 'modified' : 'unsaved'}{' '} + palette changes will be cleared from this browser session. +

+
+ + +
+ + + setPendingOpenPalette(null)} + > +

+ Your current {saveState === 'modified' ? 'modified' : 'unsaved'}{' '} + palette changes will be discarded. +

- - + + +
+
+ + setDeleteTarget(null)} + > +

+ {deleteTarget?.name} will be removed from this browser. This cannot be + undone. +

+
+ +
diff --git a/frontend/src/api/client.test.ts b/frontend/src/api/client.test.ts index ec7de81..b741367 100644 --- a/frontend/src/api/client.test.ts +++ b/frontend/src/api/client.test.ts @@ -106,7 +106,10 @@ describe('ColorCraft API client', () => { vi.stubGlobal( 'fetch', vi.fn().mockResolvedValue( - jsonResponse({ success: true, analysis: { ...analysis, accessibility: {} } }), + jsonResponse({ + success: true, + analysis: { ...analysis, accessibility: {} }, + }), ), ) @@ -118,12 +121,8 @@ describe('ColorCraft API client', () => { it('strips extraction metadata from strict palette requests', async () => { const fetchMock = vi .fn() - .mockResolvedValueOnce( - jsonResponse({ success: true, analysis }), - ) - .mockResolvedValueOnce( - jsonResponse({ success: true, suggestions: [] }), - ) + .mockResolvedValueOnce(jsonResponse({ success: true, analysis })) + .mockResolvedValueOnce(jsonResponse({ success: true, suggestions: [] })) vi.stubGlobal('fetch', fetchMock) const extractedColor = { ...red, diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 77feb84..98724ef 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -15,7 +15,9 @@ import { ColorCraftApiError, } from './errors' -const configuredBaseUrl = (import.meta.env.VITE_COLORCRAFT_API_URL || '').replace(/\/$/, '') +const configuredBaseUrl = ( + import.meta.env.VITE_COLORCRAFT_API_URL || '' +).replace(/\/$/, '') function apiUrl(path: string): string { return `${configuredBaseUrl}${path}` diff --git a/frontend/src/api/errors.ts b/frontend/src/api/errors.ts index 91efebd..e1e04a8 100644 --- a/frontend/src/api/errors.ts +++ b/frontend/src/api/errors.ts @@ -25,7 +25,10 @@ export class ColorCraftApiError extends Error { } } -export function backendError(status: number, payload: unknown): ColorCraftApiError { +export function backendError( + status: number, + payload: unknown, +): ColorCraftApiError { const parsed = errorResponseSchema.safeParse(payload) if (parsed.success) { return new ColorCraftApiError(parsed.data.error.message, { diff --git a/frontend/src/components/AnalysisResults.test.tsx b/frontend/src/components/AnalysisResults.test.tsx index c19bd4b..d7b293c 100644 --- a/frontend/src/components/AnalysisResults.test.tsx +++ b/frontend/src/components/AnalysisResults.test.tsx @@ -22,6 +22,8 @@ describe('AnalysisResults', () => { ), ).toBeInTheDocument() expect(screen.queryByText('Harmony Score')).not.toBeInTheDocument() - expect(screen.getByText('#ff0000 + #0000ff • Ratio: 2.15')).toBeInTheDocument() + expect( + screen.getByText('#ff0000 + #0000ff • Ratio: 2.15'), + ).toBeInTheDocument() }) }) diff --git a/frontend/src/components/AnalysisResults.tsx b/frontend/src/components/AnalysisResults.tsx index 9d56627..72f04e2 100644 --- a/frontend/src/components/AnalysisResults.tsx +++ b/frontend/src/components/AnalysisResults.tsx @@ -24,7 +24,11 @@ export default function AnalysisResults({ analysis }: AnalysisResultsProps) { />
- {colorTheory.tags.map((tag) => {tag})} + {colorTheory.tags.map((tag) => ( + + {tag} + + ))}
@@ -43,13 +47,19 @@ export default function AnalysisResults({ analysis }: AnalysisResultsProps) { aria-valuemax={100} aria-valuenow={colorTheory.relationshipFit} > -
+
    - {colorTheory.relationshipFactors.map((factor) =>
  • {factor}
  • )} + {colorTheory.relationshipFactors.map((factor) => ( +
  • {factor}
  • + ))}

- This measures geometric color relationships, not subjective design quality. + This measures geometric color relationships, not subjective design + quality.

@@ -57,23 +67,43 @@ export default function AnalysisResults({ analysis }: AnalysisResultsProps) {

Temperature balance

-
Balance{colorTheory.temperatureBalance.balance}
+
+ Balance + {colorTheory.temperatureBalance.balance} +
Warm colors - {colorTheory.temperatureBalance.warmCount} ({(colorTheory.temperatureBalance.warmRatio * 100).toFixed(0)}%) + + {colorTheory.temperatureBalance.warmCount} ( + {(colorTheory.temperatureBalance.warmRatio * 100).toFixed(0)} + %) +
Cool colors - {colorTheory.temperatureBalance.coolCount} ({(colorTheory.temperatureBalance.coolRatio * 100).toFixed(0)}%) + + {colorTheory.temperatureBalance.coolCount} ( + {(colorTheory.temperatureBalance.coolRatio * 100).toFixed(0)} + %) +

Color metrics

-
Hue diversity{colorTheory.metrics.hueDiversity}°
-
Average saturation{colorTheory.metrics.saturationAvg}%
-
Lightness range{colorTheory.metrics.lightnessRange}%
+
+ Hue diversity + {colorTheory.metrics.hueDiversity}° +
+
+ Average saturation + {colorTheory.metrics.saturationAvg}% +
+
+ Lightness range + {colorTheory.metrics.lightnessRange}% +
@@ -87,11 +117,26 @@ export default function AnalysisResults({ analysis }: AnalysisResultsProps) { />
- - - - - + + + + +
{accessibility.issues.length > 0 && ( @@ -99,10 +144,14 @@ export default function AnalysisResults({ analysis }: AnalysisResultsProps) {

Issues found

{accessibility.issues.map((issue) => ( - +

{issue.message}

- {issue.color1} + {issue.color2} • Ratio: {issue.ratio?.toFixed(2) ?? 'N/A'} + {issue.color1} + {issue.color2} • Ratio:{' '} + {issue.ratio?.toFixed(2) ?? 'N/A'}
))} @@ -114,20 +163,37 @@ export default function AnalysisResults({ analysis }: AnalysisResultsProps) {

Color pair contrast

{accessibility.pairs.map((pair) => ( -
+
- + - +
{pair.ratio?.toFixed(2) ?? 'N/A'}:1
- AA Normal - AA Large - AAA Normal - AAA Large + + AA Normal + + + AA Large + + + AAA Normal + + + AAA Large +
))} diff --git a/frontend/src/components/AppShell.test.tsx b/frontend/src/components/AppShell.test.tsx index 3e46ea2..3b38895 100644 --- a/frontend/src/components/AppShell.test.tsx +++ b/frontend/src/components/AppShell.test.tsx @@ -5,12 +5,15 @@ import AppShell from './AppShell' describe('AppShell navigation', () => { beforeEach(() => { localStorage.clear() - vi.stubGlobal('matchMedia', vi.fn(() => ({ - matches: false, - media: '(prefers-color-scheme: dark)', - addEventListener: vi.fn(), - removeEventListener: vi.fn(), - }))) + vi.stubGlobal( + 'matchMedia', + vi.fn(() => ({ + matches: false, + media: '(prefers-color-scheme: dark)', + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + })), + ) }) it('explains unavailable Review and Export views', () => { @@ -31,13 +34,18 @@ describe('AppShell navigation', () => { , ) const desktop = screen.getByRole('navigation', { name: 'Primary' }) - expect(within(desktop).getByRole('button', { name: 'Create' })).toBeEnabled() - expect(within(desktop).getByRole('button', { name: 'Review' })).toBeDisabled() - expect(within(desktop).getByRole('button', { name: 'Review' })).toHaveAttribute( - 'title', - 'Add two colors.', - ) - expect(within(desktop).getByRole('button', { name: 'Export' })).toBeDisabled() + expect( + within(desktop).getByRole('button', { name: 'Create' }), + ).toBeEnabled() + expect( + within(desktop).getByRole('button', { name: 'Review' }), + ).toBeDisabled() + expect( + within(desktop).getByRole('button', { name: 'Review' }), + ).toHaveAttribute('title', 'Add two colors.') + expect( + within(desktop).getByRole('button', { name: 'Export' }), + ).toBeDisabled() }) it('provides equivalent mobile navigation and shell theme control', () => { diff --git a/frontend/src/components/AppShell.tsx b/frontend/src/components/AppShell.tsx index 9e031ae..ed4b06c 100644 --- a/frontend/src/components/AppShell.tsx +++ b/frontend/src/components/AppShell.tsx @@ -1,4 +1,11 @@ -import { Download, FilePlus2, FlaskConical, Palette, Plus } from 'lucide-react' +import { + Download, + FilePlus2, + FlaskConical, + Library, + Palette, + Plus, +} from 'lucide-react' import type { ReactNode } from 'react' import type { WorkspaceView } from '../workspace' import AppMark from './ui/AppMark' @@ -19,6 +26,9 @@ interface AppShellProps { summary: string onNavigate: (view: WorkspaceView) => void onNewPalette: () => void + recentPalettes?: Array<{ id: string; name: string }> + onOpenRecent?: (id: string) => void + headerActions?: ReactNode children: ReactNode } @@ -26,6 +36,7 @@ const navigationItems = [ { view: 'create' as const, label: 'Create', icon: Palette }, { view: 'review' as const, label: 'Review', icon: FlaskConical }, { view: 'export' as const, label: 'Export', icon: Download }, + { view: 'library' as const, label: 'Library', icon: Library }, ] export default function AppShell({ @@ -36,16 +47,22 @@ export default function AppShell({ summary, onNavigate, onNewPalette, + recentPalettes = [], + onOpenRecent, + headerActions, children, }: AppShellProps) { const availability = (target: WorkspaceView) => { if (target === 'create') return { available: true, reason: '' } + if (target === 'library') return { available: true, reason: '' } return navigation[target] } const navigationContent = (location: 'sidebar' | 'mobile') => (
- Local only +
+ {headerActions} + Local only +
{children}
diff --git a/frontend/src/components/ColorSuggestions.test.tsx b/frontend/src/components/ColorSuggestions.test.tsx index a5f9c4f..724e4ca 100644 --- a/frontend/src/components/ColorSuggestions.test.tsx +++ b/frontend/src/components/ColorSuggestions.test.tsx @@ -21,7 +21,10 @@ function deferred() { return { promise, resolve } } -function response(colors: Color[], label = 'Complementary'): SuggestionResponse { +function response( + colors: Color[], + label = 'Complementary', +): SuggestionResponse { const suggested: SuggestionColor = { ...blue, name: `${label} blue`, @@ -48,14 +51,8 @@ function response(colors: Color[], label = 'Complementary'): SuggestionResponse async function loadSuggestions(colors: Color[]) { vi.mocked(suggestColors).mockResolvedValueOnce(response(colors)) - fireEvent.click( - screen.getByRole('button', { name: 'Generate suggestions' }), - ) - await screen.findByRole('heading', { name: labelFor(colors) }) -} - -function labelFor(_colors: Color[]) { - return 'Complementary' + fireEvent.click(screen.getByRole('button', { name: 'Generate suggestions' })) + await screen.findByRole('heading', { name: 'Complementary' }) } describe('ColorSuggestions palette lifecycle', () => { @@ -122,9 +119,7 @@ describe('ColorSuggestions palette lifecycle', () => { fireEvent.click( screen.getByRole('button', { name: 'Generate suggestions' }), ) - view.rerender( - , - ) + view.rerender() await waitFor(() => expect( screen.getByRole('button', { name: 'Generate suggestions' }), @@ -135,9 +130,13 @@ describe('ColorSuggestions palette lifecycle', () => { ) await act(async () => second.resolve(response([blue], 'Newest'))) - expect(await screen.findByRole('heading', { name: 'Newest' })).toBeInTheDocument() + expect( + await screen.findByRole('heading', { name: 'Newest' }), + ).toBeInTheDocument() await act(async () => first.resolve(response([red], 'Stale'))) - expect(screen.queryByRole('heading', { name: 'Stale' })).not.toBeInTheDocument() + expect( + screen.queryByRole('heading', { name: 'Stale' }), + ).not.toBeInTheDocument() expect(screen.getByRole('heading', { name: 'Newest' })).toBeInTheDocument() }) @@ -152,7 +151,9 @@ describe('ColorSuggestions palette lifecycle', () => { ) view.rerender() await act(async () => pending.resolve(response([red], 'Stale'))) - expect(screen.queryByRole('heading', { name: 'Stale' })).not.toBeInTheDocument() + expect( + screen.queryByRole('heading', { name: 'Stale' }), + ).not.toBeInTheDocument() expect( screen.getByRole('button', { name: 'Generate suggestions' }), ).toBeDisabled() @@ -161,6 +162,8 @@ describe('ColorSuggestions palette lifecycle', () => { it('marks duplicate suggestions without adding them', async () => { render() await loadSuggestions([red, blue]) - expect(screen.getByRole('button', { name: 'Already in palette #0000ff' })).toBeDisabled() + expect( + screen.getByRole('button', { name: 'Already in palette #0000ff' }), + ).toBeDisabled() }) }) diff --git a/frontend/src/components/ColorSuggestions.tsx b/frontend/src/components/ColorSuggestions.tsx index d9178bf..479e8c9 100644 --- a/frontend/src/components/ColorSuggestions.tsx +++ b/frontend/src/components/ColorSuggestions.tsx @@ -20,14 +20,19 @@ function oneSentence(value: string): string { return match?.[0].trim() ?? value.trim() } -export default function ColorSuggestions({ colors, onAddColor }: ColorSuggestionsProps) { +export default function ColorSuggestions({ + colors, + onAddColor, +}: ColorSuggestionsProps) { const [loading, setLoading] = useState(false) const [suggestions, setSuggestions] = useState([]) const [selectedColorIndex, setSelectedColorIndex] = useState(0) const [showAll, setShowAll] = useState(false) const [addedHexes, setAddedHexes] = useState>(new Set()) const [notice, setNotice] = useState(null) - const [suggestionsFingerprint, setSuggestionsFingerprint] = useState(null) + const [suggestionsFingerprint, setSuggestionsFingerprint] = useState< + string | null + >(null) const requestIdRef = useRef(0) const controllerRef = useRef(null) const fingerprint = paletteFingerprint(colors) @@ -44,7 +49,9 @@ export default function ColorSuggestions({ colors, onAddColor }: ColorSuggestion setAddedHexes(new Set()) setLoading(false) setNotice(null) - setSelectedColorIndex((current) => Math.max(0, Math.min(current, colors.length - 1))) + setSelectedColorIndex((current) => + Math.max(0, Math.min(current, colors.length - 1)), + ) }, [fingerprint, colors.length]) useEffect( @@ -73,13 +80,17 @@ export default function ColorSuggestions({ colors, onAddColor }: ColorSuggestion if ( requestId !== requestIdRef.current || requestedFingerprint !== fingerprintRef.current - ) return + ) + return setSuggestions(data.suggestions) setSuggestionsFingerprint(requestedFingerprint) } catch (error) { if (controller.signal.aborted) return console.error('Error fetching suggestions:', error) - setNotice({ message: errorMessage(error), retry: () => void fetchSuggestions() }) + setNotice({ + message: errorMessage(error), + retry: () => void fetchSuggestions(), + }) } finally { if (requestId === requestIdRef.current) setLoading(false) } @@ -88,7 +99,11 @@ export default function ColorSuggestions({ colors, onAddColor }: ColorSuggestion const addSuggestion = (suggestion: SuggestionColor) => { const key = suggestion.hex.toLowerCase() setAddedHexes((current) => new Set(current).add(key)) - onAddColor({ hex: suggestion.hex, rgb: suggestion.rgb, hsl: suggestion.hsl }) + onAddColor({ + hex: suggestion.hex, + rgb: suggestion.rgb, + hsl: suggestion.hsl, + }) } const paletteHexes = new Set(colors.map((color) => color.hex.toLowerCase())) @@ -100,18 +115,22 @@ export default function ColorSuggestions({ colors, onAddColor }: ColorSuggestion