valaxy-theme-hairy 0.2.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. package/client/index.ts +1 -0
  2. package/components/HairyBody.vue +15 -17
  3. package/components/HairyComment.vue +33 -0
  4. package/components/HairyContainer.vue +13 -0
  5. package/components/{HairyUserPopup.vue → HairyDrawer.vue} +14 -13
  6. package/components/HairyFooter.vue +12 -9
  7. package/components/HairyHeader.vue +10 -9
  8. package/components/HairyImage.vue +2 -1
  9. package/components/HairyImageGroup.vue +12 -16
  10. package/components/HairyNavbar.vue +56 -0
  11. package/components/{HairyPostList.vue → HairyPosts.vue} +3 -3
  12. package/components/{HairyNavSearch.vue → HairySearch.vue} +23 -87
  13. package/components/{HairyUserCard.vue → HairySidebar.vue} +4 -4
  14. package/components/{HairyUserTab.vue → HairyTabbar.vue} +27 -11
  15. package/components/PageTags.vue +48 -0
  16. package/components/ValaxyMain.vue +3 -3
  17. package/components/navbar/HairyNav.vue +16 -0
  18. package/components/navbar/HairyNavExpand.vue +12 -0
  19. package/components/navbar/HairyNavItem.vue +35 -0
  20. package/components/navbar/HairyNavbarBackground.vue +7 -0
  21. package/components/navbar/HairyNavbarSearch.vue +8 -0
  22. package/components/{HairyNavTitle.vue → navbar/HairyNavbarTitle.vue} +5 -3
  23. package/components/navbar/HairyNavbarToggleDark.vue +22 -0
  24. package/components/{HairyBreadcrumb.vue → parts/HairyBreadcrumb.vue} +1 -1
  25. package/components/{HairyBreadcrumbItem.vue → parts/HairyBreadcrumbItem.vue} +1 -4
  26. package/components/{lib/fish.js → parts/HairyFootFish.js} +5 -7
  27. package/components/parts/HairyFootFish.vue +38 -0
  28. package/components/{HairyPostTitle.vue → parts/HairyHeadHero.vue} +6 -5
  29. package/components/{HairyWaves.vue → parts/HairyHeadWaves.vue} +5 -5
  30. package/components/parts/HairyImageGlobal.vue +51 -0
  31. package/components/{HairyImageViewer.vue → parts/HairyImageViewer.vue} +4 -3
  32. package/components/parts/HairyLink.vue +21 -0
  33. package/components/{HairyMenu.vue → parts/HairyMenu.vue} +2 -1
  34. package/components/{HairyMenuItem.vue → parts/HairyMenuItem.vue} +11 -4
  35. package/components/parts/HairyOutline.vue +99 -0
  36. package/components/parts/HairyOutlineItem.vue +48 -0
  37. package/components/{HairySocialLinks.vue → parts/HairySocialLinks.vue} +2 -2
  38. package/components/{HairyTimelinePostItem.vue → parts/HairyTimelineContent.vue} +7 -8
  39. package/components/parts/HairyUserNav.vue +95 -0
  40. package/components/{article-layout → posts}/HairyArticleImage.vue +18 -19
  41. package/components/{article-layout → posts}/HairyArticleSeries.vue +8 -5
  42. package/components/{article-layout → posts}/HairyArticleText.vue +11 -4
  43. package/components/posts/HairyPostFooter.vue +15 -0
  44. package/components/{article-layout → posts}/HairyPostImageList.vue +4 -5
  45. package/components/{article-layout → posts}/HairyPostTextsList.vue +0 -1
  46. package/components/posts/HairyPostToggleLayout.vue +36 -0
  47. package/components/third/HairyAlgoliaSearch.vue +17 -0
  48. package/components/third/HairyFuseSearch.vue +10 -0
  49. package/components/third/HairyFuseSearchDialog.vue +32 -0
  50. package/components/third/HairyFuseSearchDropdown.vue +77 -0
  51. package/components/third/HairyFuseSearchFooter.vue +28 -0
  52. package/components/third/HairyFuseSearchHeader.vue +30 -0
  53. package/components/third/HairyFuseSearchHit.vue +52 -0
  54. package/components/third/HairySearchBtnDisplay.vue +29 -0
  55. package/components/third/HairySearchBtnInput.vue +20 -0
  56. package/components/third/HairySearchBtnKeys.vue +19 -0
  57. package/components/{HairyCarousel.vue → third/HairySwiperCarousel.vue} +6 -6
  58. package/{hooks/useYearArchives.ts → composables/archives.ts} +4 -3
  59. package/composables/category.ts +43 -0
  60. package/composables/config.ts +11 -0
  61. package/composables/dark.ts +13 -0
  62. package/composables/fuse.ts +60 -0
  63. package/composables/index.ts +8 -0
  64. package/composables/layout.ts +16 -0
  65. package/composables/outline.ts +49 -0
  66. package/composables/tags.ts +36 -0
  67. package/layouts/archive-month.vue +13 -0
  68. package/layouts/archive-year.vue +13 -0
  69. package/layouts/archive.vue +11 -0
  70. package/layouts/categories.vue +11 -4
  71. package/layouts/default.vue +8 -7
  72. package/layouts/home.vue +28 -18
  73. package/layouts/post.vue +41 -35
  74. package/layouts/tag.vue +8 -4
  75. package/layouts/tags.vue +11 -4
  76. package/{modules → library}/loading.ts +18 -6
  77. package/{modules → library}/scroll.ts +3 -2
  78. package/locales/zh-CN.yml +0 -2
  79. package/node/images/default.json +139 -0
  80. package/node/images/index.ts +46 -0
  81. package/node/index.ts +2 -0
  82. package/node/theme/index.ts +78 -0
  83. package/package.json +22 -28
  84. package/pages/archives/[year]/[month]/index.vue +15 -16
  85. package/pages/archives/[year]/index.vue +20 -18
  86. package/pages/archives/index.vue +10 -8
  87. package/pages/categories/{[...categories].vue → [...its].vue} +29 -34
  88. package/pages/index.vue +1 -1
  89. package/pages/page/[page].vue +2 -2
  90. package/pages/tags/{[tag].vue → [tag]/index.vue} +12 -12
  91. package/pages/tags/index.vue +12 -5
  92. package/setup/main.ts +1 -1
  93. package/store/index.ts +1 -0
  94. package/store/modules/global.ts +12 -0
  95. package/styles/components/index.scss +4 -0
  96. package/styles/{markdown.scss → components/markdown.scss} +2 -1
  97. package/styles/components/nprogress.scss +16 -0
  98. package/styles/css-vars.scss +11 -0
  99. package/styles/element-plus/tabs.scss +1 -1
  100. package/styles/element-plus/timeline.scss +1 -1
  101. package/styles/global.scss +39 -0
  102. package/styles/index.scss +4 -73
  103. package/tsconfig.json +27 -0
  104. package/types/index.d.ts +163 -0
  105. package/unocss.config.ts +5 -1
  106. package/utils/index.ts +21 -39
  107. package/valaxy.config.ts +21 -24
  108. package/@types/markdown-it.d.ts +0 -1
  109. package/@types/markdown-toc.d.ts +0 -1
  110. package/@types/types.d.ts +0 -1
  111. package/@types/valaxy.d.ts +0 -10
  112. package/components/HairyAlgoliaSearchBox.vue +0 -118
  113. package/components/HairyBackToTop.vue +0 -72
  114. package/components/HairyDivider.vue +0 -0
  115. package/components/HairyFooterFish.vue +0 -29
  116. package/components/HairyLayout.vue +0 -28
  117. package/components/HairyLink.vue +0 -10
  118. package/components/HairyLinks.vue +0 -69
  119. package/components/HairyMeting.vue +0 -19
  120. package/components/HairyNav.vue +0 -42
  121. package/components/HairyNavBackground.vue +0 -7
  122. package/components/HairyNavMenu.vue +0 -11
  123. package/components/HairyNavToggleDark.vue +0 -16
  124. package/components/HairyPostToggleLayout.vue +0 -33
  125. package/components/HairyToc.vue +0 -135
  126. package/components/HairyUserNav.vue +0 -64
  127. package/components/HairyWaline.vue +0 -44
  128. package/hooks/setupDefaultDark.ts +0 -11
  129. package/hooks/useCategory.ts +0 -18
  130. package/hooks/useCategoryPost.ts +0 -21
  131. package/hooks/useContext.ts +0 -13
  132. package/hooks/useHeaderHeight.ts +0 -9
  133. package/hooks/usePostLayout.ts +0 -16
  134. package/images.json +0 -140
  135. package/index.d.ts +0 -100
  136. package/layouts/archives.vue +0 -11
  137. package/layouts/hairy.vue +0 -36
  138. package/layouts/month.vue +0 -6
  139. package/layouts/year.vue +0 -6
  140. package/node/addon-hairy.ts +0 -36
  141. package/node/addon-images.ts +0 -61
  142. package/node/addon-meting.ts +0 -13
  143. package/node/addon-statistics.ts +0 -19
  144. package/node/addon-toc.ts +0 -20
  145. package/node/utils.ts +0 -20
  146. package/utils/createContext.ts +0 -40
  147. package/utils/fonts.ts +0 -15
  148. /package/components/{HairyUserStats.vue → parts/HairyUserStats.vue} +0 -0
  149. /package/components/{article-layout → posts}/HairyArticleTop.vue +0 -0
  150. /package/{modules → library}/loading.scss +0 -0
  151. /package/{shims.d.ts → node/images/shims.d.ts} +0 -0
  152. /package/styles/{aplayer.scss → components/aplayer.scss} +0 -0
  153. /package/styles/{scrollbar.scss → components/scrollbar.scss} +0 -0
