From 08f8e0da520efc25720cad9c65ec63b2d10d6f96 Mon Sep 17 00:00:00 2001 From: hypercross Date: Thu, 26 Feb 2026 10:10:05 +0800 Subject: [PATCH] feat: groupin --- content/index.md | 4 +- content/sparks.csv | 12 ++-- src/components/table.tsx | 122 ++++++++++++++++++++++++++++++--------- 3 files changed, 104 insertions(+), 34 deletions(-) diff --git a/content/index.md b/content/index.md index 80b4fce..6173e41 100644 --- a/content/index.md +++ b/content/index.md @@ -18,9 +18,9 @@ :md-table[./sparks.csv] -:md-table[./sparks.csv]{roll=true} +:md-table[./sparks.csv]{roll} -:md-table[./sparks.csv]{roll=true remix=true} +:md-table[./sparks.csv]{roll remix} ### 链接 diff --git a/content/sparks.csv b/content/sparks.csv index 99a46a1..be34f25 100644 --- a/content/sparks.csv +++ b/content/sparks.csv @@ -1,6 +1,6 @@ -label,body,adj,noun -🔥,**{{adj}}** 的{{noun}},高大,战士 -💧,{{adj}}的{{noun}},矮小,法师 -🌪️,{{adj}}的{{noun}},帅气,弓手 -🌱,{{adj}}的{{noun}},丑陋,盗贼 -⚡,{{adj}}的{{noun}},平庸,牧师 +label,body,adj,noun,group +🔥,**{{adj}}** 的{{noun}},高大,战士,基本 +💧,{{adj}}的{{noun}},矮小,法师,基本 +🌪️,{{adj}}的{{noun}},帅气,弓手,高级 +🌱,{{adj}}的{{noun}},丑陋,盗贼,高级 +⚡,{{adj}}的{{noun}},平庸,牧师,高级 diff --git a/src/components/table.tsx b/src/components/table.tsx index 58a6d93..ca86a6f 100644 --- a/src/components/table.tsx +++ b/src/components/table.tsx @@ -1,11 +1,12 @@ import { customElement, noShadowDOM } from 'solid-element'; -import { createSignal, For, Show, createEffect } from 'solid-js'; +import { createSignal, For, Show, createEffect, createMemo } from 'solid-js'; import { parse } from 'csv-parse/browser/esm/sync'; import { marked } from '../markdown'; interface TableRow { label: string; body: string; + group?: string; [key: string]: string; } @@ -13,12 +14,13 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) => noShadowDOM(); const [rows, setRows] = createSignal([]); const [activeTab, setActiveTab] = createSignal(0); + const [activeGroup, setActiveGroup] = createSignal(null); const [loaded, setLoaded] = createSignal(false); const [bodyHtml, setBodyHtml] = createSignal(''); // 从 element 的 textContent 获取 CSV 路径 const src = element?.textContent?.trim() || ''; - + // 隐藏原始文本内容 if (element) { element.textContent = ''; @@ -68,10 +70,37 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) => loadCSV(); } + // 检测是否有 group 列 + const hasGroup = createMemo(() => { + const allRows = rows(); + return allRows.length > 0 && 'group' in allRows[0]; + }); + + // 获取所有分组 + 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(); + }); + + // 根据当前选中的分组过滤行 + const filteredRows = createMemo(() => { + const allRows = rows(); + const group = activeGroup(); + if (!group) return allRows; + return allRows.filter(row => row.group === group); + }); + // 处理 body 内容中的 {{prop}} 语法并解析 markdown const processBody = (body: string, currentRow: TableRow): string => { let processedBody = body; - + if (!props.remix) { // 不启用 remix 时,只替换当前行的引用 processedBody = body.replace(/\{\{(\w+)\}\}/g, (_, key) => currentRow[key] || ''); @@ -82,62 +111,103 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) => return randomRow?.[key] || ''; }); } - + // 使用 marked 解析 markdown return marked.parse(processedBody) as string; }; // 更新 body 内容 const updateBodyContent = () => { - if (loaded() && rows().length > 0) { - const currentRow = rows()[activeTab()]; + const filtered = filteredRows(); + if (loaded() && filtered.length > 0) { + const index = Math.min(activeTab(), filtered.length - 1); + const currentRow = filtered[index]; setBodyHtml(processBody(currentRow.body, currentRow)); } }; - // 监听 activeTab 变化并更新内容 + // 监听 activeTab 和 activeGroup 变化并更新内容 createEffect(() => { activeTab(); + activeGroup(); updateBodyContent(); }); + // 切换分组时重置 tab 索引 + const handleGroupChange = (group: string | null) => { + setActiveGroup(group); + setActiveTab(0); + }; + // 随机切换 tab const handleRoll = () => { - const randomIndex = Math.floor(Math.random() * rows().length); + const randomIndex = Math.floor(Math.random() * filteredRows().length); setActiveTab(randomIndex); }; return (
- - - -
- - {(row, index) => ( +
+ {/* 分组 tabs */} + +
- )} - + + {(group) => ( + + )} + +
+
+ {/* 内容 tabs */} +
+ + + + + {(row, index) => ( + + )} + +
- 0}> + 0}>