From 65c6403accb5d6efefe3cfc48e010f30d53785ce Mon Sep 17 00:00:00 2001 From: Cagatay Civici Date: Sun, 31 Dec 2023 01:26:14 +0300 Subject: [PATCH] Stateful dark mode --- app.vue | 42 +++++++++++++++++++++++++++++++----------- layouts/default.vue | 3 +++ nuxt.config.js | 14 +------------- pages/index.vue | 10 +++++++++- plugins/app-state.js | 11 ++++++++++- 5 files changed, 54 insertions(+), 26 deletions(-) diff --git a/app.vue b/app.vue index 770079c23..912a811fd 100644 --- a/app.vue +++ b/app.vue @@ -8,9 +8,6 @@ import EventBus from '@/layouts/AppEventBus'; export default { - themeChangeListener: null, - newsActivate: null, - newsService: null, watch: { $route: { handler(to) { @@ -20,16 +17,29 @@ export default { } } }, + created() { + useServerHead({ + link: [ + { + id: 'theme-link', + rel: 'stylesheet', + href: '/themes/lara-light-green/theme.css' + }, + { + id: 'home-table-link', + rel: 'stylesheet', + href: '/styles/landing/themes/lara-light-green/theme.css' + } + ] + }); + }, mounted() { - this.themeChangeListener = (event) => { - if (!document.startViewTransition) { - this.applyTheme(event); + const preferredColorScheme = localStorage.getItem(this.$appState.colorSchemeKey); + const prefersDarkColorScheme = window.matchMedia('(prefers-color-scheme: dark)').matches; - return; - } - - document.startViewTransition(() => this.applyTheme(event)); - }; + if ((preferredColorScheme === null && prefersDarkColorScheme) || preferredColorScheme === 'dark') { + this.applyTheme({ theme: 'lara-dark-green', dark: true }); + } EventBus.on('theme-change', this.themeChangeListener); }, @@ -37,10 +47,20 @@ export default { EventBus.off('theme-change', this.themeChangeListener); }, methods: { + themeChangeListener(event) { + if (!document.startViewTransition) { + this.applyTheme(event); + + return; + } + + document.startViewTransition(() => this.applyTheme(event)); + }, applyTheme(event) { this.$primevue.changeTheme(this.$appState.theme, event.theme, 'theme-link', () => { this.$appState.theme = event.theme; this.$appState.darkTheme = event.dark; + EventBus.emit('theme-change-complete', { theme: event.theme, dark: event.dark }); }); } diff --git a/layouts/default.vue b/layouts/default.vue index c92dc3448..55e1d67e2 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -92,9 +92,12 @@ export default { if (this.$appState.darkTheme) { newTheme = currentTheme.replace('dark', 'light'); + localStorage.setItem(this.$appState.colorSchemeKey, 'light'); } else { if (currentTheme.includes('light') && currentTheme !== 'fluent-light') newTheme = currentTheme.replace('light', 'dark'); else newTheme = 'lara-dark-green'; //fallback + + localStorage.setItem(this.$appState.colorSchemeKey, 'dark'); } EventBus.emit('theme-change', { theme: newTheme, dark: !this.$appState.darkTheme }); diff --git a/nuxt.config.js b/nuxt.config.js index e53278897..b30c190fa 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -52,19 +52,7 @@ export default defineNuxtConfig({ { property: 'og:image', content: 'https://www.primefaces.org/static/social/primevue-preview.jpg' }, { property: 'og:ttl', content: '604800' } ], - link: [ - { - id: 'home-table-link', - rel: 'stylesheet', - href: baseUrl + 'styles/landing/themes/lara-light-green/theme.css' - }, - { - id: 'theme-link', - rel: 'stylesheet', - href: baseUrl + 'themes/lara-light-green/theme.css' - }, - { rel: 'icon', href: baseUrl + 'favicon.ico' } - ], + link: [{ rel: 'icon', href: baseUrl + 'favicon.ico' }], script: [ { src: baseUrl + 'scripts/prism.js', diff --git a/pages/index.vue b/pages/index.vue index 626176e45..fe054347e 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -53,13 +53,21 @@ export default { document.cookie = 'primeaffiliateid=' + afId + ';expires=' + expire.toUTCString() + ';path=/; domain:primefaces.org'; } - this.replaceTableTheme(this.$appState.darkTheme ? 'lara-dark-green' : 'lara-light-green'); + const preferredColorScheme = localStorage.getItem(this.$appState.colorSchemeKey); + const prefersDarkColorScheme = window.matchMedia('(prefers-color-scheme: dark)').matches; + + if ((preferredColorScheme === null && prefersDarkColorScheme) || preferredColorScheme === 'dark') { + this.replaceTableTheme('lara-dark-green'); + } else { + this.replaceTableTheme('lara-light-green'); + } }, methods: { onDarkModeToggle() { const newTheme = this.$appState.darkTheme ? 'lara-light-green' : 'lara-dark-green'; const newTableTheme = this.$appState.darkTheme ? this.tableTheme.replace('dark', 'light') : this.tableTheme.replace('light', 'dark'); + localStorage.setItem(this.$appState.colorSchemeKey, this.$appState.darkTheme ? 'light' : 'dark'); EventBus.emit('theme-change', { theme: newTheme, dark: !this.$appState.darkTheme }); this.replaceTableTheme(newTableTheme); }, diff --git a/plugins/app-state.js b/plugins/app-state.js index 90afbf7b8..69ba8baa1 100644 --- a/plugins/app-state.js +++ b/plugins/app-state.js @@ -1,6 +1,15 @@ const $appState = { install: (Vue, options) => { - Vue.config.globalProperties.$appState = reactive({ theme: 'lara-light-green', darkTheme: false, codeSandbox: false, sourceType: 'options-api', newsActive: false, announcement: null, storageKey: 'primevue' }); + Vue.config.globalProperties.$appState = reactive({ + theme: 'lara-light-green', + darkTheme: false, + codeSandbox: false, + sourceType: 'options-api', + newsActive: false, + announcement: null, + storageKey: 'primevue', + colorSchemeKey: 'primevue-color-scheme' + }); } };