@sugarat/theme 0.1.49 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/node.d.ts +41 -1
  2. package/node.js +24 -20
  3. package/package.json +24 -24
  4. package/src/components/BlogAlert.vue +17 -17
  5. package/src/components/BlogApp.vue +91 -50
  6. package/src/components/BlogArticleAnalyze.vue +56 -57
  7. package/src/components/BlogAuthor.vue +55 -0
  8. package/src/components/BlogComment.vue +53 -50
  9. package/src/components/BlogDocCover.vue +4 -4
  10. package/src/components/BlogFooter.vue +131 -0
  11. package/src/components/BlogFriendLink.vue +40 -31
  12. package/src/components/BlogHomeBanner.vue +22 -16
  13. package/src/components/BlogHomeInfo.vue +4 -0
  14. package/src/components/BlogHomeOverview.vue +20 -20
  15. package/src/components/BlogHomeTags.vue +49 -40
  16. package/src/components/BlogHotArticle.vue +43 -36
  17. package/src/components/BlogImagePreview.vue +7 -5
  18. package/src/components/BlogItem.vue +42 -43
  19. package/src/components/BlogList.vue +46 -42
  20. package/src/components/BlogPopover.vue +41 -39
  21. package/src/components/BlogRecommendArticle.vue +58 -48
  22. package/src/components/BlogSearch.vue +143 -145
  23. package/src/components/UserWorks.vue +214 -210
  24. package/src/composables/config/blog.ts +14 -5
  25. package/src/composables/config/index.ts +74 -31
  26. package/src/constants/svg.ts +11 -2
  27. package/src/index.ts +1 -2
  28. package/src/node.ts +2 -2
  29. package/src/styles/gongan.png +0 -0
  30. package/src/styles/scss/global.scss +0 -5
  31. package/src/utils/client/index.ts +9 -8
  32. package/src/utils/node/genFeed.ts +8 -7
  33. package/src/utils/node/index.ts +8 -6
  34. package/src/utils/node/mdPlugins.ts +29 -22
  35. package/src/utils/node/theme.ts +16 -13
  36. package/src/utils/node/vitePlugins.ts +7 -6
  37. package/types/vue-shim.d.ts +1 -1
@@ -1,22 +1,3 @@
1
- <template>
2
- <div class="card overview-data">
3
- <div class="overview-item">
4
- <span class="count">{{ notHiddenArticles.length }}</span>
5
- <span class="label">博客文章</span>
6
- </div>
7
- <div class="split"></div>
8
- <div class="overview-item">
9
- <span class="count">+{{ currentMonth?.length }}</span>
10
- <span class="label">本月更新</span>
11
- </div>
12
- <div class="split"></div>
13
- <div class="overview-item">
14
- <span class="count">+{{ currentWeek?.length }}</span>
15
- <span class="label">本周更新</span>
16
- </div>
17
- </div>
18
- </template>
19
-
20
1
  <script lang="ts" setup>
21
2
  import { computed } from 'vue'
22
3
  import { isCurrentWeek } from '../utils/client'
@@ -24,7 +5,7 @@ import { useArticles } from '../composables/config/blog'
24
5
 
25
6
  const docs = useArticles()
26
7
  const notHiddenArticles = computed(() => {
27
- return docs.value.filter((v) => v.meta?.publish !== false)
8
+ return docs.value.filter(v => v.meta?.publish !== false)
28
9
  })
29
10
  const nowMonth = new Date().getMonth()
30
11
  const nowYear = new Date().getFullYear()
@@ -43,6 +24,25 @@ const currentWeek = computed(() => {
43
24
  })
44
25
  </script>
45
26
 
27
+ <template>
28
+ <div class="card overview-data">
29
+ <div class="overview-item">
30
+ <span class="count">{{ notHiddenArticles.length }}</span>
31
+ <span class="label">博客文章</span>
32
+ </div>
33
+ <div class="split" />
34
+ <div class="overview-item">
35
+ <span class="count">+{{ currentMonth?.length }}</span>
36
+ <span class="label">本月更新</span>
37
+ </div>
38
+ <div class="split" />
39
+ <div class="overview-item">
40
+ <span class="count">+{{ currentWeek?.length }}</span>
41
+ <span class="label">本周更新</span>
42
+ </div>
43
+ </div>
44
+ </template>
45
+
46
46
  <style lang="scss" scoped>
