From e02360aea5fbc7c84e9f82355bcc6bbb55f4a2ff Mon Sep 17 00:00:00 2001 From: riefive Date: Tue, 16 Sep 2025 12:34:37 +0700 Subject: [PATCH] feat(public): add setting dark or light mode --- app/components/layout/Header.vue | 9 +++++--- app/components/layout/ThemeToggle.vue | 15 +++++++++++++ app/composables/useTheme.ts | 31 +++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 app/components/layout/ThemeToggle.vue create mode 100644 app/composables/useTheme.ts diff --git a/app/components/layout/Header.vue b/app/components/layout/Header.vue index 369b29ea..45dd38cd 100644 --- a/app/components/layout/Header.vue +++ b/app/components/layout/Header.vue @@ -1,4 +1,6 @@ + + diff --git a/app/composables/useTheme.ts b/app/composables/useTheme.ts new file mode 100644 index 00000000..f028d4c6 --- /dev/null +++ b/app/composables/useTheme.ts @@ -0,0 +1,31 @@ +import { ref, watchEffect } from 'vue' + +const THEME_KEY = 'theme-mode' + +export function useTheme() { + const theme = ref<'light' | 'dark'>(getInitialTheme()) + + function getInitialTheme() { + if (typeof window === 'undefined') return 'light' + const persisted = localStorage.getItem(THEME_KEY) + if (persisted === 'dark' || persisted === 'light') return persisted + // fallback: system preference + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' + } + + function setTheme(newTheme: 'light' | 'dark') { + theme.value = newTheme + localStorage.setItem(THEME_KEY, newTheme) + document.documentElement.classList.toggle('dark', newTheme === 'dark') + } + + function toggleTheme() { + setTheme(theme.value === 'dark' ? 'light' : 'dark') + } + + watchEffect(() => { + setTheme(theme.value) + }) + + return { theme, toggleTheme } +}