feat:增加主题模式切换
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="blog-archive blog-section">
|
||||
<div class="blog-archive blog-section card-item">
|
||||
<h4 class="module-title">文章归档</h4>
|
||||
|
||||
<el-date-picker
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="blog-category blog-section">
|
||||
<div class="blog-category blog-section card-item">
|
||||
<h4 class="module-title">文章分类</h4>
|
||||
|
||||
<span class="total">目前共计{{ blogStore.blogCategoryList.length }}个分类</span>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="blog-category-detail blog-section">
|
||||
<div class="blog-category-detail blog-section card-item">
|
||||
<span class="name">{{ route.params?.name }}</span>
|
||||
|
||||
<div class="category-detail-list">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="blog-comment">
|
||||
<div class="blog-comment card-item">
|
||||
<div class="comment-total">
|
||||
<span>共 {{ blogStore.blogNestedCommentList.length }} 条评论</span>
|
||||
</div>
|
||||
@@ -23,10 +23,6 @@ const blogStore = useBlogStore()
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #EEEEEE;
|
||||
border-radius: 10px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="blog-comment-edit">
|
||||
<div class="blog-comment-edit card-item">
|
||||
<div class="comment-title">
|
||||
<el-input v-model="blogComment.name"
|
||||
:maxlength="10" show-word-limit
|
||||
@@ -99,10 +99,6 @@ const sendCommentClick = async () => {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #EEEEEE;
|
||||
border-radius: 10px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<template>
|
||||
<div class="blog-detail blog-section" id="blog-section">
|
||||
<div class="blog-detail blog-section card-item" id="blog-section">
|
||||
<div class="blog-title">
|
||||
<span class="title">{{ blogStore.currentBlog.title }}</span>
|
||||
<blog-label :basic-blog="getBasicBlog(blogStore.currentBlog)"/>
|
||||
</div>
|
||||
|
||||
<div class="blog-md">
|
||||
<MdPreview editorId="blog-id" v-model="blogStore.currentBlog.content" />
|
||||
<div class="blog-md card-item">
|
||||
<MdPreview editorId="blog-id"
|
||||
v-model="blogStore.currentBlog.content"
|
||||
:theme="appStore.isDark ? 'dark' : 'light'"/>
|
||||
</div>
|
||||
|
||||
<div class="blog-copyright">
|
||||
@@ -42,17 +44,17 @@ import BlogComment from '@/components/Comment/BlogComment.vue'
|
||||
import { MdPreview } from 'md-editor-v3'
|
||||
import 'md-editor-v3/lib/style.css'
|
||||
import { useBlogStore } from '@/store/blog.ts'
|
||||
import { useAppStore } from '@/store/app'
|
||||
import { getBasicBlog } from '@/utils/blog/blogUtil.ts'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
const blogStore = useBlogStore()
|
||||
const appStore = useAppStore()
|
||||
const route = useRoute()
|
||||
|
||||
const currentUrl = new URL(window.location.href)
|
||||
|
||||
const blogComment = computed(() => blogStore.getEmptyBlogComment())
|
||||
|
||||
onMounted(async () => {
|
||||
const blogId = route.params.id as number
|
||||
blogStore.currentBlogId = blogId
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="blog-content-list blog-section">
|
||||
<div class="blog-content-list blog-section card-item">
|
||||
<div v-if="blogStore.blogList.length === 0"
|
||||
class="blog-content blog-content-empty" >
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<aside class="blog-aside">
|
||||
<div class="top-container card-container">
|
||||
<div class="top-container card-item">
|
||||
<blog-title />
|
||||
<blog-menu />
|
||||
</div>
|
||||
|
||||
<blog-summary class="card-container"/>
|
||||
<blog-summary class="card-item"/>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@
|
||||
|
||||
<!-- <vue-particles id="particles" :options="particlesOptions"/>-->
|
||||
<progress class="blog-progress" id="blog_progress" value="0" />
|
||||
|
||||
<el-button circle @click="appStore.toggleDark" class="theme-button">
|
||||
{{ appStore.isDark ? '🌙' : '☀️' }}
|
||||
</el-button>
|
||||
|
||||
<blog-cube/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -37,9 +42,11 @@ import { createHeartDiv } from '@/utils/blog/blogUtil.ts'
|
||||
import { Ribbon } from '@/utils/blog/ribbon'
|
||||
import { onMounted, onUnmounted } from 'vue'
|
||||
import { useBlogStore } from '@/store/blog.ts'
|
||||
import { useAppStore } from '@/store/app.ts'
|
||||
|
||||
const ribbon = new Ribbon()
|
||||
const blogStore = useBlogStore()
|
||||
const appStore = useAppStore()
|
||||
|
||||
/**
|
||||
* 处理点击事件
|
||||
@@ -71,126 +78,5 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@/styles/blog/blog.variable.module.scss" as blog;
|
||||
|
||||
.blog-tools {
|
||||
position: absolute;
|
||||
|
||||
.book-mark-link {
|
||||
border-bottom: none;
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: -2px;
|
||||
left: 20px;
|
||||
color: #222;
|
||||
font-size: 26px;
|
||||
transition: .3s;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.github-corner {
|
||||
border-bottom: none;
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
color: #222;
|
||||
font-size: 26px;
|
||||
transition: .3s;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.github-corner:hover .octo-arm {
|
||||
animation: octocat-wave 560ms ease-in-out
|
||||
}
|
||||
|
||||
@keyframes octocat-wave {
|
||||
0%, 100% {
|
||||
transform: rotate(0)
|
||||
}
|
||||
20%, 60% {
|
||||
transform: rotate(-25deg)
|
||||
}
|
||||
40%, 80% {
|
||||
transform: rotate(10deg)
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
.github-corner:hover .octo-arm {
|
||||
animation: none
|
||||
}
|
||||
.github-corner .octo-arm {
|
||||
animation: octocat-wave 560ms ease-in-out
|
||||
}
|
||||
}
|
||||
|
||||
#particles {
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.heart {
|
||||
position: fixed;
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: red;
|
||||
transform: rotate(45deg);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.heart:after, .heart:before {
|
||||
content: "";
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
background: inherit;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.heart:after {
|
||||
top: -5px;
|
||||
}
|
||||
|
||||
.heart:before {
|
||||
left: -5px;
|
||||
}
|
||||
|
||||
@keyframes move {
|
||||
100% {
|
||||
transform: translateY(-20px) rotate(45deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.blog-progress {
|
||||
/* Positioning */
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: blog.$theme-color;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.blog-progress::-webkit-progress-bar {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.blog-progress::-webkit-progress-value {
|
||||
background-color: blog.$theme-color;
|
||||
}
|
||||
|
||||
.blog-progress::-moz-progress-bar {
|
||||
background-color: blog.$theme-color;
|
||||
}
|
||||
@use "@/styles/blog/blog.tools.module.scss";
|
||||
</style>
|
||||
|
||||
49
src/store/app.ts
Normal file
49
src/store/app.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
|
||||
export const useAppStore = defineStore('ipp', {
|
||||
state: () => ({
|
||||
isDark: false,
|
||||
version: 'v1.0.0.2025042901'
|
||||
}),
|
||||
actions: {
|
||||
toggleDark(e: MouseEvent) {
|
||||
const toggleDark = useToggle(useDark())
|
||||
|
||||
if (!document.startViewTransition) {
|
||||
toggleDark()
|
||||
this.isDark = !this.isDark
|
||||
return
|
||||
}
|
||||
|
||||
const transition = document.startViewTransition(() => {
|
||||
toggleDark() // 实际切换主题
|
||||
})
|
||||
|
||||
transition.ready.then(() => {
|
||||
const x = e.clientX
|
||||
const y = e.clientY
|
||||
// 从点击点到窗口最远边缘的距离,这个距离即为圆的半径,用于确定一个圆形裁剪路径 (clip path) 的最大尺寸,以便覆盖整个视窗。
|
||||
// 勾股定理:a² + b² = c²
|
||||
const a = Math.max(x, window.innerWidth - x)
|
||||
const b = Math.max(y, window.innerHeight - y)
|
||||
const radius = Math.sqrt((a ** 2) + (b ** 2))
|
||||
|
||||
const clipPath = [`circle(0 at ${x}px ${y}px)`, `circle(${radius}px at ${x}px ${y}px)`]
|
||||
// 实现过渡的过程 circle
|
||||
document.documentElement.animate(
|
||||
{
|
||||
clipPath: this.isDark ? clipPath.reverse() : clipPath
|
||||
},
|
||||
{
|
||||
duration: 500,
|
||||
easing: 'ease-in',
|
||||
pseudoElement: this.isDark ? '::view-transition-old(root)' : '::view-transition-new(root)'
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
this.isDark = !this.isDark
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -38,7 +38,7 @@
|
||||
}
|
||||
|
||||
.title:hover {
|
||||
color: blog.$hover-text-color;
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
.item {
|
||||
display: grid;
|
||||
grid-template-columns: 40px 150px 1fr;
|
||||
grid-template-columns: 40px 200px 1fr;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
|
||||
.item:hover {
|
||||
color: blog.$hover-text-color;
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
gap: 5px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px dashed blog.$gray-text-color;
|
||||
color: blog.$normal-text-color;
|
||||
|
||||
i {
|
||||
font-size:28px;
|
||||
@@ -53,6 +54,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item:hover {
|
||||
color: var(--color-text);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
.blog-md {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 1vh 1vw;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 5px blog.$border-color;
|
||||
padding: 10px;
|
||||
overflow: auto;
|
||||
|
||||
.md-editor {
|
||||
@@ -43,11 +41,11 @@
|
||||
|
||||
.blog-copyright {
|
||||
width: 100%;
|
||||
background-color: #F8F8F8;
|
||||
padding: 1vh 1vw;
|
||||
background-color: var(--color-copyright-bg);
|
||||
|
||||
padding: 10px;
|
||||
border-left: 3px solid #FD2C17;
|
||||
font-size: blog.$small-font-size;
|
||||
color: #666666;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
@use "blog.variable.module.scss" as blog;
|
||||
|
||||
.blog-site-footer {
|
||||
padding: 1vh 0;
|
||||
padding: 10px 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1vh;
|
||||
gap: 10px;
|
||||
|
||||
span {
|
||||
font-size: blog.$small-font-size;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
.blog-container {
|
||||
// height: 100%;
|
||||
background-color: blog.$bg-color;
|
||||
background-color: var(--color-bg);
|
||||
padding: 0 5vw;
|
||||
|
||||
display: grid;
|
||||
@@ -32,9 +32,6 @@
|
||||
.blog-section {
|
||||
// height: 100%;
|
||||
min-height: 100vh;
|
||||
background-color: blog.$card-bg-color;
|
||||
border: 1px solid blog.$border-color;
|
||||
border-radius: blog.$border-radius;
|
||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12),
|
||||
0 3px 1px -2px rgba(0,0,0,0.06),
|
||||
0 1px 5px 0 rgba(0,0,0,0.12),
|
||||
@@ -52,14 +49,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.card-container {
|
||||
background-color: blog.$card-bg-color;
|
||||
border: 1px solid blog.$border-color;
|
||||
.card-item {
|
||||
background-color: var(--color-card-bg);
|
||||
border: 1px solid var(--color-border-bg);
|
||||
border-radius: blog.$border-radius;
|
||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12),
|
||||
0 3px 1px -2px rgba(0,0,0,0.06),
|
||||
0 1px 5px 0 rgba(0,0,0,0.12),
|
||||
0 -1px 0.5px 0 rgba(0,0,0,0.09);
|
||||
// box-shadow: 3px 3px 3px #CFCFCF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ $sub-title-font-size: 1rem;
|
||||
border: solid 1px blog.$normal-bg-color;
|
||||
border-radius: 15px;
|
||||
|
||||
color: white;
|
||||
color: var(--color-bg);
|
||||
font-size: blog.$small-font-size;
|
||||
font-family: "Times New Roman",serif;
|
||||
}
|
||||
@@ -74,7 +74,6 @@ $sub-title-font-size: 1rem;
|
||||
}
|
||||
|
||||
.blog-summary {
|
||||
// padding: 2vh 1vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -157,7 +156,7 @@ $sub-title-font-size: 1rem;
|
||||
}
|
||||
|
||||
.name:hover {
|
||||
color: blog.$hover-text-color;
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,8 +183,8 @@ $sub-title-font-size: 1rem;
|
||||
}
|
||||
|
||||
.item:hover {
|
||||
background-color: blog.$hover-bg-color;
|
||||
color: blog.$hover-text-color;
|
||||
background-color: var(--color-card-bg);
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +225,7 @@ $sub-title-font-size: 1rem;
|
||||
}
|
||||
|
||||
span:hover {
|
||||
color: blog.$hover-text-color;
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,7 +259,7 @@ $sub-title-font-size: 1rem;
|
||||
border-color: blog.$border-color;
|
||||
border-bottom-left-radius: blog.$border-radius;
|
||||
border-bottom-right-radius: blog.$border-radius;
|
||||
background-color: #F8F9FA;
|
||||
background-color: var(--color-scroll-card-bg);
|
||||
|
||||
text-align: center;
|
||||
|
||||
|
||||
129
src/styles/blog/blog.tools.module.scss
Normal file
129
src/styles/blog/blog.tools.module.scss
Normal file
@@ -0,0 +1,129 @@
|
||||
@use "blog.variable.module.scss" as blog;
|
||||
|
||||
.blog-tools {
|
||||
position: absolute;
|
||||
|
||||
.book-mark-link {
|
||||
border-bottom: none;
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: -2px;
|
||||
left: 20px;
|
||||
color: #222;
|
||||
font-size: 26px;
|
||||
transition: .3s;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.github-corner {
|
||||
border-bottom: none;
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
color: #222;
|
||||
font-size: 26px;
|
||||
transition: .3s;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.github-corner:hover .octo-arm {
|
||||
animation: octocat-wave 560ms ease-in-out
|
||||
}
|
||||
|
||||
@keyframes octocat-wave {
|
||||
0%, 100% {
|
||||
transform: rotate(0)
|
||||
}
|
||||
20%, 60% {
|
||||
transform: rotate(-25deg)
|
||||
}
|
||||
40%, 80% {
|
||||
transform: rotate(10deg)
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
.github-corner:hover .octo-arm {
|
||||
animation: none
|
||||
}
|
||||
.github-corner .octo-arm {
|
||||
animation: octocat-wave 560ms ease-in-out
|
||||
}
|
||||
}
|
||||
|
||||
#particles {
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.heart {
|
||||
position: fixed;
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: red;
|
||||
transform: rotate(45deg);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.heart:after, .heart:before {
|
||||
content: "";
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
background: inherit;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.heart:after {
|
||||
top: -5px;
|
||||
}
|
||||
|
||||
.heart:before {
|
||||
left: -5px;
|
||||
}
|
||||
|
||||
@keyframes move {
|
||||
100% {
|
||||
transform: translateY(-20px) rotate(45deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.blog-progress {
|
||||
/* Positioning */
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: blog.$theme-color;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.blog-progress::-webkit-progress-bar {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.blog-progress::-webkit-progress-value {
|
||||
background-color: blog.$theme-color;
|
||||
}
|
||||
|
||||
.blog-progress::-moz-progress-bar {
|
||||
background-color: blog.$theme-color;
|
||||
}
|
||||
|
||||
.theme-button {
|
||||
position: fixed;
|
||||
top: -2px;
|
||||
left: 50px;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
@@ -47,8 +47,9 @@ span, input {
|
||||
// 基础颜色
|
||||
--color-bg: #F5F5F5;
|
||||
--color-card-bg: #FFFFFF;
|
||||
--color-record-card-bg: #F5F5DC;
|
||||
--color-border-bg: #FFFFFF;
|
||||
--color-scroll-card-bg: #F8F9FA;
|
||||
--color-copyright-bg: #F8F8F8;
|
||||
--color-border-bg: #F5F5F5;
|
||||
--color-text: #000000;
|
||||
}
|
||||
|
||||
@@ -56,7 +57,8 @@ span, input {
|
||||
.dark {
|
||||
--color-bg: #000000;
|
||||
--color-card-bg: #000000;
|
||||
--color-record-card-bg: #4C4D4F;
|
||||
--color-scroll-card-bg: #4C4D4F;
|
||||
--color-copyright-bg: #4C4D4F;
|
||||
--color-border-bg: #4C4D4F;
|
||||
--color-text: #FFFFFF;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export default defineConfig({
|
||||
}
|
||||
}
|
||||
},
|
||||
base: '/blog',
|
||||
base: './',
|
||||
resolve: {
|
||||
// 配置路径别名
|
||||
alias: {
|
||||
|
||||
Reference in New Issue
Block a user