refactor: rename pastel app to color and update all references
This commit is contained in:
@@ -6,7 +6,7 @@ This file provides foundational context and instructions for Gemini CLI when wor
|
||||
|
||||
**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`.
|
||||
1. **Color**: 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).
|
||||
@@ -26,10 +26,10 @@ This file provides foundational context and instructions for Gemini CLI when wor
|
||||
```bash
|
||||
.
|
||||
├── app/ # Next.js App Router
|
||||
│ ├── (app)/ # Core Tool Pages (pastel, units, figlet, media)
|
||||
│ ├── (app)/ # Core Tool Pages (color, units, figlet, media)
|
||||
│ └── globals.css # Tailwind 4 configuration & global styles
|
||||
├── components/ # UI Components
|
||||
│ ├── [tool]/ # Tool-specific components (e.g., components/pastel/)
|
||||
│ ├── [tool]/ # Tool-specific components (e.g., components/color/)
|
||||
│ ├── layout/ # AppShell, Sidebar, Header
|
||||
│ └── ui/ # Base Atomic Components (shadcn)
|
||||
├── lib/ # Business Logic
|
||||
|
||||
10
README.md
10
README.md
@@ -15,7 +15,7 @@ Built with **Next.js 16**, **React 19**, and **Tailwind CSS 4**, Kit UI delivers
|
||||
|
||||
Kit UI is divided into four core specialized applications:
|
||||
|
||||
### 🎨 [Pastel](./app/(app)/pastel) — Professional Color Toolkit
|
||||
### 🎨 [Color](./app/(app)/color) — Professional Color Toolkit
|
||||
A comprehensive suite for color theory, manipulation, and accessibility.
|
||||
- **Color Playground**: Interactive HSL/RGB/HEX manipulation with real-time analysis.
|
||||
- **Accessibility Suite**: WCAG 2.1 Contrast Checker and a real-time Colorblindness Simulator.
|
||||
@@ -73,16 +73,16 @@ Privacy-first, local-only media conversion powered by WebAssembly.
|
||||
```bash
|
||||
.
|
||||
├── app/ # Next.js App Router (Pages & Layouts)
|
||||
│ ├── (app)/ # Core Tool Pages (Pastel, Units, Figlet, Media)
|
||||
│ ├── (app)/ # Core Tool Pages (Color, Units, Figlet, Media)
|
||||
│ └── api/ # Backend API routes
|
||||
├── components/ # Reusable UI & Logic Components
|
||||
│ ├── pastel/ # Color-specific components
|
||||
│ ├── color/ # Color-specific components
|
||||
│ ├── units/ # Converter-specific components
|
||||
│ ├── figlet/ # ASCII-specific components
|
||||
│ ├── media/ # Media conversion components
|
||||
│ └── ui/ # Base Atomic Components (Buttons, Cards, etc.)
|
||||
├── lib/ # Business Logic & Utilities
|
||||
│ ├── pastel/ # WASM wrappers & Color logic
|
||||
│ ├── color/ # WASM wrappers & Color logic
|
||||
│ ├── units/ # Conversion algorithms
|
||||
│ ├── figlet/ # Font loading & ASCII generation
|
||||
│ └── media/ # FFmpeg & ImageMagick WASM orchestration
|
||||
@@ -130,7 +130,7 @@ docker run -p 80:80 kit-ui
|
||||
## 📈 Performance & Optimization
|
||||
|
||||
- **Static Site Generation (SSG)**: Entire toolkit is exported as static HTML/JS for sub-second load times.
|
||||
- **Client-Side WASM**: Complex processing (FFmpeg, ImageMagick, Pastel) is offloaded to WebAssembly for native-level performance without server latency.
|
||||
- **Client-Side WASM**: Complex processing (FFmpeg, ImageMagick, Color) is offloaded to WebAssembly for native-level performance without server latency.
|
||||
- **CSS-First Configuration**: Leveraging Tailwind 4's native CSS variables for zero-runtime styling overhead.
|
||||
- **Automatic CI/CD**: GitHub Actions pipeline for multi-architecture Docker builds.
|
||||
|
||||
|
||||
@@ -4,16 +4,7 @@
|
||||
@source "../components/color/*.{js,ts,jsx,tsx}";
|
||||
@source "../components/layout/*.{js,ts,jsx,tsx}";
|
||||
@source "../components/providers/*.{js,ts,jsx,tsx}";
|
||||
@source "../components/tools/*.{js,ts,jsx,tsx}";
|
||||
@source "../components/ui/*.{js,ts,jsx,tsx}";
|
||||
@source "./distinct/*.{js,ts,jsx,tsx}";
|
||||
@source "./gradient/*.{js,ts,jsx,tsx}";
|
||||
@source "./harmony/*.{js,ts,jsx,tsx}";
|
||||
@source "./names/*.{js,ts,jsx,tsx}";
|
||||
@source "./batch/*.{js,ts,jsx,tsx}";
|
||||
@source "./colorblind/*.{js,ts,jsx,tsx}";
|
||||
@source "./contrast/*.{js,ts,jsx,tsx}";
|
||||
@source "./textcolor/*.{js,ts,jsx,tsx}";
|
||||
@source "*.{js,ts,jsx,tsx}";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
@@ -1,4 +1,4 @@
|
||||
export default function PastelLayout({
|
||||
export default function ColorLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
import { useState, useEffect, Suspense } from 'react';
|
||||
import { useSearchParams, useRouter } from 'next/navigation';
|
||||
import { ColorPicker } from '@/components/pastel/ColorPicker';
|
||||
import { ColorInfo } from '@/components/pastel/ColorInfo';
|
||||
import { ManipulationPanel } from '@/components/pastel/ManipulationPanel';
|
||||
import { PaletteGrid } from '@/components/pastel/PaletteGrid';
|
||||
import { ExportMenu } from '@/components/pastel/ExportMenu';
|
||||
import { ColorPicker } from '@/components/color/ColorPicker';
|
||||
import { ColorInfo } from '@/components/color/ColorInfo';
|
||||
import { ManipulationPanel } from '@/components/color/ManipulationPanel';
|
||||
import { PaletteGrid } from '@/components/color/PaletteGrid';
|
||||
import { ExportMenu } from '@/components/color/ExportMenu';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { AppPage } from '@/components/layout/AppPage';
|
||||
import { useColorInfo, useGeneratePalette, useGenerateGradient } from '@/lib/pastel/api/queries';
|
||||
import { useColorInfo, useGeneratePalette, useGenerateGradient } from '@/lib/color/api/queries';
|
||||
import { Loader2, Share2, Palette, Plus, X, Layers } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
@@ -59,7 +59,7 @@ function PlaygroundContent() {
|
||||
useEffect(() => {
|
||||
const hex = color.replace('#', '');
|
||||
if (hex.length === 6 || hex.length === 3) {
|
||||
router.push(`/pastel?color=${hex}`, { scroll: false });
|
||||
router.push(`/color?color=${hex}`, { scroll: false });
|
||||
}
|
||||
}, [color, router]);
|
||||
|
||||
@@ -72,7 +72,7 @@ function PlaygroundContent() {
|
||||
|
||||
// Share color via URL
|
||||
const handleShare = () => {
|
||||
const url = `${window.location.origin}/pastel?color=${color.replace('#', '')}`;
|
||||
const url = `${window.location.origin}/color?color=${color.replace('#', '')}`;
|
||||
navigator.clipboard.writeText(url);
|
||||
toast.success('Link copied to clipboard!');
|
||||
};
|
||||
@@ -134,7 +134,7 @@ function PlaygroundContent() {
|
||||
|
||||
return (
|
||||
<AppPage
|
||||
title="Pastel"
|
||||
title="Color"
|
||||
description="Interactive color manipulation and analysis tool"
|
||||
>
|
||||
<div className="space-y-8">
|
||||
@@ -7,7 +7,7 @@ const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000';
|
||||
export const metadata: Metadata = {
|
||||
title: 'Kit - Your Creative Toolkit',
|
||||
description: 'A curated collection of creative and utility tools for developers and creators. Features file conversion, image editing, and color manipulation.',
|
||||
keywords: ['tools', 'utilities', 'file converter', 'image editor', 'color palette', 'creative toolkit', 'convert', 'paint', 'pastel', 'open source'],
|
||||
keywords: ['tools', 'utilities', 'file converter', 'image editor', 'color palette', 'creative toolkit', 'convert', 'paint', 'color', 'open source'],
|
||||
metadataBase: new URL(siteUrl),
|
||||
icons: {
|
||||
icon: '/icon.png',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export const PastelIcon = (props: React.SVGProps<SVGSVGElement>) => (
|
||||
export const ColorIcon = (props: React.SVGProps<SVGSVGElement>) => (
|
||||
<svg {...props} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z" />
|
||||
<circle cx="6.5" cy="11.5" r="1" fill="currentColor" />
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import ToolCard from './ToolCard';
|
||||
import { PastelIcon, UnitsIcon, FigletIcon, MediaIcon } from '@/components/AppIcons';
|
||||
import { ColorIcon, UnitsIcon, FigletIcon, MediaIcon } from '@/components/AppIcons';
|
||||
|
||||
const tools = [
|
||||
{
|
||||
title: 'Pastel',
|
||||
title: 'Color',
|
||||
description: 'Modern color manipulation toolkit with palette generation, accessibility testing, and format conversion. Supports hex, RGB, HSL, Lab, and more.',
|
||||
url: '/pastel',
|
||||
url: '/color',
|
||||
gradient: 'gradient-indigo-purple',
|
||||
accentColor: '#a855f7',
|
||||
badges: ['Open Source', 'WCAG', 'Free'],
|
||||
icon: <PastelIcon className="w-12 h-12 text-white" />,
|
||||
icon: <ColorIcon className="w-12 h-12 text-white" />,
|
||||
},
|
||||
{
|
||||
title: 'Units',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { ColorInfo as ColorInfoType } from '@/lib/pastel/api/types';
|
||||
import { ColorInfo as ColorInfoType } from '@/lib/color/api/types';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Copy } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
@@ -3,7 +3,7 @@
|
||||
import { HexColorPicker } from 'react-colorful';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { cn } from '@/lib/utils/cn';
|
||||
import { hexToRgb } from '@/lib/pastel/utils/color';
|
||||
import { hexToRgb } from '@/lib/color/utils/color';
|
||||
|
||||
interface ColorPickerProps {
|
||||
color: string;
|
||||
@@ -19,8 +19,8 @@ import {
|
||||
exportAsJavaScript,
|
||||
downloadAsFile,
|
||||
type ExportColor,
|
||||
} from '@/lib/pastel/utils/export';
|
||||
import { pastelAPI } from '@/lib/pastel/api/client';
|
||||
} from '@/lib/color/utils/export';
|
||||
import { colorAPI } from '@/lib/color/api/client';
|
||||
|
||||
interface ExportMenuProps {
|
||||
colors: string[];
|
||||
@@ -46,7 +46,7 @@ export function ExportMenu({ colors, className }: ExportMenuProps) {
|
||||
|
||||
setIsConverting(true);
|
||||
try {
|
||||
const response = await pastelAPI.convertFormat({
|
||||
const response = await colorAPI.convertFormat({
|
||||
colors,
|
||||
format: colorSpace,
|
||||
});
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
useDesaturate,
|
||||
useRotate,
|
||||
useComplement
|
||||
} from '@/lib/pastel/api/queries';
|
||||
} from '@/lib/color/api/queries';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
interface ManipulationPanelProps {
|
||||
@@ -17,7 +17,7 @@ import { cn } from '@/lib/utils/cn';
|
||||
import Logo from '@/components/Logo';
|
||||
import { useSidebar } from './SidebarProvider';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { PastelIcon, UnitsIcon, FigletIcon, MediaIcon } from '@/components/AppIcons';
|
||||
import { ColorIcon, UnitsIcon, FigletIcon, MediaIcon } from '@/components/AppIcons';
|
||||
|
||||
interface NavItem {
|
||||
title: string;
|
||||
@@ -46,9 +46,9 @@ const navigation: NavGroup[] = [
|
||||
icon: <FigletIcon className="h-4 w-4" />
|
||||
},
|
||||
{
|
||||
title: 'Pastel',
|
||||
href: '/pastel',
|
||||
icon: <PastelIcon className="h-4 w-4" />
|
||||
title: 'Color Manipulation',
|
||||
href: '/color',
|
||||
icon: <ColorIcon className="h-4 w-4" />
|
||||
},
|
||||
{
|
||||
title: 'Media Converter',
|
||||
|
||||
@@ -15,15 +15,15 @@ import type {
|
||||
PaletteGenerateRequest,
|
||||
PaletteGenerateData,
|
||||
} from './types';
|
||||
import { pastelWASM } from './wasm-client';
|
||||
import { colorWASM } from './wasm-client';
|
||||
|
||||
export class PastelAPIClient {
|
||||
export class ColorAPIClient {
|
||||
private baseURL: string;
|
||||
|
||||
constructor(baseURL?: string) {
|
||||
// Use the Next.js API proxy route for runtime configuration
|
||||
// This allows changing the backend API URL without rebuilding
|
||||
this.baseURL = baseURL || '/api/pastel';
|
||||
this.baseURL = baseURL || '/api/color';
|
||||
}
|
||||
|
||||
private async request<T>(
|
||||
@@ -172,4 +172,4 @@ export class PastelAPIClient {
|
||||
|
||||
// Export singleton instance
|
||||
// Now using WASM client for zero-latency, offline-first color operations
|
||||
export const pastelAPI = pastelWASM;
|
||||
export const colorAPI = colorWASM;
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useQuery, useMutation, UseQueryOptions } from '@tanstack/react-query';
|
||||
import { pastelAPI } from './client';
|
||||
import { colorAPI } from './client';
|
||||
import {
|
||||
ColorInfoRequest,
|
||||
ColorInfoData,
|
||||
@@ -26,7 +26,7 @@ export const useColorInfo = (
|
||||
return useQuery({
|
||||
queryKey: ['colorInfo', request.colors],
|
||||
queryFn: async () => {
|
||||
const response = await pastelAPI.getColorInfo(request);
|
||||
const response = await colorAPI.getColorInfo(request);
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -41,7 +41,7 @@ export const useColorInfo = (
|
||||
export const useConvertFormat = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (request: ConvertFormatRequest) => {
|
||||
const response = await pastelAPI.convertFormat(request);
|
||||
const response = await colorAPI.convertFormat(request);
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -54,7 +54,7 @@ export const useConvertFormat = () => {
|
||||
export const useLighten = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (request: ColorManipulationRequest) => {
|
||||
const response = await pastelAPI.lighten(request);
|
||||
const response = await colorAPI.lighten(request);
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export const useLighten = () => {
|
||||
export const useDarken = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (request: ColorManipulationRequest) => {
|
||||
const response = await pastelAPI.darken(request);
|
||||
const response = await colorAPI.darken(request);
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -78,7 +78,7 @@ export const useDarken = () => {
|
||||
export const useSaturate = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (request: ColorManipulationRequest) => {
|
||||
const response = await pastelAPI.saturate(request);
|
||||
const response = await colorAPI.saturate(request);
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -90,7 +90,7 @@ export const useSaturate = () => {
|
||||
export const useDesaturate = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (request: ColorManipulationRequest) => {
|
||||
const response = await pastelAPI.desaturate(request);
|
||||
const response = await colorAPI.desaturate(request);
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -102,7 +102,7 @@ export const useDesaturate = () => {
|
||||
export const useRotate = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (request: ColorManipulationRequest) => {
|
||||
const response = await pastelAPI.rotate(request);
|
||||
const response = await colorAPI.rotate(request);
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -114,7 +114,7 @@ export const useRotate = () => {
|
||||
export const useComplement = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (colors: string[]) => {
|
||||
const response = await pastelAPI.complement(colors);
|
||||
const response = await colorAPI.complement(colors);
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -127,7 +127,7 @@ export const useComplement = () => {
|
||||
export const useGenerateRandom = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (request: RandomColorsRequest) => {
|
||||
const response = await pastelAPI.generateRandom(request);
|
||||
const response = await colorAPI.generateRandom(request);
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -139,7 +139,7 @@ export const useGenerateRandom = () => {
|
||||
export const useGenerateGradient = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (request: GradientRequest) => {
|
||||
const response = await pastelAPI.generateGradient(request);
|
||||
const response = await colorAPI.generateGradient(request);
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -153,7 +153,7 @@ export const useHealth = () => {
|
||||
return useQuery({
|
||||
queryKey: ['health'],
|
||||
queryFn: async () => {
|
||||
const response = await pastelAPI.getHealth();
|
||||
const response = await colorAPI.getHealth();
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -167,7 +167,7 @@ export const useHealth = () => {
|
||||
export const useGeneratePalette = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (request: PaletteGenerateRequest) => {
|
||||
const response = await pastelAPI.generatePalette(request);
|
||||
const response = await colorAPI.generatePalette(request);
|
||||
if (!response.success) {
|
||||
throw new Error(response.error.message);
|
||||
}
|
||||
@@ -41,11 +41,11 @@ async function ensureWasmInit() {
|
||||
}
|
||||
|
||||
/**
|
||||
* WASM-based Pastel client
|
||||
* Provides the same interface as PastelAPIClient but uses WebAssembly
|
||||
* WASM-based Color client
|
||||
* Provides the same interface as ColorAPIClient but uses WebAssembly
|
||||
* Zero network latency, works offline!
|
||||
*/
|
||||
export class PastelWASMClient {
|
||||
export class ColorWASMClient {
|
||||
constructor() {
|
||||
// Initialize WASM eagerly
|
||||
ensureWasmInit().catch(console.error);
|
||||
@@ -347,4 +347,4 @@ export class PastelWASMClient {
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const pastelWASM = new PastelWASMClient();
|
||||
export const colorWASM = new ColorWASMClient();
|
||||
Reference in New Issue
Block a user