mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-26 21:26:42 +08:00
feat(components): add theme switching animation
This commit is contained in:
parent
a9dce21878
commit
4a2dbbf1d9
@ -1,13 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { computed, nextTick } from 'vue';
|
||||
import type { PopoverPlacement } from 'naive-ui';
|
||||
import { $t } from '@/locales';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
|
||||
defineOptions({ name: 'ThemeSchemaSwitch' });
|
||||
|
||||
interface Props {
|
||||
/** Theme schema */
|
||||
themeSchema: UnionKey.ThemeScheme;
|
||||
/** Show tooltip */
|
||||
showTooltip?: boolean;
|
||||
/** Tooltip placement */
|
||||
@ -19,15 +18,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
tooltipPlacement: 'bottom'
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
(e: 'switch'): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
function handleSwitch() {
|
||||
emit('switch');
|
||||
}
|
||||
const themeStore = useThemeStore();
|
||||
|
||||
const icons: Record<UnionKey.ThemeScheme, string> = {
|
||||
light: 'material-symbols:sunny',
|
||||
@ -35,13 +26,46 @@ const icons: Record<UnionKey.ThemeScheme, string> = {
|
||||
auto: 'material-symbols:hdr-auto'
|
||||
};
|
||||
|
||||
const icon = computed(() => icons[props.themeSchema]);
|
||||
const icon = computed(() => icons[themeStore.themeScheme]);
|
||||
|
||||
const tooltipContent = computed(() => {
|
||||
if (!props.showTooltip) return '';
|
||||
|
||||
return $t('icon.themeSchema');
|
||||
});
|
||||
|
||||
function toggleDark(event: MouseEvent) {
|
||||
const isAppearanceTransition =
|
||||
document.startViewTransition && !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
if (!isAppearanceTransition) {
|
||||
themeStore.toggleThemeScheme();
|
||||
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 () => {
|
||||
themeStore.toggleThemeScheme();
|
||||
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: themeStore.darkMode ? [...clipPath].reverse() : clipPath
|
||||
},
|
||||
{
|
||||
duration: 400,
|
||||
easing: 'ease-out',
|
||||
pseudoElement: themeStore.darkMode ? '::view-transition-old(root)' : '::view-transition-new(root)'
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -49,7 +73,7 @@ const tooltipContent = computed(() => {
|
||||
:icon="icon"
|
||||
:tooltip-content="tooltipContent"
|
||||
:tooltip-placement="tooltipPlacement"
|
||||
@click="handleSwitch"
|
||||
@click="toggleDark"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
@ -41,11 +41,7 @@ const { isFullscreen, toggle } = useFullscreen();
|
||||
<GlobalSearch />
|
||||
<FullScreen v-if="!appStore.isMobile" :full="isFullscreen" @click="toggle" />
|
||||
<LangSwitch :lang="appStore.locale" :lang-options="appStore.localeOptions" @change-lang="appStore.changeLocale" />
|
||||
<ThemeSchemaSwitch
|
||||
:theme-schema="themeStore.themeScheme"
|
||||
:is-dark="themeStore.darkMode"
|
||||
@switch="themeStore.toggleThemeScheme"
|
||||
/>
|
||||
<ThemeSchemaSwitch />
|
||||
<ThemeButton />
|
||||
<UserAvatar />
|
||||
</div>
|
||||
|
@ -15,3 +15,21 @@ html {
|
||||
html.grayscale {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
::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: 9999;
|
||||
}
|
||||
.dark::view-transition-old(root) {
|
||||
z-index: 9999;
|
||||
}
|
||||
.dark::view-transition-new(root) {
|
||||
z-index: 1;
|
||||
}
|
||||
|
@ -59,12 +59,7 @@ const bgColor = computed(() => {
|
||||
<SystemLogo class="text-64px text-primary lt-sm:text-48px" />
|
||||
<h3 class="text-28px text-primary font-500 lt-sm:text-22px">{{ $t('system.title') }}</h3>
|
||||
<div class="i-flex-col">
|
||||
<ThemeSchemaSwitch
|
||||
:theme-schema="themeStore.themeScheme"
|
||||
:show-tooltip="false"
|
||||
class="text-20px lt-sm:text-18px"
|
||||
@switch="themeStore.toggleThemeScheme"
|
||||
/>
|
||||
<ThemeSchemaSwitch :show-tooltip="false" class="text-20px lt-sm:text-18px" />
|
||||
<LangSwitch
|
||||
:lang="appStore.locale"
|
||||
:lang-options="appStore.localeOptions"
|
||||
|
Loading…
Reference in New Issue
Block a user