From f28d30cfc91dc7f95b66e7cc5fe7c9258490b5d8 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Wed, 7 May 2025 10:32:29 +0900 Subject: [PATCH 1/2] =?UTF-8?q?enhance(frontend):=20=E3=83=86=E3=83=BC?= =?UTF-8?q?=E3=83=9E=E5=88=87=E3=82=8A=E6=9B=BF=E3=81=88=E3=81=AE=E3=82=A2?= =?UTF-8?q?=E3=83=8B=E3=83=A1=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92?= =?UTF-8?q?View=20Transition=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/MkFoldableSection.vue | 16 +++++- packages/frontend/src/style.scss | 39 ++++++++++++++- packages/frontend/src/theme.ts | 49 +++++++++++++------ 3 files changed, 86 insertions(+), 18 deletions(-) diff --git a/packages/frontend/src/components/MkFoldableSection.vue b/packages/frontend/src/components/MkFoldableSection.vue index b9888d9b64..0fa7bea7ab 100644 --- a/packages/frontend/src/components/MkFoldableSection.vue +++ b/packages/frontend/src/components/MkFoldableSection.vue @@ -31,9 +31,10 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 341f5cb621..9b8734b4fd 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -90,12 +90,49 @@ html { } } -html._themeChanging_ { +html._themeChangingFallback_ { &, * { transition: background 1s ease, border 1s ease !important; } } +html._themeChanging_ { + view-transition-name: theme-changing; +} + +html::view-transition-new(theme-changing) { + z-index: 4000001; + animation: themeChangingNew 1s ease; + animation-fill-mode: forwards; +} + +html::view-transition-old(theme-changing) { + z-index: 4000000; + animation: themeChangingOld 1s ease; + animation-fill-mode: forwards; +} + +@keyframes themeChangingNew { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes themeChangingOld { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } + +} + html, body, #misskey_app { diff --git a/packages/frontend/src/theme.ts b/packages/frontend/src/theme.ts index 268f879d17..064a7c254d 100644 --- a/packages/frontend/src/theme.ts +++ b/packages/frontend/src/theme.ts @@ -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 { 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,38 @@ export function applyTheme(theme: Theme, persist = true) { globalEvents.emit('themeChanging'); } +let timeout: number | null = null; + +export function applyTheme(theme: Theme, persist = true) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + + if (document.startViewTransition != null && prefer.s.animation) { + window.document.documentElement.classList.add('_themeChanging_'); + 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'); + }, 1000); + + applyThemeInternal(theme, persist); + } +} + export function compile(theme: Theme): Record { function getColor(val: string): tinycolor.Instance { if (val[0] === '@') { // ref (prop) From ccac9700c08bb53ffee6c89b4fdf7a6b210f45c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Thu, 8 May 2025 11:56:27 +0900 Subject: [PATCH 2/2] fix lint --- packages/frontend/src/theme.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/theme.ts b/packages/frontend/src/theme.ts index 064a7c254d..003fd8b6f0 100644 --- a/packages/frontend/src/theme.ts +++ b/packages/frontend/src/theme.ts @@ -130,13 +130,13 @@ let timeout: number | null = null; export function applyTheme(theme: Theme, persist = true) { if (timeout) { - clearTimeout(timeout); + window.clearTimeout(timeout); timeout = null; } - if (document.startViewTransition != null && prefer.s.animation) { + if (window.document.startViewTransition != null && prefer.s.animation) { window.document.documentElement.classList.add('_themeChanging_'); - document.startViewTransition(async () => { + window.document.startViewTransition(async () => { applyThemeInternal(theme, persist); await nextTick(); }).finished.then(() => {