修复:启用评论组件
This commit is contained in:
24
docs/.vitepress/theme/MyLayout.vue
Normal file
24
docs/.vitepress/theme/MyLayout.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<Layout>
|
||||
<template #doc-after>
|
||||
<Comment v-if="(theme.commentConfig?.showComment ?? true) && (frontmatter?.showComment ?? true)" :commentConfig="theme.commentConfig" :key="md5(page.relativePath)" />
|
||||
</template>
|
||||
<template #layout-bottom>
|
||||
<Footer v-if="(theme.footerConfig?.showFooter ?? true) && (frontmatter?.showFooter ?? true)" />
|
||||
</template>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import { useData } from 'vitepress'
|
||||
import md5 from 'blueimp-md5'
|
||||
import Comment from './components/Comment.vue'
|
||||
import Footer from './components/Footer.vue'
|
||||
|
||||
const { Layout } = DefaultTheme
|
||||
const { page, theme, frontmatter } = useData()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
124
docs/.vitepress/theme/components/ArticleMetadata.vue
Normal file
124
docs/.vitepress/theme/components/ArticleMetadata.vue
Normal file
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<div class="meta-wrapper">
|
||||
<div class="meta-item">
|
||||
<span class="meta-icon author">
|
||||
<svg role="img" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><title>原创作者</title><path d="M858.5 763.6c-18.9-44.8-46.1-85-80.6-119.5-34.5-34.5-74.7-61.6-119.5-80.6-0.4-0.2-0.8-0.3-1.2-0.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-0.4 0.2-0.8 0.3-1.2 0.5-44.8 18.9-85 46-119.5 80.6-34.5 34.5-61.6 74.7-80.6 119.5C146.9 807.5 137 854 136 901.8c-0.1 4.5 3.5 8.2 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c0.1 4.4 3.6 7.8 8 7.8h60c4.5 0 8.1-3.7 8-8.2-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"></path></svg>
|
||||
</span>
|
||||
<span class="meta-content">
|
||||
<a :href="authorLink" title="进入作者主页">{{ author }}</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<span class="meta-icon date">
|
||||
<svg role="img" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><title>发布时间</title><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64z m0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path><path d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"></path></svg>
|
||||
</span>
|
||||
<time class="meta-content" :datetime="date.toISOString()" :title="dayjs().to(dayjs(date))">{{ date.toLocaleString('zh', {year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric'}) }}</time>
|
||||
</div>
|
||||
<div class="meta-item" v-if="theme.articleMetadataConfig?.showPv ?? false">
|
||||
<span class="meta-icon pv">
|
||||
<svg role="img" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><title>阅读数</title><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3-7.7 16.2-7.7 35.2 0 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766z"></path><path d="M508 336c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176z m0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg>
|
||||
</span>
|
||||
<span id="pv" class="meta-content"></span>
|
||||
</div>
|
||||
<div class="meta-item" v-if="showCategory">
|
||||
<span class="meta-icon category">
|
||||
<svg role="img" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><title>所属分类</title><path d="M928 444H820V330.4c0-17.7-14.3-32-32-32H473L355.7 186.2a8.15 8.15 0 0 0-5.5-2.2H96c-17.7 0-32 14.3-32 32v592c0 17.7 14.3 32 32 32h698c13 0 24.8-7.9 29.7-20l134-332c1.5-3.8 2.3-7.9 2.3-12 0-17.7-14.3-32-32-32zM136 256h188.5l119.6 114.4H748V444H238c-13 0-24.8 7.9-29.7 20L136 643.2V256z m635.3 512H159l103.3-256h612.4L771.3 768z"></path></svg>
|
||||
</span>
|
||||
<span class="meta-content">
|
||||
<span v-for="(category, index) in categories" :key="index">
|
||||
<a href="javascript:void(0);" @click="router.go('/archives.html?category=' + category)" target="_self" title="按分类归档">{{ category }}</a>
|
||||
<span v-if="index != categories.length - 1">, </span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<span class="meta-icon tag">
|
||||
<svg role="img" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><title>标签列表</title><path d="M483.2 790.3L861.4 412c1.7-1.7 2.5-4 2.3-6.3l-25.5-301.4c-0.7-7.8-6.8-13.9-14.6-14.6L522.2 64.3c-2.3-0.2-4.7 0.6-6.3 2.3L137.7 444.8a8.03 8.03 0 0 0 0 11.3l334.2 334.2c3.1 3.2 8.2 3.2 11.3 0z m62.6-651.7l224.6 19 19 224.6L477.5 694 233.9 450.5l311.9-311.9z m60.16 186.23a48 48 0 1 0 67.88-67.89 48 48 0 1 0-67.88 67.89zM889.7 539.8l-39.6-39.5a8.03 8.03 0 0 0-11.3 0l-362 361.3-237.6-237a8.03 8.03 0 0 0-11.3 0l-39.6 39.5a8.03 8.03 0 0 0 0 11.3l243.2 242.8 39.6 39.5c3.1 3.1 8.2 3.1 11.3 0l407.3-406.6c3.1-3.1 3.1-8.2 0-11.3z"></path></svg>
|
||||
</span>
|
||||
<span class="meta-content">
|
||||
<span v-for="(tag, index) in tags" :key="index">
|
||||
<a href="javascript:void(0);" @click="router.go('/archives.html?tag=' + tag)" target="_self" title="按标签归档">{{ tag }}</a>
|
||||
<span v-if="index != tags.length - 1">, </span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, toRefs } from 'vue'
|
||||
import { useData, useRouter } from 'vitepress'
|
||||
import dayjs from 'dayjs'
|
||||
import 'dayjs/locale/zh-cn'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
dayjs.locale('zh-cn')
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 定义文章属性
|
||||
const props = defineProps({
|
||||
article: Object,
|
||||
showCategory: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
|
||||
// 初始化文章元数据信息
|
||||
const { theme } = useData()
|
||||
const data = reactive({
|
||||
author: props.article?.author ?? theme.value.articleMetadataConfig.author,
|
||||
authorLink: props.article?.authorLink ?? theme.value.articleMetadataConfig.authorLink,
|
||||
date: new Date(props.article.date),
|
||||
categories: props.article?.categories ?? [],
|
||||
tags: props.article?.tags ?? [],
|
||||
showCategory: props.showCategory
|
||||
})
|
||||
const { author, authorLink, date, toDate, categories, tags, showCategory } = toRefs(data)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.meta-wrapper {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.meta-item {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
max-width: 240px;
|
||||
color: var(--vp-c-text-2);
|
||||
cursor: default;
|
||||
font-size: 14px;
|
||||
}
|
||||
.meta-item:not(:last-child) {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
.meta-icon, meta-content {
|
||||
display: inline-block;
|
||||
margin-right: .375rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.meta-icon {
|
||||
position: relative;
|
||||
bottom: 1.5px;
|
||||
}
|
||||
.meta-icon.date {
|
||||
bottom: 1.3px;
|
||||
}
|
||||
.meta-icon svg {
|
||||
fill: var(--vp-c-text-2);
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
.meta-content a {
|
||||
font-weight: 400;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
.meta-content a:hover {
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
</style>
|
49
docs/.vitepress/theme/components/Comment.vue
Normal file
49
docs/.vitepress/theme/components/Comment.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div id="comment-container"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, toRefs, onMounted } from 'vue'
|
||||
import { useData } from 'vitepress'
|
||||
import md5 from 'blueimp-md5'
|
||||
import Gitalk from 'gitalk'
|
||||
import '../styles/gitalk.css'
|
||||
|
||||
// 定义属性
|
||||
const props = defineProps({
|
||||
commentConfig: Object
|
||||
})
|
||||
|
||||
const data = reactive({
|
||||
type: props.commentConfig?.type ?? 'gitalk',
|
||||
options: props.commentConfig?.options ?? {}
|
||||
})
|
||||
const { type, options } = toRefs(data)
|
||||
|
||||
// 初始化评论组件配置
|
||||
const { page } = useData()
|
||||
let gitalk
|
||||
if (type.value && type.value == 'gitalk') {
|
||||
gitalk = new Gitalk({
|
||||
clientID: options.value.clientID,
|
||||
clientSecret: options.value.clientSecret,
|
||||
repo: options.value.repo,
|
||||
owner: options.value.owner,
|
||||
admin: options.value.admin,
|
||||
id: md5(page.value.relativePath),
|
||||
language: options.value.language,
|
||||
distractionFreeMode: options.value.distractionFreeMode,
|
||||
proxy: options.value.pagerDirection
|
||||
})
|
||||
}
|
||||
|
||||
// 渲染评论组件
|
||||
onMounted(() => {
|
||||
if (type.value && type.value == 'gitalk') {
|
||||
gitalk.render('comment-container')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
87
docs/.vitepress/theme/components/Footer.vue
Normal file
87
docs/.vitepress/theme/components/Footer.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<footer class="VPFooter">
|
||||
<div class="container">
|
||||
<p class="recordCode">
|
||||
<span class="icon">
|
||||
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>ICP备案号</title><path d="M778.24 163.84c-76.8-40.96-165.888-61.44-269.312-61.44s-192.512 20.48-269.312 61.44h-133.12l23.552 337.92c8.192 113.664 67.584 217.088 162.816 280.576l215.04 144.384 215.04-144.384c96.256-63.488 155.648-166.912 163.84-280.576l23.552-337.92H778.24z m47.104 333.824c-7.168 94.208-56.32 181.248-135.168 233.472l-181.248 120.832L327.68 731.136c-78.848-53.248-129.024-139.264-135.168-233.472L173.056 225.28h136.192v-26.624c58.368-23.552 124.928-34.816 199.68-34.816s141.312 12.288 199.68 34.816V225.28H844.8l-19.456 272.384z"></path><path d="M685.056 328.704v-46.08H455.68c2.048-4.096 6.144-9.216 11.264-15.36 5.12-7.168 9.216-12.288 11.264-15.36L419.84 240.64c-31.744 46.08-75.776 87.04-133.12 123.904 4.096 4.096 10.24 11.264 18.432 21.504l17.408 17.408c23.552-15.36 45.056-31.744 63.488-50.176 26.624 25.6 49.152 43.008 67.584 51.2-46.08 15.36-104.448 27.648-175.104 35.84 2.048 5.12 6.144 13.312 9.216 24.576 4.096 11.264 6.144 19.456 7.168 24.576l39.936-7.168v218.112H389.12V680.96h238.592v19.456h54.272V481.28H348.16c60.416-12.288 114.688-27.648 163.84-46.08 49.152 19.456 118.784 34.816 210.944 46.08 5.12-17.408 10.24-34.816 17.408-51.2-62.464-4.096-116.736-12.288-161.792-24.576 38.912-20.48 74.752-46.08 106.496-76.8z m-150.528 194.56h94.208v41.984h-94.208v-41.984z m0 78.848h94.208v41.984h-94.208v-41.984z m-144.384-78.848h94.208v41.984H390.144v-41.984z m0 78.848h94.208v41.984H390.144v-41.984zM424.96 326.656h182.272c-26.624 22.528-57.344 41.984-94.208 57.344-31.744-15.36-61.44-34.816-88.064-57.344z"></path></svg>
|
||||
</span>
|
||||
<span class="content">
|
||||
<a href="https://beian.miit.gov.cn" target="_blank">{{ theme.footerConfig.icpRecordCode }}</a>
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="theme.footerConfig.publicSecurityRecordCode" class="recordCode">
|
||||
<span class="icon">
|
||||
<img src="/img/badge/gongan.png" title="联网备案号">
|
||||
</span>
|
||||
<span class="content">
|
||||
<a :href="'http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=' + theme.footerConfig.publicSecurityRecordCode.replace('号', '').substring(theme.footerConfig.publicSecurityRecordCode.indexOf('备') + 1)" target="_blank">{{ theme.footerConfig.publicSecurityRecordCode }}</a>
|
||||
</span>
|
||||
</p>
|
||||
<p class="copyright" v-html="theme.footerConfig.copyright"></p>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useData } from 'vitepress'
|
||||
const { theme } = useData()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.VPFooter {
|
||||
position: relative;
|
||||
z-index: var(--vp-z-index-footer);
|
||||
border-top: 1px solid var(--vp-c-divider-light);
|
||||
padding: 25px 24px;
|
||||
background-color: var(--vp-c-bg);
|
||||
}
|
||||
.VPFooter.has-sidebar {
|
||||
display: none;
|
||||
}
|
||||
a:hover {
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.VPFooter {
|
||||
padding: 25px;
|
||||
}
|
||||
}
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
max-width: var(--vp-layout-max-width);
|
||||
text-align: center;
|
||||
}
|
||||
.recordCode,
|
||||
.copyright {
|
||||
line-height: 24px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
.recordCode { order: 2; }
|
||||
.copyright { order: 1; }
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
.recordCode span {
|
||||
display: inline-block;
|
||||
}
|
||||
.recordCode span:not(:last-child) {
|
||||
margin-right: .175rem;
|
||||
}
|
||||
.recordCode .icon svg {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
/*fill: var(--vp-c-text-2);*/
|
||||
fill: #5791ED;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
.recordCode .icon img {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
</style>
|
56
docs/.vitepress/theme/components/WordCloud.vue
Normal file
56
docs/.vitepress/theme/components/WordCloud.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div id="wordcloud-container"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, toRefs, onBeforeUnmount, watch } from 'vue'
|
||||
import { WordCloud, G2 } from '@antv/g2plot'
|
||||
import { debounce, useDark } from '@pureadmin/utils'
|
||||
|
||||
// 定义属性
|
||||
const props = defineProps({
|
||||
dataList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// 渲染WordCloud
|
||||
const theme = G2.getTheme('dark')
|
||||
G2.registerTheme('customize-dark', {
|
||||
...theme,
|
||||
background: 'transparent',
|
||||
})
|
||||
|
||||
const { isDark } = useDark()
|
||||
let wordCloud
|
||||
debounce(() => {
|
||||
wordCloud = new WordCloud("wordcloud-container", {
|
||||
data: props.dataList,
|
||||
wordField: 'name',
|
||||
weightField: 'value',
|
||||
colorField: 'name',
|
||||
wordStyle: {
|
||||
fontFamily: 'Verdana',
|
||||
fontSize: [14, 35],
|
||||
rotation: 0,
|
||||
},
|
||||
theme: isDark.value ? 'customize-dark' : 'light',
|
||||
// 返回值设置成一个 [0, 1) 区间内的值,
|
||||
// 可以让每次渲染的位置相同(前提是每次的宽高一致)。
|
||||
random: () => 0.5,
|
||||
})
|
||||
wordCloud.render()
|
||||
}, 20)()
|
||||
|
||||
watch(isDark, (value) => {
|
||||
value
|
||||
? wordCloud?.update({ theme: 'customize-dark' })
|
||||
: wordCloud?.update({ theme: 'light' })
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
wordCloud.destroy()
|
||||
})
|
||||
</script>
|
307
docs/.vitepress/theme/components/dynamic/Archive.vue
Normal file
307
docs/.vitepress/theme/components/dynamic/Archive.vue
Normal file
@@ -0,0 +1,307 @@
|
||||
<template>
|
||||
<div class="timeline-wrap">
|
||||
<!-- 时间轴头部 -->
|
||||
<div class="timeline-header">
|
||||
<a-tag
|
||||
v-if="$category"
|
||||
class="content"
|
||||
closable
|
||||
@close="router.go('/archives.html')"
|
||||
>
|
||||
<template #icon>
|
||||
<svg class="icon" role="img" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><title>所属分类</title><path d="M928 444H820V330.4c0-17.7-14.3-32-32-32H473L355.7 186.2a8.15 8.15 0 0 0-5.5-2.2H96c-17.7 0-32 14.3-32 32v592c0 17.7 14.3 32 32 32h698c13 0 24.8-7.9 29.7-20l134-332c1.5-3.8 2.3-7.9 2.3-12 0-17.7-14.3-32-32-32zM136 256h188.5l119.6 114.4H748V444H238c-13 0-24.8 7.9-29.7 20L136 643.2V256z m635.3 512H159l103.3-256h612.4L771.3 768z"></path></svg>
|
||||
</template>
|
||||
{{ $category }} (共 {{ $articleData.length }} 篇)
|
||||
</a-tag>
|
||||
<a-tag
|
||||
v-else-if="$tag"
|
||||
class="content"
|
||||
closable
|
||||
@close="router.go('/archives.html')"
|
||||
>
|
||||
<template #icon>
|
||||
<svg class="icon" role="img" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><title>标签列表</title><path d="M483.2 790.3L861.4 412c1.7-1.7 2.5-4 2.3-6.3l-25.5-301.4c-0.7-7.8-6.8-13.9-14.6-14.6L522.2 64.3c-2.3-0.2-4.7 0.6-6.3 2.3L137.7 444.8a8.03 8.03 0 0 0 0 11.3l334.2 334.2c3.1 3.2 8.2 3.2 11.3 0z m62.6-651.7l224.6 19 19 224.6L477.5 694 233.9 450.5l311.9-311.9z m60.16 186.23a48 48 0 1 0 67.88-67.89 48 48 0 1 0-67.88 67.89zM889.7 539.8l-39.6-39.5a8.03 8.03 0 0 0-11.3 0l-362 361.3-237.6-237a8.03 8.03 0 0 0-11.3 0l-39.6 39.5a8.03 8.03 0 0 0 0 11.3l243.2 242.8 39.6 39.5c3.1 3.1 8.2 3.1 11.3 0l407.3-406.6c3.1-3.1 3.1-8.2 0-11.3z"></path></svg>
|
||||
</template>
|
||||
{{ $tag }} (共 {{ $articleData.length }} 篇)
|
||||
</a-tag>
|
||||
<a-tag
|
||||
v-else-if="$year"
|
||||
class="content"
|
||||
closable
|
||||
@close="router.go('/archives.html')"
|
||||
>
|
||||
<template #icon>
|
||||
<svg class="icon" role="img" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M832 64H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32z m-260 72h96v209.9L621.5 312 572 347.4V136z m220 752H232V136h280v296.9c0 3.3 1 6.6 3 9.3a15.9 15.9 0 0 0 22.3 3.7l83.8-59.9 81.4 59.4c2.7 2 6 3.1 9.4 3.1 8.8 0 16-7.2 16-16V136h64v752z"></path></svg>
|
||||
</template>
|
||||
{{ $year }} (共 {{ $articleData.length }} 篇)
|
||||
</a-tag>
|
||||
<a-tag
|
||||
v-else
|
||||
class="content"
|
||||
>
|
||||
<template #icon>
|
||||
<svg class="icon" role="img" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M832 64H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V96c0-17.7-14.3-32-32-32z m-260 72h96v209.9L621.5 312 572 347.4V136z m220 752H232V136h280v296.9c0 3.3 1 6.6 3 9.3a15.9 15.9 0 0 0 22.3 3.7l83.8-59.9 81.4 59.4c2.7 2 6 3.1 9.4 3.1 8.8 0 16-7.2 16-16V136h64v752z"></path></svg>
|
||||
</template>
|
||||
共 {{ articleData.length }} 篇,未完待续······
|
||||
</a-tag>
|
||||
</div>
|
||||
|
||||
<!-- 时间轴主体 -->
|
||||
<div class="timeline-item" v-for="(item, year) in archiveData">
|
||||
<div class="year">
|
||||
<img class="chinese-zodiac" @click="router.go('/archives.html?year=' + year.replace('年', ''))" :src="'/img/svg/chinese-zodiac/' + getChineseZodiac(year.replace('年', '')) + '.svg'" :title="getChineseZodiac(year.replace('年', ''))" alt="生肖">
|
||||
<span>{{ year }}</span>
|
||||
</div>
|
||||
<div class="timeline-item-content">
|
||||
<div v-for="(articles, month) in item">
|
||||
<span class="month">
|
||||
{{ month }}
|
||||
</span>
|
||||
<div class="articles">
|
||||
<span v-for="article in articles" class="article">
|
||||
<svg v-if="article.categories.includes('Bug万象集')" @click="router.go('/archives.html?category=' + article.categories[0])" role="img" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="arco-icon arco-icon-bug" stroke-width="4" stroke-linecap="butt" stroke-linejoin="miter" style="color: #f53f3f;"><title>Bug万象集</title><path d="M24 42c-6.075 0-11-4.925-11-11V18h22v13c0 6.075-4.925 11-11 11Zm0 0V23m11 4h8M5 27h8M7 14a4 4 0 0 0 4 4h26a4 4 0 0 0 4-4m0 28v-.5a6.5 6.5 0 0 0-6.5-6.5M7 42v-.5a6.5 6.5 0 0 1 6.5-6.5M17 14a7 7 0 1 1 14 0"></path></svg>
|
||||
|
||||
<svg v-else-if="article.categories.includes('杂碎逆袭史')" @click="router.go('/archives.html?category=' + article.categories[0])" role="img" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="arco-icon arco-icon-bulb" stroke-width="4" stroke-linecap="butt" stroke-linejoin="miter" style="color: #ff7d00;"><title>杂碎逆袭史</title><path d="M17 42h14m6-24c0 2.823-.9 5.437-2.43 7.568-1.539 2.147-3.185 4.32-3.77 6.897l-.623 2.756A1 1 0 0 1 29.2 36H18.8a1 1 0 0 1-.976-.779l-.624-2.756c-.584-2.576-2.23-4.75-3.77-6.897A12.94 12.94 0 0 1 11 18c0-7.18 5.82-13 13-13s13 5.82 13 13Z"></path></svg>
|
||||
|
||||
<svg v-else-if="article.categories.includes('方案春秋志')" @click="router.go('/archives.html?category=' + article.categories[0])" role="img" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" class="arco-icon arco-icon-code" stroke-width="4" stroke-linecap="butt" stroke-linejoin="miter" style="color: #165dff;"><title>方案春秋志</title><path d="M16.734 12.686 5.42 24l11.314 11.314m14.521-22.628L42.57 24 31.255 35.314M27.2 6.28l-6.251 35.453"></path></svg>
|
||||
|
||||
<svg v-else @click="router.go('/archives.html?category=' + article.categories[0])" role="img" viewBox="0 0 48 48" fill="none" stroke="currentColor" xmlns="http://www.w3.org/2000/svg" class="arco-icon arco-icon-bookmark" stroke-width="4" stroke-linecap="butt" stroke-linejoin="miter" style="color: #00b42a;"><path d="M16 16h16M16 24h8"></path><path d="M24 41H8V6h32v17"></path><path d="M30 29h11v13l-5.5-3.5L30 42V29Z"></path></svg>
|
||||
<a :href="article.path" class="title" target="_blank">{{ article.title }}</a>
|
||||
<br>
|
||||
<ArticleMetadata :article="article" :showCategory="false" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="main"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watchEffect } from 'vue'
|
||||
import { useRouter } from 'vitepress'
|
||||
import articleData from '../../../../../article-data.json'
|
||||
import { formatDate, getQueryParam } from '../../utils.ts'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 文章原始数据和归档数据
|
||||
let $articleData
|
||||
let archiveData
|
||||
|
||||
// 要筛选的分类、标签、年份
|
||||
let $category
|
||||
let $tag
|
||||
let $year
|
||||
|
||||
initTimeline()
|
||||
|
||||
/**
|
||||
* 初始化时间轴
|
||||
*/
|
||||
function initTimeline() {
|
||||
$articleData = []
|
||||
archiveData = {}
|
||||
|
||||
// 如果URL路径有category或tag或year参数, 默认筛选出指定category或tag或year的文章数据
|
||||
// 例如: /archives.html?category=Bug万象集
|
||||
// 例如: /archives.html?tag=JVM
|
||||
// 例如: /archives.html?year=2020
|
||||
$category = getQueryParam('category')
|
||||
$tag = getQueryParam('tag')
|
||||
$year = getQueryParam('year')
|
||||
if ($category && $category.trim() != '') {
|
||||
for (let i = 0; i < articleData.length; i++) {
|
||||
let article = articleData[i]
|
||||
if (article.categories && article.categories.includes($category)) {
|
||||
$articleData.push(article)
|
||||
}
|
||||
}
|
||||
} else if ($tag && $tag.trim() != '') {
|
||||
for (let i = 0; i < articleData.length; i++) {
|
||||
let article = articleData[i]
|
||||
if (article.tags && article.tags.includes($tag)) {
|
||||
$articleData.push(article)
|
||||
}
|
||||
}
|
||||
} else if ($year && $year.trim() != '') {
|
||||
for (let i = 0; i < articleData.length; i++) {
|
||||
let article = articleData[i]
|
||||
if (article.date && new Date(article.date).getFullYear() == $year) {
|
||||
$articleData.push(article)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$articleData.push(...articleData)
|
||||
}
|
||||
|
||||
// 文章数据归档处理
|
||||
// 1.对文章数据进行降序排序
|
||||
$articleData.sort((a, b) => b.date.localeCompare(a.date))
|
||||
// 2.按年、月进行归档
|
||||
for (let i = 0; i < $articleData.length; i++) {
|
||||
const article = $articleData[i]
|
||||
let year = (new Date(article.date).getFullYear()) + '年'
|
||||
let month = (new Date(article.date).getMonth() + 1) + '月'
|
||||
|
||||
if (!archiveData[year]) {
|
||||
archiveData[year] = {}
|
||||
}
|
||||
if (!(archiveData[year][month])) {
|
||||
archiveData[year][month] = []
|
||||
}
|
||||
|
||||
archiveData[year][month].push(article)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取生肖
|
||||
*/
|
||||
function getChineseZodiac(year) {
|
||||
switch(year % 12){
|
||||
case 0:
|
||||
return 'monkey'
|
||||
case 1:
|
||||
return 'rooster'
|
||||
case 2:
|
||||
return 'dog'
|
||||
case 3:
|
||||
return 'pig'
|
||||
case 4:
|
||||
return 'rat'
|
||||
case 5:
|
||||
return 'ox'
|
||||
case 6:
|
||||
return 'tiger'
|
||||
case 7:
|
||||
return 'rabbit'
|
||||
case 8:
|
||||
return 'dragon'
|
||||
case 9:
|
||||
return 'snake'
|
||||
case 10:
|
||||
return 'horse'
|
||||
case 11:
|
||||
return 'goat'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.arco-tag) {
|
||||
background-color: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
:deep(.arco-icon) {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.timeline-wrap {
|
||||
margin-top: 18px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-header {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-header .icon {
|
||||
fill: var(--vp-c-text-2);
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-header .content {
|
||||
position: relative;
|
||||
left: -17px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-item {
|
||||
padding: 0 0 0 20px;
|
||||
border-left: 1px solid #5D9DF0;
|
||||
line-height: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-item:not(:last-child) {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-item .year {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.6em;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-item .year .chinese-zodiac {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: -10.5px;
|
||||
top: -1px;
|
||||
background: #fff;
|
||||
border: 1px solid #84b9e5;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-item .timeline-item-time {
|
||||
margin-bottom: 12px;
|
||||
width: 200px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-item .month {
|
||||
padding: 8px 0 8px 0;
|
||||
display: block;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-item .timeline-item-content {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-item .articles {
|
||||
line-height: 1;
|
||||
padding-top: 7px;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-item .articles .article {
|
||||
display: block;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-item .articles svg {
|
||||
position: absolute;
|
||||
left: -27.5px;
|
||||
top: 3.5px;
|
||||
background: #fff;
|
||||
border: 1px solid #84b9e5;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.timeline-wrap .timeline-item .articles .article span {
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.vp-doc a {
|
||||
font-weight: 400;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
.vp-doc a:hover {
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
</style>
|
262
docs/.vitepress/theme/components/dynamic/Tag.vue
Normal file
262
docs/.vitepress/theme/components/dynamic/Tag.vue
Normal file
File diff suppressed because one or more lines are too long
15
docs/.vitepress/theme/index.ts
Normal file
15
docs/.vitepress/theme/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import MyLayout from "./MyLayout.vue"
|
||||
import './styles/vars.css'
|
||||
import './styles/custom.css'
|
||||
import ArticleMetadata from './components/ArticleMetadata.vue'
|
||||
import WordCloud from './components/WordCloud.vue'
|
||||
|
||||
export default {
|
||||
...DefaultTheme,
|
||||
Layout: MyLayout,
|
||||
enhanceApp({ app }) {
|
||||
app.component('ArticleMetadata', ArticleMetadata)
|
||||
app.component('WordCloud', WordCloud)
|
||||
}
|
||||
}
|
5
docs/.vitepress/theme/styles/custom.css
Normal file
5
docs/.vitepress/theme/styles/custom.css
Normal file
@@ -0,0 +1,5 @@
|
||||
.vp-doc h2 {
|
||||
margin: 15px 0 16px;
|
||||
padding-top: 10px;
|
||||
border-top: none;
|
||||
}
|
1489
docs/.vitepress/theme/styles/gitalk.css
Normal file
1489
docs/.vitepress/theme/styles/gitalk.css
Normal file
File diff suppressed because it is too large
Load Diff
31
docs/.vitepress/theme/styles/vars.css
Normal file
31
docs/.vitepress/theme/styles/vars.css
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Component: Home
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
:root {
|
||||
--vp-home-hero-name-color: transparent;
|
||||
--vp-home-hero-name-background: -webkit-linear-gradient(
|
||||
315deg,
|
||||
#42d392 25%,
|
||||
#647eff
|
||||
);
|
||||
|
||||
--vp-home-hero-image-background-image: linear-gradient(
|
||||
-45deg,
|
||||
#42d392 50%,
|
||||
#47caff 50%
|
||||
);
|
||||
--vp-home-hero-image-filter: blur(40px);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
:root {
|
||||
--vp-home-hero-image-filter: blur(56px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
:root {
|
||||
--vp-home-hero-image-filter: blur(72px);
|
||||
}
|
||||
}
|
23
docs/.vitepress/theme/utils.ts
Normal file
23
docs/.vitepress/theme/utils.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 格式化时间
|
||||
* @param date 待格式化时间
|
||||
* @returns 格式化后的时间(YYYY/MM/dd AM hh:mm)
|
||||
*/
|
||||
export function formatDate(date) {
|
||||
const formatDate = new Date(date)
|
||||
return formatDate.toLocaleString('zh', {year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric'})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取URL路径中的指定参数
|
||||
* @param paramName 参数名
|
||||
* @returns 参数值
|
||||
*/
|
||||
export function getQueryParam(paramName) {
|
||||
const reg = new RegExp("(^|&)"+ paramName +"=([^&]*)(&|$)")
|
||||
let value = decodeURIComponent(window.location.search.substr(1)).match(reg)
|
||||
if (value != null) {
|
||||
return unescape(value[2])
|
||||
}
|
||||
return null
|
||||
}
|
Reference in New Issue
Block a user