From bd05f109b4fee71070fd0294e1617b0893fe4a5c Mon Sep 17 00:00:00 2001 From: valknarness Date: Fri, 7 Nov 2025 10:55:42 +0100 Subject: [PATCH] feat: initial Next.js 15 implementation with TypeScript and Tailwind CSS 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add complete project structure and foundation: **Core Setup:** - Next.js 15.5.6 with App Router and React 19 - TypeScript 5.7 with strict mode - Tailwind CSS 4.1 with custom theme configuration - ESLint and Prettier configuration **Dependencies Installed:** - @tanstack/react-query - Server state management - zustand - Client state management - framer-motion - Animations - lucide-react - Icon library - react-colorful - Color picker component - cmdk - Command palette - sonner - Toast notifications - clsx + tailwind-merge - Class name utilities **Project Structure:** - app/ - Next.js App Router pages - components/ - React components (ui, color, tools, layout, providers) - lib/ - Utilities, API client, hooks, stores, constants - tests/ - Unit and E2E test directories **API Integration:** - Type-safe Pastel API client with all 21 endpoints - Complete TypeScript type definitions for requests/responses - Error handling and response types **UI Components:** - Button component with variants (default, outline, ghost, destructive) - Input component with focus states - Providers wrapper (React Query, Toast) - Root layout with Inter font and metadata **Pages:** - Home page with gradient hero and feature cards - Links to playground and palette generation (pages pending) **Configuration:** - Tailwind with HSL color variables for theming - Dark/light mode CSS variables - Custom animations (fade-in, slide-up, slide-down) - @tailwindcss/forms and @tailwindcss/typography plugins Build successful: 102 kB First Load JS, static generation working. Ready for color components and playground implementation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .eslintrc.json | 3 + .prettierrc | 8 + app/globals.css | 59 + app/layout.tsx | 26 + app/page.tsx | 48 + components/providers/Providers.tsx | 26 + components/ui/button.tsx | 40 + components/ui/input.tsx | 28 + lib/api/client.ts | 232 ++ lib/api/types.ts | 245 ++ lib/utils/cn.ts | 6 + next.config.ts | 31 + package.json | 59 + pnpm-lock.yaml | 5170 ++++++++++++++++++++++++++++ tailwind.config.ts | 77 + tsconfig.json | 27 + 16 files changed, 6085 insertions(+) create mode 100644 .eslintrc.json create mode 100644 .prettierrc create mode 100644 app/globals.css create mode 100644 app/layout.tsx create mode 100644 app/page.tsx create mode 100644 components/providers/Providers.tsx create mode 100644 components/ui/button.tsx create mode 100644 components/ui/input.tsx create mode 100644 lib/api/client.ts create mode 100644 lib/api/types.ts create mode 100644 lib/utils/cn.ts create mode 100644 next.config.ts create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 tailwind.config.ts create mode 100644 tsconfig.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..29b9d1f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "semi": true, + "trailingComma": "es5", + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2, + "useTabs": false +} diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..10c2d37 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,59 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + --radius: 0.5rem; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..9fc34b3 --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,26 @@ +import type { Metadata } from 'next'; +import { Inter } from 'next/font/google'; +import './globals.css'; +import { Providers } from '@/components/providers/Providers'; + +const inter = Inter({ subsets: ['latin'] }); + +export const metadata: Metadata = { + title: 'Pastel UI - Color Manipulation & Palette Generation', + description: 'Modern web UI for color manipulation, palette generation, and accessibility analysis', + keywords: ['color', 'palette', 'generator', 'accessibility', 'wcag', 'gradient', 'design'], +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..a61c367 --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,48 @@ +export default function Home() { + return ( +
+
+

+ Pastel UI +

+

+ Modern web UI for color manipulation, palette generation, and accessibility analysis +

+
+ + Open Playground + + + Generate Palettes + +
+
+
+

Color Playground

+

+ Interactive color picker with multi-format support and real-time manipulation +

+
+
+

Palette Generation

+

+ Create harmony palettes, distinct colors, and smooth gradients +

+
+
+

Accessibility Tools

+

+ WCAG contrast checker and color blindness simulation +

+
+
+
+
+ ); +} diff --git a/components/providers/Providers.tsx b/components/providers/Providers.tsx new file mode 100644 index 0000000..bf9d998 --- /dev/null +++ b/components/providers/Providers.tsx @@ -0,0 +1,26 @@ +'use client'; + +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { Toaster } from 'sonner'; +import { useState } from 'react'; + +export function Providers({ children }: { children: React.ReactNode }) { + const [queryClient] = useState( + () => + new QueryClient({ + defaultOptions: { + queries: { + staleTime: 60 * 1000, // 1 minute + refetchOnWindowFocus: false, + }, + }, + }) + ); + + return ( + + {children} + + + ); +} diff --git a/components/ui/button.tsx b/components/ui/button.tsx new file mode 100644 index 0000000..eb82511 --- /dev/null +++ b/components/ui/button.tsx @@ -0,0 +1,40 @@ +import * as React from 'react'; +import { cn } from '@/lib/utils/cn'; + +export interface ButtonProps extends React.ButtonHTMLAttributes { + variant?: 'default' | 'outline' | 'ghost' | 'destructive'; + size?: 'default' | 'sm' | 'lg' | 'icon'; +} + +const Button = React.forwardRef( + ({ className, variant = 'default', size = 'default', ...props }, ref) => { + return ( +