Initial Commit

This commit is contained in:
2026-09-16 17:22:14 +09:00
commit 858ee9e9da
335 changed files with 123898 additions and 0 deletions
@@ -0,0 +1,58 @@
import { Monitor, Moon, Sun } from "lucide-react"
import { Button } from "@/shared/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/shared/ui/dropdown-menu"
import { useThemeStore, type Theme } from "@/shared/store/themeStore"
interface ThemeToggleProps {
/** 트리거에 라벨 텍스트 함께 보일지. 기본 false (아이콘만). */
showLabel?: boolean
}
const ITEMS: { value: Theme; label: string; icon: typeof Sun }[] = [
{ value: "light", label: "라이트", icon: Sun },
{ value: "dark", label: "다크", icon: Moon },
{ value: "system", label: "시스템", icon: Monitor },
]
export function ThemeToggle({ showLabel = false }: ThemeToggleProps) {
const theme = useThemeStore((s) => s.theme)
const resolved = useThemeStore((s) => s.resolved)
const setTheme = useThemeStore((s) => s.setTheme)
const TriggerIcon = resolved === "dark" ? Moon : Sun
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size={showLabel ? "default" : "icon"}
aria-label="모드 변경"
aria-haspopup="menu"
>
<TriggerIcon className="h-4 w-4" aria-hidden="true" />
{showLabel ? <span className="ml-2 text-sm"></span> : null}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-32">
{ITEMS.map(({ value, label, icon: Icon }) => (
<DropdownMenuItem
key={value}
onClick={() => setTheme(value)}
aria-current={theme === value ? "true" : undefined}
className="gap-2"
>
<Icon className="h-4 w-4" aria-hidden="true" />
<span>{label}</span>
{theme === value ? <span className="ml-auto text-xs"></span> : null}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)
}