47
47
  .card {
48
48
  position: relative;
@@ -1,38 +1,3 @@
1
- <template>
2
- <div class="card tags" v-if="tags.length" data-pagefind-ignore="all">
3
- <!-- 头部 -->
4
- <div class="card-header">
5
- <span class="title svg-icon"><svg t="1695048840129" class="icon" viewBox="0 0 1024 1024" version="1.1"
6
- xmlns="http://www.w3.org/2000/svg" p-id="4290" width="200" height="200">
7
- <path
8
- d="M810.88 245.888a118.432 118.432 0 1 0 0 236.864 118.432 118.432 0 0 0 0-236.864z m-151.008 118.432a151.008 151.008 0 1 1 302.016 0 151.008 151.008 0 0 1-302.016 0z"
9
- fill="#D3D3D3" p-id="4291"></path>
10
- <path
11
- d="M774.08 565.6l61.76-160.64c6.4-16.64 2.56-35.84-10.24-48.64l-151.04-151.04c-12.8-12.8-31.68-16.64-48.64-10.24l-160.64 61.76c-12.16 4.8-23.36 11.84-32.64 21.12l-355.2 355.2c-17.92 17.92-17.92 46.72 0 64.32l256 256c17.92 17.92 46.72 17.92 64.32 0l355.2-355.2c9.28-9.28 16.32-20.16 21.12-32.64z m-159.36-149.12c-22.08-22.08-22.08-57.6 0-79.68 22.08-22.08 57.6-22.08 79.68 0 22.08 22.08 22.08 57.6 0 79.68-22.08 21.76-57.92 21.76-79.68 0z"
12
- fill="#FCD53F" p-id="4292"></path>
13
- <path
14
- d="M654.4 320.48c14.4 0 28.8 5.44 39.68 16.64 22.08 22.08 22.08 57.6 0 79.68-10.88 10.88-25.28 16.64-39.68 16.64-14.4 0-28.8-5.44-39.68-16.64-22.08-22.08-22.08-57.6 0-79.68 10.88-11.2 25.28-16.64 39.68-16.64z m0-30.08c-23.04 0-44.8 8.96-61.12 25.28a86.72 86.72 0 0 0 0 122.24c16.32 16.32 38.08 25.28 61.12 25.28s44.8-8.96 61.12-25.28a86.72 86.72 0 0 0 0-122.24c-16.32-16.32-38.08-25.28-61.12-25.28z"
15
- fill="#F8312F" p-id="4293"></path>
16
- <path
17
- d="M676.16 348.032c8.992 0 16.288 7.296 16.288 16.288a118.144 118.144 0 0 0 64.288 105.44h0.064c22.24 11.296 47.36 15.264 71.68 11.84a16.288 16.288 0 0 1 4.48 32.32 154.24 154.24 0 0 1-90.848-15.04 150.72 150.72 0 0 1-82.24-134.56c0-8.992 7.296-16.288 16.288-16.288z"
18
- fill="#D3D3D3" p-id="4294"></path>
19
- </svg> 标签</span>
20
- <el-tag v-if="activeTag.label" :type="(activeTag.type as any)" :effect="colorMode" closable @close="handleCloseTag">
21
- {{ activeTag.label }}
22
- </el-tag>
23
- </div>
24
- <!-- 标签列表 -->
25
- <ul class="tag-list">
26
- <li v-for="(tag, idx) in tags" :key="tag">
27
- <el-tag :type="tagType[idx % tagType.length]" @click="handleTagClick(tag, tagType[idx % tagType.length])"
28
- :effect="colorMode">
29
- {{ tag }}
30
- </el-tag>
31
- </li>
32
- </ul>
33
- </div>
34
- </template>
35
-
36
1
  <script lang="ts" setup>
37
2
  import { computed, watch } from 'vue'
38
3
  import { ElTag } from 'element-plus'
@@ -47,7 +12,7 @@ import {
47
12
  const docs = useArticles()
48
13
 
49
14
  const tags = computed(() => {
50
- return [...new Set(docs.value.map((v) => v.meta.tag || []).flat(3))]
15
+ return [...new Set(docs.value.map(v => v.meta.tag || []).flat(3))]
51
16
  })
52
17
 
53
18
  const activeTag = useActiveTag()
@@ -60,18 +25,18 @@ const colorMode = computed(() => (isDark.value ? 'light' : 'dark'))
60
25
 
61
26
  const tagType: any = ['', 'info', 'success', 'warning', 'danger']
62
27
  const currentPage = useCurrentPageNum()
28
+ const router = useRouter()
63
29
 
64
- const handleCloseTag = () => {
30
+ function handleCloseTag() {
65
31
  activeTag.value.label = ''
66
32
  activeTag.value.type = ''
67
33
  currentPage.value = 1
68
34
  router.go(`${window.location.origin}${router.route.path}`)
69
35
  }
70
36
 
71
- const router = useRouter()
72
37
  const location = useBrowserLocation()
73
38
 
74
- const handleTagClick = (tag: string, type: string) => {
39
+ function handleTagClick(tag: string, type: string) {
75
40
  if (tag === activeTag.value.label) {
76
41
  handleCloseTag()
77
42
  return
@@ -99,6 +64,49 @@ watch(
99
64
  )
100
65
  </script>
101
66
 
67
+ <template>
68
+ <div v-if="tags.length" class="card tags" data-pagefind-ignore="all">
69
+ <!-- 头部 -->
70
+ <div class="card-header">
71
+ <span class="title svg-icon"><svg
72
+ t="1695048840129" class="icon" viewBox="0 0 1024 1024" version="1.1"
73
+ xmlns="http://www.w3.org/2000/svg" p-id="4290" width="200" height="200"
74
+ >
75
+ <path
76
+ d="M810.88 245.888a118.432 118.432 0 1 0 0 236.864 118.432 118.432 0 0 0 0-236.864z m-151.008 118.432a151.008 151.008 0 1 1 302.016 0 151.008 151.008 0 0 1-302.016 0z"
77
+ fill="#D3D3D3" p-id="4291"
78
+ />
79
+ <path
80
+ d="M774.08 565.6l61.76-160.64c6.4-16.64 2.56-35.84-10.24-48.64l-151.04-151.04c-12.8-12.8-31.68-16.64-48.64-10.24l-160.64 61.76c-12.16 4.8-23.36 11.84-32.64 21.12l-355.2 355.2c-17.92 17.92-17.92 46.72 0 64.32l256 256c17.92 17.92 46.72 17.92 64.32 0l355.2-355.2c9.28-9.28 16.32-20.16 21.12-32.64z m-159.36-149.12c-22.08-22.08-22.08-57.6 0-79.68 22.08-22.08 57.6-22.08 79.68 0 22.08 22.08 22.08 57.6 0 79.68-22.08 21.76-57.92 21.76-79.68 0z"
81
+ fill="#FCD53F" p-id="4292"
82
+ />
83
+ <path
84
+ d="M654.4 320.48c14.4 0 28.8 5.44 39.68 16.64 22.08 22.08 22.08 57.6 0 79.68-10.88 10.88-25.28 16.64-39.68 16.64-14.4 0-28.8-5.44-39.68-16.64-22.08-22.08-22.08-57.6 0-79.68 10.88-11.2 25.28-16.64 39.68-16.64z m0-30.08c-23.04 0-44.8 8.96-61.12 25.28a86.72 86.72 0 0 0 0 122.24c16.32 16.32 38.08 25.28 61.12 25.28s44.8-8.96 61.12-25.28a86.72 86.72 0 0 0 0-122.24c-16.32-16.32-38.08-25.28-61.12-25.28z"
85
+ fill="#F8312F" p-id="4293"
86
+ />
87
+ <path
88
+ d="M676.16 348.032c8.992 0 16.288 7.296 16.288 16.288a118.144 118.144 0 0 0 64.288 105.44h0.064c22.24 11.296 47.36 15.264 71.68 11.84a16.288 16.288 0 0 1 4.48 32.32 154.24 154.24 0 0 1-90.848-15.04 150.72 150.72 0 0 1-82.24-134.56c0-8.992 7.296-16.288 16.288-16.288z"
89
+ fill="#D3D3D3" p-id="4294"
90
+ />
91
+ </svg> 标签</span>
92
+ <ElTag v-if="activeTag.label" :type="activeTag.type as any" :effect="colorMode" closable @close="handleCloseTag">
93
+ {{ activeTag.label }}
94
+ </ElTag>
95
+ </div>
96
+ <!-- 标签列表 -->
97
+ <ul class="tag-list">
98
+ <li v-for="(tag, idx) in tags" :key="tag">
99
+ <ElTag
100
+ :type="tagType[idx % tagType.length]" :effect="colorMode"
101
+ @click="handleTagClick(tag, tagType[idx % tagType.length])"
102
+ >
103
+ {{ tag }}
104
+ </ElTag>
105
+ </li>
106
+ </ul>
107
+ </div>
108
+ </template>
109
+
102
110
  <style lang="scss" scoped>
103
111
  .card {
104
112
  position: relative;
@@ -145,4 +153,5 @@ watch(
145
153
  margin-bottom: 10px;
146
154
  cursor: pointer;
147
155
  }
148
- }</style>
156
+ }
157
+ </style>
@@ -1,40 +1,11 @@
1
- <template>
2
- <div class="card recommend" v-if="recommendList.length || empty" data-pagefind-ignore="all">
3
- <!-- 头部 -->
4
- <div class="card-header">
5
- <span class="title" v-html="title"></span>
6
- <el-button v-if="showChangeBtn" size="small" type="primary" text @click="changePage">{{ nextText }}</el-button>
7
- </div>
8
- <!-- 文章列表 -->
9
- <ol class="recommend-container" v-if="currentWikiData.length">
10
- <li v-for="(v, idx) in currentWikiData" :key="v.route">
11
- <!-- 序号 -->
12
- <i class="num">{{ idx + 1 }}</i>
13
- <!-- 简介 -->
14
- <div class="des">
15
- <!-- title -->
16
- <el-link type="info" class="title" :href="withBase(v.route)">{{
17
- v.meta.title
18
- }}</el-link>
19
- <!-- 描述信息 -->
20
- <div class="suffix">
21
- <!-- 日期 -->
22
- <span class="tag">{{ formatShowDate(v.meta.date) }}</span>
23
- </div>
24
- </div>
25
- </li>
26
- </ol>
27
- <div class="empty-text" v-else>{{ empty }}</div>
28
- </div>
29
- </template>
30
-
31
1
  <script lang="ts" setup>
32
- import { ref, computed } from 'vue'
2
+ import { computed, ref } from 'vue'
33
3
  import { ElButton, ElLink } from 'element-plus'
34
4
  import { withBase } from 'vitepress'
35
5
  import { useArticles, useBlogConfig } from '../composables/config/blog'
36
6
  import { formatShowDate } from '../utils/client'
37
7
  import { fireSVG } from '../constants/svg'
8
+
38
9
  const { hotArticle } = useBlogConfig()
39
10
  const title = computed(() => hotArticle?.title || (`<span class="svg-icon">${fireSVG}</span>` + ' 精选文章'))
40
11
  const nextText = computed(() => hotArticle?.nextText || '换一组')
@@ -44,15 +15,15 @@ const empty = computed(() => hotArticle?.empty ?? '暂无精选内容')
44
15
  const docs = useArticles()
45
16
 
46
17
  const recommendList = computed(() => {
47
- const data = docs.value.filter((v) => v.meta.sticky)
18
+ const data = docs.value.filter(v => v.meta.sticky)
48
19
  data.sort((a, b) => b.meta.sticky! - a.meta.sticky!)
49
20
  return [...data]
50
21
  })
51
22
 
52
23
  const currentPage = ref(1)
53
- const changePage = () => {
54
- const newIdx =
55
- currentPage.value % Math.ceil(recommendList.value.length / pageSize.value)
24
+ function changePage() {
25
+ const newIdx
26
+ = currentPage.value % Math.ceil(recommendList.value.length / pageSize.value)
56
27
  currentPage.value = newIdx + 1
57
28
  }
58
29
 
@@ -67,6 +38,42 @@ const showChangeBtn = computed(() => {
67
38
  })
68
39
  </script>
69
40
 
41
+ <template>
42
+ <div v-if="recommendList.length || empty" class="card recommend" data-pagefind-ignore="all">
43
+ <!-- 头部 -->
44
+ <div class="card-header">
45
+ <span class="title" v-html="title" />
46
+ <ElButton v-if="showChangeBtn" size="small" type="primary" text @click="changePage">
47
+ {{ nextText }}
48
+ </ElButton>
49
+ </div>
50
+ <!-- 文章列表 -->
51
+ <ol v-if="currentWikiData.length" class="recommend-container">
52
+ <li v-for="(v, idx) in currentWikiData" :key="v.route">
53
+ <!-- 序号 -->
54
+ <i class="num">{{ idx + 1 }}</i>
55
+ <!-- 简介 -->
56
+ <div class="des">
57
+ <!-- title -->
58
+ <ElLink type="info" class="title" :href="withBase(v.route)">
59
+ {{
60
+ v.meta.title
61
+ }}
62
+ </ElLink>
63
+ <!-- 描述信息 -->
64
+ <div class="suffix">
65
+ <!-- 日期 -->
66
+ <span class="tag">{{ formatShowDate(v.meta.date) }}</span>
67
+ </div>
68
+ </div>
69
+ </li>
70
+ </ol>
71
+ <div v-else class="empty-text">
72
+ {{ empty }}
73
+ </div>
74
+ </div>
75
+ </template>
76
+
70
77
  <style lang="scss" scoped>
71
78
  .card {
72
79
  position: relative;
@@ -170,4 +177,4 @@ const showChangeBtn = computed(() => {
170
177
  font-size: 14px;
171
178
  text-align: center;
172
179
  }
173
- </style>
180
+ </style>
@@ -10,15 +10,15 @@ const previewImageInfo = reactive<{ url: string; list: string[]; idx: number }>(
10
10
  idx: 0
11
11
  }
12
12
  )
13
- const previewImage = (e: Event) => {
13
+ function previewImage(e: Event) {
14
14
  const target = e.target as HTMLElement
15
15
  const currentTarget = e.currentTarget as HTMLElement
16
16
  if (target.tagName.toLowerCase() === 'img') {
17
17
  const imgs = currentTarget.querySelectorAll<HTMLImageElement>(
18
18
  '.content-container .main img'
19
19
  )
20
- const idx = Array.from(imgs).findIndex((el) => el === target)
21
- const urls = Array.from(imgs).map((el) => el.src)
20
+ const idx = Array.from(imgs).findIndex(el => el === target)
21
+ const urls = Array.from(imgs).map(el => el.src)
22
22
 
23
23
  const url = target.getAttribute('src')
24
24
  previewImageInfo.url = url!
@@ -45,6 +45,8 @@ onUnmounted(() => {
45
45
  </script>
46
46
 
47
47
  <template>
48
- <ElImageViewer :infinite="false" hide-on-click-modal teleported @close="show = false" :url-list="previewImageInfo.list"
49
- :initial-index="previewImageInfo.idx" v-if="show" />
48
+ <ElImageViewer
49
+ v-if="show" :infinite="false" hide-on-click-modal teleported :url-list="previewImageInfo.list"
50
+ :initial-index="previewImageInfo.idx" @close="show = false"
51
+ />
50
52
  </template>
@@ -1,51 +1,9 @@
1
- <template>
2
- <a class="blog-item" :href="withBase(route)">
3
- <i class="pin" v-if="!!pin"></i>
4
- <!-- 标题 -->
5
- <p class="title" v-if="inMobile">{{ title }}</p>
6
- <div class="info-container">
7
- <!-- 左侧信息 -->
8
- <div class="info-part">
9
- <!-- 标题 -->
10
- <p class="title" v-if="!inMobile">{{ title }}</p>
11
- <!-- 简短描述 -->
12
- <p class="description" v-if="!descriptionHTML && !!description">
13
- {{ description }}
14
- </p>
15
- <template v-if="descriptionHTML">
16
- <div class="description-html" v-html="descriptionHTML"></div>
17
- </template>
18
- <!-- 底部补充描述 -->
19
- <div class="badge-list" v-if="!inMobile">
20
- <span class="split" v-if="author">{{ author }}</span>
21
- <span class="split">{{ showTime }}</span>
22
- <span class="split" v-if="tag?.length">{{ tag.join(' · ') }}</span>
23
- </div>
24
- </div>
25
- <!-- 右侧封面图 -->
26
- <div
27
- v-if="cover"
28
- class="cover-img"
29
- :style="`background-image: url(${cover});`"
30
- ></div>
31
- </div>
32
- <!-- 底部补充描述 -->
33
- <div class="badge-list" v-if="inMobile">
34
- <span class="split" v-if="author">{{ author }}</span>
35
- <span class="split">{{ showTime }}</span>
36
- <span class="split" v-if="tag?.length">{{ tag.join(' · ') }}</span>
37
- </div>
38
- </a>
39
- </template>
40
-
41
1
  <script lang="ts" setup>
42
2
  import { withBase } from 'vitepress'
43
3
  import { computed } from 'vue'
44
4
  import { useWindowSize } from '@vueuse/core'
45
5
  import { formatShowDate } from '../utils/client'
46
6
 
47
- const { width } = useWindowSize()
48
- const inMobile = computed(() => width.value <= 500)
49
7
  const props = defineProps<{
50
8
  route: string
51
9
  title: string
@@ -58,7 +16,8 @@ const props = defineProps<{
58
16
  cover?: string | boolean
59
17
  pin?: number
60
18
  }>()
61
-
19
+ const { width } = useWindowSize()
20
+ const inMobile = computed(() => width.value <= 500)
62
21
  const showTime = computed(() => {
63
22
  return formatShowDate(props.date)
64
23
  })
@@ -77,6 +36,46 @@ const showTime = computed(() => {
77
36
  // }
78
37
  </script>
79
38
 
39
+ <template>
40
+ <a class="blog-item" :href="withBase(route)">
41
+ <i v-if="!!pin" class="pin" />
42
+ <!-- 标题 -->
43
+ <p v-if="inMobile" class="title">{{ title }}</p>
44
+ <div class="info-container">
45
+ <!-- 左侧信息 -->
46
+ <div class="info-part">
47
+ <!-- 标题 -->
48
+ <p v-if="!inMobile" class="title">{{ title }}</p>
49
+ <!-- 简短描述 -->
50
+ <p v-if="!descriptionHTML && !!description" class="description">
51
+ {{ description }}
52
+ </p>
53
+ <template v-if="descriptionHTML">
54
+ <div class="description-html" v-html="descriptionHTML" />
55
+ </template>
56
+ <!-- 底部补充描述 -->
57
+ <div v-if="!inMobile" class="badge-list">
58
+ <span v-if="author" class="split">{{ author }}</span>
59
+ <span class="split">{{ showTime }}</span>
60
+ <span v-if="tag?.length" class="split">{{ tag.join(' · ') }}</span>
61
+ </div>
62
+ </div>
63
+ <!-- 右侧封面图 -->
64
+ <div
65
+ v-if="cover"
66
+ class="cover-img"
67
+ :style="`background-image: url(${cover});`"
68
+ />
69
+ </div>
70
+ <!-- 底部补充描述 -->
71
+ <div v-if="inMobile" class="badge-list">
72
+ <span v-if="author" class="split">{{ author }}</span>
73
+ <span class="split">{{ showTime }}</span>
74
+ <span v-if="tag?.length" class="split">{{ tag.join(' · ') }}</span>
75
+ </div>
76
+ </a>
77
+ </template>
78
+
80
79
  <style lang="scss" scoped>
81
80
  .blog-item .pin {
82
81
  position: absolute;
@@ -1,49 +1,16 @@
1
- <template>
2
- <ul data-pagefind-ignore="all">
3
- <li v-for="v in currentWikiData" :key="v.route">
4
- <blog-item
5
- :route="v.route"
6
- :title="v.meta.title"
7
- :description="v.meta.description"
8
- :description-h-t-m-l="v.meta.descriptionHTML"
9
- :date="v.meta.date"
10
- :tag="v.meta.tag"
11
- :cover="v.meta.cover"
12
- :author="v.meta.author || globalAuthor"
13
- :pin="v.meta.top"
14
- />
15
- </li>
16
- </ul>
17
- <!-- 解决element-ui bug -->
18
- <ClientOnly>
19
- <div class="el-pagination-wrapper">
20
- <el-pagination
21
- v-if="wikiList.length >= pageSize"
22
- small
23
- background
24
- :default-current-page="1"
25
- :current-page="currentPage"
26
- @update:current-page="handleUpdatePageNum"
27
- :page-size="pageSize"
28
- :total="filterData.length"
29
- layout="prev, pager, next, jumper"
30
- />
31
- </div>
32
- </ClientOnly>
33
- </template>
34
1
  <script setup lang="ts">
35
2
  import { computed, watch } from 'vue'
36
3
  import { ElPagination } from 'element-plus'
37
4
  import { useData, useRouter } from 'vitepress'
38
5
  import { useBrowserLocation } from '@vueuse/core'
39
- import BlogItem from './BlogItem.vue'
40
6
  import {
41
- useArticles,
42
7
  useActiveTag,
8
+ useArticles,
43
9
  useBlogConfig,
44
10
  useCurrentPageNum
45
11
  } from '../composables/config/blog'
46
- import { Theme } from '../composables/config'
12
+ import type { Theme } from '../composables/config'
13
+ import BlogItem from './BlogItem.vue'
47
14
 
48
15
  const { theme, frontmatter } = useData<Theme.Config>()
49
16
  const globalAuthor = computed(() => theme.value.blog?.author || '')
@@ -54,22 +21,23 @@ const activeTag = useActiveTag()
54
21
  const activeTagLabel = computed(() => activeTag.value.label)
55
22
 
56
23
  const wikiList = computed(() => {
57
- const topList = docs.value.filter((v) => !v.meta.hidden && !!v.meta.top)
24
+ const topList = docs.value.filter(v => !v.meta.hidden && !!v.meta.top)
58
25
  topList.sort((a, b) => {
59
26
  const aTop = a?.meta?.top
60
27
  const bTop = b?.meta.top
61
28
  return Number(aTop) - Number(bTop)
62
29
  })
63
30
  const data = docs.value.filter(
64
- (v) => v.meta.date && v.meta.title && !v.meta.top && !v.meta.hidden
31
+ v => v.meta.date && v.meta.title && !v.meta.top && !v.meta.hidden
65
32
  )
66
33
  data.sort((a, b) => +new Date(b.meta.date) - +new Date(a.meta.date))
67
34
  return topList.concat(data)
68
35
  })
69
36
 
70
37
  const filterData = computed(() => {
71
- if (!activeTagLabel.value) return wikiList.value
72
- return wikiList.value.filter((v) =>
38
+ if (!activeTagLabel.value)
39
+ return wikiList.value
40
+ return wikiList.value.filter(v =>
73
41
  v.meta?.tag?.includes(activeTagLabel.value)
74
42
  )
75
43
  })
@@ -88,7 +56,7 @@ const currentWikiData = computed(() => {
88
56
  const router = useRouter()
89
57
  const location = useBrowserLocation()
90
58
  const queryPageNumKey = 'pageNum'
91
- const handleUpdatePageNum = (current: number) => {
59
+ function handleUpdatePageNum(current: number) {
92
60
  if (currentPage.value === current) {
93
61
  return
94
62
  }
@@ -108,7 +76,8 @@ watch(
108
76
  const { searchParams } = new URL(location.value.href)
109
77
  if (searchParams.has(queryPageNumKey)) {
110
78
  currentPage.value = Number(searchParams.get(queryPageNumKey))
111
- } else {
79
+ }
80
+ else {
112
81
  currentPage.value = 1
113
82
  }
114
83
  }
@@ -118,6 +87,41 @@ watch(
118
87
  }
119
88
  )
120
89
  </script>
90
+
91
+ <template>
92
+ <ul data-pagefind-ignore="all">
93
+ <li v-for="v in currentWikiData" :key="v.route">
94
+ <BlogItem
95
+ :route="v.route"
96
+ :title="v.meta.title"
97
+ :description="v.meta.description"
98
+ :description-h-t-m-l="v.meta.descriptionHTML"
99
+ :date="v.meta.date"
100
+ :tag="v.meta.tag"
101
+ :cover="v.meta.cover"
102
+ :author="v.meta.author || globalAuthor"
103
+ :pin="v.meta.top"
104
+ />
105
+ </li>
106
+ </ul>
107
+ <!-- 解决element-ui bug -->
108
+ <ClientOnly>
109
+ <div class="el-pagination-wrapper">
110
+ <ElPagination
111
+ v-if="wikiList.length >= pageSize"
112
+ small
113
+ background
114
+ :default-current-page="1"
115
+ :current-page="currentPage"
116
+ :page-size="pageSize"
117
+ :total="filterData.length"
118
+ layout="prev, pager, next, jumper"
119
+ @update:current-page="handleUpdatePageNum"
120
+ />
121
+ </div>
122
+ </ClientOnly>
123
+ </template>
124
+
121
125
  <style lang="scss" scoped>
122
126
  .el-pagination-wrapper {
123
127
  :deep(.el-pagination li.is-active.number) {
@@ -1,39 +1,7 @@
1
- <template>
2
- <div class="theme-blog-popover" v-show="show" data-pagefind-ignore="all">
3
- <div class="header">
4
- <div class="title-wrapper">
5
- <el-icon size="20px"><Flag /></el-icon>
6
- <span class="title">{{ popoverProps?.title }}</span>
7
- </div>
8
- <el-icon @click="show = false" class="close-icon" size="20px"
9
- ><CircleCloseFilled
10
- /></el-icon>
11
- </div>
12
- <div class="body content" v-if="bodyContent.length">
13
- <PopoverValue v-for="(v, idx) in bodyContent" :key="idx" :item="v">
14
- {{ v.type !== 'image' ? v.content : '' }}
15
- </PopoverValue>
16
- <hr v-if="footerContent.length" />
17
- </div>
18
- <div class="footer content">
19
- <PopoverValue v-for="(v, idx) in footerContent" :key="idx" :item="v">
20
- {{ v.type !== 'image' ? v.content : '' }}
21
- </PopoverValue>
22
- </div>
23
- </div>
24
- <div
25
- class="theme-blog-popover-close"
26
- v-show="!show && (popoverProps?.reopen ?? true) && popoverProps?.title"
27
- @click="show = true"
28
- >
29
- <el-icon size="20px"><Flag /></el-icon>
30
- </div>
31
- </template>
32
-
33
1
  <script lang="ts" setup>
34
- import { ElIcon, ElButton } from 'element-plus'
35
- import { Flag, CircleCloseFilled } from '@element-plus/icons-vue'
36
- import { computed, onMounted, ref, h } from 'vue'
2
+ import { ElButton, ElIcon } from 'element-plus'
3
+ import { CircleCloseFilled, Flag } from '@element-plus/icons-vue'
4
+ import { computed, h, onMounted, ref } from 'vue'
37
5
  import type { BlogPopover } from '@sugarat/theme'
38
6
  import { parseStringStyle } from '@vue/shared'
39
7
  import { useBlogConfig } from '../composables/config/blog'
@@ -77,10 +45,8 @@ onMounted(() => {
77
45
  }
78
46
  })
79
47
 
80
- const PopoverValue = (
81
- props: { key: number; item: BlogPopover.Value },
82
- { slots }: any
83
- ) => {
48
+ function PopoverValue(props: { key: number; item: BlogPopover.Value },
49
+ { slots }: any) {
84
50
  const { key, item } = props
85
51
  if (item.type === 'title') {
86
52
  return h(
@@ -130,6 +96,42 @@ const PopoverValue = (
130
96
  }
131
97
  </script>
132
98
 
99
+ <template>
100
+ <div v-show="show" class="theme-blog-popover" data-pagefind-ignore="all">
101
+ <div class="header">
102
+ <div class="title-wrapper">
103
+ <ElIcon size="20px">
104
+ <Flag />
105
+ </ElIcon>
106
+ <span class="title">{{ popoverProps?.title }}</span>
107
+ </div>
108
+ <ElIcon class="close-icon" size="20px" @click="show = false">
109
+ <CircleCloseFilled />
110
+ </ElIcon>
111
+ </div>
112
+ <div v-if="bodyContent.length" class="body content">
113
+ <PopoverValue v-for="(v, idx) in bodyContent" :key="idx" :item="v">
114
+ {{ v.type !== 'image' ? v.content : '' }}
115
+ </PopoverValue>
116
+ <hr v-if="footerContent.length">
117
+ </div>
118
+ <div class="footer content">
119
+ <PopoverValue v-for="(v, idx) in footerContent" :key="idx" :item="v">
120
+ {{ v.type !== 'image' ? v.content : '' }}
121
+ </PopoverValue>
122
+ </div>
123
+ </div>
124
+ <div
125
+ v-show="!show && (popoverProps?.reopen ?? true) && popoverProps?.title"
126
+ class="theme-blog-popover-close"
127
+ @click="show = true"
128
+ >
129
+ <ElIcon size="20px">
130
+ <Flag />
131
+ </ElIcon>
132
+ </div>
133
+ </template>
134
+
133
135
  <style lang="scss" scoped>
134
136
  .theme-blog-popover {
135
137
  width: 258px;