Files
blogflare/src/routes/posts/[slug]/+page.server.ts
T

134 lines
3.5 KiB
TypeScript

import type { PageServerLoad } from './$types';
import { error, isHttpError } from '@sveltejs/kit';
interface PostRow {
id: number;
slug: string;
title: string;
content: string;
cover: string | null;
date: string;
category_name: string | null;
category_slug: string | null;
author: string | null;
series_id: number | null;
series_name: string | null;
series_slug: string | null;
series_description: string | null;
series_weight: number | null;
}
export const load: PageServerLoad = async ({ platform, params }) => {
const db = platform?.env?.DB;
const { slug } = params;
if (!db) {
const dummyMarkdown = `
欢迎来到 BlogFlare 博客系统。由于当前在 \`vite dev\` 模式下没有连接到本地数据库,您看到的是兜底(Fallback)渲染的测试内容。
### DoIt 风格的 Admonitions 测试
> [!NOTE]
> 这是一个 Note (笔记) 提示框,可以用来补充额外的说明信息。
> [!TIP]
> 这是一个 Tip (提示) 提示框,通常用来给出最佳实践或小技巧。
> [!WARNING]
> 这是一个 Warning (警告) 提示框,用来引起用户的注意,避免发生错误。
> [!DANGER]
> 这是一个 Danger (危险) 提示框,警告用户该操作可能产生严重后果(比如删除数据)。
正文测试结束。
`;
return {
post: {
id: 1,
slug,
title: slug === 'hello-world' ? 'Hello, BlogFlare! (Fallback)' : 'The Beauty of Typecho Theme VOID',
content: dummyMarkdown,
cover: null,
date: '2026-07-12',
author: 'Admin'
},
tags: [
{ name: 'Welcome', id: 1 },
{ name: 'Design', id: 2 }
],
series: null,
seriesPosts: []
};
}
try {
const post = await db.prepare(
`SELECT p.id, p.slug, p.title, p.content, p.cover, p.published_at as date,
c.name as category_name, c.slug as category_slug,
u.username as author,
s.id as series_id, s.name as series_name, s.slug as series_slug,
s.description as series_description, p.series_weight
FROM posts p
LEFT JOIN categories c ON p.category_id = c.id
LEFT JOIN users u ON p.author_id = u.id
LEFT JOIN series s ON p.series_id = s.id
WHERE p.slug = ?`
).bind(slug).first<PostRow>();
if (!post) {
error(404, 'Post not found');
}
const tagsQuery = await db.prepare(
`SELECT t.name, t.id
FROM tags t
JOIN post_tags pt ON t.id = pt.tag_id
WHERE pt.post_id = ?`
).bind(post.id).all<{ name: string; id: number }>();
const tags = tagsQuery.results || [];
let series: {
id: number;
name: string;
slug: string;
description: string | null;
} | null = null;
let seriesPosts: Array<{
id: number;
slug: string;
title: string;
series_weight: number | null;
published_at: string;
}> = [];
if (post.series_id && post.series_name && post.series_slug) {
series = {
id: post.series_id,
name: post.series_name,
slug: post.series_slug,
description: post.series_description
};
const seriesQuery = await db.prepare(
`SELECT id, slug, title, series_weight, published_at
FROM posts
WHERE series_id = ?
ORDER BY series_weight IS NULL, series_weight ASC, published_at ASC, id ASC`
).bind(post.series_id).all();
seriesPosts = seriesQuery.results as unknown as typeof seriesPosts;
}
return {
post: {
...post,
date: new Date(post.date as string).toLocaleDateString()
},
tags,
series,
seriesPosts
};
} catch (err: unknown) {
if (isHttpError(err, 404)) throw err;
console.error('Error fetching post:', err);
error(500, 'Internal Server Error');
}
};