feat: 代码片段功能与 Markdown 内嵌片段渲染、文档截图等

This commit is contained in:
2026-10-09 18:53:38 +08:00
parent 5598e1cbb7
commit da72843c70
64 changed files with 7047 additions and 248 deletions

View File

@@ -0,0 +1,111 @@
"use client";
import { Suspense, useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { apiMe, apiGetSnippet } from "@/lib/api";
import SnippetEditor from "@/components/SnippetEditor";
function EditSnippetInner({ id }: { id: number }) {
const router = useRouter();
const [ready, setReady] = useState(false);
const [snippet, setSnippet] = useState<{
title: string;
language: string;
description: string;
code: string;
visibility: "public" | "private";
user_id: number;
} | null>(null);
useEffect(() => {
let cancelled = false;
(async () => {
const me = await apiMe().catch(() => null);
if (cancelled) return;
if (!me?.user) {
router.push(`/login?redirect=/snippets/${id}/edit`);
return;
}
try {
const data = await apiGetSnippet(id);
if (cancelled) return;
if (!data) {
router.push("/snippets");
return;
}
// 仅 owner 或 staff 可编辑(后端会再次校验)
setSnippet({
title: data.snippet.title,
language: data.snippet.language,
description: data.snippet.description,
code: data.snippet.code,
visibility: data.snippet.visibility,
user_id: data.snippet.user_id,
});
setReady(true);
} catch {
if (!cancelled) router.push("/snippets");
}
})();
return () => {
cancelled = true;
};
}, [router, id]);
if (!ready || !snippet) {
return (
<div className="j13-compose-stage is-studio px-8 py-16 text-center">
<p className="meta">正在加载片段…</p>
</div>
);
}
return (
<SnippetEditor
mode="edit"
snippetId={id}
initialTitle={snippet.title}
initialLanguage={snippet.language}
initialDescription={snippet.description}
initialCode={snippet.code}
initialVisibility={snippet.visibility}
/>
);
}
export default function EditSnippetPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const [id, setId] = useState<number | null>(null);
useEffect(() => {
params.then((p) => {
const numId = Number(p.id);
if (Number.isInteger(numId) && numId > 0) setId(numId);
});
}, [params]);
if (id === null) {
return (
<div className="j13-compose-stage is-studio px-8 py-16 text-center">
<p className="meta">正在加载…</p>
</div>
);
}
return (
<div className="j13-compose-page">
<Suspense
fallback={
<div className="j13-compose-stage is-studio px-8 py-16 text-center">
<p className="meta">正在加载片段…</p>
</div>
}
>
<EditSnippetInner id={id} />
</Suspense>
</div>
);
}