From 493ac02bab735148006f84b3044f915152966ceb Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Sun, 8 Mar 2026 20:56:54 +0100 Subject: [PATCH] Create centralized theme management with useTheme composable - Extract theme initialization logic from main.ts into useTheme composable - Add setTheme() and initTheme() functions for consistent theme handling - Update ThemePreferences to use useTheme instead of duplicate logic - Remove unused DarkmodeToggle component - Clean up main.ts from ~49 to 28 lines (theme logic now in composable) - Establish single source of truth for theme management - Follow Vue 3 composables pattern for better organization and testability --- src/App.vue | 3 -- src/components/ui/DarkmodeToggle.vue | 48 ------------------------ src/composables/useTheme.ts | 56 ++++++++++++++++++++++++++++ src/main.ts | 32 +--------------- 4 files changed, 58 insertions(+), 81 deletions(-) delete mode 100644 src/components/ui/DarkmodeToggle.vue create mode 100644 src/composables/useTheme.ts diff --git a/src/App.vue b/src/App.vue index 3bf3726..5d5db27 100644 --- a/src/App.vue +++ b/src/App.vue @@ -13,8 +13,6 @@ - - @@ -25,7 +23,6 @@ import NavigationHeader from "@/components/header/NavigationHeader.vue"; import NavigationIcons from "@/components/header/NavigationIcons.vue"; import Popup from "@/components/Popup.vue"; - import DarkmodeToggle from "@/components/ui/DarkmodeToggle.vue"; import CommandPalette from "@/components/ui/CommandPalette.vue"; const router = useRouter(); diff --git a/src/components/ui/DarkmodeToggle.vue b/src/components/ui/DarkmodeToggle.vue deleted file mode 100644 index 9d3de1a..0000000 --- a/src/components/ui/DarkmodeToggle.vue +++ /dev/null @@ -1,48 +0,0 @@ - - - - - diff --git a/src/composables/useTheme.ts b/src/composables/useTheme.ts new file mode 100644 index 0000000..09856d1 --- /dev/null +++ b/src/composables/useTheme.ts @@ -0,0 +1,56 @@ +import { ref, computed } from "vue"; + +type Theme = "light" | "dark" | "auto"; + +const currentTheme = ref("auto"); + +function systemDarkModeEnabled(): boolean { + const computedStyle = window.getComputedStyle(document.body); + if (computedStyle?.colorScheme != null) { + return computedStyle.colorScheme.includes("dark"); + } + return false; +} + +function applyTheme(theme: Theme) { + if (theme === "auto") { + const systemDark = systemDarkModeEnabled(); + document.body.className = systemDark ? "dark" : "light"; + } else { + document.body.className = theme; + } +} + +export function useTheme() { + const savedTheme = computed(() => { + return (localStorage.getItem("theme-preference") as Theme) || "auto"; + }); + + function initTheme() { + const theme = savedTheme.value; + currentTheme.value = theme; + applyTheme(theme); + + // Listen for system theme changes when in auto mode + const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); + mediaQuery.addEventListener("change", e => { + const currentSetting = localStorage.getItem("theme-preference") as Theme; + if (currentSetting === "auto") { + document.body.className = e.matches ? "dark" : "light"; + } + }); + } + + function setTheme(theme: Theme) { + currentTheme.value = theme; + localStorage.setItem("theme-preference", theme); + applyTheme(theme); + } + + return { + currentTheme, + savedTheme, + initTheme, + setTheme + }; +} diff --git a/src/main.ts b/src/main.ts index 406c66d..fb4beb0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,42 +2,14 @@ import { createApp } from "vue"; import router from "./routes"; import store from "./store"; import Toast from "./plugins/Toast"; +import { useTheme } from "./composables/useTheme"; import App from "./App.vue"; -// Initialize theme from localStorage -function initTheme() { - const savedTheme = localStorage.getItem("theme-preference") || "auto"; - - function systemDarkModeEnabled() { - const computedStyle = window.getComputedStyle(document.body); - if (computedStyle?.colorScheme != null) { - return computedStyle.colorScheme.includes("dark"); - } - return false; - } - - if (savedTheme === "auto") { - const systemDark = systemDarkModeEnabled(); - document.body.className = systemDark ? "dark" : "light"; - - // Listen for system theme changes - const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); - mediaQuery.addEventListener("change", e => { - const currentTheme = localStorage.getItem("theme-preference"); - if (currentTheme === "auto") { - document.body.className = e.matches ? "dark" : "light"; - } - }); - } else { - document.body.className = savedTheme; - } -} - // Initialize theme before mounting +const { initTheme } = useTheme(); initTheme(); -store.dispatch("darkmodeModule/findAndSetDarkmodeSupported"); store.dispatch("user/initUserFromCookie"); const app = createApp(App);