import { customElement, noShadowDOM } from "solid-element"; import { createSignal, onCleanup } from "solid-js"; import { render } from "solid-js/web"; import { Article } from "./Article"; customElement("md-link", {}, (props, { element }) => { noShadowDOM(); const [showArticle, setShowArticle] = createSignal(false); let articleContainer: HTMLDivElement | undefined; let disposeArticle: (() => void) | null = null; // 从 element 的 textContent 获取链接目标(支持 path#section 语法) const rawLinkSrc = element?.textContent?.trim() || ""; // 解析 section(支持 path#section 语法) const hashIndex = rawLinkSrc.indexOf('#'); const path = hashIndex >= 0 ? rawLinkSrc.slice(0, hashIndex) : rawLinkSrc; const section = hashIndex >= 0 ? rawLinkSrc.slice(hashIndex + 1) : undefined; // 隐藏原始文本内容 if (element) { element.textContent = ""; } // 从父节点 article 的 data-src 获取当前 markdown 文件完整路径 const articleEl = element?.closest('article[data-src]'); const articlePath = articleEl?.getAttribute('data-src') || ''; // 解析相对路径(相对于 markdown 文件所在目录) const resolvePath = (base: string, relative: string): string => { if (relative.startsWith('/')) { return relative; } const baseDir = base.substring(0, base.lastIndexOf('/') + 1); return baseDir + relative; }; const linkSrc = resolvePath(articlePath, path); // 查找包含此元素的 p 标签 const parentP = element?.closest("p"); const toggleArticle = () => { if (!parentP) return; if (showArticle()) { // 隐藏文章 if (articleContainer) { if (disposeArticle) { disposeArticle(); disposeArticle = null; } articleContainer.remove(); articleContainer = undefined; } setShowArticle(false); } else { // 显示文章 articleContainer = document.createElement("div"); articleContainer.classList.add("md-link-article"); articleContainer.classList.add("ml-4", "border-l-2", "border-gray-200", "pl-4"); parentP.after(articleContainer); // 渲染 Article 组件 disposeArticle = render(() => (
console.log("Article loaded:", linkSrc)} onError={(err) => console.error("Article error:", err)} /> ), articleContainer); setShowArticle(true); } }; onCleanup(() => { if (disposeArticle) { disposeArticle(); disposeArticle = null; } }); return ( { e.preventDefault(); toggleArticle(); }} class="text-blue-600 hover:text-blue-800 hover:underline" > {section || rawLinkSrc} ); });