Files
SuBlog/pages/series/[name].vue
T

84 lines
3.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { siteConfig } from '~/config/site'
import { decodeRouteParam, formatPostDate, getReadTime, isVisiblePost, normalizeSeriesName, sortPostsForSeries } from '~/utils/posts'
const route = useRoute()
const rawName = Array.isArray(route.params.name) ? route.params.name[0] : route.params.name
const seriesName = decodeRouteParam(String(rawName || ''))
const { data: posts } = await useAsyncData(`series-${seriesName}`, () =>
queryCollection('posts')
.order('published', 'ASC')
.all()
)
const seriesPosts = computed(() =>
sortPostsForSeries(
(posts.value || [])
.filter(isVisiblePost)
.filter(post => normalizeSeriesName(post.series) === seriesName)
)
)
if (!seriesPosts.value.length) {
throw createError({ statusCode: 404, message: '系列不存在' })
}
useSeoMeta({
title: `${seriesName} - ${siteConfig.siteName}`,
description: `${siteConfig.siteName} 的「${seriesName}」系列文章`,
})
</script>
<template>
<div class="container mx-auto max-w-4xl px-4 py-12">
<header class="mb-12 anim-fade-in-up">
<NuxtLink to="/series" class="mb-5 inline-flex items-center gap-1 text-sm hover:underline" style="color: var(--color-primary)">
<Icon icon="mdi:arrow-left" class="h-4 w-4" />
返回系列
</NuxtLink>
<h1 class="mb-4 text-4xl font-bold">{{ seriesName }}</h1>
<p class="text-muted-foreground">
{{ seriesPosts.length }} 篇文章按阅读顺序排列
</p>
</header>
<div class="space-y-4 anim-fade-in-up anim-delay-1">
<NuxtLink
v-for="(post, index) in seriesPosts"
:key="post.path || post.id"
:to="post.path || '/posts'"
class="group grid gap-4 rounded-xl border p-5 transition-all hover:-translate-y-0.5 hover:shadow-lg md:grid-cols-[3.5rem_1fr]"
style="border-color: var(--color-border); background-color: var(--color-bg-card);"
>
<div class="flex h-12 w-12 items-center justify-center rounded-full text-lg font-bold" style="background-color: var(--color-bg-hover); color: var(--color-primary);">
{{ post.seriesOrder || index + 1 }}
</div>
<div class="min-w-0">
<div class="mb-2 flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
<time v-if="post.published">{{ formatPostDate(post.published) }}</time>
<span>· {{ getReadTime(post) }} 分钟</span>
<span v-if="post.difficulty">· {{ post.difficulty }}</span>
</div>
<h2 class="text-xl font-semibold transition-opacity group-hover:opacity-70">
{{ post.title }}
</h2>
<p v-if="post.description" class="mt-2 text-sm text-muted-foreground">
{{ post.description }}
</p>
<div v-if="post.tags?.length" class="mt-3 flex flex-wrap gap-1.5">
<span v-for="tag in post.tags" :key="tag" class="tag-pill">
{{ tag }}
</span>
</div>
</div>
</NuxtLink>
</div>
</div>
</template>