u
This commit is contained in:
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>
|
||||
Reference in new issue
Block a user