diff --git a/src/assets/icons/svg/size.svg b/src/assets/icons/svg/size.svg index ddb25b8..1a409f5 100644 --- a/src/assets/icons/svg/size.svg +++ b/src/assets/icons/svg/size.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/assets/styles/transition.scss b/src/assets/styles/transition.scss index 137e6c3..b59c481 100644 --- a/src/assets/styles/transition.scss +++ b/src/assets/styles/transition.scss @@ -47,3 +47,34 @@ .breadcrumb-leave-active { position: absolute; } + +/* 黑暗模式下过渡效果 */ +::view-transition-new(root), ::view-transition-old(root) { + animation: none !important; + backface-visibility: hidden; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.dark::view-transition-old(root) { + z-index: 2147483646; + background: var(--bg-color-dark); +} + +.dark::view-transition-new(root) { + z-index: 1; + background: var(--bg-color); +} + +::view-transition-old(root) { + z-index: 1; + background: var(--bg-color); +} + +::view-transition-new(root) { + z-index: 2147483646; + background: var(--bg-color-dark); +} diff --git a/src/assets/styles/variables.module.scss b/src/assets/styles/variables.module.scss index 09e510b..4532651 100644 --- a/src/assets/styles/variables.module.scss +++ b/src/assets/styles/variables.module.scss @@ -89,6 +89,9 @@ html.dark { --el-text-color-regular: #d0d0d0; --el-border-color: #434343; --el-border-color-light: #434343; + + /* primary */ + --primary-bg: #18212b; /* 侧边栏 */ --sidebar-bg: #141414; @@ -173,6 +176,33 @@ html.dark { } } + /* 按钮样式覆盖 */ + .el-button--primary.is-plain { + background-color: var(--primary-bg); + border: 1px solid var(--el-color-primary-light-2); + color: var(--el-color-primary-light-2); + + &:hover { + background-color: var(--el-button-hover-bg-color); + border-color: var(--el-button-hover-border-color); + color: var(--el-button-hover-text-color); + } + + &.is-disabled { + background-color: var(--link-active-bg-color); + border-color: var(--el-color-primary-light-3); + color: var(--el-color-primary-light-3); + opacity: 0.5; + } + } + + /* primary tag 样式覆盖 */ + .el-tag--primary { + background-color: var(--primary-bg); + border: 1px solid var(--el-border-color-light); + color: var(--el-color-primary); + } + /* 表格样式覆盖 */ .el-table { --el-table-header-bg-color: var(--el-bg-color-overlay) !important; diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue index 38ba18e..c5d03af 100644 --- a/src/layout/components/Navbar.vue +++ b/src/layout/components/Navbar.vue @@ -111,8 +111,44 @@ function setLayout() { emits('setLayout') } -function toggleTheme() { - settingsStore.toggleTheme() +async function toggleTheme(event) { + const x = event?.clientX || window.innerWidth / 2 + const y = event?.clientY || window.innerHeight / 2 + const wasDark = settingsStore.isDark + + const isReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches + const isSupported = document.startViewTransition && !isReducedMotion + + if (!isSupported) { + settingsStore.toggleTheme() + return + } + + try { + const transition = document.startViewTransition(async () => { + await new Promise((resolve) => setTimeout(resolve, 10)) + settingsStore.toggleTheme() + await nextTick() + }) + await transition.ready + + const endRadius = Math.hypot(Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y)) + const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`] + document.documentElement.animate( + { + clipPath: !wasDark ? [...clipPath].reverse() : clipPath + }, { + duration: 650, + easing: "cubic-bezier(0.4, 0, 0.2, 1)", + fill: "forwards", + pseudoElement: !wasDark ? "::view-transition-old(root)" : "::view-transition-new(root)" + } + ) + await transition.finished + } catch (error) { + console.warn("View transition failed, falling back to immediate toggle:", error) + settingsStore.toggleTheme() + } }