diff --git a/app/layout.tsx b/app/layout.tsx
index 9fc34b3..5983bbb 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -2,6 +2,7 @@ import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
import { Providers } from '@/components/providers/Providers';
+import { Navbar } from '@/components/layout/Navbar';
const inter = Inter({ subsets: ['latin'] });
@@ -19,7 +20,10 @@ export default function RootLayout({
return (
- {children}
+
+
+ {children}
+
);
diff --git a/components/layout/Navbar.tsx b/components/layout/Navbar.tsx
new file mode 100644
index 0000000..2eb471b
--- /dev/null
+++ b/components/layout/Navbar.tsx
@@ -0,0 +1,77 @@
+'use client';
+
+import Link from 'next/link';
+import { usePathname } from 'next/navigation';
+import { ThemeToggle } from './ThemeToggle';
+import { cn } from '@/lib/utils/cn';
+import { Palette } from 'lucide-react';
+
+const navigation = [
+ { name: 'Home', href: '/' },
+ { name: 'Playground', href: '/playground' },
+ { name: 'Palettes', href: '/palettes' },
+ { name: 'Accessibility', href: '/accessibility' },
+ { name: 'Named Colors', href: '/names' },
+ { name: 'Batch', href: '/batch' },
+];
+
+export function Navbar() {
+ const pathname = usePathname();
+
+ return (
+
+ );
+}
diff --git a/components/layout/ThemeToggle.tsx b/components/layout/ThemeToggle.tsx
new file mode 100644
index 0000000..df20157
--- /dev/null
+++ b/components/layout/ThemeToggle.tsx
@@ -0,0 +1,28 @@
+'use client';
+
+import { Moon, Sun } from 'lucide-react';
+import { useTheme } from '@/components/providers/ThemeProvider';
+import { Button } from '@/components/ui/button';
+
+export function ThemeToggle() {
+ const { theme, setTheme, resolvedTheme } = useTheme();
+
+ const toggleTheme = () => {
+ setTheme(resolvedTheme === 'dark' ? 'light' : 'dark');
+ };
+
+ return (
+
+ );
+}
diff --git a/components/providers/Providers.tsx b/components/providers/Providers.tsx
index bf9d998..217d0b9 100644
--- a/components/providers/Providers.tsx
+++ b/components/providers/Providers.tsx
@@ -3,6 +3,7 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Toaster } from 'sonner';
import { useState } from 'react';
+import { ThemeProvider } from './ThemeProvider';
export function Providers({ children }: { children: React.ReactNode }) {
const [queryClient] = useState(
@@ -18,9 +19,11 @@ export function Providers({ children }: { children: React.ReactNode }) {
);
return (
-
- {children}
-
-
+
+
+ {children}
+
+
+
);
}
diff --git a/components/providers/ThemeProvider.tsx b/components/providers/ThemeProvider.tsx
new file mode 100644
index 0000000..490c787
--- /dev/null
+++ b/components/providers/ThemeProvider.tsx
@@ -0,0 +1,78 @@
+'use client';
+
+import { createContext, useContext, useEffect, useState } from 'react';
+
+type Theme = 'light' | 'dark' | 'system';
+
+interface ThemeContextType {
+ theme: Theme;
+ setTheme: (theme: Theme) => void;
+ resolvedTheme: 'light' | 'dark';
+}
+
+const ThemeContext = createContext(undefined);
+
+export function ThemeProvider({ children }: { children: React.ReactNode }) {
+ const [theme, setTheme] = useState('system');
+ const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>('light');
+
+ useEffect(() => {
+ // Load theme from localStorage
+ const stored = localStorage.getItem('theme') as Theme | null;
+ if (stored) {
+ setTheme(stored);
+ }
+ }, []);
+
+ useEffect(() => {
+ const root = window.document.documentElement;
+
+ // Remove previous theme classes
+ root.classList.remove('light', 'dark');
+
+ if (theme === 'system') {
+ const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
+ ? 'dark'
+ : 'light';
+ root.classList.add(systemTheme);
+ setResolvedTheme(systemTheme);
+ } else {
+ root.classList.add(theme);
+ setResolvedTheme(theme);
+ }
+
+ // Save to localStorage
+ localStorage.setItem('theme', theme);
+ }, [theme]);
+
+ // Listen for system theme changes
+ useEffect(() => {
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
+
+ const handleChange = () => {
+ if (theme === 'system') {
+ const systemTheme = mediaQuery.matches ? 'dark' : 'light';
+ setResolvedTheme(systemTheme);
+ window.document.documentElement.classList.remove('light', 'dark');
+ window.document.documentElement.classList.add(systemTheme);
+ }
+ };
+
+ mediaQuery.addEventListener('change', handleChange);
+ return () => mediaQuery.removeEventListener('change', handleChange);
+ }, [theme]);
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function useTheme() {
+ const context = useContext(ThemeContext);
+ if (context === undefined) {
+ throw new Error('useTheme must be used within a ThemeProvider');
+ }
+ return context;
+}