diff options
| author | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-01-16 08:30:14 +0900 |
|---|---|---|
| committer | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-01-16 08:30:14 +0900 |
| commit | 3fbb9a18372f2b6a675dd6c039ba52be76f3eeb4 (patch) | |
| tree | aa694a36cdd323a7853672ee7a2ba60409ac3b06 /ui/shadcn/.claude/commands/setup-dark-mode.md | |
updates
Diffstat (limited to 'ui/shadcn/.claude/commands/setup-dark-mode.md')
| -rw-r--r-- | ui/shadcn/.claude/commands/setup-dark-mode.md | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/ui/shadcn/.claude/commands/setup-dark-mode.md b/ui/shadcn/.claude/commands/setup-dark-mode.md new file mode 100644 index 0000000..c9867b6 --- /dev/null +++ b/ui/shadcn/.claude/commands/setup-dark-mode.md @@ -0,0 +1,243 @@ +--- +description: Configure dark mode for your framework +argument-hint: "[framework]" +allowed-tools: Read, Write, Edit, Bash +--- + +Set up dark mode with theme switching for your specific framework. + +## Instructions + +Based on the framework detected or specified: +1. Install required dependencies +2. Set up theme provider +3. Configure CSS variables +4. Create theme toggle component +5. Set up persistence (cookies/localStorage) + +## Framework Configurations + +### Next.js (App Router) +```bash +npm install next-themes +``` + +Create `components/theme-provider.tsx`: +```tsx +"use client" + +import * as React from "react" +import { ThemeProvider as NextThemesProvider } from "next-themes" +import { type ThemeProviderProps } from "next-themes/dist/types" + +export function ThemeProvider({ children, ...props }: ThemeProviderProps) { + return <NextThemesProvider {...props}>{children}</NextThemesProvider> +} +``` + +Wrap in `app/layout.tsx`: +```tsx +<ThemeProvider + attribute="class" + defaultTheme="system" + enableSystem + disableTransitionOnChange +> + {children} +</ThemeProvider> +``` + +### Vite +Create `components/theme-provider.tsx`: +```tsx +import { createContext, useContext, useEffect, useState } from "react" + +type Theme = "dark" | "light" | "system" + +const ThemeProviderContext = createContext<{ + theme: Theme + setTheme: (theme: Theme) => void +}>({ + theme: "system", + setTheme: () => null, +}) + +export function ThemeProvider({ children }: { children: React.ReactNode }) { + const [theme, setTheme] = useState<Theme>( + () => (localStorage.getItem("theme") as Theme) || "system" + ) + + useEffect(() => { + const root = window.document.documentElement + root.classList.remove("light", "dark") + + if (theme === "system") { + const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") + .matches + ? "dark" + : "light" + root.classList.add(systemTheme) + return + } + + root.classList.add(theme) + }, [theme]) + + const value = { + theme, + setTheme: (theme: Theme) => { + localStorage.setItem("theme", theme) + setTheme(theme) + }, + } + + return ( + <ThemeProviderContext.Provider value={value}> + {children} + </ThemeProviderContext.Provider> + ) +} + +export const useTheme = () => { + const context = useContext(ThemeProviderContext) + if (context === undefined) + throw new Error("useTheme must be used within a ThemeProvider") + return context +} +``` + +### Remix +```bash +npm install remix-themes +``` + +In `app/root.tsx`: +```tsx +import { themeSessionResolver } from "remix-themes" +import { + PreventFlashOnWrongTheme, + ThemeProvider, + useTheme, +} from "remix-themes" + +export async function loader({ request }: LoaderFunctionArgs) { + const { getTheme } = await themeSessionResolver(request) + return { theme: getTheme() } +} + +export default function App() { + const data = useLoaderData<typeof loader>() + const [theme] = useTheme() + + return ( + <html lang="en" className={theme ?? ""}> + <head> + <PreventFlashOnWrongTheme ssrTheme={Boolean(data.theme)} /> + </head> + <body> + <ThemeProvider + specifiedTheme={data.theme} + themeAction="/action/set-theme" + > + <Outlet /> + </ThemeProvider> + </body> + </html> + ) +} +``` + +### Astro +In layout file: +```astro +<script is:inline> + const theme = (() => { + if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) { + return localStorage.getItem('theme') + } + if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + return 'dark' + } + return 'light' + })() + + if (theme === 'light') { + document.documentElement.classList.remove('dark') + } else { + document.documentElement.classList.add('dark') + } + window.localStorage.setItem('theme', theme) +</script> +``` + +## Theme Toggle Component + +Create `components/theme-toggle.tsx`: +```tsx +import { Moon, Sun } from "lucide-react" +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { useTheme } from "@/components/theme-provider" // or "next-themes" + +export function ThemeToggle() { + const { setTheme } = useTheme() + + return ( + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button variant="outline" size="icon"> + <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" /> + <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" /> + <span className="sr-only">Toggle theme</span> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align="end"> + <DropdownMenuItem onClick={() => setTheme("light")}> + Light + </DropdownMenuItem> + <DropdownMenuItem onClick={() => setTheme("dark")}> + Dark + </DropdownMenuItem> + <DropdownMenuItem onClick={() => setTheme("system")}> + System + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + ) +} +``` + +## CSS Configuration + +Ensure `globals.css` has: +```css +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + /* ... other variables ... */ + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + /* ... other variables ... */ + } +} +``` + +## Example + +If the user says: `/setup-dark-mode next` + +1. Install next-themes +2. Create ThemeProvider component +3. Wrap app in ThemeProvider +4. Create ThemeToggle component +5. Add to navigation/header +6. Test theme switching
\ No newline at end of file |
