feat(docs): theme switch use startViewTransition api (#14489)

* feat(docs): theme switch use startViewTransition api

* chore: format

* feat: update
This commit is contained in:
btea 2023-10-12 21:33:26 +08:00 committed by GitHub
parent ef0d5820b4
commit e0f47610e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 2 deletions

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { nextTick, ref, watch } from 'vue'
import { isDark, toggleDark } from '../../composables/dark'
import DarkIcon from '../icons/dark.vue'
import LightIcon from '../icons/light.vue'
@ -12,13 +12,60 @@ watch(
toggleDark()
}
)
let resolveFn: (value: boolean | PromiseLike<boolean>) => void
const switchTheme = (event: MouseEvent) => {
const isAppearanceTransition =
// @ts-expect-error
document.startViewTransition &&
!window.matchMedia('(prefers-reduced-motion: reduce)').matches
if (!isAppearanceTransition || !event) {
resolveFn(true)
return
}
const x = event.clientX
const y = event.clientY
const endRadius = Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y)
)
// @ts-expect-error: Transition API
const transition = document.startViewTransition(async () => {
resolveFn(true)
await nextTick()
})
transition.ready.then(() => {
const clipPath = [
`circle(0px at ${x}px ${y}px)`,
`circle(${endRadius}px at ${x}px ${y}px)`,
]
document.documentElement.animate(
{
clipPath: isDark.value ? [...clipPath].reverse() : clipPath,
},
{
duration: 400,
easing: 'ease-in',
pseudoElement: isDark.value
? '::view-transition-old(root)'
: '::view-transition-new(root)',
}
)
})
}
const beforeChange = (): Promise<boolean> => {
return new Promise((resolve) => {
resolveFn = resolve
})
}
</script>
<template>
<div>
<div @click.stop="switchTheme">
<ClientOnly>
<el-switch
v-model="darkMode"
:before-change="beforeChange"
:active-action-icon="DarkIcon"
:inactive-action-icon="LightIcon"
/>

View File

@ -171,6 +171,7 @@ a.header-anchor {
padding-right: 0.23em;
font-size: 0.85em;
opacity: 0;
&:hover,
:focus {
text-decoration: none;
@ -200,6 +201,7 @@ li > ol {
overflow-y: hidden;
overflow-x: auto;
margin-bottom: 45px;
& > table {
border-collapse: collapse;
width: 100%;
@ -271,6 +273,7 @@ details {
p:not(.custom-block-title) {
font-size: 0.9rem;
}
&.tip {
padding: 8px 16px;
background-color: var(--block-tip-bg-color);
@ -297,3 +300,25 @@ details {
white-space: nowrap;
width: 1px;
}
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
mix-blend-mode: normal;
}
::view-transition-old(root) {
z-index: 1;
}
::view-transition-new(root) {
z-index: 2147483646;
}
.dark::view-transition-old(root) {
z-index: 2147483646;
}
.dark::view-transition-new(root) {
z-index: 1;
}