2026-06-25 20:43:40 +08:00
|
|
|
|
import { customElement, noShadowDOM } from "solid-element";
|
2026-07-08 16:24:09 +08:00
|
|
|
|
import { createResource, Show, createEffect } from "solid-js";
|
2026-06-25 20:43:40 +08:00
|
|
|
|
import { getIndexedData } from "../data-loader/file-index";
|
|
|
|
|
|
import { extractSection } from "../data-loader";
|
|
|
|
|
|
import { parseMarkdown } from "../markdown";
|
|
|
|
|
|
import { resolvePath } from "./utils/path";
|
|
|
|
|
|
import mermaid from "mermaid";
|
|
|
|
|
|
|
|
|
|
|
|
export interface EmbedProps {
|
|
|
|
|
|
/** 是否在嵌入内容的每一级标题前提升 heading 层级 */
|
|
|
|
|
|
headingBase?: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
customElement("md-embed", { headingBase: 0 }, (props, { element }) => {
|
|
|
|
|
|
noShadowDOM();
|
|
|
|
|
|
|
|
|
|
|
|
const rawPath = element?.textContent?.trim() || "";
|
|
|
|
|
|
if (element) element.textContent = "";
|
|
|
|
|
|
|
|
|
|
|
|
// 解析 section(支持 path#section 语法)
|
|
|
|
|
|
const hashIndex = rawPath.indexOf("#");
|
|
|
|
|
|
const filePath = hashIndex >= 0 ? rawPath.slice(0, hashIndex) : rawPath;
|
|
|
|
|
|
const section = hashIndex >= 0 ? rawPath.slice(hashIndex + 1) : undefined;
|
|
|
|
|
|
|
|
|
|
|
|
// 从父节点 article 获取路径上下文
|
|
|
|
|
|
const articleEl = element?.closest("article[data-src]") as HTMLElement;
|
|
|
|
|
|
const articlePath = articleEl?.getAttribute("data-src") || "";
|
|
|
|
|
|
const resolvedPath = resolvePath(articlePath, filePath);
|
|
|
|
|
|
|
|
|
|
|
|
const [content] = createResource(
|
|
|
|
|
|
() => ({ path: resolvedPath, section }),
|
|
|
|
|
|
async ({ path, section }) => {
|
|
|
|
|
|
const text = await getIndexedData(path);
|
|
|
|
|
|
return section ? extractSection(text, section) : text;
|
|
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
createEffect(() => {
|
|
|
|
|
|
if (content() && !content.loading) {
|
|
|
|
|
|
void mermaid.run();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div class="md-embed not-prose">
|
|
|
|
|
|
<Show when={content.loading}>
|
|
|
|
|
|
<div class="text-gray-400 italic">加载中...</div>
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
<Show when={content.error}>
|
|
|
|
|
|
<div class="text-red-500">
|
|
|
|
|
|
加载失败:{content.error?.message || "未知错误"}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
<Show when={!content.loading && !content.error && content()}>
|
|
|
|
|
|
{/* biome-ignore lint/security/noDangerouslySetInnerHtml: markdown render */}
|
2026-07-08 16:38:19 +08:00
|
|
|
|
<div
|
|
|
|
|
|
class="prose"
|
|
|
|
|
|
innerHTML={parseMarkdown(content()!, resolvedPath)}
|
|
|
|
|
|
/>
|
2026-06-25 20:43:40 +08:00
|
|
|
|
</Show>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
});
|