@@ -0,0 +1,29 @@
1
+ <script lang="ts" setup>
2
+ import '@docsearch/css'
3
+ </script>
4
+
5
+ <template>
6
+ <div class="VPNavBarSearch">
7
+ <button type="button" class="DocSearch DocSearch-Button" aria-label="Search">
8
+ <span class="DocSearch-Button-Container lt-sm:text-size-xl">
9
+ <svg
10
+ class="DocSearch-Search-Icon"
11
+ width="20"
12
+ height="20"
13
+ viewBox="0 0 20 20"
14
+ >
15
+ <path
16
+ d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z"
17
+ stroke="currentColor"
18
+ fill="none"
19
+ fill-rule="evenodd"
20
+ stroke-linecap="round"
21
+ stroke-linejoin="round"
22
+ />
23
+ </svg>
24
+ <span class="DocSearch-Button-Placeholder">Search</span>
25
+ </span>
26
+ <HairySearchBtnKeys />
27
+ </button>
28
+ </div>
29
+ </template>
@@ -0,0 +1,20 @@
1
+ <template>
2
+ <span class="DocSearch-Button-Container lt-sm:text-size-xl">
3
+ <svg
4
+ class="DocSearch-Search-Icon"
5
+ width="20"
6
+ height="20"
7
+ viewBox="0 0 20 20"
8
+ >
9
+ <path
10
+ d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z"
11
+ stroke="currentColor"
12
+ fill="none"
13
+ fill-rule="evenodd"
14
+ stroke-linecap="round"
15
+ stroke-linejoin="round"
16
+ />
17
+ </svg>
18
+ <span class="DocSearch-Button-Placeholder">Search</span>
19
+ </span>
20
+ </template>
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <span class="DocSearch-Button-Keys">
3
+ <kbd class="DocSearch-Button-Key">
4
+ <svg
5
+ width="15" height="15"
6
+ class="DocSearch-Control-Key-Icon"
7
+ >
8
+ <path
9
+ d="M4.505 4.496h2M5.505 5.496v5M8.216 4.496l.055 5.993M10 7.5c.333.333.5.667.5 1v2M12.326 4.5v5.996M8.384 4.496c1.674 0 2.116 0 2.116 1.5s-.442 1.5-2.116 1.5M3.205 9.303c-.09.448-.277 1.21-1.241 1.203C1 10.5.5 9.513.5 8V7c0-1.57.5-2.5 1.464-2.494.964.006 1.134.598 1.24 1.342M12.553 10.5h1.953"
10
+ stroke-width="1.2"
11
+ stroke="currentColor"
12
+ fill="none"
13
+ stroke-linecap="square"
14
+ />
15
+ </svg>
16
+ </kbd>
17
+ <kbd class="DocSearch-Button-Key">K</kbd>
18
+ </span>
19
+ </template>
@@ -1,7 +1,7 @@
1
1
  <script lang="ts" setup>
