mirror of
https://github.com/BewlyBewly/BewlyBewly.git
synced 2025-04-14 13:15:29 +00:00
refactor: group dark mode logic to useDark (#694)
* refactor: group dark mode logic to useDark * fix: cannot get the bewlyWrapper --------- Co-authored-by: hakadao <a578457889743@gmail.com>
This commit is contained in:
1
src/auto-imports.d.ts
vendored
1
src/auto-imports.d.ts
vendored
@@ -59,6 +59,7 @@ declare global {
|
||||
const useBewlyImage: typeof import('./composables/useImage')['useBewlyImage']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVars: typeof import('vue')['useCssVars']
|
||||
const useDark: typeof import('./composables/useDark')['useDark']
|
||||
const useDelayedHover: typeof import('./composables/useDelayedHover')['useDelayedHover']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const useStorageLocal: typeof import('./composables/useStorageLocal')['useStorageLocal']
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { usePreferredDark } from '@vueuse/core'
|
||||
import type { HoveringDockItem } from './types'
|
||||
import { AppPage } from '~/enums/appEnums'
|
||||
import { settings } from '~/logic'
|
||||
@@ -10,9 +9,9 @@ import { useMainStore } from '~/stores/mainStore'
|
||||
defineProps<{ activatedPage: AppPage }>()
|
||||
|
||||
const emit = defineEmits(['change-page', 'settings-visibility-change'])
|
||||
const { mainAppRef } = useBewlyApp()
|
||||
|
||||
const mainStore = useMainStore()
|
||||
const { isDark, toggleDark } = useDark()
|
||||
|
||||
const hideDock = ref<boolean>(false)
|
||||
const hoveringDockItem = reactive<HoveringDockItem>({
|
||||
@@ -31,16 +30,6 @@ const tooltipPlacement = computed(() => {
|
||||
return 'right'
|
||||
})
|
||||
|
||||
const isPreferredDark = usePreferredDark()
|
||||
const currentSystemColorScheme = computed(() => isPreferredDark.value ? 'dark' : 'light')
|
||||
|
||||
const currentAppColorScheme = computed((): 'dark' | 'light' => {
|
||||
if (settings.value.theme !== 'auto')
|
||||
return settings.value.theme
|
||||
else
|
||||
return currentSystemColorScheme.value
|
||||
})
|
||||
|
||||
watch(() => settings.value.autoHideDock, (newValue) => {
|
||||
hideDock.value = newValue
|
||||
})
|
||||
@@ -76,78 +65,6 @@ onMounted(() => {
|
||||
currentDockItems.value = computeDockItem()
|
||||
})
|
||||
|
||||
function toggleDark(e: MouseEvent) {
|
||||
const updateThemeSettings = () => {
|
||||
if (currentAppColorScheme.value !== currentSystemColorScheme.value)
|
||||
settings.value.theme = 'auto'
|
||||
else
|
||||
settings.value.theme = isPreferredDark.value ? 'light' : 'dark'
|
||||
}
|
||||
|
||||
const isAppearanceTransition = typeof document !== 'undefined'
|
||||
// @ts-expect-error: Transition API
|
||||
&& document.startViewTransition
|
||||
&& !window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
if (!isAppearanceTransition) {
|
||||
updateThemeSettings()
|
||||
}
|
||||
else {
|
||||
const x = e.clientX
|
||||
const y = e.clientY
|
||||
const endRadius = Math.hypot(
|
||||
Math.max(x, innerWidth - x),
|
||||
Math.max(y, innerHeight - y),
|
||||
)
|
||||
// https://github.com/vueuse/vueuse/pull/3129
|
||||
const style = document.createElement('style')
|
||||
const styleString = `
|
||||
*, *::before, *::after
|
||||
{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}`
|
||||
style.appendChild(document.createTextNode(styleString))
|
||||
document.head.appendChild(style)
|
||||
|
||||
// Since the above normal dom style cannot be applied in shadow dom style
|
||||
// We need to add this style again to the shadow dom
|
||||
const shadowDomStyle = document.createElement('style')
|
||||
const shadowDomStyleString = `
|
||||
*, *::before, *::after
|
||||
{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important; will-change: background}`
|
||||
shadowDomStyle.appendChild(document.createTextNode(shadowDomStyleString))
|
||||
mainAppRef.value.appendChild(shadowDomStyle)
|
||||
|
||||
// @ts-expect-error: Transition API
|
||||
const transition = document.startViewTransition(async () => {
|
||||
updateThemeSettings()
|
||||
await nextTick()
|
||||
})
|
||||
|
||||
transition.ready.then(() => {
|
||||
const clipPath = [
|
||||
`circle(0px at ${x}px ${y}px)`,
|
||||
`circle(${endRadius}px at ${x}px ${y}px)`,
|
||||
]
|
||||
const animation = document.documentElement.animate(
|
||||
{
|
||||
clipPath: currentAppColorScheme.value === 'dark'
|
||||
? [...clipPath].reverse()
|
||||
: clipPath,
|
||||
},
|
||||
{
|
||||
duration: 300,
|
||||
easing: 'ease-in-out',
|
||||
pseudoElement: currentAppColorScheme.value === 'dark'
|
||||
? '::view-transition-old(root)'
|
||||
: '::view-transition-new(root)',
|
||||
},
|
||||
)
|
||||
animation.addEventListener('finish', () => {
|
||||
document.head.removeChild(style!)
|
||||
mainAppRef.value.removeChild(shadowDomStyle!)
|
||||
}, { once: true })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function toggleDockHide(hide: boolean) {
|
||||
if (settings.value.autoHideDock)
|
||||
hideDock.value = hide
|
||||
@@ -209,7 +126,7 @@ function toggleDockHide(hide: boolean) {
|
||||
<!-- dividing line -->
|
||||
<div class="divider" />
|
||||
|
||||
<Tooltip :content="currentAppColorScheme === 'dark' ? $t('dock.dark_mode') : $t('dock.light_mode')" :placement="tooltipPlacement">
|
||||
<Tooltip :content="isDark ? $t('dock.dark_mode') : $t('dock.light_mode')" :placement="tooltipPlacement">
|
||||
<button
|
||||
class="dock-item"
|
||||
@click="toggleDark"
|
||||
@@ -218,13 +135,13 @@ function toggleDockHide(hide: boolean) {
|
||||
>
|
||||
<Transition name="fade">
|
||||
<div v-show="hoveringDockItem.themeMode" absolute>
|
||||
<line-md:sunny-outline-to-moon-loop-transition v-if="currentAppColorScheme === 'dark'" />
|
||||
<line-md:sunny-outline-to-moon-loop-transition v-if="isDark" />
|
||||
<line-md:moon-alt-to-sunny-outline-loop-transition v-else />
|
||||
</div>
|
||||
</Transition>
|
||||
<Transition name="fade">
|
||||
<div v-show="!hoveringDockItem.themeMode" absolute>
|
||||
<line-md:sunny-outline-to-moon-transition v-if="currentAppColorScheme === 'dark'" />
|
||||
<line-md:sunny-outline-to-moon-transition v-if="isDark" />
|
||||
<line-md:moon-to-sunny-outline-transition v-else />
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
@@ -1,97 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { usePreferredDark } from '@vueuse/core'
|
||||
import type { HoveringDockItem } from './types'
|
||||
import { settings } from '~/logic'
|
||||
|
||||
const emit = defineEmits(['settings-visibility-change'])
|
||||
const { mainAppRef } = useBewlyApp()
|
||||
const { isDark, toggleDark } = useDark()
|
||||
|
||||
const hoveringDockItem = reactive<HoveringDockItem>({
|
||||
themeMode: false,
|
||||
settings: false,
|
||||
})
|
||||
|
||||
const isPreferredDark = usePreferredDark()
|
||||
const currentSystemColorScheme = computed(() => isPreferredDark.value ? 'dark' : 'light')
|
||||
|
||||
const currentAppColorScheme = computed((): 'dark' | 'light' => {
|
||||
if (settings.value.theme !== 'auto')
|
||||
return settings.value.theme
|
||||
else
|
||||
return currentSystemColorScheme.value
|
||||
})
|
||||
|
||||
function toggleDark(e: MouseEvent) {
|
||||
const updateThemeSettings = () => {
|
||||
if (currentAppColorScheme.value !== currentSystemColorScheme.value)
|
||||
settings.value.theme = 'auto'
|
||||
else
|
||||
settings.value.theme = isPreferredDark.value ? 'light' : 'dark'
|
||||
}
|
||||
|
||||
const isAppearanceTransition = typeof document !== 'undefined'
|
||||
// @ts-expect-error: Transition API
|
||||
&& document.startViewTransition
|
||||
&& !window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
if (!isAppearanceTransition) {
|
||||
updateThemeSettings()
|
||||
}
|
||||
else {
|
||||
const x = e.clientX
|
||||
const y = e.clientY
|
||||
const endRadius = Math.hypot(
|
||||
Math.max(x, innerWidth - x),
|
||||
Math.max(y, innerHeight - y),
|
||||
)
|
||||
// https://github.com/vueuse/vueuse/pull/3129
|
||||
const style = document.createElement('style')
|
||||
const styleString = `
|
||||
*, *::before, *::after
|
||||
{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}`
|
||||
style.appendChild(document.createTextNode(styleString))
|
||||
document.head.appendChild(style)
|
||||
|
||||
// Since normal dom style cannot be applied in shadow dom style
|
||||
// We need to add this style again to the shadow dom
|
||||
const shadowDomStyle = document.createElement('style')
|
||||
const shadowDomStyleString = `
|
||||
*, *::before, *::after
|
||||
{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}`
|
||||
shadowDomStyle.appendChild(document.createTextNode(shadowDomStyleString))
|
||||
mainAppRef.value.appendChild(shadowDomStyle)
|
||||
|
||||
// @ts-expect-error: Transition API
|
||||
const transition = document.startViewTransition(async () => {
|
||||
updateThemeSettings()
|
||||
await nextTick()
|
||||
})
|
||||
|
||||
transition.ready.then(() => {
|
||||
const clipPath = [
|
||||
`circle(0px at ${x}px ${y}px)`,
|
||||
`circle(${endRadius}px at ${x}px ${y}px)`,
|
||||
]
|
||||
const animation = document.documentElement.animate(
|
||||
{
|
||||
clipPath: currentAppColorScheme.value === 'dark'
|
||||
? [...clipPath].reverse()
|
||||
: clipPath,
|
||||
},
|
||||
{
|
||||
duration: 300,
|
||||
easing: 'ease-in-out',
|
||||
pseudoElement: currentAppColorScheme.value === 'dark'
|
||||
? '::view-transition-old(root)'
|
||||
: '::view-transition-new(root)',
|
||||
},
|
||||
)
|
||||
animation.addEventListener('finish', () => {
|
||||
document.head.removeChild(style!)
|
||||
mainAppRef.value.removeChild(shadowDomStyle!)
|
||||
}, { once: true })
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -100,7 +16,7 @@ function toggleDark(e: MouseEvent) {
|
||||
pointer-events-none
|
||||
>
|
||||
<div flex="~ gap-2 col" pointer-events-auto>
|
||||
<Tooltip :content="currentAppColorScheme === 'dark' ? $t('dock.dark_mode') : $t('dock.light_mode')" placement="left">
|
||||
<Tooltip :content="isDark ? $t('dock.dark_mode') : $t('dock.light_mode')" placement="left">
|
||||
<Button
|
||||
class="ctrl-btn"
|
||||
style="backdrop-filter: var(--bew-filter-glass-1);"
|
||||
@@ -111,13 +27,13 @@ function toggleDark(e: MouseEvent) {
|
||||
>
|
||||
<Transition name="fade">
|
||||
<div v-show="hoveringDockItem.themeMode" absolute>
|
||||
<line-md:sunny-outline-to-moon-loop-transition v-if="currentAppColorScheme === 'dark'" />
|
||||
<line-md:sunny-outline-to-moon-loop-transition v-if="isDark" />
|
||||
<line-md:moon-alt-to-sunny-outline-loop-transition v-else />
|
||||
</div>
|
||||
</Transition>
|
||||
<Transition name="fade">
|
||||
<div v-show="!hoveringDockItem.themeMode" absolute>
|
||||
<line-md:sunny-outline-to-moon-transition v-if="currentAppColorScheme === 'dark'" />
|
||||
<line-md:sunny-outline-to-moon-transition v-if="isDark" />
|
||||
<line-md:moon-to-sunny-outline-transition v-else />
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
122
src/composables/useDark.ts
Normal file
122
src/composables/useDark.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import { usePreferredDark } from '@vueuse/core'
|
||||
import { settings } from '~/logic'
|
||||
|
||||
export function useDark() {
|
||||
const isPreferredDark = usePreferredDark()
|
||||
const currentSystemColorScheme = computed(() => isPreferredDark.value ? 'dark' : 'light')
|
||||
const currentAppColorScheme = computed((): 'dark' | 'light' => {
|
||||
if (settings.value.theme !== 'auto')
|
||||
return settings.value.theme
|
||||
else
|
||||
return currentSystemColorScheme.value
|
||||
})
|
||||
const isDark = computed(() => currentAppColorScheme.value === 'dark')
|
||||
|
||||
// Watch for changes in the 'settings.value.theme' variable and add the 'dark' class to the 'mainApp' element
|
||||
// to prevent some Unocss dark-specific styles from failing to take effect
|
||||
watch(
|
||||
() => [settings.value.theme, isPreferredDark.value],
|
||||
() => {
|
||||
setAppAppearance()
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
/**
|
||||
* Watch for changes in the 'settings.value.theme' variable and add the 'dark' class to the 'mainApp' element
|
||||
* to prevent some Unocss dark-specific styles from failing to take effect
|
||||
*/
|
||||
function setAppAppearance() {
|
||||
if (isDark.value) {
|
||||
document.querySelector('#bewly')?.classList.add('dark')
|
||||
document.documentElement.classList.add('dark')
|
||||
}
|
||||
else {
|
||||
document.querySelector('#bewly')?.classList.remove('dark')
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
}
|
||||
|
||||
function toggleDark(e: MouseEvent) {
|
||||
const updateThemeSettings = () => {
|
||||
if (currentAppColorScheme.value !== currentSystemColorScheme.value)
|
||||
settings.value.theme = 'auto'
|
||||
else
|
||||
settings.value.theme = isPreferredDark.value ? 'light' : 'dark'
|
||||
}
|
||||
|
||||
const isAppearanceTransition = typeof document !== 'undefined'
|
||||
// @ts-expect-error: Transition API
|
||||
&& document.startViewTransition
|
||||
&& !window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
if (!isAppearanceTransition) {
|
||||
updateThemeSettings()
|
||||
}
|
||||
else {
|
||||
const x = e.clientX
|
||||
const y = e.clientY
|
||||
const endRadius = Math.hypot(
|
||||
Math.max(x, innerWidth - x),
|
||||
Math.max(y, innerHeight - y),
|
||||
)
|
||||
// https://github.com/vueuse/vueuse/pull/3129
|
||||
const style = document.createElement('style')
|
||||
const styleString = `
|
||||
*, *::before, *::after
|
||||
{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}`
|
||||
style.appendChild(document.createTextNode(styleString))
|
||||
document.head.appendChild(style)
|
||||
|
||||
// Since the above normal dom style cannot be applied in shadow dom style
|
||||
// We need to add this style again to the shadow dom
|
||||
const shadowDomStyle = document.createElement('style')
|
||||
const shadowDomStyleString = `
|
||||
*, *::before, *::after
|
||||
{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important; will-change: background}`
|
||||
shadowDomStyle.appendChild(document.createTextNode(shadowDomStyleString))
|
||||
|
||||
const bewlyShadowRoot = document.getElementById('bewly')?.shadowRoot
|
||||
const bewlyWrapper = bewlyShadowRoot?.getElementById('bewly-wrapper')
|
||||
if (!bewlyWrapper)
|
||||
throw new Error('mainAppRef is not found')
|
||||
|
||||
bewlyWrapper.appendChild(shadowDomStyle)
|
||||
|
||||
// @ts-expect-error: Transition API
|
||||
const transition = document.startViewTransition(async () => {
|
||||
updateThemeSettings()
|
||||
await nextTick()
|
||||
})
|
||||
|
||||
transition.ready.then(() => {
|
||||
const clipPath = [
|
||||
`circle(0px at ${x}px ${y}px)`,
|
||||
`circle(${endRadius}px at ${x}px ${y}px)`,
|
||||
]
|
||||
const animation = document.documentElement.animate(
|
||||
{
|
||||
clipPath: currentAppColorScheme.value === 'dark'
|
||||
? [...clipPath].reverse()
|
||||
: clipPath,
|
||||
},
|
||||
{
|
||||
duration: 300,
|
||||
easing: 'ease-in-out',
|
||||
pseudoElement: currentAppColorScheme.value === 'dark'
|
||||
? '::view-transition-old(root)'
|
||||
: '::view-transition-new(root)',
|
||||
},
|
||||
)
|
||||
animation.addEventListener('finish', () => {
|
||||
document.head.removeChild(style!)
|
||||
bewlyWrapper.removeChild(shadowDomStyle!)
|
||||
}, { once: true })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isDark,
|
||||
toggleDark,
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { usePreferredDark, useThrottleFn, useToggle } from '@vueuse/core'
|
||||
import { useThrottleFn, useToggle } from '@vueuse/core'
|
||||
import type { Ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import browser from 'webextension-polyfill'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
import { accessKey, settings } from '~/logic'
|
||||
import { AppPage, LanguageType } from '~/enums/appEnums'
|
||||
import { getUserID, hexToRGBA, isHomePage, smoothScrollToTop } from '~/utils/main'
|
||||
import type { BewlyAppProvider } from '~/composables/useAppProvider'
|
||||
import { AppPage, LanguageType } from '~/enums/appEnums'
|
||||
import { accessKey, settings } from '~/logic'
|
||||
import { getUserID, hexToRGBA, isHomePage, smoothScrollToTop } from '~/utils/main'
|
||||
|
||||
const { isDark } = useDark()
|
||||
const activatedPage = ref<AppPage>(settings.value.dockItemVisibilityList.find(e => e.visible === true)?.page ?? AppPage.Home)
|
||||
const { locale } = useI18n()
|
||||
const [showSettings, toggleSettings] = useToggle(false)
|
||||
@@ -29,13 +30,6 @@ const handleThrottledPageRefresh = useThrottleFn(() => handlePageRefresh.value?.
|
||||
const handleThrottledReachBottom = useThrottleFn(() => handleReachBottom.value?.(), 500)
|
||||
const topBarRef = ref()
|
||||
|
||||
const isPreferredDark = usePreferredDark()
|
||||
const isDark = computed(() => {
|
||||
if (settings.value.theme === 'auto')
|
||||
return isPreferredDark.value
|
||||
return settings.value.theme === 'dark'
|
||||
})
|
||||
|
||||
const isVideoPage = computed(() => {
|
||||
if (/https?:\/\/(www.)?bilibili.com\/video\/.*/.test(location.href))
|
||||
return true
|
||||
@@ -82,12 +76,6 @@ watch(
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
// Watch for changes in the 'settings.value.theme' variable and add the 'dark' class to the 'mainApp' element
|
||||
// to prevent some Unocss dark-specific styles from failing to take effect
|
||||
watch(() => settings.value.theme, () => {
|
||||
setAppAppearance()
|
||||
}, { immediate: true })
|
||||
|
||||
watch(() => settings.value.language, () => {
|
||||
setAppLanguage()
|
||||
})
|
||||
@@ -133,10 +121,7 @@ onMounted(() => {
|
||||
else showTopBarMask.value = false
|
||||
})
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', setAppAppearance)
|
||||
|
||||
handleChangeAccessKey()
|
||||
setAppAppearance()
|
||||
setAppLanguage()
|
||||
})
|
||||
|
||||
@@ -184,21 +169,6 @@ async function setAppLanguage() {
|
||||
locale.value = settings.value.language
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch for changes in the 'settings.value.theme' variable and add the 'dark' class to the 'mainApp' element
|
||||
* to prevent some Unocss dark-specific styles from failing to take effect
|
||||
*/
|
||||
function setAppAppearance() {
|
||||
if (isDark.value) {
|
||||
document.querySelector('#bewly')?.classList.add('dark')
|
||||
document.documentElement.classList.add('dark')
|
||||
}
|
||||
else {
|
||||
document.querySelector('#bewly')?.classList.remove('dark')
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
}
|
||||
|
||||
function setAppThemeColor() {
|
||||
const bewlyElement = document.querySelector('#bewly') as HTMLElement
|
||||
if (bewlyElement) {
|
||||
@@ -311,7 +281,7 @@ provide<BewlyAppProvider>('BEWLY_APP', {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="mainAppRef" class="bewly-wrapper" :class="{ dark: isDark }" text="$bew-text-1">
|
||||
<div id="bewly-wrapper" ref="mainAppRef" class="bewly-wrapper" :class="{ dark: isDark }" text="$bew-text-1">
|
||||
<!-- Background -->
|
||||
<template v-if="isHomePage() && !settings.useOriginalBilibiliHomepage">
|
||||
<AppBackground :activated-page="activatedPage" />
|
||||
|
||||
Reference in New Issue
Block a user