valaxy-theme-hairy 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +21 -21
- package/client/index.ts +1 -1
- package/components/HairyBody.vue +49 -49
- package/components/HairyCodepen.vue +40 -40
- package/components/HairyComment.vue +33 -33
- package/components/HairyContainer.vue +17 -17
- package/components/HairyDrawer.vue +44 -44
- package/components/HairyFooter.vue +62 -62
- package/components/HairyHeader.vue +32 -32
- package/components/HairyImage.vue +15 -15
- package/components/HairyImageGroup.vue +65 -65
- package/components/HairyNavbar.vue +56 -56
- package/components/HairyPageArchives.vue +59 -59
- package/components/HairyPageTags.vue +48 -48
- package/components/HairyPosts.vue +54 -54
- package/components/HairySearch.vue +201 -201
- package/components/HairySidebar.vue +30 -30
- package/components/HairyTabbar.vue +56 -56
- package/components/PageTags.vue +48 -48
- package/components/ValaxyMain.vue +45 -45
- package/components/navbar/HairyNav.vue +16 -16
- package/components/navbar/HairyNavExpand.vue +12 -12
- package/components/navbar/HairyNavItem.vue +35 -35
- package/components/navbar/HairyNavbarBackground.vue +7 -7
- package/components/navbar/HairyNavbarSearch.vue +8 -8
- package/components/navbar/HairyNavbarTitle.vue +15 -15
- package/components/navbar/HairyNavbarToggleDark.vue +22 -22
- package/components/parts/HairyBreadcrumb.vue +51 -51
- package/components/parts/HairyBreadcrumbItem.vue +11 -11
- package/components/parts/HairyFootFish.js +352 -352
- package/components/parts/HairyFootFish.vue +38 -38
- package/components/parts/HairyHeadHero.vue +34 -34
- package/components/parts/HairyHeadWaves.vue +67 -67
- package/components/parts/HairyImageGlobal.vue +51 -51
- package/components/parts/HairyImageViewer.vue +23 -23
- package/components/parts/HairyLink.vue +21 -21
- package/components/parts/HairyMenu.vue +16 -16
- package/components/parts/HairyMenuItem.vue +47 -47
- package/components/parts/HairyOutline.vue +99 -99
- package/components/parts/HairyOutlineItem.vue +48 -48
- package/components/parts/HairySocialLinks.vue +27 -27
- package/components/parts/HairyTimelineContent.vue +39 -39
- package/components/parts/HairyUserNav.vue +95 -95
- package/components/parts/HairyUserStats.vue +18 -18
- package/components/posts/HairyArticleImage.vue +126 -126
- package/components/posts/HairyArticleSeries.vue +89 -89
- package/components/posts/HairyArticleText.vue +43 -43
- package/components/posts/HairyPostFooter.vue +15 -15
- package/components/posts/HairyPostImageList.vue +27 -27
- package/components/posts/HairyPostTextsList.vue +22 -22
- package/components/posts/HairyPostToggleLayout.vue +36 -36
- package/components/third/HairyAlgoliaSearch.vue +17 -17
- package/components/third/HairyFuseSearch.vue +10 -10
- package/components/third/HairyFuseSearchDialog.vue +32 -32
- package/components/third/HairyFuseSearchDropdown.vue +77 -77
- package/components/third/HairyFuseSearchFooter.vue +28 -28
- package/components/third/HairyFuseSearchHeader.vue +30 -30
- package/components/third/HairyFuseSearchHit.vue +52 -52
- package/components/third/HairySearchBtnDisplay.vue +29 -29
- package/components/third/HairySearchBtnInput.vue +20 -20
- package/components/third/HairySearchBtnKeys.vue +19 -19
- package/components/third/HairySwiperCarousel.vue +45 -45
- package/composables/archives.ts +48 -48
- package/composables/category.ts +43 -43
- package/composables/config.ts +11 -11
- package/composables/dark.ts +13 -13
- package/composables/fuse.ts +60 -60
- package/composables/index.ts +7 -7
- package/composables/layout.ts +16 -16
- package/composables/outline.ts +49 -49
- package/composables/tags.ts +36 -36
- package/layouts/archive-month.vue +13 -13
- package/layouts/archive-year.vue +13 -13
- package/layouts/archives.vue +11 -11
- package/layouts/categories.vue +13 -13
- package/layouts/default.vue +13 -15
- package/layouts/home.vue +33 -33
- package/layouts/post.vue +54 -54
- package/layouts/tag.vue +10 -10
- package/layouts/tags.vue +10 -14
- package/library/loading.scss +535 -535
- package/library/loading.ts +60 -60
- package/library/scroll.ts +22 -22
- package/locales/en.yml +1 -1
- package/locales/zh-CN.yml +1 -1
- package/node/images/default.json +139 -139
- package/node/images/index.ts +46 -46
- package/node/images/shims.d.ts +8 -8
- package/node/index.ts +2 -2
- package/node/theme/index.ts +78 -78
- package/package.json +1 -1
- package/pages/archives/[year]/[month]/index.vue +48 -48
- package/pages/archives/[year]/index.vue +73 -73
- package/pages/archives/index.md +6 -0
- package/pages/categories/[...its].vue +108 -108
- package/pages/index.vue +8 -8
- package/pages/page/[page].vue +12 -12
- package/pages/tags/[tag]/index.vue +38 -38
- package/pages/tags/index.md +7 -0
- package/setup/main.ts +9 -9
- package/store/index.ts +1 -1
- package/store/modules/global.ts +12 -12
- package/styles/components/aplayer.scss +75 -75
- package/styles/components/index.scss +3 -3
- package/styles/components/markdown.scss +89 -89
- package/styles/components/nprogress.scss +15 -15
- package/styles/components/scrollbar.scss +25 -25
- package/styles/css-vars.scss +171 -171
- package/styles/element-plus/index.scss +1 -1
- package/styles/element-plus/tabs.scss +25 -25
- package/styles/element-plus/timeline.scss +18 -18
- package/styles/font-face.scss +19 -19
- package/styles/global.scss +38 -38
- package/styles/index.scss +3 -3
- package/tsconfig.json +27 -27
- package/types/index.d.ts +163 -163
- package/unocss.config.ts +43 -43
- package/utils/index.ts +37 -37
- package/valaxy.config.ts +26 -26
- package/pages/archives/index.vue +0 -6
- package/pages/tags/index.vue +0 -6
@@ -1,29 +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>
|
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>
|
@@ -1,20 +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>
|
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>
|
@@ -1,19 +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
|
+
<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,45 +1,45 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import images from '@hairy:images:home'
|
3
|
-
import { Swiper, SwiperSlide } from 'swiper/vue'
|
4
|
-
import { Autoplay, EffectFade } from 'swiper/modules'
|
5
|
-
import 'swiper/css'
|
6
|
-
import 'swiper/css/autoplay'
|
7
|
-
import 'swiper/css/effect-fade'
|
8
|
-
|
9
|
-
images.sort(() => Math.random() - 0.5)
|
10
|
-
</script>
|
11
|
-
|
12
|
-
<template>
|
13
|
-
<Swiper
|
14
|
-
effect="fade" :speed="2000" :fade-effect="{ crossFade: true }" :modules="[Autoplay, EffectFade]"
|
15
|
-
:slides-per-view="1" :space-between="50" :autoplay="{
|
16
|
-
delay: 4000,
|
17
|
-
}" class="HairyCarousel swiper-no-swiping"
|
18
|
-
>
|
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
|
-
</template>
|
24
|
-
|
25
|
-
<style lang="scss">
|
26
|
-
.HairyCarousel {
|
27
|
-
&::before {
|
28
|
-
content: '';
|
29
|
-
display: block;
|
30
|
-
position: absolute;
|
31
|
-
top: 0;
|
32
|
-
left: 0;
|
33
|
-
width: 100%;
|
34
|
-
height: 100%;
|
35
|
-
background-color: rgba(0, 0, 0, .2);
|
36
|
-
z-index: 2;
|
37
|
-
transition: all .2s ease-in-out 0s;
|
38
|
-
}
|
39
|
-
}
|
40
|
-
.dark {
|
41
|
-
.HairyCarousel::before {
|
42
|
-
background-color: rgba(0,0,0,.4);
|
43
|
-
}
|
44
|
-
}
|
45
|
-
</style>
|
1
|
+
<script lang="ts" setup>
|
2
|
+
import images from '@hairy:images:home'
|
3
|
+
import { Swiper, SwiperSlide } from 'swiper/vue'
|
4
|
+
import { Autoplay, EffectFade } from 'swiper/modules'
|
5
|
+
import 'swiper/css'
|
6
|
+
import 'swiper/css/autoplay'
|
7
|
+
import 'swiper/css/effect-fade'
|
8
|
+
|
9
|
+
images.sort(() => Math.random() - 0.5)
|
10
|
+
</script>
|
11
|
+
|
12
|
+
<template>
|
13
|
+
<Swiper
|
14
|
+
effect="fade" :speed="2000" :fade-effect="{ crossFade: true }" :modules="[Autoplay, EffectFade]"
|
15
|
+
:slides-per-view="1" :space-between="50" :autoplay="{
|
16
|
+
delay: 4000,
|
17
|
+
}" class="HairyCarousel swiper-no-swiping"
|
18
|
+
>
|
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
|
+
</template>
|
24
|
+
|
25
|
+
<style lang="scss">
|
26
|
+
.HairyCarousel {
|
27
|
+
&::before {
|
28
|
+
content: '';
|
29
|
+
display: block;
|
30
|
+
position: absolute;
|
31
|
+
top: 0;
|
32
|
+
left: 0;
|
33
|
+
width: 100%;
|
34
|
+
height: 100%;
|
35
|
+
background-color: rgba(0, 0, 0, .2);
|
36
|
+
z-index: 2;
|
37
|
+
transition: all .2s ease-in-out 0s;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
.dark {
|
41
|
+
.HairyCarousel::before {
|
42
|
+
background-color: rgba(0,0,0,.4);
|
43
|
+
}
|
44
|
+
}
|
45
|
+
</style>
|
package/composables/archives.ts
CHANGED
@@ -1,48 +1,48 @@
|
|
1
|
-
/* eslint-disable style/max-statements-per-line */
|
2
|
-
import type { Post } from 'valaxy'
|
3
|
-
import { usePostList } from 'valaxy'
|
4
|
-
import { computed } from 'vue'
|
5
|
-
import dayjs from 'dayjs'
|
6
|
-
|
7
|
-
interface ArchiveYearMaps {
|
8
|
-
[year: string]: {
|
9
|
-
[month: string]: { count: number, posts: Post[] }
|
10
|
-
}
|
11
|
-
}
|
12
|
-
interface ArchiveYear {
|
13
|
-
year: string
|
14
|
-
month: string
|
15
|
-
count: number
|
16
|
-
posts: Post[]
|
17
|
-
}
|
18
|
-
|
19
|
-
export function useYearArchives() {
|
20
|
-
const posts = usePostList()
|
21
|
-
const archives = computed(() => {
|
22
|
-
const maps: ArchiveYearMaps = {}
|
23
|
-
const items: ArchiveYear[] = []
|
24
|
-
for (const post of posts.value) {
|
25
|
-
if (!post.date)
|
26
|
-
continue
|
27
|
-
const days = dayjs(post.date)
|
28
|
-
const [year, month] = [days.format('YYYY'), days.format('MM')]
|
29
|
-
if (!maps[year])
|
30
|
-
maps[year] = {}
|
31
|
-
if (!maps[year][month]) { maps[year][month] = { count: 1, posts: [post as any] } }
|
32
|
-
else {
|
33
|
-
maps[year][month].count++
|
34
|
-
maps[year][month].posts.unshift(post as any)
|
35
|
-
}
|
36
|
-
}
|
37
|
-
for (const [year, months] of Object.entries(maps)) {
|
38
|
-
for (const [month, { count, posts }] of Object.entries(months))
|
39
|
-
items.unshift({ year, month, count, posts })
|
40
|
-
}
|
41
|
-
return items.sort((a, b) => {
|
42
|
-
const aTime = `${a.year}-${a.month}`
|
43
|
-
const bTime = `${b.year}-${b.month}`
|
44
|
-
return bTime > aTime ? 1 : -1
|
45
|
-
})
|
46
|
-
})
|
47
|
-
return archives
|
48
|
-
}
|
1
|
+
/* eslint-disable style/max-statements-per-line */
|
2
|
+
import type { Post } from 'valaxy'
|
3
|
+
import { usePostList } from 'valaxy'
|
4
|
+
import { computed } from 'vue'
|
5
|
+
import dayjs from 'dayjs'
|
6
|
+
|
7
|
+
interface ArchiveYearMaps {
|
8
|
+
[year: string]: {
|
9
|
+
[month: string]: { count: number, posts: Post[] }
|
10
|
+
}
|
11
|
+
}
|
12
|
+
interface ArchiveYear {
|
13
|
+
year: string
|
14
|
+
month: string
|
15
|
+
count: number
|
16
|
+
posts: Post[]
|
17
|
+
}
|
18
|
+
|
19
|
+
export function useYearArchives() {
|
20
|
+
const posts = usePostList()
|
21
|
+
const archives = computed(() => {
|
22
|
+
const maps: ArchiveYearMaps = {}
|
23
|
+
const items: ArchiveYear[] = []
|
24
|
+
for (const post of posts.value) {
|
25
|
+
if (!post.date)
|
26
|
+
continue
|
27
|
+
const days = dayjs(post.date)
|
28
|
+
const [year, month] = [days.format('YYYY'), days.format('MM')]
|
29
|
+
if (!maps[year])
|
30
|
+
maps[year] = {}
|
31
|
+
if (!maps[year][month]) { maps[year][month] = { count: 1, posts: [post as any] } }
|
32
|
+
else {
|
33
|
+
maps[year][month].count++
|
34
|
+
maps[year][month].posts.unshift(post as any)
|
35
|
+
}
|
36
|
+
}
|
37
|
+
for (const [year, months] of Object.entries(maps)) {
|
38
|
+
for (const [month, { count, posts }] of Object.entries(months))
|
39
|
+
items.unshift({ year, month, count, posts })
|
40
|
+
}
|
41
|
+
return items.sort((a, b) => {
|
42
|
+
const aTime = `${a.year}-${a.month}`
|
43
|
+
const bTime = `${b.year}-${b.month}`
|
44
|
+
return bTime > aTime ? 1 : -1
|
45
|
+
})
|
46
|
+
})
|
47
|
+
return archives
|
48
|
+
}
|
package/composables/category.ts
CHANGED
@@ -1,43 +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
|
-
}
|
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
|
+
}
|
package/composables/config.ts
CHANGED
@@ -1,11 +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
|
-
}
|
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
|
+
}
|
package/composables/dark.ts
CHANGED
@@ -1,13 +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
|
-
}
|
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
|
+
}
|
package/composables/fuse.ts
CHANGED
@@ -1,60 +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
|
-
}
|
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
|
+
}
|
package/composables/index.ts
CHANGED
@@ -1,8 +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'
|
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
8
|
export * from './dark'
|
package/composables/layout.ts
CHANGED
@@ -1,16 +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
|
-
}
|
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
|
+
}
|