Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 89 additions & 18 deletions frontend/components/theme-toggle.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
"use client"

import { useTheme } from "next-themes"
import { Moon, Sun } from "lucide-react"
import { Moon, Sun, Monitor } from "lucide-react"
import { useEffect, useState } from "react"
import { Button } from "@/components/ui/button"
import * as Popover from "@radix-ui/react-popover"


export function ThemeToggle() {
const { theme, setTheme } = useTheme()
const [mounted, setMounted] = useState(false)

// useEffect only runs on the client, so now we can safely show the UI
useEffect(() => {
setMounted(true)
}, [])
Expand All @@ -19,7 +20,7 @@ export function ThemeToggle() {
<Button
variant="ghost"
size="icon"
className="w-9 h-9 rounded-md shadow-sm dark:shadow-none"
className="w-9 h-9 rounded-full shadow-sm dark:shadow-none"
disabled
>
<Sun className="h-4 w-4" />
Expand All @@ -28,20 +29,90 @@ export function ThemeToggle() {
)
}

const getActiveIcon = () => {
if (theme === "system") return <Monitor className="h-4 w-4" />
if (theme === "dark") return <Moon className="h-4 w-4" />
return <Sun className="h-4 w-4" />
}

return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
className="w-9 h-9 rounded-md hover:bg-gray-100 dark:hover:bg-accent hover:text-foreground transition-colors shadow-sm dark:shadow-none border border-gray-200 dark:border-border"
title={`Switch to ${theme === "light" ? "dark" : "light"} theme`}
>
{theme === "light" ? (
<Moon className="h-4 w-4" />
) : (
<Sun className="h-4 w-4" />
)}
<span className="sr-only">Toggle theme</span>
</Button>
<Popover.Root>
<Popover.Trigger asChild>
<Button
variant="ghost"
size="icon"
className="w-9 h-9 rounded-full hover:bg-gray-100 dark:hover:bg-accent hover:text-foreground transition-colors shadow-sm dark:shadow-none border border-gray-200 dark:border-border"
title="Select theme"
>
{getActiveIcon()}
<span className="sr-only">Toggle theme</span>
</Button>
</Popover.Trigger>
<Popover.Portal>
<Popover.Content
sideOffset={8}
className="flex gap-1 px-2 py-1 rounded-full z-[100] shadow-lg"
style={{
backgroundColor: theme === "dark" ? "#23272f" : "#3a3a3a",
zIndex: 100,
}}
>
<Button
variant="ghost"
size="icon"
className={`w-10 h-10 rounded-full flex items-center justify-center transition-colors
focus:outline-none focus:ring-0 active:bg-transparent
${theme === "system" ? "bg-gray-700 dark:bg-gray-700" : ""}
hover:bg-gray-600 dark:hover:bg-gray-700
`}
onClick={() => setTheme("system")}
title="System"
>
<Monitor
className={`h-6 w-6 transition-colors
${theme === "system" ? "text-white" : "text-gray-300"}
hover:text-yellow-400
`}
/>
</Button>
<Button
variant="ghost"
size="icon"
className={`w-10 h-10 rounded-full flex items-center justify-center transition-colors
focus:outline-none focus:ring-0 active:bg-transparent
${theme === "light" ? "bg-gray-700 dark:bg-gray-700" : ""}
hover:bg-gray-600 dark:hover:bg-gray-700
`}
onClick={() => setTheme("light")}
title="Light"
>
<Sun
className={`h-6 w-6 transition-colors
${theme === "light" ? "text-white" : "text-gray-300"}
hover:text-yellow-400
`}
/>
</Button>
<Button
variant="ghost"
size="icon"
className={`w-10 h-10 rounded-full flex items-center justify-center transition-colors
focus:outline-none focus:ring-0 active:bg-transparent
${theme === "dark" ? "bg-gray-700 dark:bg-gray-700" : ""}
hover:bg-gray-600 dark:hover:bg-gray-700
`}
onClick={() => setTheme("dark")}
title="Dark"
>
<Moon
className={`h-6 w-6 transition-colors
${theme === "dark" ? "text-white" : "text-gray-300"}
hover:text-yellow-400
`}
/>
</Button>
</Popover.Content>
</Popover.Portal>
</Popover.Root>
)
}
}
43 changes: 31 additions & 12 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"dependencies": {
"@radix-ui/react-popover": "^1.1.15",
"framer-motion": "^12.23.12"
}
}