diff --git a/package.json b/package.json index 24aca6a..9324dc7 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@radix-ui/react-checkbox": "^1.0.3", + "@radix-ui/react-dropdown-menu": "^2.1.12", "@radix-ui/react-popover": "^1.0.5", "@radix-ui/react-select": "^1.2.0", "@tanstack/react-query": "^4.20.2", @@ -26,6 +27,7 @@ "graphemer": "^1.4.0", "lucide-react": "^0.119.0", "next": "^13.2.1", + "next-themes": "^0.4.6", "react": "18.2.0", "react-dom": "18.2.0", "superjson": "1.9.1", diff --git a/src/components/ThemeToggle.tsx b/src/components/ThemeToggle.tsx new file mode 100644 index 0000000..de734f4 --- /dev/null +++ b/src/components/ThemeToggle.tsx @@ -0,0 +1,87 @@ +"use client"; + +import * as React from "react"; +import { Moon, Sun, Monitor } from "lucide-react"; +import { useTheme } from "next-themes"; +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; + +import { Button } from "~/components/Button"; +import { cn } from "~/utils/cn"; + +// Basic styles for dropdown content and item - adapt as needed +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; + +export function ThemeToggle() { + const { setTheme, theme } = useTheme(); + const [mounted, setMounted] = React.useState(false); + + // useEffect only runs on the client, so we can safely show the UI + React.useEffect(() => { + setMounted(true); + }, []); + + if (!mounted) { + // Render a placeholder or null on the server to avoid hydration mismatch + return
; // Placeholder with same size as button + } + + return ( + + + + + + setTheme("light")}> + + Light + + setTheme("dark")}> + + Dark + + setTheme("system")}> + + System + + + + ); +} \ No newline at end of file diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 7e4887c..dc8d969 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,4 +1,5 @@ import { type AppType } from "next/app"; +import { ThemeProvider } from 'next-themes'; import { api } from "~/utils/api"; import { Analytics } from "@vercel/analytics/react"; @@ -6,10 +7,10 @@ import "~/styles/globals.css"; const MyApp: AppType = ({ Component, pageProps }) => { return ( - <> + - + ); }; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index b314439..7c410ca 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -7,6 +7,7 @@ import Head from "next/head"; import { useMemo, useState } from "react"; import { Github, Twitter } from "lucide-react"; +import { ThemeToggle } from "~/components/ThemeToggle"; import { ChatGPTEditor } from "../sections/ChatGPTEditor"; import { EncoderSelect } from "~/sections/EncoderSelect"; import { TokenViewer } from "~/sections/TokenViewer"; @@ -78,7 +79,7 @@ const Home: NextPage<