valaxy-theme-hairy 0.0.10 → 0.0.11

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.
@@ -1,17 +1,30 @@
1
1
  <script lang="ts" setup>
2
2
  import { useFrontmatter } from 'valaxy'
3
- import { computed } from 'vue'
3
+ import { computed, inject, nextTick, ref } from 'vue'
4
+ import { useRouter } from 'vue-router'
4
5
  import { toArr } from '../utils'
5
6
  import { useCurrentCategory } from '../hooks/useCategory'
6
7
 
7
8
  const frontmatter = useFrontmatter()
8
9
  const paths = computed(() => toArr(frontmatter.value.categories).filter(Boolean) as string[])
9
10
  const category = useCurrentCategory(paths)
10
- const posts = computed(() => category.value.posts || [])
11
+ const posts = computed(() => {
12
+ const result = category.value.posts || []
13
+ return result.sort((a, b) => (a.date || 1) > (b.date || 1) ? 1 : -1)
14
+ })
15
+ const router = useRouter()
16
+
17
+ const active = inject('HairyUserTab:active', ref(''))
11
18
 
12
19
  function isCurrent(title = '') {
13
20
  return frontmatter.value.title === title
14
21
  }
22
+
23
+ async function changePost(path = '') {
24
+ router.push(path)
25
+ await nextTick()
26
+ active.value = 'aside'
27
+ }
15
28
  </script>
16
29
 
17
30
  <template>
