Skip to content
Open
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
23 changes: 21 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,27 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
<html lang="en" suppressHydrationWarning>
<body className={inter.className}>
{/* Set theme before React hydration to prevent FOUC */}
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
try {
var stored = localStorage.getItem('theme');
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
var theme = stored || (prefersDark ? 'dark' : 'light');
var root = document.documentElement;
if (theme === 'dark') root.classList.add('dark');
else root.classList.remove('dark');
} catch (e) {}
})();
`,
}}
/>
{children}
</body>
</html>
);
}
5 changes: 5 additions & 0 deletions src/components/nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useState, useEffect } from "react";
import { GitHubStarsButton } from '@/components/animate-ui/buttons/github-stars';
import { useRouter } from "next/navigation";
import { supabase } from "@/lib/supabaseclient";
import ThemeToggle from "@/components/theme-toggle";

export function NavbarDemo() {
const navItems = [
Expand Down Expand Up @@ -59,6 +60,8 @@ export function NavbarDemo() {
<NavItems items={navItems} />
<div className="flex items-center gap-4">
<GitHubStarsButton username="kris70lesgo" repo="s1" />
{/* Theme toggle allows users to switch light/dark mode */}
<ThemeToggle />
{user === null && (
<NavbarButton variant="secondary" onClick={() => router.push('/sign')}>Login</NavbarButton>
)}
Expand Down Expand Up @@ -99,6 +102,8 @@ export function NavbarDemo() {
Login
</NavbarButton>
)}
{/* Mobile theme toggle */}
<ThemeToggle />
</div>
</MobileNavMenu>
</MobileNav>
Expand Down
48 changes: 48 additions & 0 deletions src/components/theme-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use client";
import { useEffect, useState } from "react";
import { Moon, Sun } from "lucide-react";

// Simple theme toggler that updates the <html> class and persists preference
export default function ThemeToggle() {
const [theme, setTheme] = useState<"light" | "dark">("light");

useEffect(() => {
// Initialize from current DOM (set by inline script) or system
const isDark = document.documentElement.classList.contains("dark");
setTheme(isDark ? "dark" : "light");
}, []);

const toggle = () => {
const next = theme === "dark" ? "light" : "dark";
setTheme(next);

const root = document.documentElement;
if (next === "dark") root.classList.add("dark");
else root.classList.remove("dark");

try {
localStorage.setItem("theme", next);
} catch {}
};

return (
<button
type="button"
onClick={toggle}
aria-label="Toggle theme"
className="inline-flex items-center gap-2 rounded-md border border-border px-3 py-1.5 text-sm hover:bg-secondary/60 dark:hover:bg-secondary/40 transition-colors"
>
{theme === "dark" ? (
<>
<Sun className="h-4 w-4" />
<span>Light</span>
</>
) : (
<>
<Moon className="h-4 w-4" />
<span>Dark</span>
</>
)}
</button>
);
}