feat: 代码片段功能与 Markdown 内嵌片段渲染、文档截图等
This commit is contained in:
@@ -27,7 +27,8 @@ export type ContentSegment =
|
||||
| { type: "timeline"; items: TimelineItem[]; rawBody: string }
|
||||
| { type: "entries"; items: EntryItem[]; rawBody: string }
|
||||
| { type: "details"; title: string; body: string }
|
||||
| { type: "video"; provider: "bilibili" | "youtube"; id: string };
|
||||
| { type: "video"; provider: "bilibili" | "youtube"; id: string }
|
||||
| { type: "snippet"; id: number };
|
||||
|
||||
function isTimelineClose(line: string): boolean {
|
||||
return line.trim().toLowerCase() === "[/timeline]";
|
||||
@@ -57,6 +58,18 @@ export function parseDetailsOpen(trimmed: string): string {
|
||||
return title || DETAILS_DEFAULT_TITLE;
|
||||
}
|
||||
|
||||
/* ---------- [snippet id=N] 代码片段嵌入(整行单标记) ---------- */
|
||||
|
||||
const SNIPPET_LINE_RE = /^\[snippet\s+id=(\d+)\]$/i;
|
||||
|
||||
/** 整行 `[snippet id=N]`。解析失败返回 null(该行按普通 Markdown 处理)。 */
|
||||
export function parseSnippetLine(trimmed: string): number | null {
|
||||
const m = trimmed.match(SNIPPET_LINE_RE);
|
||||
if (!m) return null;
|
||||
const id = Number(m[1]);
|
||||
return Number.isInteger(id) && id > 0 ? id : null;
|
||||
}
|
||||
|
||||
/* ---------- [bilibili] / [youtube] 视频嵌入(整行单标记) ---------- */
|
||||
|
||||
const VIDEO_LINE_RE = /^\[(bilibili|youtube)\]([^\[\]]+)\[\/\1\]$/i;
|
||||
@@ -122,6 +135,7 @@ export function splitContentSegments(
|
||||
| { type: "entries"; body: string }
|
||||
| { type: "details"; title: string; body: string }
|
||||
| { type: "video"; provider: "bilibili" | "youtube"; id: string }
|
||||
| { type: "snippet"; id: number }
|
||||
> = [];
|
||||
let buf: string[] = [];
|
||||
let inCode = false;
|
||||
@@ -228,6 +242,15 @@ export function splitContentSegments(
|
||||
continue;
|
||||
}
|
||||
|
||||
// [snippet id=N] 整行片段嵌入
|
||||
const snippetId = parseSnippetLine(trimmed);
|
||||
if (snippetId != null) {
|
||||
flushMd();
|
||||
raw.push({ type: "snippet", id: snippetId });
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// [entries:off] 例外块:body 原样进 md 缓冲(标记行丢弃),
|
||||
// 不再参与 entries/timeline 拆分;未闭合时整块当普通 Markdown
|
||||
if (isEntriesOffOpen(trimmed)) {
|
||||
@@ -273,6 +296,10 @@ export function splitContentSegments(
|
||||
out.push({ type: "video", provider: part.provider, id: part.id });
|
||||
continue;
|
||||
}
|
||||
if (part.type === "snippet") {
|
||||
out.push({ type: "snippet", id: part.id });
|
||||
continue;
|
||||
}
|
||||
const hideSegs = splitHideSegments(part.text) as HideSegment[];
|
||||
for (const s of hideSegs) {
|
||||
if (s.type === "md") {
|
||||
|
||||
Reference in New Issue
Block a user