feat: export posts and sources

This commit is contained in:
2026-07-19 05:36:52 +08:00
parent 05ddafb0d9
commit 591981b7c8
8 changed files with 50 additions and 7 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ export default async function PostPage({ params, searchParams }: { params: Promi
const bookmark = user ? db.prepare("SELECT kind FROM bookmarks WHERE user_id=? AND post_id=?").get(user.id, id) as { kind: string } | undefined : undefined;
const comments = db.prepare("SELECT c.*,u.username FROM comments c JOIN users u ON u.id=c.author_id WHERE c.post_id=? AND c.hidden=0 ORDER BY c.created_at").all(id) as any[];
const reactions = db.prepare("SELECT emoji,count(*) count FROM reactions WHERE post_id=? GROUP BY emoji").all(id) as any[];
let tags: string[] = []; try { tags = canonicalTags(JSON.parse(post.tags_json)); } catch {} const publishedAt = post.remote_created_at || post.created_at; return <article><p className="meta">@{post.username} · {post.remote_display_name || post.name || "Hub"} · {new Date(publishedAt).toLocaleString("zh-TW")}{post.remote_url && <> · <a href={post.remote_url} target="_blank" rel="noreferrer"> Memos </a></>}</p><section className="card"><Markdown content={post.content} tags={tags} /></section><Attachments json={post.attachments_json} sourceBaseUrl={post.source_base_url} />
let tags: string[] = []; try { tags = canonicalTags(JSON.parse(post.tags_json)); } catch {} const publishedAt = post.remote_created_at || post.created_at; const canExport = Boolean(user && (post.author_id === user.id || (post.source_id && db.prepare("SELECT 1 FROM source_members WHERE source_id=? AND user_id=?").get(post.source_id, user.id)))); return <article><p className="meta">@{post.username} · {post.remote_display_name || post.name || "Hub"} · {new Date(publishedAt).toLocaleString("zh-TW")}{post.remote_url && <> · <a href={post.remote_url} target="_blank" rel="noreferrer"> Memos </a></>}</p>{canExport && <p className="row"><a href={`/api/export/posts/${id}?format=json`}> JSON</a><a href={`/api/export/posts/${id}?format=markdown`}> Markdown</a></p>}<section className="card"><Markdown content={post.content} tags={tags} /></section><Attachments json={post.attachments_json} sourceBaseUrl={post.source_base_url} />
<section className="row">{reactions.map((reaction: any) => <span className="tag" key={reaction.emoji}>{reaction.emoji} {reaction.count}</span>)}{user && <><form action="/api/bookmarks" method="post"><input type="hidden" name="postId" value={id} /><input type="hidden" name="kind" value="saved" /><button>{bookmark?.kind === "saved" ? "取消收藏" : "收藏"}</button></form><form action="/api/bookmarks" method="post"><input type="hidden" name="postId" value={id} /><input type="hidden" name="kind" value="later" /><button>{bookmark?.kind === "later" ? "取消稍後閱讀" : "稍後閱讀"}</button></form></>}{user && ["👍", "❤️", "🎉", "🤔"].map((emoji) => <form action="/api/reactions" method="post" key={emoji}><input type="hidden" name="postId" value={id} /><input type="hidden" name="emoji" value={emoji} /><button>{emoji}</button></form>)}</section>
<section><h2></h2>{user ? <><form action="/api/comments" method="post"><input type="hidden" name="postId" value={id} /><textarea name="content" required placeholder="在 Hub 留下留言" /><button></button></form><details><summary></summary>{query.reported && <p></p>}<form action="/api/reports" method="post"><input type="hidden" name="postId" value={id} /><label><input name="reason" required minLength={3} maxLength={500} /></label><button className="danger"></button></form></details></> : <p></p>}{comments.map((comment) => <div className="card" key={comment.id}><strong>@{comment.username}</strong><p>{comment.content}</p><span className="meta">{new Date(comment.created_at).toLocaleString("zh-TW")}</span></div>)}</section>
</article>;