chore: update @sugarat/theme to version 0.5.17 and add pnpm as a dependency

This commit is contained in:
2026-04-04 23:04:27 +08:00
parent 473a5b4935
commit 9dd80fb073
19 changed files with 3726 additions and 3216 deletions

View File

@@ -1,82 +1,82 @@
import { defineConfig } from 'vitepress'
// 导入主题的配置
import { blogTheme } from './blog-theme'
// 如果使用 GitHub/Gitee Pages 等公共平台部署
// 通常需要修改 base 路径,通常为“/仓库名/”
// 如果项目名已经为 name.github.io 域名,则不需要修改!
// const base = process.env.GITHUB_ACTIONS === 'true'
// ? '/vitepress-blog-sugar-template/'
// : '/'
// Vitepress 默认配置
// 详见文档https://vitepress.dev/reference/site-config
export default defineConfig({
// 继承博客主题(@sugarat/theme)
extends: blogTheme,
// base,
lang: 'zh-cn',
title: 'SIMON BLOG',
description: '同是天涯沦落人,相逢何必曾相识',
lastUpdated: true,
markdown: {
math: true
},
// 详见https://vitepress.dev/zh/reference/site-config#head
head: [
// 配置网站的图标(显示在浏览器的 tab 上)
// ['link', { rel: 'icon', href: `${base}favicon.ico` }], // 修改了 base 这里也需要同步修改
['link', { rel: 'icon', href: '/favicon.ico' }]
],
themeConfig: {
// 展示 2,3 级标题在目录中
outline: {
level: [2, 3],
label: '目录'
},
// 默认文案修改
returnToTopLabel: '回到顶部',
sidebarMenuLabel: '相关文章',
lastUpdatedText: '上次更新于',
// 设置logo
logo: '/logo.jpg',
// editLink: {
// pattern:
// 'https://github.com/ATQQ/sugar-blog/tree/master/packages/blogpress/:path',
// text: '去 GitHub 上编辑内容'
// },
nav: [
{ text: '首页', link: '/' },
// { text: '导航页', link: 'http://home.zhuzihan.com/' },
{ text: '个人导航', link: 'https://home.zhuzihan.com/' },
{ text: '主题仓库', link: 'https://github.com/ATQQ/sugar-blog/tree/master/packages/theme' },
{ text: '关于作者', link: 'https://github.com/handsomezhuzhu' },
{ text: '探针', link: 'https://state.zhuzihan.com/' },
{ text: 'AI API测活', link: 'https://api-test.zhuzihan.com/' },
{ text: '文件快递柜', link: 'https://file.zhuzihan.com/' },
{ text: 'OpenWebUI', link: 'https://ai.zhuzihan.com/' },
{ text: '临时2fa', link: 'https://2fa.zhuzihan.com/' }
],
socialLinks: [
{
icon: 'github',
link: 'https://github.com/handsomezhuzhu'
}
]
},
vite: {
css: {
preprocessorOptions: {
scss: {
api: 'modern-compiler'
}
}
}
}
})
import { defineConfig } from 'vitepress'
// 导入主题的配置
import { blogTheme } from './blog-theme'
// 如果使用 GitHub/Gitee Pages 等公共平台部署
// 通常需要修改 base 路径,通常为“/仓库名/”
// 如果项目名已经为 name.github.io 域名,则不需要修改!
// const base = process.env.GITHUB_ACTIONS === 'true'
// ? '/vitepress-blog-sugar-template/'
// : '/'
// Vitepress 默认配置
// 详见文档https://vitepress.dev/reference/site-config
export default defineConfig({
// 继承博客主题(@sugarat/theme)
extends: blogTheme,
// base,
lang: 'zh-cn',
title: 'SIMON BLOG',
description: '同是天涯沦落人,相逢何必曾相识',
lastUpdated: true,
markdown: {
math: true
},
// 详见https://vitepress.dev/zh/reference/site-config#head
head: [
// 配置网站的图标(显示在浏览器的 tab 上)
// ['link', { rel: 'icon', href: `${base}favicon.ico` }], // 修改了 base 这里也需要同步修改
['link', { rel: 'icon', href: '/favicon.ico' }]
],
themeConfig: {
// 展示 2,3 级标题在目录中
outline: {
level: [2, 3],
label: '目录'
},
// 默认文案修改
returnToTopLabel: '回到顶部',
sidebarMenuLabel: '相关文章',
lastUpdatedText: '上次更新于',
// 设置logo
logo: '/logo.jpg',
// editLink: {
// pattern:
// 'https://github.com/ATQQ/sugar-blog/tree/master/packages/blogpress/:path',
// text: '去 GitHub 上编辑内容'
// },
nav: [
{ text: '首页', link: '/' },
// { text: '导航页', link: 'http://home.zhuzihan.com/' },
{ text: '个人导航', link: 'https://home.zhuzihan.com/' },
{ text: '主题仓库', link: 'https://github.com/ATQQ/sugar-blog/tree/master/packages/theme' },
{ text: '关于作者', link: 'https://github.com/handsomezhuzhu' },
{ text: '探针', link: 'https://state.zhuzihan.com/' },
{ text: 'AI API测活', link: 'https://api-test.zhuzihan.com/' },
{ text: '文件快递柜', link: 'https://file.zhuzihan.com/' },
{ text: 'OpenWebUI', link: 'https://ai.zhuzihan.com/' },
{ text: '临时2fa', link: 'https://2fa.zhuzihan.com/' }
],
socialLinks: [
{
icon: 'github',
link: 'https://github.com/handsomezhuzhu'
}
]
},
vite: {
css: {
preprocessorOptions: {
scss: {
api: 'modern-compiler'
}
}
}
}
})

