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,126 +1,126 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import type { Post } from 'valaxy'
|
3
|
-
import { computed, defineProps } from 'vue'
|
4
|
-
import dayjs from 'dayjs'
|
5
|
-
import { useRouter } from 'vue-router'
|
6
|
-
import { useI18n } from 'vue-i18n'
|
7
|
-
import { removeTags, toArray } from '../../utils'
|
8
|
-
import { useLayoutPost } from '../../composables'
|
9
|
-
|
10
|
-
const props = defineProps<{
|
11
|
-
post: Post
|
12
|
-
reverse?: boolean
|
13
|
-
}>()
|
14
|
-
|
15
|
-
const router = useRouter()
|
16
|
-
const layout = useLayoutPost()
|
17
|
-
const slice = computed(() => layout.value.includes('slice'))
|
18
|
-
const image = computed(() => props.post.image?.toString())
|
19
|
-
const text = computed(() => removeTags(props.post.excerpt))
|
20
|
-
const i18n = useI18n()
|
21
|
-
function onReadMore() {
|
22
|
-
if (props.post.path)
|
23
|
-
router.push(props.post.path)
|
24
|
-
}
|
25
|
-
|
26
|
-
function displayCategory(keys: string | string[] = []) {
|
27
|
-
router.push({ path: `/categories/${toArray(keys).join('/')}` })
|
28
|
-
}
|
29
|
-
</script>
|
30
|
-
|
31
|
-
<template>
|
32
|
-
<li class="HairyArticleImage mb-10 py-2" :class="[slice && 'slice', reverse && 'reverse']">
|
33
|
-
<article>
|
34
|
-
<div class="flex justify-between items-center">
|
35
|
-
<a class="text-size-2xl font-bold truncate cursor-pointer lt-sm:text-size-lg" :class="[reverse ? 'order-last' : 'order-first']" @click="onReadMore">{{ post.title }}</a>
|
36
|
-
<div class="flex justify-end gap-2 text-size-sm lt-sm:text-size-xs">
|
37
|
-
<span>{{ dayjs(post.date).format('YYYY-MM-DD') }}</span>
|
38
|
-
<span>{{ post.wordCount }}字</span>
|
39
|
-
<span class="lt-sm:hidden">{{ post.readingTime }}分钟</span>
|
40
|
-
</div>
|
41
|
-
</div>
|
42
|
-
<div class="h-200px lt-sm:h-150px flex bg-light-2 dark:bg-transparent rounded-5" :class="[reverse ? 'pl-4' : 'pr-4']">
|
43
|
-
<div class="flex-1 post-image-content" :class="[reverse ? 'order-last' : 'order-first']">
|
44
|
-
<img
|
45
|
-
class="post-image rounded-1 w-full h-full object-cover cursor-pointer" :src="image"
|
46
|
-
@click="onReadMore"
|
47
|
-
>
|
48
|
-
</div>
|
49
|
-
<div class="flex-1 flex flex-col justify-between py-2 dark:py-0">
|
50
|
-
<div class="flex-1 text-size-sm">
|
51
|
-
<div class="line-clamp-text">
|
52
|
-
{{ text }}
|
53
|
-
</div>
|
54
|
-
</div>
|
55
|
-
<div class="flex justify-between items-center">
|
56
|
-
<a class="cursor-pointer" :class="[reverse && 'order-1']">
|
57
|
-
<span v-if="post.categories?.length" @click="displayCategory(post.categories)">
|
58
|
-
{{ i18n.t(toArray(post.categories).at(-1) || '') }}
|
59
|
-
</span>
|
60
|
-
</a>
|
61
|
-
<div class="text-base leading-6 font-medium">
|
62
|
-
<a class="link cursor-pointer" aria-label="read more" @click="onReadMore">
|
63
|
-
<span v-if="reverse">←</span>
|
64
|
-
<span class="hidden md:block">Read more</span>
|
65
|
-
<span v-if="!reverse">→</span>
|
66
|
-
</a>
|
67
|
-
</div>
|
68
|
-
</div>
|
69
|
-
</div>
|
70
|
-
</div>
|
71
|
-
</article>
|
72
|
-
</li>
|
73
|
-
</template>
|
74
|
-
|
75
|
-
<style lang="scss" scoped>
|
76
|
-
.line-clamp-text {
|
77
|
-
word-break: break-all;
|
78
|
-
overflow: hidden;
|
79
|
-
text-overflow: ellipsis;
|
80
|
-
display: -webkit-box;
|
81
|
-
text-overflow: ellipsis;
|
82
|
-
-webkit-box-orient: vertical;
|
83
|
-
-webkit-line-clamp: 5;
|
84
|
-
}
|
85
|
-
|
86
|
-
.dark {
|
87
|
-
.post-image {
|
88
|
-
@apply opacity-75 hover:opacity-90 ;
|
89
|
-
}
|
90
|
-
}
|
91
|
-
|
92
|
-
.post-image-content {
|
93
|
-
margin-right: 1rem;
|
94
|
-
}
|
95
|
-
|
96
|
-
.slice {
|
97
|
-
.post-image-content {
|
98
|
-
webkit-clip-path: polygon(0 0, 92% 0, 100% 100%, 0 100%);
|
99
|
-
clip-path: polygon(0 0, 92% 0, 100% 100%, 0 100%);
|
100
|
-
border-radius: 0.625rem 0 0 0.625rem;
|
101
|
-
overflow: hidden;
|
102
|
-
}
|
103
|
-
}
|
104
|
-
|
105
|
-
.reverse {
|
106
|
-
.post-image-content {
|
107
|
-
margin-right: 0;
|
108
|
-
margin-left: 1rem;
|
109
|
-
clip-path: polygon(0 0,100% 0,100% 100%,8% 100%);
|
110
|
-
border-radius: 0 0.625rem 0.625rem 0;
|
111
|
-
overflow: hidden;
|
112
|
-
}
|
113
|
-
}
|
114
|
-
|
115
|
-
.HairyArticleImage.slice {
|
116
|
-
.post-image {
|
117
|
-
// @apply transition-all;
|
118
|
-
}
|
119
|
-
|
120
|
-
&:hover {
|
121
|
-
.post-image {
|
122
|
-
transform: scale(1.05) rotate(1deg);
|
123
|
-
}
|
124
|
-
}
|
125
|
-
}
|
126
|
-
</style>
|
1
|
+
<script lang="ts" setup>
|
2
|
+
import type { Post } from 'valaxy'
|
3
|
+
import { computed, defineProps } from 'vue'
|
4
|
+
import dayjs from 'dayjs'
|
5
|
+
import { useRouter } from 'vue-router'
|
6
|
+
import { useI18n } from 'vue-i18n'
|
7
|
+
import { removeTags, toArray } from '../../utils'
|
8
|
+
import { useLayoutPost } from '../../composables'
|
9
|
+
|
10
|
+
const props = defineProps<{
|
11
|
+
post: Post
|
12
|
+
reverse?: boolean
|
13
|
+
}>()
|
14
|
+
|
15
|
+
const router = useRouter()
|
16
|
+
const layout = useLayoutPost()
|
17
|
+
const slice = computed(() => layout.value.includes('slice'))
|
18
|
+
const image = computed(() => props.post.image?.toString())
|
19
|
+
const text = computed(() => removeTags(props.post.excerpt))
|
20
|
+
const i18n = useI18n()
|
21
|
+
function onReadMore() {
|
22
|
+
if (props.post.path)
|
23
|
+
router.push(props.post.path)
|
24
|
+
}
|
25
|
+
|
26
|
+
function displayCategory(keys: string | string[] = []) {
|
27
|
+
router.push({ path: `/categories/${toArray(keys).join('/')}` })
|
28
|
+
}
|
29
|
+
</script>
|
30
|
+
|
31
|
+
<template>
|
32
|
+
<li class="HairyArticleImage mb-10 py-2" :class="[slice && 'slice', reverse && 'reverse']">
|
33
|
+
<article>
|
34
|
+
<div class="flex justify-between items-center">
|
35
|
+
<a class="text-size-2xl font-bold truncate cursor-pointer lt-sm:text-size-lg" :class="[reverse ? 'order-last' : 'order-first']" @click="onReadMore">{{ post.title }}</a>
|
36
|
+
<div class="flex justify-end gap-2 text-size-sm lt-sm:text-size-xs">
|
37
|
+
<span>{{ dayjs(post.date).format('YYYY-MM-DD') }}</span>
|
38
|
+
<span>{{ post.wordCount }}字</span>
|
39
|
+
<span class="lt-sm:hidden">{{ post.readingTime }}分钟</span>
|
40
|
+
</div>
|
41
|
+
</div>
|
42
|
+
<div class="h-200px lt-sm:h-150px flex bg-light-2 dark:bg-transparent rounded-5" :class="[reverse ? 'pl-4' : 'pr-4']">
|
43
|
+
<div class="flex-1 post-image-content" :class="[reverse ? 'order-last' : 'order-first']">
|
44
|
+
<img
|
45
|
+
class="post-image rounded-1 w-full h-full object-cover cursor-pointer" :src="image"
|
46
|
+
@click="onReadMore"
|
47
|
+
>
|
48
|
+
</div>
|
49
|
+
<div class="flex-1 flex flex-col justify-between py-2 dark:py-0">
|
50
|
+
<div class="flex-1 text-size-sm">
|
51
|
+
<div class="line-clamp-text">
|
52
|
+
{{ text }}
|
53
|
+
</div>
|
54
|
+
</div>
|
55
|
+
<div class="flex justify-between items-center">
|
56
|
+
<a class="cursor-pointer" :class="[reverse && 'order-1']">
|
57
|
+
<span v-if="post.categories?.length" @click="displayCategory(post.categories)">
|
58
|
+
{{ i18n.t(toArray(post.categories).at(-1) || '') }}
|
59
|
+
</span>
|
60
|
+
</a>
|
61
|
+
<div class="text-base leading-6 font-medium">
|
62
|
+
<a class="link cursor-pointer" aria-label="read more" @click="onReadMore">
|
63
|
+
<span v-if="reverse">←</span>
|
64
|
+
<span class="hidden md:block">Read more</span>
|
65
|
+
<span v-if="!reverse">→</span>
|
66
|
+
</a>
|
67
|
+
</div>
|
68
|
+
</div>
|
69
|
+
</div>
|
70
|
+
</div>
|
71
|
+
</article>
|
72
|
+
</li>
|
73
|
+
</template>
|
74
|
+
|
75
|
+
<style lang="scss" scoped>
|
76
|
+
.line-clamp-text {
|
77
|
+
word-break: break-all;
|
78
|
+
overflow: hidden;
|
79
|
+
text-overflow: ellipsis;
|
80
|
+
display: -webkit-box;
|
81
|
+
text-overflow: ellipsis;
|
82
|
+
-webkit-box-orient: vertical;
|
83
|
+
-webkit-line-clamp: 5;
|
84
|
+
}
|
85
|
+
|
86
|
+
.dark {
|
87
|
+
.post-image {
|
88
|
+
@apply opacity-75 hover:opacity-90 ;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
.post-image-content {
|
93
|
+
margin-right: 1rem;
|
94
|
+
}
|
95
|
+
|
96
|
+
.slice {
|
97
|
+
.post-image-content {
|
98
|
+
webkit-clip-path: polygon(0 0, 92% 0, 100% 100%, 0 100%);
|
99
|
+
clip-path: polygon(0 0, 92% 0, 100% 100%, 0 100%);
|
100
|
+
border-radius: 0.625rem 0 0 0.625rem;
|
101
|
+
overflow: hidden;
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
.reverse {
|
106
|
+
.post-image-content {
|
107
|
+
margin-right: 0;
|
108
|
+
margin-left: 1rem;
|
109
|
+
clip-path: polygon(0 0,100% 0,100% 100%,8% 100%);
|
110
|
+
border-radius: 0 0.625rem 0.625rem 0;
|
111
|
+
overflow: hidden;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
.HairyArticleImage.slice {
|
116
|
+
.post-image {
|
117
|
+
// @apply transition-all;
|
118
|
+
}
|
119
|
+
|
120
|
+
&:hover {
|
121
|
+
.post-image {
|
122
|
+
transform: scale(1.05) rotate(1deg);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
</style>
|
@@ -1,89 +1,89 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import type { PostFrontMatter } from 'valaxy'
|
3
|
-
import { useFrontmatter } from 'valaxy'
|
4
|
-
import { computed, inject, nextTick, ref } from 'vue'
|
5
|
-
import { useRouter } from 'vue-router'
|
6
|
-
import { toArray } from '../../utils'
|
7
|
-
import { useCategory } from '../../composables'
|
8
|
-
|
9
|
-
const frontmatter = useFrontmatter()
|
10
|
-
const paths = computed(() => toArray(frontmatter.value.categories).filter(Boolean) as string[])
|
11
|
-
const category = useCategory(paths)
|
12
|
-
|
13
|
-
const posts = computed(() => {
|
14
|
-
const result = [...(category.value.children?.values() || [])] as PostFrontMatter[]
|
15
|
-
return result.sort((a, b) => (a.date || 1) > (b.date || 1) ? 1 : -1)
|
16
|
-
})
|
17
|
-
|
18
|
-
const router = useRouter()
|
19
|
-
|
20
|
-
const active = inject('HairyUserTab:active', ref(''))
|
21
|
-
|
22
|
-
function isCurrent(title = '') {
|
23
|
-
return frontmatter.value.title === title
|
24
|
-
}
|
25
|
-
|
26
|
-
async function changePost(path = '') {
|
27
|
-
router.push(path)
|
28
|
-
await nextTick()
|
29
|
-
active.value = 'aside'
|
30
|
-
}
|
31
|
-
</script>
|
32
|
-
|
33
|
-
<template>
|
34
|
-
<div class="pl-16px text-14px relative overflow-hidden animate__animated animate__fadeIn">
|
35
|
-
<div class="outline-title">
|
36
|
-
On this Series
|
37
|
-
</div>
|
38
|
-
<ul class="va-toc relative z-1">
|
39
|
-
<a v-for="(item, index) of posts" :key="index" class="va-toc-item" @click="changePost(item.path)">
|
40
|
-
<a class="outline-link" :class="[isCurrent(item.title) && 'active']">{{ index + 1 }}.{{ item.title }}</a>
|
41
|
-
</a>
|
42
|
-
</ul>
|
43
|
-
</div>
|
44
|
-
</template>
|
45
|
-
|
46
|
-
<style lang="scss" scoped>
|
47
|
-
.outline-title {
|
48
|
-
letter-spacing: 0.4px;
|
49
|
-
line-height: 28px;
|
50
|
-
font-size: 14px;
|
51
|
-
font-weight: 600;
|
52
|
-
}
|
53
|
-
|
54
|
-
.outline-link {
|
55
|
-
display: block;
|
56
|
-
position: relative;
|
57
|
-
line-height: 28px;
|
58
|
-
color: var(--va-c-text-light);
|
59
|
-
white-space: nowrap;
|
60
|
-
text-overflow: ellipsis;
|
61
|
-
transition: color 0.5s;
|
62
|
-
cursor: pointer;
|
63
|
-
|
64
|
-
&:hover {
|
65
|
-
color: var(--va-c-brand);
|
66
|
-
transition: color 0.25s;
|
67
|
-
}
|
68
|
-
|
69
|
-
&.active {
|
70
|
-
color: var(--va-c-brand);
|
71
|
-
transition: color .25s;
|
72
|
-
|
73
|
-
&::after {
|
74
|
-
position: absolute;
|
75
|
-
content: '';
|
76
|
-
left: -1.12rem;
|
77
|
-
top: 0;
|
78
|
-
bottom: 0;
|
79
|
-
margin: auto;
|
80
|
-
width: 4px;
|
81
|
-
height: 18px;
|
82
|
-
background-color: var(--va-c-brand);
|
83
|
-
transition: top 0.25s cubic-bezier(0, 1, 0.5, 1), background-color 0.5s, opacity 0.25s;
|
84
|
-
border-top-right-radius: 2px;
|
85
|
-
border-bottom-right-radius: 2px;
|
86
|
-
}
|
87
|
-
}
|
88
|
-
}
|
89
|
-
</style>
|
1
|
+
<script lang="ts" setup>
|
2
|
+
import type { PostFrontMatter } from 'valaxy'
|
3
|
+
import { useFrontmatter } from 'valaxy'
|
4
|
+
import { computed, inject, nextTick, ref } from 'vue'
|
5
|
+
import { useRouter } from 'vue-router'
|
6
|
+
import { toArray } from '../../utils'
|
7
|
+
import { useCategory } from '../../composables'
|
8
|
+
|
9
|
+
const frontmatter = useFrontmatter()
|
10
|
+
const paths = computed(() => toArray(frontmatter.value.categories).filter(Boolean) as string[])
|
11
|
+
const category = useCategory(paths)
|
12
|
+
|
13
|
+
const posts = computed(() => {
|
14
|
+
const result = [...(category.value.children?.values() || [])] as PostFrontMatter[]
|
15
|
+
return result.sort((a, b) => (a.date || 1) > (b.date || 1) ? 1 : -1)
|
16
|
+
})
|
17
|
+
|
18
|
+
const router = useRouter()
|
19
|
+
|
20
|
+
const active = inject('HairyUserTab:active', ref(''))
|
21
|
+
|
22
|
+
function isCurrent(title = '') {
|
23
|
+
return frontmatter.value.title === title
|
24
|
+
}
|
25
|
+
|
26
|
+
async function changePost(path = '') {
|
27
|
+
router.push(path)
|
28
|
+
await nextTick()
|
29
|
+
active.value = 'aside'
|
30
|
+
}
|
31
|
+
</script>
|
32
|
+
|
33
|
+
<template>
|
34
|
+
<div class="pl-16px text-14px relative overflow-hidden animate__animated animate__fadeIn">
|
35
|
+
<div class="outline-title">
|
36
|
+
On this Series
|
37
|
+
</div>
|
38
|
+
<ul class="va-toc relative z-1">
|
39
|
+
<a v-for="(item, index) of posts" :key="index" class="va-toc-item" @click="changePost(item.path)">
|
40
|
+
<a class="outline-link" :class="[isCurrent(item.title) && 'active']">{{ index + 1 }}.{{ item.title }}</a>
|
41
|
+
</a>
|
42
|
+
</ul>
|
43
|
+
</div>
|
44
|
+
</template>
|
45
|
+
|
46
|
+
<style lang="scss" scoped>
|
47
|
+
.outline-title {
|
48
|
+
letter-spacing: 0.4px;
|
49
|
+
line-height: 28px;
|
50
|
+
font-size: 14px;
|
51
|
+
font-weight: 600;
|
52
|
+
}
|
53
|
+
|
54
|
+
.outline-link {
|
55
|
+
display: block;
|
56
|
+
position: relative;
|
57
|
+
line-height: 28px;
|
58
|
+
color: var(--va-c-text-light);
|
59
|
+
white-space: nowrap;
|
60
|
+
text-overflow: ellipsis;
|
61
|
+
transition: color 0.5s;
|
62
|
+
cursor: pointer;
|
63
|
+
|
64
|
+
&:hover {
|
65
|
+
color: var(--va-c-brand);
|
66
|
+
transition: color 0.25s;
|
67
|
+
}
|
68
|
+
|
69
|
+
&.active {
|
70
|
+
color: var(--va-c-brand);
|
71
|
+
transition: color .25s;
|
72
|
+
|
73
|
+
&::after {
|
74
|
+
position: absolute;
|
75
|
+
content: '';
|
76
|
+
left: -1.12rem;
|
77
|
+
top: 0;
|
78
|
+
bottom: 0;
|
79
|
+
margin: auto;
|
80
|
+
width: 4px;
|
81
|
+
height: 18px;
|
82
|
+
background-color: var(--va-c-brand);
|
83
|
+
transition: top 0.25s cubic-bezier(0, 1, 0.5, 1), background-color 0.5s, opacity 0.25s;
|
84
|
+
border-top-right-radius: 2px;
|
85
|
+
border-bottom-right-radius: 2px;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
</style>
|
@@ -1,43 +1,43 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import type { Post } from 'valaxy'
|
3
|
-
import { computed, defineProps } from 'vue'
|
4
|
-
import { removeTags } from '../../utils'
|
5
|
-
import { useLayoutPost } from '../../composables'
|
6
|
-
|
7
|
-
const props = defineProps<{
|
8
|
-
post: Post
|
9
|
-
}>()
|
10
|
-
|
11
|
-
const layout = useLayoutPost()
|
12
|
-
|
13
|
-
const text = computed(() => {
|
14
|
-
if (layout.value === 'text')
|
15
|
-
return removeTags(props.post.excerpt)
|
16
|
-
return props.post.excerpt
|
17
|
-
})
|
18
|
-
</script>
|
19
|
-
|
20
|
-
<template>
|
21
|
-
<li class="py-12">
|
22
|
-
<article class="space-y-2 xl:grid xl:grid-cols-4 xl:space-y-0 xl:items-baseline">
|
23
|
-
<div class="space-y-5 xl:col-span-4">
|
24
|
-
<div class="space-y-6">
|
25
|
-
<h2 class="text-2xl leading-8 font-bold tracking-tight">
|
26
|
-
<a class="st-text" :href="post.path">{{ post.title }}</a>
|
27
|
-
</h2>
|
28
|
-
<div
|
29
|
-
v-if="text"
|
30
|
-
class="prose max-w-none text-gray-500"
|
31
|
-
v-html="text"
|
32
|
-
/>
|
33
|
-
</div>
|
34
|
-
<div class="text-base leading-6 font-medium">
|
35
|
-
<a class="link" aria-label="read more" :href="post.path">
|
36
|
-
<span class="hidden md:block">Read more</span>
|
37
|
-
<span> →</span>
|
38
|
-
</a>
|
39
|
-
</div>
|
40
|
-
</div>
|
41
|
-
</article>
|
42
|
-
</li>
|
43
|
-
</template>
|
1
|
+
<script lang="ts" setup>
|
2
|
+
import type { Post } from 'valaxy'
|
3
|
+
import { computed, defineProps } from 'vue'
|
4
|
+
import { removeTags } from '../../utils'
|
5
|
+
import { useLayoutPost } from '../../composables'
|
6
|
+
|
7
|
+
const props = defineProps<{
|
8
|
+
post: Post
|
9
|
+
}>()
|
10
|
+
|
11
|
+
const layout = useLayoutPost()
|
12
|
+
|
13
|
+
const text = computed(() => {
|
14
|
+
if (layout.value === 'text')
|
15
|
+
return removeTags(props.post.excerpt)
|
16
|
+
return props.post.excerpt
|
17
|
+
})
|
18
|
+
</script>
|
19
|
+
|
20
|
+
<template>
|
21
|
+
<li class="py-12">
|
22
|
+
<article class="space-y-2 xl:grid xl:grid-cols-4 xl:space-y-0 xl:items-baseline">
|
23
|
+
<div class="space-y-5 xl:col-span-4">
|
24
|
+
<div class="space-y-6">
|
25
|
+
<h2 class="text-2xl leading-8 font-bold tracking-tight">
|
26
|
+
<a class="st-text" :href="post.path">{{ post.title }}</a>
|
27
|
+
</h2>
|
28
|
+
<div
|
29
|
+
v-if="text"
|
30
|
+
class="prose max-w-none text-gray-500"
|
31
|
+
v-html="text"
|
32
|
+
/>
|
33
|
+
</div>
|
34
|
+
<div class="text-base leading-6 font-medium">
|
35
|
+
<a class="link" aria-label="read more" :href="post.path">
|
36
|
+
<span class="hidden md:block">Read more</span>
|
37
|
+
<span> →</span>
|
38
|
+
</a>
|
39
|
+
</div>
|
40
|
+
</div>
|
41
|
+
</article>
|
42
|
+
</li>
|
43
|
+
</template>
|
@@ -1,15 +1,15 @@
|
|
1
|
-
<script lang="ts" setup>
|
2
|
-
import { useRoute } from 'vue-router'
|
3
|
-
|
4
|
-
const route = useRoute()
|
5
|
-
</script>
|
6
|
-
|
7
|
-
<template>
|
8
|
-
<div class="mb-15">
|
9
|
-
<div class="border-t border-gray-200 dark:border-gray-600" />
|
10
|
-
<div class="flex items-center justify-end mt-2">
|
11
|
-
<div class="i-ri-eye-fill mr-2" />
|
12
|
-
阅读次数 <span class="waline-pageview-count mx-2" :data-path="route.path"> - </span> 次
|
13
|
-
</div>
|
14
|
-
</div>
|
15
|
-
</template>
|
1
|
+
<script lang="ts" setup>
|
2
|
+
import { useRoute } from 'vue-router'
|
3
|
+
|
4
|
+
const route = useRoute()
|
5
|
+
</script>
|
6
|
+
|
7
|
+
<template>
|
8
|
+
<div class="mb-15">
|
9
|
+
<div class="border-t border-gray-200 dark:border-gray-600" />
|
10
|
+
<div class="flex items-center justify-end mt-2">
|
11
|
+
<div class="i-ri-eye-fill mr-2" />
|
12
|
+
阅读次数 <span class="waline-pageview-count mx-2" :data-path="route.path"> - </span> 次
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
</template>
|
@@ -1,27 +1,27 @@
|
|
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
|
-
import { useLayoutPost } from '../../composables'
|
7
|
-
|
8
|
-
const props = withDefaults(defineProps<{
|
9
|
-
type?: string
|
10
|
-
posts?: Post[]
|
11
|
-
}>(), {
|
12
|
-
})
|
13
|
-
|
14
|
-
const layout = useLayoutPost()
|
15
|
-
const reverse = computed(() => layout.value.includes('reverse'))
|
16
|
-
|
17
|
-
const routes = usePostList() as any as Ref<Post[]>
|
18
|
-
const posts = computed(() => props.posts || routes.value)
|
19
|
-
</script>
|
20
|
-
|
21
|
-
<template>
|
22
|
-
<ul class="divide-y divide-gray-200 dark:divide-gray-700">
|
23
|
-
<Transition v-for="post, i in posts" :key="i" name="fade">
|
24
|
-
<HairyArticleImage :post="post" :reverse="reverse && !((i % 2) === 0)" />
|
25
|
-
</Transition>
|
26
|
-
</ul>
|
27
|
-
</template>
|
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
|
+
import { useLayoutPost } from '../../composables'
|
7
|
+
|
8
|
+
const props = withDefaults(defineProps<{
|
9
|
+
type?: string
|
10
|
+
posts?: Post[]
|
11
|
+
}>(), {
|
12
|
+
})
|
13
|
+
|
14
|
+
const layout = useLayoutPost()
|
15
|
+
const reverse = computed(() => layout.value.includes('reverse'))
|
16
|
+
|
17
|
+
const routes = usePostList() as any as Ref<Post[]>
|
18
|
+
const posts = computed(() => props.posts || routes.value)
|
19
|
+
</script>
|
20
|
+
|
21
|
+
<template>
|
22
|
+
<ul class="divide-y divide-gray-200 dark:divide-gray-700">
|
23
|
+
<Transition v-for="post, i in posts" :key="i" name="fade">
|
24
|
+
<HairyArticleImage :post="post" :reverse="reverse && !((i % 2) === 0)" />
|
25
|
+
</Transition>
|
26
|
+
</ul>
|
27
|
+
</template>
|
@@ -1,22 +1,22 @@
|
|
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>
|
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>
|