diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
index 8ef775d0..cd9505e5 100644
--- a/src/components/Navbar.jsx
+++ b/src/components/Navbar.jsx
@@ -1,12 +1,31 @@
-import { useState } from "react";
+import { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import logo from "../assets/logo_light_160.png";
import { SideSheet } from "@douyinfe/semi-ui";
import { IconMenu } from "@douyinfe/semi-icons";
import { socials } from "../data/socials";
+import { getTheme, toggleTheme, onSystemPrefChange } from "../theme";
export default function Navbar() {
const [openMenu, setOpenMenu] = useState(false);
+ const [isDark, setIsDark] = useState(() => getTheme() === "dark");
+
+ useEffect(() => {
+ // Keep local state synced when system preference changes (only when user hasn't chosen a theme)
+ const unsubscribe = onSystemPrefChange((prefersDark) => {
+ // if there's an explicit stored preference, ignore system changes
+ try {
+ const stored = window.localStorage && window.localStorage.getItem("drawdb:theme");
+ if (!stored) {
+ setIsDark(prefersDark);
+ }
+ } catch (e) {
+ // ignore storage errors
+ }
+ });
+
+ return () => unsubscribe && unsubscribe();
+ }, []);
return (
<>
@@ -75,12 +94,48 @@ export default function Navbar() {
-
+
+
+
+
+
system > default dark
+export function getTheme() {
+ const stored = getStoredTheme();
+ if (stored === "dark" || stored === "light") return stored;
+ const sys = isSystemDark() ? "dark" : "light";
+ return sys || "dark";
+}
+
+export function applyTheme(theme) {
+ applyThemeClass(theme);
+}
+
+// toggle and persist
+export function toggleTheme() {
+ const current = getTheme();
+ const next = current === "dark" ? "light" : "dark";
+ try {
+ setStoredTheme(next);
+ } catch (e) {
+ // ignore
+ }
+ applyThemeClass(next);
+ return next;
+}
+
+// Initialize on page load: apply stored or system preference, defaulting to dark
+export function initTheme() {
+ const stored = getStoredTheme();
+ const theme = stored === "dark" || stored === "light" ? stored : (isSystemDark() ? "dark" : "light");
+ applyThemeClass(theme);
+}
+
+// Listen to system preference changes and call callback(prefersDark)
+// Returns an unsubscribe function
+export function onSystemPrefChange(cb) {
+ try {
+ if (typeof window === "undefined" || !window.matchMedia) return () => {};
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
+ const handler = (ev) => cb(!!ev.matches);
+ // modern API
+ if (mq.addEventListener) mq.addEventListener("change", handler);
+ else mq.addListener && mq.addListener(handler);
+ return () => {
+ if (mq.removeEventListener) mq.removeEventListener("change", handler);
+ else mq.removeListener && mq.removeListener(handler);
+ };
+ } catch (e) {
+ return () => {};
+ }
+}
+
+// Auto-init if running in browser
+if (typeof window !== "undefined") {
+ try {
+ initTheme();
+ } catch (e) {
+ // ignore
+ }
+}
+
+export default {
+ getTheme,
+ applyTheme,
+ toggleTheme,
+ initTheme,
+ onSystemPrefChange,
+};