View File

@@ -1,152 +1,152 @@
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { useData, useRoute } from 'vitepress'
const { isDark, frontmatter } = useData()
const route = useRoute()
// 图片配置
const darkImages = [
// '/bg.webp',
'/bg2.webp',
'/bg3.jpeg'
]
const lightImages = [
'/bgw.webp',
'/bgw2.jpeg'
]
const currentImages = computed(() => isDark.value ? darkImages : lightImages)
const currentIndex = ref(0)
const nextIndex = ref(1)
// 控制显示的图片
const activeImage = computed(() => currentImages.value[currentIndex.value])
// const nextImage = computed(() => currentImages.value[nextIndex.value])
// 简单的淡入淡出逻辑:
// 我们使用 <transition> 包裹一个 div 作为背景
// 也可以使用两个 div 叠加,一个 fadeOut 一个 fadeIn
// 这里使用 Vue Transition Group 或 Key 切换
// --- 配置区域 ---
const INTERVAL_TIME = 15000 // 轮换间隔5000ms = 5秒
// ----------------
let timer: any = null
const startRotation = () => {
stopRotation()
timer = setInterval(() => {
currentIndex.value = (currentIndex.value + 1) % currentImages.value.length
}, INTERVAL_TIME)
}
const stopRotation = () => {
if (timer) clearInterval(timer)
}
// 监听模式变化,重置索引,防止索引越界
watch(isDark, () => {
// 切换模式时,重置 index确保展示对应模式的第一张图
currentIndex.value = 0
})
const preloadImages = (images: string[]) => {
images.forEach(src => {
const img = new Image()
img.src = src
})
}
onMounted(() => {
// 预加载所有图片
preloadImages([...darkImages, ...lightImages])
startRotation()
})
onUnmounted(() => {
stopRotation()
})
// 只在首页显示
const show = computed(() => frontmatter.value.layout === 'home')
</script>
<template>
<ClientOnly>
<div v-show="show" class="bg-slider-container">
<transition name="bg-fade">
<div
:key="activeImage"
class="bg-slide-item"
:style="{ backgroundImage: `url(${activeImage})` }"
></div>
</transition>
</div>
</ClientOnly>
</template>
<style scoped>
.bg-slider-container {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -10; /* 放在最底层 */
pointer-events: none;
overflow: hidden;
}
.bg-slide-item {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
/* 保持与原主题一致的暗度调整,如果需要的话。
原主题是在 .VPHome 上盖了一层渐变,所以这里只需要纯图片。
*/
}
/* Vue Transition 动画 */
.bg-fade-enter-active {
transition: opacity 1.5s ease;
z-index: 2; /* 新图片在最上面 */
}
.bg-fade-leave-active {
/* 旧图片保持显示,直到被新图片覆盖 */
transition: opacity 1.5s ease;
z-index: 1; /* 旧图片在中间 */
}
.bg-fade-enter-from {
opacity: 0;
}
.bg-fade-enter-to {
opacity: 1;
}
.bg-fade-leave-from {
opacity: 1;
}
.bg-fade-leave-to {
/* 旧图片保持不透明(或者可以设为 0 但在 enter 之后)
这里设为 0因为如果 enter 是 opacity 1它覆盖在上面。
如果设为 1可能会在 transition 结束后突然消失,如果新图片有透明度的话。
但我们的图片是背景图,理论上是不透明的。
为了保险,我们让旧图片淡出,但新图片覆盖在上面。
如果新图片淡入 (0->1) 同时旧图片淡出 (1->0),中间时刻 (0.5+0.5) 可能会透。
所以策略是:旧图片 保持 1 (或极慢淡出),新图片 淡入。
*/
opacity: 1;
}
</style>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { useData, useRoute } from 'vitepress'
const { isDark, frontmatter } = useData()
const route = useRoute()
// 图片配置
const darkImages = [
// '/bg.webp',
'/bg2.webp',
'/bg3.jpeg'
]
const lightImages = [
'/bgw.webp',
'/bgw2.jpeg'
]
const currentImages = computed(() => isDark.value ? darkImages : lightImages)
const currentIndex = ref(0)
const nextIndex = ref(1)
// 控制显示的图片
const activeImage = computed(() => currentImages.value[currentIndex.value])
// const nextImage = computed(() => currentImages.value[nextIndex.value])
// 简单的淡入淡出逻辑:
// 我们使用 <transition> 包裹一个 div 作为背景
// 也可以使用两个 div 叠加,一个 fadeOut 一个 fadeIn
// 这里使用 Vue Transition Group 或 Key 切换
// --- 配置区域 ---
const INTERVAL_TIME = 15000 // 轮换间隔5000ms = 5秒
// ----------------
let timer: any = null
const startRotation = () => {
stopRotation()
timer = setInterval(() => {
currentIndex.value = (currentIndex.value + 1) % currentImages.value.length
}, INTERVAL_TIME)
}
const stopRotation = () => {
if (timer) clearInterval(timer)
}
// 监听模式变化,重置索引,防止索引越界
watch(isDark, () => {
// 切换模式时,重置 index确保展示对应模式的第一张图
currentIndex.value = 0
})
const preloadImages = (images: string[]) => {
images.forEach(src => {
const img = new Image()
img.src = src
})
}
onMounted(() => {
// 预加载所有图片
preloadImages([...darkImages, ...lightImages])
startRotation()
})
onUnmounted(() => {
stopRotation()
})
// 只在首页显示
const show = computed(() => frontmatter.value.layout === 'home')
</script>
<template>
<ClientOnly>
<div v-show="show" class="bg-slider-container">
<transition name="bg-fade">
<div
:key="activeImage"
class="bg-slide-item"
:style="{ backgroundImage: `url(${activeImage})` }"
></div>
</transition>
</div>
</ClientOnly>
</template>
<style scoped>
.bg-slider-container {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -10; /* 放在最底层 */
pointer-events: none;
overflow: hidden;
}
.bg-slide-item {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
/* 保持与原主题一致的暗度调整,如果需要的话。
原主题是在 .VPHome 上盖了一层渐变,所以这里只需要纯图片。
*/
}
/* Vue Transition 动画 */
.bg-fade-enter-active {
transition: opacity 1.5s ease;
z-index: 2; /* 新图片在最上面 */
}
.bg-fade-leave-active {
/* 旧图片保持显示,直到被新图片覆盖 */
transition: opacity 1.5s ease;
z-index: 1; /* 旧图片在中间 */
}
.bg-fade-enter-from {
opacity: 0;
}
.bg-fade-enter-to {
opacity: 1;
}
.bg-fade-leave-from {
opacity: 1;
}
.bg-fade-leave-to {
/* 旧图片保持不透明(或者可以设为 0 但在 enter 之后)
这里设为 0因为如果 enter 是 opacity 1它覆盖在上面。
如果设为 1可能会在 transition 结束后突然消失,如果新图片有透明度的话。
但我们的图片是背景图,理论上是不透明的。
为了保险,我们让旧图片淡出,但新图片覆盖在上面。
如果新图片淡入 (0->1) 同时旧图片淡出 (1->0),中间时刻 (0.5+0.5) 可能会透。
所以策略是:旧图片 保持 1 (或极慢淡出),新图片 淡入。
*/
opacity: 1;
}
</style>

