94 lines
4.5 KiB
Plaintext
94 lines
4.5 KiB
Plaintext
---
|
|
import type { CollectionEntry } from 'astro:content';
|
|
|
|
interface Props {
|
|
title?: string;
|
|
articles: CollectionEntry<'articles'>[];
|
|
}
|
|
|
|
const {
|
|
title = "文章时间线",
|
|
articles = []
|
|
} = Astro.props;
|
|
|
|
// 按日期排序文章
|
|
const sortedArticles = articles.sort(
|
|
(a, b) => b.data.date.getTime() - a.data.date.getTime()
|
|
);
|
|
---
|
|
|
|
<div class="container mx-auto px-4 py-8">
|
|
{title && <h1 class="text-3xl font-bold mb-6 text-primary-900 dark:text-primary-100">{title}</h1>}
|
|
|
|
<div id="article-timeline" class="relative space-y-8 before:absolute before:inset-0 before:ml-5 before:h-full before:w-0.5 before:-translate-x-px before:bg-gradient-to-b before:from-transparent before:via-primary-300 before:to-transparent md:before:mx-auto md:before:translate-x-0">
|
|
{sortedArticles.length > 0 ? (
|
|
sortedArticles.map((article, index) => {
|
|
const isEven = index % 2 === 0;
|
|
return (
|
|
<div class="relative group">
|
|
{/* 时间线节点 */}
|
|
<div class="absolute left-5 -translate-x-1/2 md:left-1/2 top-6 flex h-3 w-3 items-center justify-center">
|
|
<div class="h-2 w-2 rounded-full bg-primary-500 dark:bg-primary-400 ring-2 ring-white dark:ring-gray-900 ring-offset-2 ring-offset-white dark:ring-offset-gray-900"></div>
|
|
</div>
|
|
|
|
{/* 文章卡片 */}
|
|
<a href={`/articles/${article.id}`}
|
|
class={`group/card ml-10 md:ml-0 ${isEven ? 'md:mr-[50%] md:pr-8' : 'md:ml-[50%] md:pl-8'} block`}>
|
|
<article class="relative flex flex-col gap-4 rounded-xl bg-white dark:bg-gray-800 p-6 shadow-lg hover:shadow-xl hover:-translate-y-1 transition-all duration-300 border border-gray-200 dark:border-gray-700">
|
|
{/* 日期标签 */}
|
|
<time datetime={article.data.date.toISOString()}
|
|
class="absolute top-4 right-4 text-xs font-medium text-secondary-500 dark:text-secondary-400">
|
|
{article.data.date.toLocaleDateString('zh-CN', {year: 'numeric', month: 'long', day: 'numeric'})}
|
|
</time>
|
|
|
|
{/* 文章标题 */}
|
|
<h3 class="pr-16 text-xl font-bold text-gray-900 dark:text-gray-100 group-hover/card:text-primary-600 dark:group-hover/card:text-primary-400 transition-colors">
|
|
{article.data.title}
|
|
</h3>
|
|
|
|
{/* 文章摘要 */}
|
|
{article.data.summary && (
|
|
<p class="text-secondary-600 dark:text-secondary-300 line-clamp-2">
|
|
{article.data.summary}
|
|
</p>
|
|
)}
|
|
|
|
{/* 文章元信息 */}
|
|
<div class="flex flex-wrap items-center gap-4 text-sm">
|
|
{article.data.section && (
|
|
<span class="flex items-center text-secondary-500 dark:text-secondary-400">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
|
|
</svg>
|
|
{article.data.section}
|
|
</span>
|
|
)}
|
|
|
|
{article.data.tags && article.data.tags.length > 0 && (
|
|
<div class="flex flex-wrap gap-2">
|
|
{article.data.tags.map(tag => (
|
|
<span class="text-xs bg-primary-50 dark:bg-primary-900/30 text-primary-600 dark:text-primary-400 py-1 px-2 rounded-full">
|
|
#{tag}
|
|
</span>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* 阅读更多指示器 */}
|
|
<div class="flex items-center text-sm text-primary-600 dark:text-primary-400 group-hover/card:translate-x-1 transition-transform">
|
|
<span class="font-medium">阅读全文</span>
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
|
|
</svg>
|
|
</div>
|
|
</article>
|
|
</a>
|
|
</div>
|
|
);
|
|
})
|
|
) : (
|
|
<div class="text-center py-4 text-secondary-600 dark:text-secondary-400">暂无文章数据</div>
|
|
)}
|
|
</div>
|
|
</div> |