enhance(frontend): テーマ切り替えのアニメーションをView Transitionに変更 (#15974)

* enhance(frontend): テーマ切り替えのアニメーションをView Transitionに変更

* fix lint

* fix: 切り替え時間を0.5sに
This commit is contained in:
かっこかり
2025-05-21 14:19:34 +09:00
committed by GitHub
parent bd7633c70e
commit 2619f69238
3 changed files with 86 additions and 19 deletions

View File

@@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { ref } from 'vue';
import { ref, nextTick } from 'vue';
import tinycolor from 'tinycolor2';
import lightTheme from '@@/themes/_light.json5';
import darkTheme from '@@/themes/_dark.json5';
@@ -88,20 +88,7 @@ export async function removeTheme(theme: Theme): Promise<void> {
prefer.commit('themes', themes);
}
let timeout: number | null = null;
export function applyTheme(theme: Theme, persist = true) {
if (timeout) window.clearTimeout(timeout);
window.document.documentElement.classList.add('_themeChanging_');
timeout = window.setTimeout(() => {
window.document.documentElement.classList.remove('_themeChanging_');
// 色計算など再度行えるようにクライアント全体に通知
globalEvents.emit('themeChanged');
}, 1000);
function applyThemeInternal(theme: Theme, persist: boolean) {
const colorScheme = theme.base === 'dark' ? 'dark' : 'light';
window.document.documentElement.dataset.colorScheme = colorScheme;
@@ -139,6 +126,37 @@ export function applyTheme(theme: Theme, persist = true) {
globalEvents.emit('themeChanging');
}
let timeout: number | null = null;
export function applyTheme(theme: Theme, persist = true) {
if (timeout) {
window.clearTimeout(timeout);
timeout = null;
}
if (window.document.startViewTransition != null && prefer.s.animation) {
window.document.documentElement.classList.add('_themeChanging_');
window.document.startViewTransition(async () => {
applyThemeInternal(theme, persist);
await nextTick();
}).finished.then(() => {
window.document.documentElement.classList.remove('_themeChanging_');
// 色計算など再度行えるようにクライアント全体に通知
globalEvents.emit('themeChanged');
});
} else {
// TODO: ViewTransition API が主要ブラウザで対応したら消す
window.document.documentElement.classList.add('_themeChangingFallback_');
timeout = window.setTimeout(() => {
window.document.documentElement.classList.remove('_themeChangingFallback_');
// 色計算など再度行えるようにクライアント全体に通知
globalEvents.emit('themeChanged');
}, 500);
applyThemeInternal(theme, persist);
}
}
export function compile(theme: Theme): Record<string, string> {
function getColor(val: string): tinycolor.Instance {
if (val[0] === '@') { // ref (prop)