@@ -20,7 +33,7 @@ function isCurrent(title = '') {
20
33
  On this Series
21
34
  </div>
22
35
  <ul class="va-toc relative z-1">
23
- <a v-for="(item, index) of posts" :key="index" class="va-toc-item" @click="$router.push(item.path || '')">
36
+ <a v-for="(item, index) of posts" :key="index" class="va-toc-item" @click="changePost(item.path)">
24
37
  <a class="outline-link" :class="[isCurrent(item.title) && 'active']">{{ index + 1 }}.{{ item.title }}</a>
25
38
  </a>
26
39
  </ul>
@@ -1,24 +1,51 @@
1
1
  <script lang="ts" setup>
2
- import type { Ref } from 'vue'
3
- import { computed } from 'vue'
2
+ import { computed, defineProps, ref, withDefaults } from 'vue'
4
3
  import type { Post } from 'valaxy'
5
4
  import { usePostList } from 'valaxy'
5
+ import { usePostLayout } from '../hooks/usePostLayout'
6
6
 
7
7
  const props = withDefaults(defineProps<{
8
8
  type?: string
9
9
  posts?: Post[]
10
+ curPage?: number
11
+ pagination?: boolean
10
12
  }>(), {
13
+ curPage: 1,
14
+ pagination: false,
11
15
  })
16
+ const layout = usePostLayout()
12
17
 
13
- const routes = usePostList() as any as Ref<Post[]>
14
- const posts = computed(() => props.posts || routes.value)
18
+ const pageSize = ref(7)
19
+ const routes = usePostList({ type: props.type || '' })
20
+ const posts = computed<any[]>(() => props.posts || routes.value)
21
+ const pagePosts = computed(() => posts.value.slice((props.curPage - 1) * pageSize.value, props.curPage * pageSize.value))
22
+ const displayedPosts = computed(() => props.pagination ? pagePosts.value : posts.value)
15
23
  </script>
16
24
 
17
25
  <template>
18
- <ul class="divide-y divide-gray-200 dark:divide-gray-700">
19
- <Transition v-for="post, i in posts" :key="i" name="fade">
20
- <HairyArticleText :post="post" />
21
- </Transition>
22
- </ul>
26
+ <HairyPostImageList v-if="layout.includes('image')" :posts="displayedPosts" />
27
+ <HairyPostTextsList v-else :posts="displayedPosts" />
28
+ <ValaxyPagination v-if="pagination" :cur-page="curPage" :page-size="pageSize" :total="posts.length" />
23
29
  </template>
24
30
 
31
+ <style lang="scss">
32
+ .pagination {
33
+ font-size: 16px;
34
+ }
35
+
36
+ .pagination .prev.active,
37
+ .pagination .next.active,
38
+ .pagination .page-number.active {
39
+ font-weight: normal;
40
+ background: transparent;
41
+ color: var(--hy-c-primary);
42
+ cursor: default;
43
+ }
44
+
45
+ .pagination .prev:hover,
46
+ .pagination .next:hover,
47
+ .pagination .page-number:hover {
48
+ color: var(--va-c-bg);
49
+ background: rgba(143, 230, 213, 0.8);
50
+ }
51
+ </style>
@@ -0,0 +1,23 @@
1
+ <script lang="ts" setup>
2
+ import type { Ref } from 'vue'
3
+ import { computed } from 'vue'
4
+ import type { Post } from 'valaxy'
5
+ import { usePostList } from 'valaxy'
6
+
7
+ const props = withDefaults(defineProps<{
8
+ type?: string
9
+ posts?: Post[]
10
+ }>(), {})
11
+
12
+ const routes = usePostList() as any as Ref<Post[]>
13
+ const posts = computed(() => props.posts || routes.value)
14
+ </script>
15
+
16
+ <template>
17
+ <ul class="divide-y divide-gray-200 dark:divide-gray-700">
18
+ <Transition v-for="post, i in posts" :key="i" name="fade">
19
+ <HairyArticleText :post="post" />
20
+ </Transition>
21
+ </ul>
22
+ </template>
23
+
@@ -1,8 +1,23 @@
1
1
  <script lang="ts" setup>
2
- import { useCategory, usePostList, useTag } from 'valaxy'
3
- const category = useCategory()
2
+ import { usePostList, useTag } from 'valaxy'
3
+ import { computed } from 'vue'
4
+ import { toArr } from '../utils'
4
5
  const posts = usePostList()
5
6
  const tags = useTag()
7
+
8
+ const total = computed(() => {
9
+ const categories = posts.value.map(v => toArr(v.categories || [])).filter(v => v.length)
10
+ const maps: string[] = []
11
+ for (const category of categories) {
12
+ let caches: string[] = []
13
+ for (const iterator of category) {
14
+ caches.push(iterator)
15
+ maps.push(caches.join('-'))
16
+ }
17
+ caches = []
18
+ }
19
+ return new Set(maps).size
20
+ })
6
21
  </script>
7
22
 
8
23
  <template>
@@ -11,7 +26,7 @@ const tags = useTag()
11
26
  文章
12
27
  </HairyUserStats>
13
28
  <div class="w-1px bg-gray bg-opacity-50" />
14
- <HairyUserStats :count="category.total" @click="$router.push('/categories/')">
29
+ <HairyUserStats :count="total" @click="$router.push('/categories/')">
15
30
  分类
16
31
  </HairyUserStats>
17
32
  <div class="w-1px bg-gray bg-opacity-50" />
@@ -2,9 +2,9 @@
2
2
  import { ElTabPane, ElTabs } from 'element-plus/es/components/tabs/index'
3
3
  import 'element-plus/es/components/tabs/style/index'
4
4
  import 'element-plus/es/components/tab-pane/style/index'
5
- import { ref } from 'vue'
6
-
5
+ import { provide, ref } from 'vue'
7
6
  const active = ref('aside')
7
+ provide('HairyUserTab:active', active)
8
8
  </script>
9
9
 
10
10
  <template>
@@ -27,17 +27,21 @@ export function useYearArchives() {
27
27
  const [year, month] = [days.format('YYYY'), days.format('MM')]
28
28
  if (!maps[year])
29
29
  maps[year] = {}
30
- if (!maps[year][month]) { maps[year][month] = { count: 1, posts: [post] } }
30
+ if (!maps[year][month]) { maps[year][month] = { count: 1, posts: [post as any] } }
31
31
  else {
32
32
  maps[year][month].count++
33
- maps[year][month].posts.push(post)
33
+ maps[year][month].posts.unshift(post as any)
34
34
  }
35
35
  }
36
36
  for (const [year, months] of Object.entries(maps)) {
37
37
  for (const [month, { count, posts }] of Object.entries(months))
38
- items.push({ year, month, count, posts })
38
+ items.unshift({ year, month, count, posts })
39
39
  }
40
- return items
40
+ return items.sort((a, b) => {
41
+ const aTime = `${a.year}-${a.month}`
42
+ const bTime = `${b.year}-${b.month}`
43
+ return bTime > aTime ? 1 : -1
44
+ })
41
45
  })
42
46
  return archives
