120 lines
3.9 KiB
Vue
120 lines
3.9 KiB
Vue
<script setup lang="ts">
|
|
// 获取 blog 集合的所有文章
|
|
const { data: articles } = await useAsyncData('blog-articles', () => {
|
|
return queryCollection('blog')
|
|
.select('path', 'title', 'description', 'img', 'date')
|
|
.where('path', 'NOT LIKE', '%navigation%')
|
|
.all()
|
|
})
|
|
|
|
// 格式化日期
|
|
const formatDate = (date: string | Date | null | undefined) => {
|
|
if (!date) return '未知时间'
|
|
try {
|
|
const d = new Date(date)
|
|
return d.toLocaleDateString('zh-CN', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
})
|
|
} catch {
|
|
return '未知时间'
|
|
}
|
|
}
|
|
|
|
// 计算阅读时间(基于文章内容长度估算)
|
|
// const getReadingTime = (content: string | null | undefined) => {
|
|
// if (!content) return 1
|
|
// try {
|
|
// const wordsPerMinute = 200
|
|
// const wordCount = String(content).split(/\s+/).length
|
|
// return Math.max(1, Math.ceil(wordCount / wordsPerMinute))
|
|
// } catch {
|
|
// return 1
|
|
// }
|
|
// }
|
|
</script>
|
|
|
|
<template>
|
|
<div class="w-full bg-gray-50 dark:bg-gray-900 min-h-screen mt-4">
|
|
<div class="max-w-4xl mx-auto ">
|
|
|
|
|
|
<!-- 文章列表 -->
|
|
<div class="space-y-6 w-full">
|
|
<NuxtLink
|
|
v-for="item in articles"
|
|
:key="item.path"
|
|
:to="item.path"
|
|
class="block w-full"
|
|
>
|
|
<article
|
|
class="pr-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden hover:shadow-md transition-all duration-200 cursor-pointer group"
|
|
>
|
|
<!-- 文章内容布局 -->
|
|
<div class="flex flex-row">
|
|
<!-- 图片预览区域 -->
|
|
<div class="w-32 h-32 md:w-40 md:h-40 mt-2 ml-2 mb-2 md:mr-2 -mr-1 bg-gray-100 dark:bg-gray-700 rounded-xl overflow-hidden">
|
|
<img
|
|
:src="item.img || '/images/default-blog.jpg'"
|
|
:alt="item.title"
|
|
class="w-full h-full object-contain group-hover:scale-110 transition-transform duration-300"
|
|
/>
|
|
</div>
|
|
|
|
<!-- 文字内容区域 -->
|
|
<div class="flex-1 p-4 md:p-6">
|
|
<!-- 文章头部 -->
|
|
<div class="mb-4">
|
|
<h2 class="md:text-2xl text-xl font-bold text-gray-900 dark:text-white mb-2 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">
|
|
{{ item.title }}
|
|
</h2>
|
|
|
|
<!-- 文章描述 -->
|
|
<p
|
|
v-if="item.description"
|
|
class="text-gray-600 dark:text-gray-300 md:text-sm text-xs line-clamp-2"
|
|
>
|
|
{{ item.description }}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- 文章元信息 -->
|
|
<div class="flex items-center justify-between text-xs text-gray-500 dark:text-gray-400">
|
|
<div class="flex items-center gap-4">
|
|
<!-- 文章时间 -->
|
|
<div class="flex items-center gap-1">
|
|
<UIcon
|
|
name="lucide-clock"
|
|
size="14"
|
|
/>
|
|
<span>{{ formatDate(item.date) }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
</NuxtLink>
|
|
</div>
|
|
|
|
<!-- 空状态 -->
|
|
<div
|
|
v-if="!articles || articles.length === 0"
|
|
class="text-center py-12"
|
|
>
|
|
<UIcon
|
|
name="lucide-file-text"
|
|
class="mx-auto text-4xl text-gray-400 mb-4"
|
|
/>
|
|
<h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
|
暂无文章
|
|
</h3>
|
|
<p class="text-gray-500 dark:text-gray-400">
|
|
还没有发布任何博客文章
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|