diff --git a/src/components/md-deck/PrintPreview.tsx b/src/components/md-deck/PrintPreview.tsx
index 1d1fd6d..a4e8df5 100644
--- a/src/components/md-deck/PrintPreview.tsx
+++ b/src/components/md-deck/PrintPreview.tsx
@@ -115,7 +115,7 @@ export function PrintPreview(props: PrintPreviewProps) {
}
>
-
+
{
- noShadowDOM();
- const [rows, setRows] = createSignal>([] as unknown as CSV);
- const [activeTab, setActiveTab] = createSignal(0);
- const [activeGroup, setActiveGroup] = createSignal(null);
- const [bodyHtml, setBodyHtml] = createSignal('');
- let tabsContainer: HTMLDivElement | undefined;
+customElement(
+ "md-table",
+ { roll: false, remix: false },
+ (props, { element }) => {
+ noShadowDOM();
+ const [rows, setRows] = createSignal>(
+ [] as unknown as CSV,
+ );
+ const [activeTab, setActiveTab] = createSignal(0);
+ const [activeGroup, setActiveGroup] = createSignal(null);
+ const [bodyHtml, setBodyHtml] = createSignal("");
+ let tabsContainer: HTMLDivElement | undefined;
- // 从 element 的 textContent 获取 CSV 路径或 inline CSV 数据
- const rawContent = element?.textContent?.trim() || '';
+ // 从 element 的 textContent 获取 CSV 路径或 inline CSV 数据
+ const rawContent = element?.textContent?.trim() || "";
- // 隐藏原始文本内容
- if (element) {
- element.textContent = '';
- }
-
- // 从父节点 article 的 data-src 获取当前 markdown 文件完整路径
- const articleEl = element?.closest('article[data-src]');
- const articlePath = articleEl?.getAttribute('data-src') || '';
-
- // 如果是 inline CSV,直接使用;否则解析相对路径
- const contentOrPath = isCSV(rawContent) ? rawContent : resolvePath(articlePath, rawContent);
-
- // 使用 createResource 加载 CSV,自动响应路径变化并避免重复加载
- const [csvData] = createResource(() => contentOrPath, loadCSV);
-
- // 当数据加载完成后更新 rows
- createEffect(() => {
- const data = csvData();
- if (data) {
- // 将加载的数据赋值给 rows,CSV 类型已经包含 sourcePath 等属性
- setRows(data as unknown as CSV);
+ // 隐藏原始文本内容
+ if (element) {
+ element.textContent = "";
}
- });
- // 检测是否有 group 列
- const hasGroup = createMemo(() => {
- const allRows = rows();
- return allRows.length > 0 && 'group' in allRows[0];
- });
+ // 从父节点 article 的 data-src 获取当前 markdown 文件完整路径
+ const articleEl = element?.closest("article[data-src]");
+ const articlePath = articleEl?.getAttribute("data-src") || "";
- // 获取所有分组
- const groups = createMemo(() => {
- if (!hasGroup()) return [];
- const allRows = rows();
- const groupSet = new Set();
- for (const row of allRows) {
- if (row.group) {
- groupSet.add(row.group);
+ // 如果是 inline CSV,直接使用;否则解析相对路径
+ const contentOrPath = isCSV(rawContent)
+ ? rawContent
+ : resolvePath(articlePath, rawContent);
+
+ // 使用 createResource 加载 CSV,自动响应路径变化并避免重复加载
+ const [csvData] = createResource(() => contentOrPath, loadCSV);
+
+ // 当数据加载完成后更新 rows
+ createEffect(() => {
+ const data = csvData();
+ if (data) {
+ // 将加载的数据赋值给 rows,CSV 类型已经包含 sourcePath 等属性
+ setRows(data as unknown as CSV);
}
- }
- return Array.from(groupSet).sort();
- });
+ });
- // 根据当前选中的分组过滤行
- const filteredRows = createMemo(() => {
- const allRows = rows();
- const group = activeGroup();
- if (!group) return allRows;
- return allRows.filter(row => row.group === group);
- });
+ // 检测是否有 group 列
+ const hasGroup = createMemo(() => {
+ const allRows = rows();
+ return allRows.length > 0 && "group" in allRows[0];
+ });
- // 处理 body 内容中的 {{prop}} 语法并解析 markdown
- const processBody = (body: string, currentRow: TableRow): string => {
- // 使用 marked 解析 markdown
- return marked.parse(processVariables(body, currentRow, rows(), filteredRows(), props.remix)) as string;
- };
+ // 获取所有分组
+ const groups = createMemo(() => {
+ if (!hasGroup()) return [];
+ const allRows = rows();
+ const groupSet = new Set();
+ for (const row of allRows) {
+ if (row.group) {
+ groupSet.add(row.group);
+ }
+ }
+ return Array.from(groupSet).sort();
+ });
- // 更新 body 内容
- const updateBodyContent = () => {
- const filtered = filteredRows();
- if (!csvData.loading && filtered.length > 0) {
- const index = Math.min(activeTab(), filtered.length - 1);
- const currentRow = filtered[index];
- setBodyHtml(processBody(currentRow.body, currentRow));
- }
- };
+ // 根据当前选中的分组过滤行
+ const filteredRows = createMemo(() => {
+ const allRows = rows();
+ const group = activeGroup();
+ if (!group) return allRows;
+ return allRows.filter((row) => row.group === group);
+ });
- // 监听 activeTab 和 activeGroup 变化并更新内容
- createEffect(() => {
- activeTab();
- activeGroup();
- updateBodyContent();
- });
+ // 处理 body 内容中的 {{prop}} 语法并解析 markdown
+ const processBody = (body: string, currentRow: TableRow): string => {
+ // 使用 marked 解析 markdown
+ return marked.parse(
+ processVariables(body, currentRow, rows(), filteredRows(), props.remix),
+ ) as string;
+ };
- // 切换分组时重置 tab 索引
- const handleGroupChange = (group: string | null) => {
- setActiveGroup(group);
- setActiveTab(0);
- };
+ // 更新 body 内容
+ const updateBodyContent = () => {
+ const filtered = filteredRows();
+ if (!csvData.loading && filtered.length > 0) {
+ const index = Math.min(activeTab(), filtered.length - 1);
+ const currentRow = filtered[index];
+ setBodyHtml(processBody(currentRow.body, currentRow));
+ }
+ };
- // 随机切换 tab
- const handleRoll = () => {
- const filtered = filteredRows();
- if (filtered.length === 0) return;
-
- // 检查所有 label 是否都是整数/整数范围格式
- const labels = filtered.map(row => row.label);
- if (areAllLabelsNumeric(labels)) {
- // 使用加权随机
- const randomIndex = weightedRandomIndex(labels);
- if (randomIndex !== -1) {
+ // 监听 activeTab 和 activeGroup 变化并更新内容
+ createEffect(() => {
+ activeTab();
+ activeGroup();
+ updateBodyContent();
+ });
+
+ // 切换分组时重置 tab 索引
+ const handleGroupChange = (group: string | null) => {
+ setActiveGroup(group);
+ setActiveTab(0);
+ };
+
+ // 随机切换 tab
+ const handleRoll = () => {
+ const filtered = filteredRows();
+ if (filtered.length === 0) return;
+
+ // 检查所有 label 是否都是整数/整数范围格式
+ const labels = filtered.map((row) => row.label);
+ if (areAllLabelsNumeric(labels)) {
+ // 使用加权随机
+ const randomIndex = weightedRandomIndex(labels);
+ if (randomIndex !== -1) {
+ setActiveTab(randomIndex);
+ }
+ } else {
+ // 使用简单随机
+ const randomIndex = Math.floor(Math.random() * filtered.length);
setActiveTab(randomIndex);
}
- } else {
- // 使用简单随机
- const randomIndex = Math.floor(Math.random() * filtered.length);
- setActiveTab(randomIndex);
- }
-
- // 滚动到可视区域
- setTimeout(() => {
- const activeButton = tabsContainer?.querySelector('.border-blue-600');
- activeButton?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });
- }, 50);
- };
- return (
-
-
-
- {/* 分组 tabs */}
-
-
-
-
- {(group) => (
-
- )}
-
-
-
- {/* 内容 tabs */}
-
-
-
+ // 滚动到可视区域
+ setTimeout(() => {
+ const activeButton = tabsContainer?.querySelector(".border-blue-600");
+ activeButton?.scrollIntoView({
+ behavior: "smooth",
+ block: "nearest",
+ inline: "nearest",
+ });
+ }, 50);
+ };
+
+ return (
+
+
+
+ {/* 分组 tabs */}
+
+
+
+
+ {(group) => (
+
+ )}
+
+
-
-
- {(row, index) => (
-
- )}
-
+ {/* 内容 tabs */}
+
+
+
+
+
+
+ {(row, index) => (
+
+ )}
+
+
+
-
-
- );
-});
+ );
+ },
+);