43
47
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valaxy-theme-hairy",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "packageManager": "pnpm@7.5.0",
5
5
  "author": {
6
6
  "email": "wwu710632@gmail.com",
@@ -33,7 +33,6 @@ const post = computed(() => months.value.flatMap(item => item.posts))
33
33
  {{ month }}月
34
34
  </HairyBreadcrumbItem>
35
35
  </HairyBreadcrumb>
36
-
37
36
  <el-timeline>
38
37
  <el-timeline-item
39
38
  v-for="(item, index) in post"
@@ -26,15 +26,21 @@ const posts = usePostList()
26
26
  size="large"
27
27
  >
28
28
  <div class="activity inline-flex items-center">
29
- <HairyLink @click="$router.push(getArchiveLink(activity.year))">
29
+ <HairyLink class="text-size-8" @click="$router.push(getArchiveLink(activity.year))">
30
30
  {{ activity.year }}
31
31
  </HairyLink>
32
- <span class="text-gray-5 text-size-5 mx-2">/</span>
33
- <HairyLink @click="$router.push(getArchiveLink(activity.year, activity.month))">
32
+ <span class="text-gray-5 mx-2">/</span>
33
+ <HairyLink class="text-size-8" @click="$router.push(getArchiveLink(activity.year, activity.month))">
34
34
  {{ activity.month }}
35
35
  </HairyLink>
36
36
  <span class="text-gray-5 text-size-5 ml-1">({{ activity.count }}篇)</span>
37
37
  </div>
38
+ <HairyTimelinePostItem v-for="(item, index) in activity.posts.slice(0, 2)" :key="index" :post="item" />
39
+ <div v-if="activity.posts.length > 2">
40
+ <HairyLink @click="$router.push(getArchiveLink(activity.year))">
41
+ ....
42
+ </HairyLink>
43
+ </div>
38
44
  </el-timeline-item>
39
45
  </el-timeline>
40
46
  </template>
@@ -22,18 +22,20 @@ const router = useRouter()
22
22
 
23
23
  const paths = computed(() => props.categories.split('/').filter(Boolean))
24
24
  const current = useCurrentCategory(paths)
25
-
26
25
  const posts = useCategoryPost(paths)
27
26
 
28
27
  const i18n = useI18n()
29
28
 
29
+ const s = '/'
30
+
30
31
  const getBreadcrumbPath = (index: number) => {
31
- if (paths.value[index] === paths.value[paths.value.length - 1])
32
+ const paths = props.categories.split('/').filter(Boolean)
33
+ if (paths[index] === paths[paths.length - 1])
32
34
  return ''
33
- return `/categories/${paths.value.slice(0, index)}`
35
+ return `/categories/${paths.slice(0, index + 1).join('/')}`
34
36
  }
35
37
  const displayCategory = (key: string) => {
36
- router.push({ path: `/categories/${[...paths.value, key].join('/')}` })
38
+ router.push({ path: `/categories/${[key, ...paths.value].reverse().join('/')}` })
37
39
  }
38
40
  </script>
39
41
 
@@ -45,10 +47,11 @@ const displayCategory = (key: string) => {
45
47
  <HairyBreadcrumbItem :to="paths.length && '/categories/' || ''">
46
48
  全部
47
49
  </HairyBreadcrumbItem>
48
- <HairyBreadcrumbItem v-for="(key, index) in paths" :key="key" :to="getBreadcrumbPath(index)">
50
+ <HairyBreadcrumbItem v-for="(key, index) in categories.split(s)" :key="key" :to="getBreadcrumbPath(index)">
49
51
  {{ i18n.t(key) }}
50
52
  </HairyBreadcrumbItem>
51
53
  </HairyBreadcrumb>
54
+
52
55
  <div class="grid__view dark:text-gray-3 flex-wrap">
53
56
  <template v-for="([key, item]) in current.children" :key="key">
54
57
  <div
package/pages/index.vue CHANGED
@@ -1,11 +1,5 @@
1
- <script lang="ts" setup>
2
- import { usePostLayout } from '../hooks/usePostLayout'
3
- const layout = usePostLayout()
4
- </script>
5
-
6
1
  <template>
7
- <HairyPostImageList v-if="layout.includes('image')" />
8
- <HairyPostList v-else />
2
+ <HairyPostList :pagination="true" />
9
3
  </template>
10
4
 
11
5
  <route lang="yaml">
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ defineProps<{ page: string }>()
3
+ </script>
4
+
5
+ <template>
6
+ <HairyPostList :pagination="true" :cur-page="parseInt(page)" />
7
+ </template>
8
+
9
+ <route lang="yaml">
10
+ meta:
11
+ layout: home
12
+ </route>
@@ -4,7 +4,7 @@ import { useRouter } from 'vue-router'
4
4
  const router = useRouter()
5
5
 
6
6
  const { tags, getTagStyle } = useTags({
7
- primary: 'red',
7
+ primary: '#1bc9a6',
8
8
  })
9
9
 
10
10
  const displayTag = (tag: string) => {
@@ -17,7 +17,7 @@ const displayTag = (tag: string) => {
17
17
  <div text="center" class="text-size-2.5em pt-10 mb-5">
18
18
  目前共计 {{ Array.from(tags).length }} 个标签
19
19
  </div>
20
- <div text="center">
20
+ <div text="center" class="max-w-7xl flex flex-wrap justify-center items-center gap-2">
21
21
  <a v-for="[key, tag] in Array.from(tags).sort()" :key="key" class="post-tag cursor-pointer" :style="getTagStyle(tag.count)" p="1" @click="displayTag(key.toString())">
22
22
  {{ key }}
23
23
  </a>
@@ -29,3 +29,13 @@ const displayTag = (tag: string) => {
29
29
  meta:
30
30
  layout: tags
31
31
  </route>
32
+
33
+ <style lang="scss" scoped>
34
+ a {
35
+ color: var(--yun-tag-color);
36
+ &:hover {
37
+ --un-text-opacity: 1;
38
+ color: var(--hy-c-primary-dark);
39
+ }
40
+ }
41
+ </style>