Skip to content

Commit

Permalink
feat: 主题风格切换
Browse files Browse the repository at this point in the history
  • Loading branch information
terwer committed Mar 19, 2023
1 parent 641d0e5 commit 472341c
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 23 deletions.
17 changes: 7 additions & 10 deletions app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,13 @@ export default defineAppConfig({
// archive: false, // 是否打开归档功能,默认true
// categoryText: '随笔', // 碎片化文章(_posts文件夹的文章)预设生成的分类值,默认'随笔'

// pageStyle: 'line', // 页面风格,可选值:'card'卡片 | 'line' 线(未设置bodyBgImg时才生效), 默认'card'。 说明:card时背景显示灰色衬托出卡片样式,line时背景显示纯色,并且部分模块带线条边框
pageStyle: "line", // 页面风格,可选值:'card'卡片 | 'line' 线(未设置bodyBgImg时才生效), 默认'card'。 说明:card时背景显示灰色衬托出卡片样式,line时背景显示纯色,并且部分模块带线条边框

bodyBgImg: <string[] | string>[
"https://ghproxy.com/https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/20200507175828.jpeg",
"https://ghproxy.com/https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/20200507175845.jpeg",
"https://ghproxy.com/https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/20200507175846.jpeg",
],
bodyBgImg: <string[] | string>[],
// bodyBgImg: [
// 'https://fastly.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175828.jpeg',
// 'https://fastly.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175845.jpeg',
// 'https://fastly.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175846.jpeg'
// "https://ghproxy.com/https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/20200507175828.jpeg",
// "https://ghproxy.com/https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/20200507175845.jpeg",
// "https://ghproxy.com/https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/20200507175846.jpeg",
// ], // body背景大图,默认无。 单张图片 String | 多张图片 Array, 多张图片时隔bodyBgImgInterval切换一张。
bodyBgImgOpacity: 0.5,
// bodyBgImgOpacity: 0.5, // body背景图透明度,选值 0.1~1.0, 默认0.5
Expand All @@ -146,7 +142,7 @@ export default defineAppConfig({
// pageButton: false, // 是否显示快捷翻页按钮,默认true

// 默认外观模式(用户未在页面手动修改过模式时才生效,否则以用户设置的模式为准),可选:'auto' | 'light' | 'dark' | 'read',默认'auto'。
// defaultMode: 'auto',
defaultMode: "auto",

// 侧边栏 'structuring' | { mode: 'structuring', collapsable: Boolean} | 'auto' | <自定义> 温馨提示:目录页数据依赖于结构化的侧边栏数据,如果你不设置为'structuring',将无法使用目录页
sidebar: "structuring",
Expand All @@ -166,6 +162,7 @@ export default defineAppConfig({

// 社交图标 (显示于博主信息栏和页脚栏。内置图标:https://doc.xugaoyi.com/pages/a20ce8/#social)
social: {
iconfontCssFile: undefined,
// iconfontCssFile: '//at.alicdn.com/t/xxx.css', // 可选,阿里图标库在线css文件地址,对于主题没有的图标可自己添加。阿里图片库:https://www.iconfont.cn/
icons: [
{
Expand Down
182 changes: 182 additions & 0 deletions components/vdoing/Buttons.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
<template>
<div class="buttons">
<transition name="fade">
<div
title="返回顶部"
class="button blur go-to-top iconfont icon-fanhuidingbu"
v-show="computes.showToTop.value"
@click="methods.scrollToTop"
/>
</transition>
<div
title="去评论"
class="button blur go-to-comment iconfont icon-pinglun"
v-show="datas.showCommentBut"
@click="methods.scrollToComment"
/>
<div
title="主题模式"
class="button blur theme-mode-but iconfont icon-zhuti"
@mouseenter="datas.showModeBox = true"
@mouseleave="datas.showModeBox = false"
@click="datas.showModeBox = true"
>
<transition name="mode">
<ul class="select-box" ref="modeBox" v-show="datas.showModeBox" @click.stop @touchstart.stop>
<li
v-for="item in datas.modeList"
:key="item.KEY"
class="iconfont"
:class="[item.icon, { active: item.KEY === datas.currentMode }]"
@click="methods.toggleMode(item.KEY)"
>
{{ item.name }}
</li>
</ul>
</transition>
</div>
</div>
</template>

<script lang="ts" setup>
import storage from "good-storage"
import { EmitsOptions } from "@vue/runtime-core" // 本地存储
const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl
const appConfig = useAppConfig()
// datas
const datas = reactive({
threshold: 100,
scrollTop: null,
showCommentBut: false,
commentTop: null,
currentMode: "",
showModeBox: false,
modeList: [
{
name: "跟随系统",
icon: "icon-zidong",
KEY: "auto",
},
{
name: "浅色模式",
icon: "icon-rijianmoshi",
KEY: "light",
},
{
name: "深色模式",
icon: "icon-yejianmoshi",
KEY: "dark",
},
{
name: "阅读模式",
icon: "icon-yuedu",
KEY: "read",
},
],
_scrollTimer: null,
_textareaEl: null,
_recordScrollTop: null,
COMMENT_SELECTOR_1: "#vuepress-plugin-comment", // 评论区元素的选择器1
COMMENT_SELECTOR_2: "#valine-vuepress-comment", // 评论区元素的选择器2
COMMENT_SELECTOR_3: ".vssue", // 评论区元素的选择器3
})
// computes
const computes = {
showToTop: computed(() => {
return datas.scrollTop && datas.scrollTop > datas.threshold
}),
}
// emits
const emit = defineEmits(["toggle-theme-mode"])
// methods
const methods = {
toggleMode: (key: string) => {
datas.currentMode = key
emit("toggle-theme-mode", key)
},
scrollToTop: () => {
const a = 1
},
scrollToComment: () => {
const a = 1
},
}
// lifecycle
onMounted(() => {
datas.currentMode = storage.get("mode") || appConfig.themeConfig.defaultMode || "auto"
})
</script>

<style lang="stylus">
@require "../assets/vdoing/styles/index"
.yellowBorder
// border: #FFE089 1px solid!important
border-radius 5px
box-shadow 0 0 15px #FFE089 !important
.buttons
position fixed
right 2rem
bottom 2.5rem
z-index 11
@media (max-width $MQNarrow)
right 1rem
bottom 1.5rem
.button
width 2.2rem
height 2.2rem
line-height 2.2rem
border-radius 50%
box-shadow 0 2px 6px rgba(0, 0, 0, 0.15)
margin-top 0.9rem
text-align center
cursor pointer
transition all 0.5s
background var(--blurBg)
&.hover
background $accentColor
box-shadow 0 0 15px $accentColor
&:before
color #fff
@media (any-hover hover)
&:hover
background $accentColor
box-shadow 0 0 15px $accentColor
&:before
color #fff
.select-box
margin 0
padding 0.8rem 0
position absolute
bottom 0rem
right 1.5rem
background var(--mainBg)
border 1px solid var(--borderColor)
width 120px
border-radius 6px
box-shadow 0 0 15px rgba(255, 255, 255, 0.2)
li
list-style none
line-height 2rem
font-size 0.95rem
&:hover
color $accentColor
&.active
background-color rgba(150, 150, 150, 0.2)
color $accentColor
.mode-enter-active, .mode-leave-active
transition all 0.3s
.mode-enter, .mode-leave-to
opacity 0
transform scale(0.8)
.fade-enter-active, .fade-leave-active
transition opacity 0.2s
.fade-enter, .fade-leave-to
opacity 0
</style>
83 changes: 71 additions & 12 deletions layouts/vdoing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@

<Footer />

<!--
<Buttons ref="buttons" @toggle-theme-mode="toggleThemeMode" />
-->
<Buttons ref="buttons" @toggle-theme-mode="methods.toggleThemeMode" />

<BodyBgImg v-if="appConfig.themeConfig.bodyBgImg" />

Expand All @@ -56,17 +54,19 @@
import Navbar from "~/components/vdoing/Navbar.vue"
import Footer from "~/components/vdoing/Footer.vue"
import BodyBgImg from "~/components/vdoing/BodyBgImg.vue"
import Buttons from "~/components/vdoing/Buttons.vue"
import storage from "good-storage"
const appConfig = useAppConfig()
// seo
useHead({
title: appConfig.siteTitle + " - " + appConfig.siteSlogan,
meta: [{ name: "description", content: appConfig.siteDescription }],
bodyAttrs: {
class: "theme-mode-light theme-style-card",
},
htmlAttrs: {},
// bodyAttrs: {
// class: "theme-mode-light theme-style-card",
// },
// htmlAttrs: {},
})
// datas
Expand Down Expand Up @@ -139,6 +139,25 @@ const methods = {
console.log(datas.isSidebarOpen)
// this.$emit('toggle-sidebar', this.isSidebarOpen)
},
_autoMode: () => {
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
// 系统处于深色模式
datas.themeMode = "dark"
} else {
datas.themeMode = "light"
}
},
toggleThemeMode: (key: string) => {
console.log("toggleThemeMode triggered", key)
if (key === "auto") {
methods._autoMode()
} else {
datas.themeMode = key
}
storage.set("mode", key)
},
windowLB: () => {
return "<p>test1</p>"
// return this.getHtmlStr('windowLB')
Expand All @@ -147,17 +166,57 @@ const methods = {
return "<p>test2</p>"
// return this.getHtmlStr('windowRB')
},
setBodyClass: () => {
const bodyBgImg = appConfig.themeConfig.bodyBgImg
let pageStyle = appConfig.themeConfig.pageStyle ?? "card"
if ((pageStyle !== "card" && pageStyle !== "line") || bodyBgImg) {
pageStyle = "card"
}
document.body.className = `theme-mode-${datas.themeMode} theme-style-${pageStyle}`
},
}
// lifecycles
// onBeforeMount(() => {
// document.body.classList.toggle("theme-mode-light")
// document.body.classList.toggle("theme-style-card")
// })
onBeforeMount(() => {
// this.isSidebarOpenOfclientWidth()
const mode = storage.get("mode") // 不放在created是因为vuepress不能在created访问浏览器api,如window
const { defaultMode } = appConfig.themeConfig
console.log("mode=>", mode)
console.log("defaultMode", defaultMode)
if (defaultMode && defaultMode !== "auto" && !mode) {
datas.themeMode = defaultMode
} else if (!mode || mode === "auto" || (!mode && defaultMode === "auto")) {
// 当未切换过模式,或模式处于'跟随系统'时
methods._autoMode()
} else {
console.log("zzzzz", mode)
datas.themeMode = mode
}
methods.setBodyClass()
// 引入图标库
const social = appConfig.themeConfig.social
if (social && social.iconfontCssFile) {
let linkElm = document.createElement("link")
linkElm.setAttribute("rel", "stylesheet")
linkElm.setAttribute("type", "text/css")
linkElm.setAttribute("href", social.iconfontCssFile)
document.head.appendChild(linkElm)
}
})
watch(
() => datas.themeMode,
() => {
methods.setBodyClass()
}
)
</script>

<style lang="stylus">
@require "../assets/vdoing/styles/palette"
@require "../assets/vdoing/styles/index"
.custom-html-window
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"vue-tsc": "^1.2.0"
},
"dependencies": {
"good-storage": "^1.1.1",
"vue-instantsearch": "^4.8.7",
"zhi-sdk": "^1.0.12"
},
Expand Down
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion types/custom.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
// declare module "vue-instantsearch/vue3/es"
declare module "vue-instantsearch/vue3/es"
declare module "vue-instantsearch/vue3/es"
declare module "good-storage"

0 comments on commit 472341c

Please sign in to comment.