feat: 站点单页、时间线导入与行级 BBCode 短代码

首页右栏接入单页入口与公告置顶/全部页;Markdown 编辑器支持可视化时间线与 Git 导入;隐藏块改为 [hide]/[timeline] 命名闭合,并修复单页/公告 GORM 更新只改 updated_at 的问题。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-17 19:52:06 +08:00
parent 2aacf99a49
commit a83276060f
52 changed files with 5073 additions and 648 deletions

View File

@@ -27,6 +27,8 @@ type MdHideBlockProps = {
points?: number;
locked?: boolean;
postId?: number;
/** 登录跳转路径(公告等无 postId 时使用) */
loginHref?: string;
loggedIn?: boolean;
children?: ReactNode;
};
@@ -37,6 +39,7 @@ export default function MdHideBlock({
points = 0,
locked = false,
postId,
loginHref,
loggedIn = false,
children,
}: MdHideBlockProps) {
@@ -46,6 +49,9 @@ export default function MdHideBlock({
const [pwd, setPwd] = useState("");
const [pwdError, setPwdError] = useState("");
const label = hideKindLabel(kind);
const loginTo =
loginHref ||
(postId ? `/login?redirect=${encodeURIComponent(`/post/${postId}`)}` : "/login");
if (locked) {
const unlockPoints = async () => {
@@ -115,11 +121,8 @@ export default function MdHideBlock({
: "登录后即可阅读此段"}
</p>
<div className="j13-hide-gate-actions">
{kind === "login" && !loggedIn && postId && (
<Link
href={`/login?redirect=${encodeURIComponent(`/post/${postId}`)}`}
className="btn btn-primary"
>
{kind === "login" && !loggedIn && (
<Link href={loginTo} className="btn btn-primary">
去登录
</Link>
)}
@@ -133,23 +136,24 @@ export default function MdHideBlock({
{busy ? "解锁中…" : `支付 ${points || 0} 积分解锁`}
</button>
)}
{kind === "points" && !loggedIn && postId && (
<Link
href={`/login?redirect=${encodeURIComponent(`/post/${postId}`)}`}
className="btn btn-primary"
>
{kind === "points" && !loggedIn && (
<Link href={loginTo} className="btn btn-primary">
登录后解锁
</Link>
)}
{kind === "reply" && postId && !loggedIn && (
{kind === "reply" && !loggedIn && (
<Link
href={`/login?redirect=${encodeURIComponent(`/post/${postId}#comment-input`)}`}
href={
postId
? `/login?redirect=${encodeURIComponent(`/post/${postId}#comment-input`)}`
: loginTo
}
className="btn btn-primary"
>
登录后去回复
</Link>
)}
{kind === "reply" && loggedIn && (
{kind === "reply" && loggedIn && postId && (
<a
href="#comment-input"
className="btn btn-primary"