2
2
  import images from '@hairy:images:home'
3
3
  import { Swiper, SwiperSlide } from 'swiper/vue'
4
- import { Autoplay, EffectFade } from 'swiper'
4
+ import { Autoplay, EffectFade } from 'swiper/modules'
5
5
  import 'swiper/css'
6
6
  import 'swiper/css/autoplay'
7
7
  import 'swiper/css/effect-fade'
@@ -10,16 +10,16 @@ images.sort(() => Math.random() - 0.5)
10
10
  </script>
11
11
 
12
12
  <template>
13
- <swiper
13
+ <Swiper
14
14
  effect="fade" :speed="2000" :fade-effect="{ crossFade: true }" :modules="[Autoplay, EffectFade]"
15
15
  :slides-per-view="1" :space-between="50" :autoplay="{
16
16
  delay: 4000,
17
17
  }" class="HairyCarousel swiper-no-swiping"
18
18
  >
19
- <swiper-slide v-for="(item, index) in images" :key="index" class="w-full h-full">
20
- <img class="w-full h-full object-cover" :src="item" />
21
- </swiper-slide>
22
- </swiper>
19
+ <SwiperSlide v-for="(item, index) in images" :key="index" class="w-full h-full">
20
+ <img class="w-full h-full object-cover" :src="item">
21
+ </SwiperSlide>
22
+ </Swiper>
23
23
  </template>
