feat: 优化首页个人名片与内容入口
This commit is contained in:
+103
-6
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { siteConfig } from '~/config/site'
|
||||
import { formatPostDate, isVisiblePost, sortPostsForSeries } from '~/utils/posts'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
@@ -28,12 +29,38 @@ useSeoMeta({
|
||||
twitterImage: post.value.image || siteConfig.ogImage,
|
||||
})
|
||||
|
||||
const { data: seriesSourcePosts } = await useAsyncData(`series-source-${slug}`, () =>
|
||||
queryCollection('posts')
|
||||
.order('published', 'ASC')
|
||||
.all()
|
||||
)
|
||||
|
||||
const seriesPosts = computed(() => {
|
||||
if (!post.value?.series) return []
|
||||
|
||||
return sortPostsForSeries(
|
||||
(seriesSourcePosts.value || [])
|
||||
.filter(isVisiblePost)
|
||||
.filter(item => item.series === post.value?.series)
|
||||
)
|
||||
})
|
||||
|
||||
const currentSeriesIndex = computed(() =>
|
||||
seriesPosts.value.findIndex(item => item.path === post.value?.path)
|
||||
)
|
||||
|
||||
const previousSeriesPost = computed(() => {
|
||||
if (currentSeriesIndex.value <= 0) return null
|
||||
return seriesPosts.value[currentSeriesIndex.value - 1]
|
||||
})
|
||||
|
||||
const nextSeriesPost = computed(() => {
|
||||
if (currentSeriesIndex.value < 0) return null
|
||||
return seriesPosts.value[currentSeriesIndex.value + 1] || null
|
||||
})
|
||||
|
||||
function formatDate(date: string) {
|
||||
return new Date(date).toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
})
|
||||
return formatPostDate(date)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -41,10 +68,24 @@ function formatDate(date: string) {
|
||||
<article v-if="post" class="container mx-auto max-w-3xl px-4 py-12">
|
||||
|
||||
<header class="mb-8 anim-fade-in-up">
|
||||
<div class="mb-4 flex items-center gap-2">
|
||||
<div class="mb-4 flex flex-wrap items-center gap-x-3 gap-y-2">
|
||||
<time v-if="post.published" class="text-sm text-muted-foreground">
|
||||
{{ formatDate(post.published) }}
|
||||
</time>
|
||||
<span v-if="post.updated" class="text-sm text-muted-foreground">
|
||||
更新 {{ formatDate(post.updated) }}
|
||||
</span>
|
||||
<span v-if="post.difficulty" class="text-sm text-muted-foreground">
|
||||
{{ post.difficulty }}
|
||||
</span>
|
||||
<NuxtLink
|
||||
v-if="post.series"
|
||||
:to="`/series/${encodeURIComponent(post.series)}`"
|
||||
class="inline-flex items-center rounded-full px-2.5 py-1 text-xs font-medium hover:opacity-80"
|
||||
style="background: var(--color-bg-hover); color: var(--color-primary);"
|
||||
>
|
||||
{{ post.series }}
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<h1 class="mb-4 text-4xl font-bold">{{ post.title }}</h1>
|
||||
@@ -89,6 +130,62 @@ function formatDate(date: string) {
|
||||
<ContentRenderer :value="post" />
|
||||
</div>
|
||||
|
||||
<section
|
||||
v-if="post.series && seriesPosts.length > 1"
|
||||
class="mt-12 pt-8 anim-fade-in-up anim-delay-2"
|
||||
style="border-top: 1px solid var(--color-border)"
|
||||
>
|
||||
<div class="mb-4 flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">
|
||||
<div>
|
||||
<p class="text-sm text-muted-foreground">当前系列</p>
|
||||
<h2 class="text-xl font-semibold">{{ post.series }}</h2>
|
||||
</div>
|
||||
<NuxtLink
|
||||
:to="`/series/${encodeURIComponent(post.series)}`"
|
||||
class="text-sm hover:underline"
|
||||
style="color: var(--color-primary)"
|
||||
>
|
||||
查看全部 {{ seriesPosts.length }} 篇
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-3 md:grid-cols-2">
|
||||
<NuxtLink
|
||||
v-if="previousSeriesPost"
|
||||
:to="previousSeriesPost.path || '/posts'"
|
||||
class="group rounded-lg border p-4 transition-colors hover:bg-muted"
|
||||
style="border-color: var(--color-border);"
|
||||
>
|
||||
<p class="mb-1 text-xs text-muted-foreground">上一篇</p>
|
||||
<p class="font-medium transition-opacity group-hover:opacity-70">{{ previousSeriesPost.title }}</p>
|
||||
</NuxtLink>
|
||||
<div
|
||||
v-else
|
||||
class="rounded-lg border p-4 text-sm text-muted-foreground"
|
||||
style="border-color: var(--color-border);"
|
||||
>
|
||||
已经是本系列第一篇
|
||||
</div>
|
||||
|
||||
<NuxtLink
|
||||
v-if="nextSeriesPost"
|
||||
:to="nextSeriesPost.path || '/posts'"
|
||||
class="group rounded-lg border p-4 text-right transition-colors hover:bg-muted"
|
||||
style="border-color: var(--color-border);"
|
||||
>
|
||||
<p class="mb-1 text-xs text-muted-foreground">下一篇</p>
|
||||
<p class="font-medium transition-opacity group-hover:opacity-70">{{ nextSeriesPost.title }}</p>
|
||||
</NuxtLink>
|
||||
<div
|
||||
v-else
|
||||
class="rounded-lg border p-4 text-right text-sm text-muted-foreground"
|
||||
style="border-color: var(--color-border);"
|
||||
>
|
||||
已经是本系列最后一篇
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="anim-fade-in-up anim-delay-2">
|
||||
<BlogGiscus class="mt-16" />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user