This commit is contained in:
oneao committed 2026-10-09 22:05:02 +08:00
1 parent 0be0b0767a
commit 5f28a10d89
852 files changed
+8962 -111755

No files matched your search

@@ -0,0 +1,124 @@
<script setup lang="ts">
import { Moon, Sun } from '@lucide/vue'
import { computed } from 'vue'
import { useData } from 'vitepress'
// 顶栏最右侧的主题切换:图标按钮(亮=太阳 / 暗=月亮),替代 VitePress
// 默认的「太阳/月亮滑块开关」。默认开关由 custom.css 隐藏
// (.VPNavBarAppearance 与 .VPNavBarExtra)。
//
// 图标表达「当前」主题,与内置开关的语义一致。若想改成「点击后将切到的
// 主题」,把下方 .is-sun / .is-moon 两条显隐规则对调即可。
const { isDark, theme } = useData()
// isDark 是可写 ref:写入后 VitePress 自行持久化到 localStorage 并更新
// <html class="dark">;本主题的 Layout.vue 再把它桥接到 <html data-g3-theme>。
function toggleAppearance() {
isDark.value = !isDark.value
}
// 用 computed(而非 ref + watchPostEffect):这样预渲染出的 aria-label /
// title 就是真实文案,而不是空串。
const title = computed(() =>
isDark.value
? theme.value.lightModeSwitchTitle || '切换为亮色主题'
: theme.value.darkModeSwitchTitle || '切换为暗色主题',
)
</script>
<template>
<div class="g3-appearance">
<button
type="button"
class="g3-appearance-toggle"
:title="title"
:aria-label="title"
:aria-pressed="isDark"
@click="toggleAppearance"
>
<!-- 两个图标都渲染,由 .dark 决定显隐(与 VitePress 内置开关同一手法):
预渲染时无法得知用户存的是哪套主题,用 v-if 会在水合时报分支不匹配。 -->
<Sun class="g3-appearance-icon is-sun" :size="18" :stroke-width="1.8" aria-hidden="true" />
<Moon class="g3-appearance-icon is-moon" :size="18" :stroke-width="1.8" aria-hidden="true" />
</button>
</div>
</template>
<style>
/* 刻意不写 scoped(与主题其它样式一致):靠 g3- 前缀隔离,
便于在组件外按同一套选择器调整配色与尺寸。 */
.g3-appearance {
display: flex;
align-items: center;
flex-shrink: 0;
}
/* 左侧竖分割线。规格对齐 VitePress 自带的间隔符
(.menu + .appearance::before):1px × 24px,--vp-c-divider。
两侧各 12px,与 .g3-header-sections 的 margin-left 同宽。 */
.g3-appearance::before {
content: '';
flex-shrink: 0;
width: 1px;
height: 24px;
margin: 0 12px;
background-color: var(--vp-c-divider);
}
.g3-appearance-toggle {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 36px;
height: 36px;
border: 0;
border-radius: 6px;
background: transparent;
color: var(--vp-c-text-2);
cursor: pointer;
transition:
color 0.25s,
background-color 0.25s;
}
.g3-appearance-toggle:hover {
color: var(--vp-c-text-1);
background-color: var(--vp-c-default-soft);
}
/* 太阳 / 月亮叠在按钮中心,只过渡 opacity / transform
(不碰 width / height,避免首帧被动画量错尺寸) */
.g3-appearance-icon {
position: absolute;
transition:
opacity 0.2s ease,
transform 0.2s ease;
}
.g3-appearance .is-sun {
opacity: 1;
transform: none;
}
.g3-appearance .is-moon {
opacity: 0;
transform: rotate(-45deg) scale(0.75);
}
.dark .g3-appearance .is-sun {
opacity: 0;
transform: rotate(45deg) scale(0.75);
}
.dark .g3-appearance .is-moon {
opacity: 1;
transform: none;
}
@media (prefers-reduced-motion: reduce) {
.g3-appearance-icon {
transition: none;
}
}
</style>