24
24
 
25
25
  <style lang="scss">
@@ -1,3 +1,4 @@
1
+ /* eslint-disable style/max-statements-per-line */
1
2
  import type { Post } from 'valaxy'
2
3
  import { usePostList } from 'valaxy'
3
4
  import { computed } from 'vue'
@@ -5,10 +6,10 @@ import dayjs from 'dayjs'
5
6
 
6
7
  interface ArchiveYearMaps {
7
8
  [year: string]: {
8
- [month: string]: { count: number; posts: Post[] }
9
+ [month: string]: { count: number, posts: Post[] }
9
10
  }
10
11
  }
11
- interface ArchiveYearItem {
12
+ interface ArchiveYear {
12
13
  year: string
13
14
  month: string
14
15
  count: number
@@ -19,7 +20,7 @@ export function useYearArchives() {
19
20
  const posts = usePostList()
20
21
  const archives = computed(() => {
21
22
  const maps: ArchiveYearMaps = {}
22
- const items: ArchiveYearItem[] = []
23
+ const items: ArchiveYear[] = []
23
24
  for (const post of posts.value) {
24
25
  if (!post.date)
25
26
  continue
@@ -0,0 +1,43 @@
1
+ import type { CategoryList, PostFrontMatter } from 'valaxy'
2
+ import { useCategories, usePostList } from 'valaxy'
3
+ import type { MaybeRef } from '@vueuse/core'
4
+ import { computed, unref } from 'vue'
5
+
6
+ import { isEqual } from 'lodash-es'
7
+
8
+ export function useCategory(categories: MaybeRef<string[]>) {
9
+ const all = useCategories()
10
+
11
+ unref(categories)
12
+ // [BBB]
13
+ return computed(() => {
14
+ let parent: PostFrontMatter & Partial<CategoryList> = all.value as any
15
+ for (const category of unref(categories)) {
16
+ const children = (parent.children || new Map([]))
17
+ for (const [key, value] of children) {
18
+ if (key === category && !key.startsWith('/posts')) {
19
+ parent = (value as PostFrontMatter)
20
+ continue
21
+ }
22
+ }
23
+ }
24
+ return parent
25
+ })
26
+ }
27
+
28
+ export function useCategoryPost(categories: MaybeRef<string[]>) {
29
+ const postList = usePostList()
30
+ return computed(() => {
31
+ if (!unref(categories).length)
32
+ return postList.value
33
+ return postList.value.filter((item) => {
34
+ let target = Array.isArray(item.categories)
35
+ ? item.categories
36
+ : [item.categories || '']
37
+ target = target.filter(Boolean)
38
+ if (unref(categories)[0] === 'Uncategorized')
39
+ return !target.length
40
+ return isEqual(target.sort(), unref(categories).sort())
41
+ }) as any
42
+ })
43
+ }
@@ -0,0 +1,11 @@
1
+ import { computed } from 'vue'
2
+ import { useConfig } from 'valaxy'
3
+ import type { ThemeConfig } from '../types'
4
+
5
+ /**
6
+ * getThemeConfig
7
+ */
8
+ export function useThemeConfig<T = ThemeConfig>() {
9
+ const config = useConfig<T>()
10
+ return computed(() => config!.value.themeConfig)
11
+ }
@@ -0,0 +1,13 @@
1
+ import { useAppStore, useThemeConfig } from 'valaxy'
2
+ import { useLocalStorage } from '@vueuse/core'
3
+ import type { ThemeConfig } from 'valaxy-theme-hairy'
4
+
5
+ export function setupDefaultDark() {
6
+ const theme = useThemeConfig<ThemeConfig>()
7
+ const { toggleDark } = useAppStore()
8
+ const local = useLocalStorage('--hairy-mode', '')
9
+ if (theme.value.theme && !local.value) {
10
+ local.value = theme.value.theme
11
+ toggleDark()
12
+ }
13
+ }
@@ -0,0 +1,60 @@
1
+ import { computed, onMounted, ref } from 'vue'
2
+ import type { UseFuseOptions } from '@vueuse/integrations/useFuse'
3
+ import { useFuse } from '@vueuse/integrations/useFuse'
4
+ import type { FuseListItem } from 'valaxy/types'
5
+ import { useSiteConfig } from 'valaxy'
6
+ import type { MaybeRefOrGetter } from '@vueuse/shared'
7
+
8
+ export function useFuseParsed(input: MaybeRefOrGetter<string>) {
9
+ const siteConfig = useSiteConfig()
10
+ const data = ref<FuseListItem[]>([])
11
+
12
+ const keys = computed(() => {
13
+ const defKs = ['title', 'tags', 'categories', 'excerpt']
14
+ const ks = siteConfig.value.fuse.options.keys || []
15
+ return ks.length === 0 ? defKs : ks
16
+ })
17
+
18
+ const fuseOptions = computed<UseFuseOptions<FuseListItem>>(() => ({
19
+ fuseOptions: {
20
+ ...siteConfig.value.fuse.options,
21
+ keys: keys.value,
22
+ // threshold: 0.99,
23
+ // ignoreLocation: true,
24
+ },
25
+ includeMatches: true,
26
+ findAllMatches: true,
27
+ // resultLimit: resultLimit.value,
28
+ // matchAllWhenSearchEmpty: matchAllWhenSearchEmpty.value,
29
+ }))
30
+
31
+ onMounted(async () => {
32
+ const path = !siteConfig.value.fuse.dataPath.startsWith('http')
33
+ ? `${import.meta.env.BASE_URL}${siteConfig.value.fuse.dataPath}`
34
+ : siteConfig.value.fuse.dataPath
35
+ data.value = await fetch(path).then(r => r.json() || [])
36
+ })
37
+
38
+ const { fuse, results: _results } = useFuse(input, data, fuseOptions)
39
+ const results = computed(() => _results.value.map((v) => {
40
+ return {
41
+ ...v,
42
+ item: {
43
+ ...v.item,
44
+ excerpt: removeTags(v.item.excerpt || ''),
45
+ },
46
+ }
47
+ }))
48
+ return { results, fuse, data }
49
+ }
50
+
51
+ function removeTags(content = '') {
52
+ content = content.replace(/<\/?[^>]*>/g, '')
53
+ content = content.replace(/[|]/g, '')
54
+ content = content.replace(/```.*?\n/sg, '')
55
+ content = content.replace(/:::.*?\n/sg, '')
56
+ content = content.replace(/\[\[toc\]\]/g, '')
57
+ content = content.replace(/\{lang=".*?\}/sg, '')
58
+ content = content.replace(/#.*? /sg, '')
59
+ return content
60
+ }
@@ -0,0 +1,8 @@
1
+ export * from './config'
2
+ export * from './fuse'
3
+ export * from './layout'
4
+ export * from './category'
5
+ export * from './archives'
6
+ export * from './tags'
7
+ export * from './outline'
8
+ export * from './dark'
@@ -0,0 +1,16 @@
1
+ import { useThemeConfig } from 'valaxy'
2
+ import { createSharedComposable, useStorage } from '@vueuse/core'
3
+ import { computed } from 'vue'
4
+ import type { HairyTheme } from '../types'
5
+
6
+ const useSharedStorage = createSharedComposable(useStorage)
7
+
8
+ export function useLayoutPost() {
9
+ const themeConfig = useThemeConfig<HairyTheme.Config>()
10
+ const cache = useSharedStorage<HairyTheme.Layout['post']>('--hairy-theme:post-layout', null)
11
+ const layout = computed({
12
+ get: () => cache.value || themeConfig.value.layout?.post || 'image',
13
+ set: value => cache.value = value,
14
+ })
15
+ return layout
16
+ }
@@ -0,0 +1,49 @@
1
+ import { defineStore } from 'pinia'
2
+ import type { MenuItem } from 'valaxy'
3
+ import { getHeaders, onContentUpdated, useFrontmatter, useThemeConfig } from 'valaxy'
4
+ import type { DefaultTheme } from 'valaxy/types'
5
+ import { computed } from 'vue'
6
+ import { useRoute } from 'vue-router'
7
+
8
+ const useOutlineStore = defineStore('OutlineStore', {
9
+ state: () => ({} as Record<string, MenuItem[]>),
10
+ })
11
+
12
+ /**
13
+ * export headers & handleClick to generate outline
14
+ */
15
+ export function useOutline() {
16
+ const frontmatter = useFrontmatter()
17
+ const themeConfig = useThemeConfig()
18
+ const route = useRoute()
19
+ const store = useOutlineStore()
20
+
21
+ const pageOutline = computed<DefaultTheme.Config['outline']>(
22
+ () => frontmatter.value.outline ?? themeConfig.value.outline,
23
+ )
24
+
25
+ const headers = computed(() => store.$state[route.path] || [])
26
+
27
+ onContentUpdated(() => {
28
+ if (pageOutline.value === false)
29
+ return
30
+ store.$state[route.path] = getHeaders(pageOutline.value)
31
+ })
32
+
33
+ const handleClick = ({ target: el }: Event) => {
34
+ const id = (el as HTMLAnchorElement).href!.split('#')[1]
35
+ const heading = document.getElementById(decodeURIComponent(id)) as HTMLAnchorElement
36
+ heading?.focus({ preventScroll: true })
37
+ }
38
+
39
+ return {
40
+ /**
41
+ * headers for toc
42
+ */
43
+ headers,
44
+ /**
45
+ * click hash heading
46
+ */
47
+ handleClick,
48
+ }
49
+ }
@@ -0,0 +1,36 @@
1
+ import { TinyColor } from '@ctrl/tinycolor'
2
+ import { useTags } from 'valaxy'
3
+
4
+ /**
5
+ * get utils about tags
6
+ */
7
+ export function useHairyTags(options: {
8
+ /**
9
+ * Primary Color
10
+ */
11
+ primary: string
12
+ } = {
13
+ primary: '#0078E7',
14
+ }) {
15
+ const tags = useTags()
16
+
17
+ const gray = new TinyColor('#999999')
18
+ const primaryColor = new TinyColor(options.primary)
19
+
20
+ const getTagStyle = (count: number) => {
21
+ const counts = Array.from(tags.value).map(([_, value]) => value.count)
22
+ const max = Math.max(...counts)
23
+ const min = Math.min(...counts)
24
+ const range = max - min
25
+ const percent = (count - min) / range
26
+ return {
27
+ '--yun-tag-color': gray.mix(primaryColor, percent * 100).toString(),
28
+ 'fontSize': `${percent * 36 + 12}px`,
29
+ }
30
+ }
31
+
32
+ return {
33
+ tags,
34
+ getTagStyle,
35
+ }
36
+ }
@@ -0,0 +1,13 @@
1
+ <script lang="ts" setup>
2
+ </script>
3
+
4
+ <template>
5
+ <HairyContainer>
6
+ <HairyNavbar />
7
+ <HairyHeader :title="`发表于'${$route.params.year}年${$route.params.month}月'的文章`" />
8
+ <HairyBody>
9
+ <router-view />
10
+ </HairyBody>
11
+ <HairyFooter />
12
+ </HairyContainer>
13
+ </template>
@@ -0,0 +1,13 @@
1
+ <script lang="ts" setup>
2
+ </script>
3
+
4
+ <template>
5
+ <HairyContainer>
6
+ <HairyNavbar />
7
+ <HairyHeader :title="`发表于'${$route.params.year}年'的文章`" />
8
+ <HairyBody>
9
+ <router-view />
10
+ </HairyBody>
11
+ <HairyFooter />
12
+ </HairyContainer>
13
+ </template>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <HairyContainer>
3
+ <HairyNavbar />
4
+ <HairyHeader />
5
+ <HairyBody>
6
+ <router-view />
7
+ </HairyBody>
8
+ <HairyFooter />
9
+ <HairyDrawer />
10
+ </HairyContainer>
11
+ </template>
@@ -1,6 +1,13 @@
1
+ <script lang="ts" setup>
2
+ </script>
3
+
1
4
  <template>
2
- <HairyLayout :header="{ title: '分类' }">
3
- <router-view />
4
- </HairyLayout>
5
+ <HairyContainer>
6
+ <HairyNavbar />
7
+ <HairyHeader title="分类" />
8
+ <HairyBody>
9
+ <router-view />
10
+ </HairyBody>
11
+ <HairyFooter />
12
+ </HairyContainer>
5
13
  </template>
6
-
@@ -1,9 +1,10 @@
1
- <script lang="ts" setup>
2
- </script>
3
-
4
1
  <template>
5
- <HairyLayout :header="$route.meta.frontmatter">
6
- <router-view />
7
- </HairyLayout>
2
+ <HairyContainer>
3
+ <HairyNavbar />
4
+ <HairyHeader />
5
+ <HairyBody>
6
+ <router-view />
7
+ </HairyBody>
8
+ <HairyFooter />
9
+ </HairyContainer>
8
10
  </template>
9
-
package/layouts/home.vue CHANGED
@@ -1,23 +1,33 @@
1
1
  <script lang="ts" setup>
2
- import { useConfig } from 'valaxy'
3
- const config = useConfig()
2
+ import { useSiteConfig } from 'valaxy'
3
+ import dayjs from 'dayjs'
4
+ import { riposte } from '../utils'
5
+
6
+ const config = useSiteConfig()
7
+
8
+ const hour = dayjs().hour()
9
+ const hello = riposte(
10
+ [hour >= 5 && hour < 12, 'Good morning'],
11
+ [hour >= 12 && hour < 18, 'Good afternoon'],
12
+ [true, 'Good evening'],
13
+ )
4
14
  </script>
5
15
 
6
16
  <template>
7
- <HairyLayout
8
- class="HairyHomeLayout"
9
- :header="{
10
- headline: config.title,
11
- title: config.author.name,
12
- description: 'good evening, how are you doing?',
13
- }"
14
- >
15
- <router-view />
16
- </HairyLayout>
17
+ <HairyContainer>
18
+ <HairyNavbar>
19
+ <template #nav>
20
+ <slot name="header-nav" />
21
+ </template>
22
+ </HairyNavbar>
23
+ <HairyHeader
24
+ :headline="config.title"
25
+ :title="config.author.name"
26
+ :description="`${hello}, how are you doing?`"
27
+ />
28
+ <HairyBody>
29
+ <router-view />
30
+ </HairyBody>
31
+ <HairyFooter />
32
+ </HairyContainer>
17
33
  </template>
18
-
19
- <style>
20
- .HairyHomeHeader .title {
21
- @apply tracking-5;
22
- }
23
- </style>
package/layouts/post.vue CHANGED
@@ -1,48 +1,54 @@
1
1
  <script lang="ts" setup>
2
+ import { dayjs } from 'element-plus'
2
3
  import { useFrontmatter } from 'valaxy'
4
+ import { useRouter } from 'vue-router'
3
5
  import { ElTag } from 'element-plus/es/components/tag/index'
4
6
  import 'element-plus/es/components/tag/style/index'
5
- import dayjs from 'dayjs'
6
- import { useRouter } from 'vue-router'
7
- const router = useRouter()
8
7
 
8
+ defineProps<{
9
+ header?: {
10
+ title?: string
11
+ headline?: string
12
+ description?: string
13
+ }
14
+ }>()
15
+
16
+ const router = useRouter()
9
17
  const post = useFrontmatter()
10
18
 
11
- const displayTag = (tag: string) => {
19
+ function displayTag(tag: string) {
12
20
  router.push(`/tags/${tag}`)
13
21
  }
14
22
  </script>
15
23
 
16
24
  <template>
17
- <HairyLayout :header="{ title: post.title }">
18
- <template #header-description>
19
- <div class="text-center">
20
- {{ post.description }}
21
- </div>
22
- <div class="flex gap-2">
23
- <span>发表于 {{ dayjs(post.date).format('YYYY-MM-DD') }}</span>
24
- <span>本文字数 {{ (post.length / 1000).toFixed(1) }}k 字</span>
25
- <span>阅读时长 {{ post.durations.minutes.toFixed(2) }} 分钟</span>
26
- </div>
27
- <div v-if="post.tags?.length" class="tags flex-center gap-2 mt-2">
28
- <el-tag v-for="(tag) in post.tags" :key="tag" class="dark:bg-dark-50 cursor-pointer" @click="displayTag(tag)">
29
- {{ tag }}
30
- </el-tag>
31
- </div>
32
- </template>
33
- <router-view />
34
- <div class="mb-15">
35
- <div class="border-t border-gray-200 dark:border-gray-600"></div>
36
- <div class="flex items-center justify-end mt-2">
37
- <div class="i-ri-eye-fill mr-2" />
38
- 阅读次数 <span class="waline-pageview-count mx-2">1</span> 次
39
- </div>
40
- </div>
41
- <template #body-slide>
42
- <HairyUserTab />
43
- </template>
44
- </HairyLayout>
25
+ <HairyContainer>
26
+ <HairyNavbar />
27
+ <HairyHeader :title="post.title">
28
+ <template #description>
29
+ <div class="flex gap-2">
30
+ <span>发表于 {{ dayjs(post.date).format('YYYY-MM-DD') }}</span>
31
+ <span>本文字数 {{ post.wordCount }} 字</span>
32
+ <span>阅读时长 {{ post.readingTime }} 分钟</span>
33
+ </div>
34
+ <div v-if="post.tags?.length" class="tags flex-center gap-2 mt-2">
35
+ <ElTag v-for="(tag) in post.tags" :key="tag" class="dark:bg-dark-50 cursor-pointer" @click="displayTag(tag)">
36
+ {{ tag }}
37
+ </ElTag>
38
+ </div>
39
+ </template>
40
+ </HairyHeader>
41
+ <HairyBody>
42
+ <template #default>
43
+ <HairyImageGlobal>
44
+ <router-view />
45
+ </HairyImageGlobal>
46
+ <HairyPostFooter />
47
+ </template>
48
+ <template #slide>
49
+ <HairyTabbar />
50
+ </template>
51
+ </HairyBody>
52
+ <HairyFooter />
53
+ </HairyContainer>
45
54
  </template>
46
-
47
- <style lang="scss">
48
- </style>
package/layouts/tag.vue CHANGED
@@ -1,6 +1,10 @@
1
1
  <template>
2
- <HairyLayout :header="{ title: `包含标签'${$route.params.tag}'的标签` }">
3
- <router-view />
4
- </HairyLayout>
2
+ <HairyContainer>
3
+ <HairyNavbar />
4
+ <HairyHeader :title="`包含标签'${$route.params.tag}'的标签`" />
5
+ <HairyBody>
6
+ <router-view />
7
+ </HairyBody>
8
+ <HairyFooter />
9
+ </HairyContainer>
5
10
  </template>
6
-
package/layouts/tags.vue CHANGED
@@ -1,6 +1,13 @@
1
+ <script lang="ts" setup>
2
+ </script>
3
+
1
4
  <template>
2
- <HairyLayout :header="{ title: '所有标签' }">
3
- <router-view />
4
- </HairyLayout>
5
+ <HairyContainer>
6
+ <HairyNavbar />
7
+ <HairyHeader title="所有标签" />
8
+ <HairyBody>
9
+ <router-view />
10
+ </HairyBody>
11
+ <HairyFooter />
12
+ </HairyContainer>
5
13
  </template>
6
-