修复文章所有的问题
This commit is contained in:
parent
ab83710eb6
commit
9ed938c946
@ -1,94 +0,0 @@
|
|||||||
---
|
|
||||||
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>
|
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
import { getCollection, render } from 'astro:content';
|
import { getCollection, render } from 'astro:content';
|
||||||
import { contentStructure, getRelativePath, getBasename, getDirPath, getOriginalPath, getSpecialPath } from '@/content.config';
|
import { contentStructure, getRelativePath, getBasename, getDirPath, getSpecialPath } from '@/content.config';
|
||||||
import type { SectionStructure } from '@/content.config';
|
import type { SectionStructure } from '@/content.config';
|
||||||
import Layout from '@/components/Layout.astro';
|
import Layout from '@/components/Layout.astro';
|
||||||
import Breadcrumb from '@/components/Breadcrumb.astro';
|
import Breadcrumb from '@/components/Breadcrumb.astro';
|
||||||
@ -10,6 +10,7 @@ export const prerender = true;
|
|||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const articles = await getCollection('articles');
|
const articles = await getCollection('articles');
|
||||||
|
const views = ['grid', 'timeline'];
|
||||||
|
|
||||||
// 为每篇文章添加section信息
|
// 为每篇文章添加section信息
|
||||||
const articlesWithSections = articles.map(article => {
|
const articlesWithSections = articles.map(article => {
|
||||||
@ -67,23 +68,41 @@ export async function getStaticPaths() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 为每篇文章生成路由参数
|
// 为每篇文章生成路由参数
|
||||||
return articlesWithSections.map(article => {
|
const paths = [];
|
||||||
|
for (const article of articlesWithSections) {
|
||||||
// 检查文章ID是否需要特殊处理
|
// 检查文章ID是否需要特殊处理
|
||||||
const specialId = getSpecialPath(article.id);
|
const specialId = getSpecialPath(article.id);
|
||||||
|
|
||||||
return {
|
// 添加基本路由
|
||||||
|
paths.push({
|
||||||
params: { id: specialId },
|
params: { id: specialId },
|
||||||
props: {
|
props: {
|
||||||
article,
|
article,
|
||||||
section: article.section,
|
section: article.section,
|
||||||
originalId: specialId !== article.id ? article.id : undefined
|
originalId: specialId !== article.id ? article.id : undefined,
|
||||||
|
view: undefined
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
});
|
|
||||||
|
// 为每个视图添加路由
|
||||||
|
for (const view of views) {
|
||||||
|
paths.push({
|
||||||
|
params: { id: `${specialId}/${view}` },
|
||||||
|
props: {
|
||||||
|
article,
|
||||||
|
section: article.section,
|
||||||
|
originalId: specialId !== article.id ? article.id : undefined,
|
||||||
|
view
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取文章内容
|
// 获取文章内容
|
||||||
const { article, section, originalId } = Astro.props;
|
const { article, section, originalId, view } = Astro.props;
|
||||||
|
|
||||||
// 如果有原始ID,使用它来渲染内容
|
// 如果有原始ID,使用它来渲染内容
|
||||||
const articleToRender = originalId ? { ...article, id: originalId } : article;
|
const articleToRender = originalId ? { ...article, id: originalId } : article;
|
||||||
@ -108,7 +127,7 @@ const description = article.data.summary || `${article.data.title} - 发布于 $
|
|||||||
|
|
||||||
// 处理特殊ID的函数
|
// 处理特殊ID的函数
|
||||||
function getArticleUrl(articleId: string) {
|
function getArticleUrl(articleId: string) {
|
||||||
return `/articles/${getSpecialPath(articleId)}`;
|
return `/articles/${getSpecialPath(articleId)}${view ? `/${view}` : ''}`;
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -139,7 +158,7 @@ function getArticleUrl(articleId: string) {
|
|||||||
|
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
{/* 返回按钮 */}
|
{/* 返回按钮 */}
|
||||||
<a href="/articles" class="text-secondary-500 dark:text-secondary-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors flex items-center text-sm">
|
<a href={`/articles${view ? `/${view}` : ''}`} class="text-secondary-500 dark:text-secondary-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors flex items-center text-sm">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<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="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -4,7 +4,6 @@ import type { CollectionEntry } from 'astro:content';
|
|||||||
import { contentStructure } from '../../content.config';
|
import { contentStructure } from '../../content.config';
|
||||||
import Layout from '@/components/Layout.astro';
|
import Layout from '@/components/Layout.astro';
|
||||||
import Breadcrumb from '@/components/Breadcrumb.astro';
|
import Breadcrumb from '@/components/Breadcrumb.astro';
|
||||||
import ArticleTimeline from '@/components/ArticleTimeline.astro';
|
|
||||||
|
|
||||||
// 启用静态预渲染
|
// 启用静态预渲染
|
||||||
export const prerender = true;
|
export const prerender = true;
|
||||||
@ -194,7 +193,7 @@ interface Breadcrumb {
|
|||||||
|
|
||||||
// 处理特殊ID的函数
|
// 处理特殊ID的函数
|
||||||
function getArticleUrl(articleId: string) {
|
function getArticleUrl(articleId: string) {
|
||||||
return `/articles/${articleId}`;
|
return `/articles/${articleId}${view ? `/${view}` : ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -245,7 +244,7 @@ function getArticleUrl(articleId: string) {
|
|||||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
||||||
{/* 上一级目录卡片 - 仅在浏览目录时显示 */}
|
{/* 上一级目录卡片 - 仅在浏览目录时显示 */}
|
||||||
{!tagFilter && pathSegments.length > 0 && (
|
{!tagFilter && pathSegments.length > 0 && (
|
||||||
<a href={`/articles/${pathSegments.length > 1 ? pathSegments.slice(0, -1).join('/') : ''}`}
|
<a href={`/articles/${pathSegments.length > 1 ? pathSegments.slice(0, -1).join('/') : ''}/${view}`}
|
||||||
class="group flex flex-col h-full p-5 border border-gray-200 dark:border-gray-700 rounded-xl bg-white dark:bg-gray-800 hover:shadow-xl hover:-translate-y-1 transition-all duration-300 shadow-lg">
|
class="group flex flex-col h-full p-5 border border-gray-200 dark:border-gray-700 rounded-xl bg-white dark:bg-gray-800 hover:shadow-xl hover:-translate-y-1 transition-all duration-300 shadow-lg">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="w-10 h-10 flex items-center justify-center rounded-lg bg-primary-100 text-primary-600 group-hover:bg-primary-200 transition-colors">
|
<div class="w-10 h-10 flex items-center justify-center rounded-lg bg-primary-100 text-primary-600 group-hover:bg-primary-200 transition-colors">
|
||||||
@ -447,7 +446,80 @@ function getArticleUrl(articleId: string) {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<ArticleTimeline title="" articles={sortedArticles} />
|
<div class="container mx-auto px-4 py-8">
|
||||||
|
{/* 时间线视图 */}
|
||||||
|
<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}${viewMode ? `/${viewMode}` : ''}`}
|
||||||
|
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.body && (
|
||||||
|
<p class="text-secondary-600 dark:text-secondary-300 line-clamp-2">
|
||||||
|
{extractSummary(article.body)}
|
||||||
|
</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>
|
||||||
)}
|
)}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user