diff --git a/CONTEXT.md b/CONTEXT.md
index a90fe07..2da08ac 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -75,6 +75,23 @@ The project uses shadcn/ui components located in `@/components/ui`. These are un
These components follow a consistent pattern using React's `forwardRef` and use the `cn()` utility for class name merging. Many are built on Radix UI primitives for accessibility and customized with Tailwind CSS.
+## Theme Toggle Component
+
+A pre-built theme toggle component is available for easy integration:
+
+```tsx
+import { ThemeToggle } from "@/components/theme-toggle";
+
+function Header() {
+ return (
+
+
My App
+
+
+ );
+}
+```
+
## Nostr Protocol Integration
This project comes with custom hooks for querying and publishing events on the Nostr network.
diff --git a/src/App.tsx b/src/App.tsx
index a7afb31..2f89457 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -2,6 +2,7 @@
// To add new routes, edit the AppRouter.tsx file.
import NostrProvider from '@/components/NostrProvider'
+import { ThemeProvider } from "@/components/ThemeProvider";
import { Toaster } from "@/components/ui/toaster";
import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
@@ -28,17 +29,19 @@ const queryClient = new QueryClient({
export function App() {
return (
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/components/ThemeProvider.tsx b/src/components/ThemeProvider.tsx
new file mode 100644
index 0000000..8fdf742
--- /dev/null
+++ b/src/components/ThemeProvider.tsx
@@ -0,0 +1,69 @@
+import { useEffect, useState } from "react"
+import { Theme, ThemeProviderContext } from "@/lib/theme-context"
+
+type ThemeProviderProps = {
+ children: React.ReactNode
+ defaultTheme?: Theme
+ storageKey?: string
+}
+
+export function ThemeProvider({
+ children,
+ defaultTheme = "system",
+ storageKey = "theme",
+ ...props
+}: ThemeProviderProps) {
+ const [theme, setTheme] = useState(
+ () => (localStorage.getItem(storageKey) as Theme) || defaultTheme
+ )
+
+ 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])
+
+ useEffect(() => {
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
+
+ const handleChange = () => {
+ if (theme === "system") {
+ const root = window.document.documentElement
+ root.classList.remove("light", "dark")
+
+ const systemTheme = mediaQuery.matches ? "dark" : "light"
+ root.classList.add(systemTheme)
+ }
+ }
+
+ mediaQuery.addEventListener("change", handleChange)
+ return () => mediaQuery.removeEventListener("change", handleChange)
+ }, [theme])
+
+ const value = {
+ theme,
+ setTheme: (theme: Theme) => {
+ localStorage.setItem(storageKey, theme)
+ setTheme(theme)
+ },
+ }
+
+ return (
+
+ {children}
+
+ )
+}
+
diff --git a/src/components/ThemeToggle.tsx b/src/components/ThemeToggle.tsx
new file mode 100644
index 0000000..54bf602
--- /dev/null
+++ b/src/components/ThemeToggle.tsx
@@ -0,0 +1,37 @@
+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 "@/hooks/useTheme"
+
+export function ThemeToggle() {
+ const { setTheme } = useTheme()
+
+ return (
+
+
+
+
+
+ setTheme("light")}>
+ Light
+
+ setTheme("dark")}>
+ Dark
+
+ setTheme("system")}>
+ System
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/hooks/useTheme.ts b/src/hooks/useTheme.ts
new file mode 100644
index 0000000..937d68c
--- /dev/null
+++ b/src/hooks/useTheme.ts
@@ -0,0 +1,11 @@
+import { useContext } from "react"
+import { ThemeProviderContext } from "@/lib/theme-context"
+
+export const useTheme = () => {
+ const context = useContext(ThemeProviderContext)
+
+ if (context === undefined)
+ throw new Error("useTheme must be used within a ThemeProvider")
+
+ return context
+}
\ No newline at end of file
diff --git a/src/lib/theme-context.ts b/src/lib/theme-context.ts
new file mode 100644
index 0000000..638a1cc
--- /dev/null
+++ b/src/lib/theme-context.ts
@@ -0,0 +1,15 @@
+import { createContext } from "react";
+
+export type Theme = "dark" | "light" | "system";
+
+export type ThemeProviderState = {
+ theme: Theme;
+ setTheme: (theme: Theme) => void;
+};
+
+const initialState: ThemeProviderState = {
+ theme: "system",
+ setTheme: () => null,
+};
+
+export const ThemeProviderContext = createContext(initialState);
\ No newline at end of file