From 061ea1d806760e977b0a2f018765a3912183c388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Thu, 26 Feb 2026 12:07:21 +0100 Subject: [PATCH] feat: unify pastel application into single playground and remove standalone pages --- GEMINI.md | 66 +++++ app/(app)/pastel/batch/page.tsx | 219 -------------- app/(app)/pastel/colorblind/page.tsx | 230 --------------- app/(app)/pastel/contrast/page.tsx | 184 ------------ app/(app)/pastel/distinct/page.tsx | 138 --------- app/(app)/pastel/gradient/page.tsx | 170 ----------- app/(app)/pastel/harmony/page.tsx | 161 ---------- app/(app)/pastel/names/page.tsx | 122 -------- app/(app)/pastel/page.tsx | 426 +++++++++++++++++++-------- app/(app)/pastel/textcolor/page.tsx | 227 -------------- components/layout/AppSidebar.tsx | 12 +- components/pastel/ColorPicker.tsx | 46 ++- components/pastel/ExportMenu.tsx | 109 +++++-- lib/pastel/api/client.ts | 73 ----- lib/pastel/api/queries.ts | 76 +---- lib/pastel/api/types.ts | 92 +----- lib/pastel/api/wasm-client.ts | 170 ++--------- lib/pastel/index.ts | 1 - lib/pastel/stores/historyStore.ts | 68 ----- lib/pastel/utils/color.ts | 44 --- lib/pastel/utils/export.ts | 12 +- 21 files changed, 519 insertions(+), 2127 deletions(-) create mode 100644 GEMINI.md delete mode 100644 app/(app)/pastel/batch/page.tsx delete mode 100644 app/(app)/pastel/colorblind/page.tsx delete mode 100644 app/(app)/pastel/contrast/page.tsx delete mode 100644 app/(app)/pastel/distinct/page.tsx delete mode 100644 app/(app)/pastel/gradient/page.tsx delete mode 100644 app/(app)/pastel/harmony/page.tsx delete mode 100644 app/(app)/pastel/names/page.tsx delete mode 100644 app/(app)/pastel/textcolor/page.tsx delete mode 100644 lib/pastel/stores/historyStore.ts diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..59c10cb --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,66 @@ +# GEMINI.md - Kit UI Context + +This file provides foundational context and instructions for Gemini CLI when working in the `kit-ui` workspace. + +## 🚀 Project Overview + +**Kit UI** is a high-performance, aesthetically pleasing toolkit built with **Next.js 16**, **React 19**, and **Tailwind CSS 4**. It provides four core specialized applications: + +1. **Pastel**: Advanced color theory, manipulation, and accessibility suite powered by `@valknarthing/pastel-wasm`. +2. **Units**: Smart unit converter supporting 187+ units across 23 categories, including a custom `tempo` measure. +3. **Figlet**: ASCII Art generator with 373 fonts and multi-format export. +4. **Media**: Browser-based file converter using **FFmpeg** and **ImageMagick** via WebAssembly (Zero server uploads). + +## 🛠️ Tech Stack & Architecture + +- **Framework**: Next.js 16 (App Router, Static Export). +- **Library**: React 19. +- **Styling**: Tailwind CSS 4 (CSS-first configuration in `app/globals.css`). +- **Animations**: Framer Motion 12. +- **State Management**: Zustand & React Query. +- **Performance**: Heavy logic (Color, Media) is offloaded to **WebAssembly (WASM)**. +- **UI Components**: shadcn/ui (customized for a glassmorphic aesthetic). + +## 📁 Project Structure + +```bash +. +├── app/ # Next.js App Router +│ ├── (app)/ # Core Tool Pages (pastel, units, figlet, media) +│ └── globals.css # Tailwind 4 configuration & global styles +├── components/ # UI Components +│ ├── [tool]/ # Tool-specific components (e.g., components/pastel/) +│ ├── layout/ # AppShell, Sidebar, Header +│ └── ui/ # Base Atomic Components (shadcn) +├── lib/ # Business Logic +│ ├── [tool]/ # Tool-specific logic & WASM wrappers +│ └── utils/ # General utilities (cn, format, etc.) +├── public/ # Static assets +│ ├── wasm/ # WASM binaries (ffmpeg, imagemagick) +│ └── fonts/ # Figlet fonts (.flf) +└── types/ # TypeScript definitions +``` + +## ⚙️ Development Workflows + +### Key Commands + +- **Development**: `pnpm dev` (Uses Next.js Turbopack). +- **Build**: `pnpm build` (Generates a static export in `/out`). +- **Lint**: `pnpm lint`. +- **WASM Setup**: `pnpm postinstall` (Automatically copies WASM binaries to `public/wasm/`). + +### Coding Standards + +1. **Tailwind 4**: Use the new CSS-first approach. Avoid `tailwind.config.js`. Define theme variables and utilities in `app/globals.css`. +2. **Glassmorphism**: Use the `@utility glass` for translucent components. +3. **WASM Orchestration**: Heavy processing should stay in `lib/[tool]/` and utilize WASM where possible. Refer to `lib/media/wasm/wasmLoader.ts` for pattern-loading FFmpeg/ImageMagick. +4. **Client-Side Only**: Since this is a static export toolkit that relies on browser APIs (WASM, File API), ensure components using these are marked with `'use client'`. +5. **Icons**: Exclusively use `lucide-react`. + +## 🧠 Strategic Instructions for Gemini + +- **Surgical Updates**: When modifying tools, ensure the logic remains in `lib/` and the UI in `components/`. +- **WASM Handling**: Do not attempt to run WASM-dependent logic in the terminal/Node environment unless specifically configured. These tools are designed for the browser. +- **Styling**: Adhere to the `glass` and gradient utilities (`gradient-purple-blue`, etc.) defined in `app/globals.css`. +- **Component Consistency**: Use shadcn components from `components/ui/` as the building blocks for new features. diff --git a/app/(app)/pastel/batch/page.tsx b/app/(app)/pastel/batch/page.tsx deleted file mode 100644 index 3515a3d..0000000 --- a/app/(app)/pastel/batch/page.tsx +++ /dev/null @@ -1,219 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import { Button } from '@/components/ui/button'; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select'; -import { Input } from '@/components/ui/input'; -import { Textarea } from '@/components/ui/textarea'; -import { Slider } from '@/components/ui/slider'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { PaletteGrid } from '@/components/pastel/PaletteGrid'; -import { ExportMenu } from '@/components/pastel/ExportMenu'; -import { AppPage } from '@/components/layout/AppPage'; -import { useLighten, useDarken, useSaturate, useDesaturate, useRotate } from '@/lib/pastel/api/queries'; -import { Loader2, Upload, Download } from 'lucide-react'; -import { toast } from 'sonner'; - -type Operation = 'lighten' | 'darken' | 'saturate' | 'desaturate' | 'rotate'; - -export default function BatchPage() { - const [inputColors, setInputColors] = useState(''); - const [operation, setOperation] = useState('lighten'); - const [amount, setAmount] = useState(0.2); - const [outputColors, setOutputColors] = useState([]); - - const lightenMutation = useLighten(); - const darkenMutation = useDarken(); - const saturateMutation = useSaturate(); - const desaturateMutation = useDesaturate(); - const rotateMutation = useRotate(); - - const parseColors = (text: string): string[] => { - // Parse colors from text (one per line, or comma-separated) - return text - .split(/[\n,]/) - .map((c) => c.trim()) - .filter((c) => c.length > 0 && c.match(/^#?[0-9a-fA-F]{3,8}$/)); - }; - - const handleProcess = async () => { - const colors = parseColors(inputColors); - - if (colors.length === 0) { - toast.error('No valid colors found'); - return; - } - - if (colors.length > 100) { - toast.error('Maximum 100 colors allowed'); - return; - } - - try { - let result; - - switch (operation) { - case 'lighten': - result = await lightenMutation.mutateAsync({ colors, amount }); - break; - case 'darken': - result = await darkenMutation.mutateAsync({ colors, amount }); - break; - case 'saturate': - result = await saturateMutation.mutateAsync({ colors, amount }); - break; - case 'desaturate': - result = await desaturateMutation.mutateAsync({ colors, amount }); - break; - case 'rotate': - result = await rotateMutation.mutateAsync({ colors, amount: amount * 360 }); - break; - } - - // Extract output colors from the result - const processed = result.colors.map((c) => c.output); - setOutputColors(processed); - toast.success(`Processed ${processed.length} colors`); - } catch (error) { - toast.error('Failed to process colors'); - console.error(error); - } - }; - - const isPending = - lightenMutation.isPending || - darkenMutation.isPending || - saturateMutation.isPending || - desaturateMutation.isPending || - rotateMutation.isPending; - - return ( - -
- {/* Input */} -
- - - Input Colors - - -

- Enter colors (one per line or comma-separated). Supports hex format -

- -