theme toggle

This commit is contained in:
Oliver Bryan
2026-01-07 12:32:16 +00:00
parent 019b8545f1
commit 5d2ee6cc13
4 changed files with 42 additions and 4 deletions

View File

@@ -9,7 +9,7 @@
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.1.18",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"lucide-react": "^0.561.0", "lucide-react": "^0.562.0",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-router-dom": "^7.10.1", "react-router-dom": "^7.10.1",
@@ -321,7 +321,7 @@
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"lucide-react": ["lucide-react@0.561.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Y59gMY38tl4/i0qewcqohPdEbieBy7SovpBL9IFebhc2mDd8x4PZSOsiFRkpPcOq6bj1r/mjH/Rk73gSlIJP2A=="], "lucide-react": ["lucide-react@0.562.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],

View File

@@ -14,7 +14,7 @@
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.1.18",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"lucide-react": "^0.561.0", "lucide-react": "^0.562.0",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-router-dom": "^7.10.1", "react-router-dom": "^7.10.1",

View File

@@ -1,8 +1,11 @@
import ThemeToggle from "./components/theme-toggle";
function Index() { function Index() {
return ( return (
<div className="flex flex-col h-[100vh] items-center"> <div className="flex flex-col h-[100vh] items-center">
<header className="w-full flex items-center justify-center border-b h-12"> <header className="w-full flex items-center justify-between border-b h-12 p-2">
<h1 className="text-3xl font-bold">The Shape of Sound</h1> <h1 className="text-3xl font-bold">The Shape of Sound</h1>
<ThemeToggle />
</header> </header>
<main className="w-full flex-1 p-4 flex items-center justify-center"> <main className="w-full flex-1 p-4 flex items-center justify-center">
<div className="w-64 h-64 bg-orange-600 rounded-full" /> <div className="w-64 h-64 bg-orange-600 rounded-full" />

View File

@@ -0,0 +1,35 @@
import { Moon, Sun } from "lucide-react";
import { useEffect, useState } from "react";
function ThemeToggle() {
const [theme, setTheme] = useState<string | null>();
useEffect(() => {
const savedTheme = localStorage.getItem("theme");
if (savedTheme) {
setTheme(savedTheme);
}
}, []);
function updateTheme(newTheme: string) {
setTheme(newTheme);
localStorage.setItem("theme", newTheme);
document.documentElement.classList.toggle("dark");
}
return (
<button
type="button"
className="rounded cursor-pointer"
onClick={() => {
if (!theme || theme === "light") updateTheme("dark");
else updateTheme("light");
}}
>
{theme === "dark" ? <Sun /> : <Moon />}
</button>
);
}
export default ThemeToggle;