fix(vuepress-theme-reco): mode switching logic with SSR

This commit is contained in:
stevapple 2020-04-10 19:22:19 +08:00
parent f84750b17a
commit 46e3590d94
5 changed files with 73 additions and 59 deletions

View File

@ -13,7 +13,7 @@
</template> </template>
<script> <script>
import setMode from './setMode' import applyMode from './applyMode'
export default { export default {
name: 'ModeOptions', name: 'ModeOptions',
@ -29,18 +29,27 @@ export default {
}, },
mounted () { mounted () {
const mode = localStorage.getItem('mode') // modePicker 使
const { mode: customMode, modePicker } = this.$themeConfig this.currentMode = localStorage.getItem('mode') || this.$themeConfig.mode || 'auto'
const themeMode = customMode || 'auto'
this.currentMode = modePicker === false ? themeMode : mode || themeMode // Dark and Light autoswitches
setMode(this.currentMode) // server-side Vue
var that = this
window.matchMedia('(prefers-color-scheme: dark)').addListener(() => {
that.$data.currentMode === 'auto' && applyMode(that.$data.currentMode)
})
window.matchMedia('(prefers-color-scheme: light)').addListener(() => {
that.$data.currentMode === 'auto' && applyMode(that.$data.currentMode)
})
applyMode(this.currentMode)
}, },
methods: { methods: {
selectMode (mode) { selectMode (mode) {
if (mode !== this.currentMode) { if (mode !== this.currentMode) {
this.currentMode = mode this.currentMode = mode
setMode(mode) applyMode(mode)
localStorage.setItem('mode', mode) localStorage.setItem('mode', mode)
} }
}, },

View File

@ -0,0 +1,35 @@
import modeOptions from './modeOptions'
function render (mode) {
const rootElement = document.querySelector(':root')
const options = modeOptions[mode]
for (const k in options) {
rootElement.style.setProperty(k, options[k])
}
}
/**
* Sets a color scheme for the website.
* If browser supports "prefers-color-scheme", 'auto' mode will respect the setting for light or dark mode
* otherwise it will set a dark theme during night time
*/
export default function applyMode (mode) {
if (mode !== 'auto') {
render(mode)
return
}
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
const isLightMode = window.matchMedia('(prefers-color-scheme: light)').matches
if (isDarkMode) render('dark')
if (isLightMode) render('light')
if (!isDarkMode && !isLightMode) {
console.log('You specified no preference for a color scheme or your browser does not support it. I schedule dark mode during night time.')
const hour = new Date().getHours()
if (hour < 6 || hour >= 18) render('dark')
else render('light')
}
}

View File

@ -1,5 +1,5 @@
<template> <template>
<div v-click-outside="hideMenu" class="color-picker"> <div v-click-outside="hideMenu" class="color-picker" v-if="$themeConfig.modePicker !== false" >
<a class="color-button" @click.prevent="showMenu = !showMenu"> <a class="color-button" @click.prevent="showMenu = !showMenu">
<i class="iconfont reco-color"></i> <i class="iconfont reco-color"></i>
</a> </a>
@ -14,6 +14,7 @@
<script> <script>
import ClickOutside from 'vue-click-outside' import ClickOutside from 'vue-click-outside'
import ModePicker from './ModePicker' import ModePicker from './ModePicker'
import applyMode from './applyMode'
export default { export default {
name: 'UserSettings', name: 'UserSettings',
@ -32,6 +33,25 @@ export default {
} }
}, },
// modePicker SSR Mode modePicker
mounted () {
// modePicker 使
const themeMode = this.$themeConfig.mode || 'auto'
const { modePicker } = this.$themeConfig
if (modePicker === false) {
// 'auto'
if (themeMode === 'auto') {
window.matchMedia('(prefers-color-scheme: dark)').addListener(() => {
applyMode(themeMode)
})
window.matchMedia('(prefers-color-scheme: light)').addListener(() => {
applyMode(themeMode)
})
}
applyMode(themeMode)
}
},
methods: { methods: {
hideMenu () { hideMenu () {
this.showMenu = false this.showMenu = false

View File

@ -1,50 +0,0 @@
import modeOptions from './modeOptions'
function activateMode (mode) {
const rootElement = document.querySelector(':root')
const options = modeOptions[mode]
for (const k in options) {
rootElement.style.setProperty(k, options[k])
}
}
/**
* Sets a color scheme for the website.
* If browser supports "prefers-color-scheme", 'auto' mode will respect the setting for light or dark mode
* otherwise it will set a dark theme during night time
*/
export default function setMode (mode = 'auto') {
// Dark and Light autoswitches
// 这里的声明需要挪到 setMode 函数中,否则 windows 会报错
const onDark = (e) => e.matches && activateMode('dark')
const onLight = (e) => e.matches && activateMode('light')
const darkScheme = window.matchMedia('(prefers-color-scheme: dark)')
const lightScheme = window.matchMedia('(prefers-color-scheme: light)')
if (mode !== 'auto') {
darkScheme.removeListener(onDark)
lightScheme.removeListener(onLight)
activateMode(mode)
return
}
darkScheme.addListener(onDark)
lightScheme.addListener(onLight)
const isDarkMode = darkScheme.matches
const isLightMode = lightScheme.matches
if (isDarkMode) activateMode('dark')
if (isLightMode) activateMode('light')
if (!isDarkMode && !isLightMode) {
console.log('You specified no preference for a color scheme or your browser does not support it. I schedule dark mode during night time.')
const now = new Date()
const hour = now.getHours()
if (hour < 6 || hour >= 18) {
activateMode('dark')
}
}
}

View File

@ -22,7 +22,7 @@
'max-width': linksWrapMaxWidth + 'px' 'max-width': linksWrapMaxWidth + 'px'
} : {}"> } : {}">
<Mode v-if="$themeConfig.modePicker !== false" /> <Mode />
<AlgoliaSearchBox <AlgoliaSearchBox
v-if="isAlgoliaSearch" v-if="isAlgoliaSearch"
:options="algolia"/> :options="algolia"/>