-
Notifications
You must be signed in to change notification settings - Fork 97
/
plugin.client.ts
108 lines (93 loc) 路 3.13 KB
/
plugin.client.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { computed, reactive, watch } from 'vue'
import type { ColorModeInstance } from './types'
import { defineNuxtPlugin, isVue2, isVue3, useRouter, useHead, useState } from '#imports'
import { globalName, storageKey, dataValue } from '#color-mode-options'
// Initialise to empty object to avoid hard error when hydrating app in test mode
const helper = (window[globalName] || {}) as unknown as {
preference: string
value: string
getColorScheme: () => string
addColorScheme: (className: string) => void
removeColorScheme: (className: string) => void
}
export default defineNuxtPlugin((nuxtApp) => {
const colorMode = useState<ColorModeInstance>('color-mode', () => reactive({
// For SPA mode or fallback
preference: helper.preference,
value: helper.value,
unknown: false,
forced: false
})).value
if (dataValue) {
if (isVue3) {
useHead({
htmlAttrs: { [`data-${dataValue}`]: computed(() => colorMode.value) }
})
} else {
const app = nuxtApp.nuxt2Context.app
const originalHead = app.head
app.head = function () {
const head = (typeof originalHead === 'function' ? originalHead.call(this) : originalHead) || {}
head.htmlAttrs = head.htmlAttrs || {}
head.htmlAttrs[`data-${dataValue}`] = colorMode.value
return head
}
}
}
useRouter().afterEach((to) => {
const forcedColorMode = isVue2
? (to.matched[0]?.components.default as any)?.options.colorMode
: to.meta.colorMode
if (forcedColorMode && forcedColorMode !== 'system') {
colorMode.value = forcedColorMode
colorMode.forced = true
} else {
if (forcedColorMode === 'system') {
// eslint-disable-next-line no-console
console.warn('You cannot force the colorMode to system at the page level.')
}
colorMode.forced = false
colorMode.value = colorMode.preference === 'system'
? helper.getColorScheme()
: colorMode.preference
}
})
let darkWatcher: MediaQueryList
function watchMedia () {
if (darkWatcher || !window.matchMedia) { return }
darkWatcher = window.matchMedia('(prefers-color-scheme: dark)')
darkWatcher.addEventListener('change', () => {
if (!colorMode.forced && colorMode.preference === 'system') {
colorMode.value = helper.getColorScheme()
}
})
}
watch(() => colorMode.preference, (preference) => {
if (colorMode.forced) {
return
}
if (preference === 'system') {
colorMode.value = helper.getColorScheme()
watchMedia()
} else {
colorMode.value = preference
}
// Local storage to sync with other tabs
window.localStorage?.setItem(storageKey, preference)
}, { immediate: true })
watch(() => colorMode.value, (newValue, oldValue) => {
helper.removeColorScheme(oldValue)
helper.addColorScheme(newValue)
})
if (colorMode.preference === 'system') {
watchMedia()
}
nuxtApp.hook('app:mounted', () => {
if (colorMode.unknown) {
colorMode.preference = helper.preference
colorMode.value = helper.value
colorMode.unknown = false
}
})
nuxtApp.provide('colorMode', colorMode)
})