View File

@@ -1,156 +1,156 @@
<template>
<div class="music-player-wrapper" v-if="show">
<div class="music-control">
<button class="toggle-btn" @click="togglePlayer" :title="isOpen ? '收起播放器' : '展开播放器'">
<span v-if="isOpen">🎵</span>
<span v-else>🎵</span>
</button>
</div>
<transition name="slide">
<div class="music-player-container" v-show="isOpen">
<vue3-aplayer
:audio="audioList"
:fixed="false"
:autoplay="false"
:loop="'all'"
:order="'random'"
:preload="'auto'"
:volume="0.7"
:mutex="true"
:lrcType="0"
:listFolded="false"
:listMaxHeight="'250px'"
theme="#b7daff"
/>
</div>
</transition>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import Vue3Aplayer from 'vue3-aplayer'
const show = ref(false)
const isOpen = ref(false)
// 音乐列表配置 - 您可以根据需要修改这里的音乐
const audioList = ref([
{
name: '夜的钢琴曲',
artist: '石进',
url: 'https://music.163.com/song/media/outer/url?id=27867140.mp3',
cover: 'https://p1.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg',
lrc: ''
},
{
name: 'River Flows In You',
artist: 'Yiruma',
url: 'https://music.163.com/song/media/outer/url?id=2133562.mp3',
cover: 'https://p2.music.126.net/w3av4SHuMAgbBF2KKByaVw==/19217832579785884.jpg',
lrc: ''
},
{
name: 'Kiss The Rain',
artist: 'Yiruma',
url: 'https://music.163.com/song/media/outer/url?id=2618520.mp3',
cover: 'https://p1.music.126.net/VjN74c1hoYgPCEZ9DngeQw==/109951163240682406.jpg',
lrc: ''
}
])
const togglePlayer = () => {
isOpen.value = !isOpen.value
}
onMounted(() => {
// 页面加载完成后显示播放器
setTimeout(() => {
show.value = true
}, 500)
})
</script>
<style scoped>
.music-player-wrapper {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
}
.music-control {
position: relative;
}
.toggle-btn {
width: 50px;
height: 50px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
color: white;
font-size: 24px;
cursor: pointer;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.toggle-btn:hover {
transform: scale(1.1);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
}
.music-player-container {
position: absolute;
bottom: 60px;
right: 0;
width: 350px;
max-width: 90vw;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 12px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.3);
}
/* 深色模式适配 */
.dark .music-player-container {
background: rgba(30, 30, 30, 0.95);
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* 过渡动画 */
.slide-enter-active,
.slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter-from,
.slide-leave-to {
opacity: 0;
transform: translateY(20px);
}
/* 移动端适配 */
@media (max-width: 768px) {
.music-player-wrapper {
bottom: 10px;
right: 10px;
}
.music-player-container {
width: 300px;
}
.toggle-btn {
width: 45px;
height: 45px;
font-size: 20px;
}
}
</style>
<template>
<div class="music-player-wrapper" v-if="show">
<div class="music-control">
<button class="toggle-btn" @click="togglePlayer" :title="isOpen ? '收起播放器' : '展开播放器'">
<span v-if="isOpen">🎵</span>
<span v-else>🎵</span>
</button>
</div>
<transition name="slide">
<div class="music-player-container" v-show="isOpen">
<vue3-aplayer
:audio="audioList"
:fixed="false"
:autoplay="false"
:loop="'all'"
:order="'random'"
:preload="'auto'"
:volume="0.7"
:mutex="true"
:lrcType="0"
:listFolded="false"
:listMaxHeight="'250px'"
theme="#b7daff"
/>
</div>
</transition>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import Vue3Aplayer from 'vue3-aplayer'
const show = ref(false)
const isOpen = ref(false)
// 音乐列表配置 - 您可以根据需要修改这里的音乐
const audioList = ref([
{
name: '夜的钢琴曲',
artist: '石进',
url: 'https://music.163.com/song/media/outer/url?id=27867140.mp3',
cover: 'https://p1.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg',
lrc: ''
},
{
name: 'River Flows In You',
artist: 'Yiruma',
url: 'https://music.163.com/song/media/outer/url?id=2133562.mp3',
cover: 'https://p2.music.126.net/w3av4SHuMAgbBF2KKByaVw==/19217832579785884.jpg',
lrc: ''
},
{
name: 'Kiss The Rain',
artist: 'Yiruma',
url: 'https://music.163.com/song/media/outer/url?id=2618520.mp3',
cover: 'https://p1.music.126.net/VjN74c1hoYgPCEZ9DngeQw==/109951163240682406.jpg',
lrc: ''
}
])
const togglePlayer = () => {
isOpen.value = !isOpen.value
}
onMounted(() => {
// 页面加载完成后显示播放器
setTimeout(() => {
show.value = true
}, 500)
})
</script>
<style scoped>
.music-player-wrapper {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
}
.music-control {
position: relative;
}
.toggle-btn {
width: 50px;
height: 50px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
color: white;
font-size: 24px;
cursor: pointer;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.toggle-btn:hover {
transform: scale(1.1);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
}
.music-player-container {
position: absolute;
bottom: 60px;
right: 0;
width: 350px;
max-width: 90vw;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 12px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.3);
}
/* 深色模式适配 */
.dark .music-player-container {
background: rgba(30, 30, 30, 0.95);
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* 过渡动画 */
.slide-enter-active,
.slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter-from,
.slide-leave-to {
opacity: 0;
transform: translateY(20px);
}
/* 移动端适配 */
@media (max-width: 768px) {
.music-player-wrapper {
bottom: 10px;
right: 10px;
}
.music-player-container {
width: 300px;
}
.toggle-btn {
width: 45px;
height: 45px;
font-size: 20px;
}
}
</style>

View File

@@ -62,4 +62,48 @@
@media (max-width: 768px) {
font-size: 2.2rem !important;
}
}
}
/* 美化文章底部的 TIP 提示块和标题图标 */
.vp-doc .custom-block.tip {
border: 1px solid rgba(25, 118, 210, 0.16);
background:
linear-gradient(135deg, rgba(25, 118, 210, 0.08), rgba(255, 255, 255, 0.92));
border-radius: 16px;
box-shadow: 0 10px 24px rgba(25, 118, 210, 0.08);
}
.dark .vp-doc .custom-block.tip {
background:
linear-gradient(135deg, rgba(77, 171, 247, 0.12), rgba(17, 24, 39, 0.9));
border-color: rgba(77, 171, 247, 0.22);
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.22);
}
.vp-doc .custom-block.tip .custom-block-title {
display: flex;
align-items: center;
gap: 10px;
color: #1565c0;
font-weight: 700;
letter-spacing: 0.02em;
}
.dark .vp-doc .custom-block.tip .custom-block-title {
color: #74c0fc;
}
.vp-doc .custom-block.tip .custom-block-title::before {
content: "i";
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
border-radius: 999px;
background: linear-gradient(135deg, #1e88e5, #42a5f5);
color: #fff;
font-size: 13px;
font-weight: 700;
box-shadow: 0 6px 14px rgba(30, 136, 229, 0.28);
}