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()
+ }
}