import { customElement, noShadowDOM } from 'solid-element'; import { createSignal, For, Show, createEffect } from 'solid-js'; import { parse } from 'csv-parse/browser/esm/sync'; interface TableRow { label: string; body: string; [key: string]: string; } customElement('md-table', { roll: false, remix: false }, (props, { element }) => { noShadowDOM(); const [rows, setRows] = createSignal([]); const [activeTab, setActiveTab] = createSignal(0); const [loaded, setLoaded] = createSignal(false); const [bodyContent, setBodyContent] = createSignal(''); // 从 element 的 textContent 获取 CSV 路径 const src = element?.textContent?.trim() || ''; // 从父节点 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 resolvedSrc = resolvePath(articlePath, src); // 解析 CSV 内容 const parseCSV = (content: string) => { const records = parse(content, { columns: true, comment: '#', trim: true, skipEmptyLines: true }); setRows(records as TableRow[]); setLoaded(true); }; // 加载 CSV 文件 const loadCSV = async () => { try { const response = await fetch(resolvedSrc); const content = await response.text(); parseCSV(content); } catch (error) { console.error('Failed to load CSV:', error); setLoaded(true); } }; // 初始化加载 if (!loaded()) { loadCSV(); } // 处理 body 内容中的 {{prop}} 语法 const processBody = (body: string, currentRow: TableRow): string => { if (!props.remix) { // 不启用 remix 时,只替换当前行的引用 return body.replace(/\{\{(\w+)\}\}/g, (_, key) => currentRow[key] || ''); } else { // 启用 remix 时,每次引用使用随机行的内容 return body.replace(/\{\{(\w+)\}\}/g, (_, key) => { const randomRow = rows()[Math.floor(Math.random() * rows().length)]; return randomRow?.[key] || ''; }); } }; // 更新 body 内容 const updateBodyContent = () => { if (loaded() && rows().length > 0) { const currentRow = rows()[activeTab()]; setBodyContent(processBody(currentRow.body, currentRow)); } }; // 监听 activeTab 变化并更新内容 createEffect(() => { activeTab(); updateBodyContent(); }); // 随机切换 tab const handleRoll = () => { const randomIndex = Math.floor(Math.random() * rows().length); setActiveTab(randomIndex); }; return (
{(row, index) => ( )}
0}>
); });