Add auth and theme switcher

This commit is contained in:
2025-07-04 18:53:15 +02:00
parent f3c92cdab6
commit a12a8e4e1b
13 changed files with 858 additions and 33 deletions

View File

@ -0,0 +1,15 @@
"use client"
import { signIn, signOut } from "next-auth/react"
export function SignInOutButton({ session }: { session: any }) {
return session ? (
<button onClick={() => signOut()} className="text-sm underline">
Sign out
</button>
) : (
<button onClick={() => signIn("github")} className="text-sm underline">
Sign in with GitHub
</button>
)
}

View File

@ -1,11 +1,18 @@
import { auth } from "@/auth";
import { SignInOutButton } from "../auth/SignInOutButton";
import ModeToggle from "./ModeToggle";
import TopNav from "./TopNav";
export default function Header() {
export default async function Header() {
const session = await auth()
return (
<div className="flex items-center justify-between">
<TopNav />
<ModeToggle />
<div className="flex items-center justify-between gap-4">
<SignInOutButton session={session} />
<ModeToggle />
</div>
</div>
);
}

View File

@ -3,37 +3,80 @@
import { Moon, Sun } from "lucide-react"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { cn } from "@/lib/utils"
import { useEffect, useState } from "react"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select"
const modes = ["light", "dark"] as const
const accents = ["zinc", "red", "rose", "orange", "green", "blue", "yellow", "violet", "default"] as const
const modeIcons = {
light: <Sun className="h-4 w-4" />,
dark: <Moon className="h-4 w-4" />,
}
export default function ModeToggle() {
const { setTheme } = useTheme()
const { setTheme, theme, resolvedTheme } = useTheme()
const [mode, setMode] = useState("dark")
const [accent, setAccent] = useState("violet")
useEffect(() => {
const parts = theme?.split("-")
if (parts?.length === 2) {
setMode(parts[0])
setAccent(parts[1])
}
}, [theme])
function updateTheme(newMode: string, newAccent: string) {
const fullTheme = `${newMode}-${newAccent}`
setTheme(fullTheme)
}
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
<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>
<div className="flex gap-4 items-center">
<Select
value={mode}
onValueChange={(value) => {
setMode(value)
updateTheme(value, accent)
}}
>
<SelectTrigger className="w-[70px]">
<SelectValue
placeholder="Mode"
className="flex items-center gap-2"
/>
</SelectTrigger>
<SelectContent>
{modes.map((m) => (
<SelectItem key={m} value={m}>
<span className="flex items-center gap-2">
{modeIcons[m]}
</span>
</SelectItem>
))}
</SelectContent>
</Select>
<Select
value={accent}
onValueChange={(value) => {
setAccent(value)
updateTheme(mode, value)
}}
>
<SelectTrigger className="w-[120px]">
<SelectValue placeholder="Accent" />
</SelectTrigger>
<SelectContent>
{accents.map((a) => (
<SelectItem key={a} value={a} className={cn(`text-${a}-600`)}>
{a.charAt(0).toUpperCase() + a.slice(1)}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
)
}