fix: table roll

This commit is contained in:
hypercross 2026-02-26 01:21:53 +08:00
parent 3098328a27
commit ceaf5f23d0
3 changed files with 50 additions and 36 deletions

View File

@ -36,7 +36,7 @@ cli应当搜索目录下的所有`.md`文件,并为每个文件创建一条路
另外,支持一些可选属性: 另外,支持一些可选属性:
- `{roll=true}`:添加一个骰子图标在标签页前点击会随机切换到一个tab。 - `{roll=true}`添加一个骰子标签点击会随机切换到一个tab。
- `{remix=true}``body`的内容每次引用`{{prop}}`时,使用随机行的内容,而不是同一行。 - `{remix=true}``body`的内容每次引用`{{prop}}`时,使用随机行的内容,而不是同一行。
## 样式 ## 样式

View File

@ -1,6 +1,6 @@
label,body,description,icon label,body,adj,noun
🔥,火焰火花,你召唤出一朵小小的火焰,可以点燃蜡烛或篝火。,造成 1d4 点火焰伤害。,🔥 🔥,{{adj}}的{{noun}},高大,战士
💧,水流,你制造一股水流,可以扑灭小型火焰或弄湿目标。,造成 1d4 点水击伤害。,💧 💧,{{adj}}的{{noun}},矮小,法师
🌪️, 旋风,你制造一阵小旋风,可以吹散烟雾或轻小物体。,推开目标 5 尺。, 🌪️,{{adj}}的{{noun}},帅气,弓手
🌱,生长,你让一颗种子迅速发芽,长成小植物。,创造一个小植物障碍。,🌱 🌱,{{adj}}的{{noun}},丑陋,盗贼
⚡,电击,你释放一道微弱的电流,可以麻痹目标。,造成 1d4 点闪电伤害。,⚡ ⚡,{{adj}}的{{noun}},平庸,牧师

1 label body description adj icon noun
2 🔥 火焰火花,你召唤出一朵小小的火焰,可以点燃蜡烛或篝火。 {{adj}}的{{noun}} 造成 1d4 点火焰伤害。 高大 🔥 战士
3 💧 水流,你制造一股水流,可以扑灭小型火焰或弄湿目标。 {{adj}}的{{noun}} 造成 1d4 点水击伤害。 矮小 💧 法师
4 🌪️ 旋风,你制造一阵小旋风,可以吹散烟雾或轻小物体。 {{adj}}的{{noun}} 推开目标 5 尺。 帅气 弓手
5 🌱 生长,你让一颗种子迅速发芽,长成小植物。 {{adj}}的{{noun}} 创造一个小植物障碍。 丑陋 🌱 盗贼
6 电击,你释放一道微弱的电流,可以麻痹目标。 {{adj}}的{{noun}} 造成 1d4 点闪电伤害。 平庸 牧师

View File

@ -1,5 +1,5 @@
import { customElement, noShadowDOM } from 'solid-element'; import { customElement, noShadowDOM } from 'solid-element';
import { createSignal, For, Show } from 'solid-js'; import { createSignal, For, Show, createEffect } from 'solid-js';
import { parse } from 'csv-parse/browser/esm/sync'; import { parse } from 'csv-parse/browser/esm/sync';
interface TableRow { interface TableRow {
@ -13,6 +13,7 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
const [rows, setRows] = createSignal<TableRow[]>([]); const [rows, setRows] = createSignal<TableRow[]>([]);
const [activeTab, setActiveTab] = createSignal(0); const [activeTab, setActiveTab] = createSignal(0);
const [loaded, setLoaded] = createSignal(false); const [loaded, setLoaded] = createSignal(false);
const [bodyContent, setBodyContent] = createSignal('');
// 从 element 的 textContent 获取 CSV 路径 // 从 element 的 textContent 获取 CSV 路径
const src = element?.textContent?.trim() || ''; const src = element?.textContent?.trim() || '';
@ -61,12 +62,6 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
loadCSV(); loadCSV();
} }
// 随机切换 tab
const handleRoll = () => {
const randomIndex = Math.floor(Math.random() * rows().length);
setActiveTab(randomIndex);
};
// 处理 body 内容中的 {{prop}} 语法 // 处理 body 内容中的 {{prop}} 语法
const processBody = (body: string, currentRow: TableRow): string => { const processBody = (body: string, currentRow: TableRow): string => {
if (!props.remix) { if (!props.remix) {
@ -81,9 +76,30 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
} }
}; };
// 更新 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 ( return (
<div class="ttrpg-table"> <div class="ttrpg-table">
<div class="flex gap-2 border-b border-gray-200"> <div class="flex items-center gap-2 border-b border-gray-200">
<div class="flex gap-2">
<For each={rows()}> <For each={rows()}>
{(row, index) => ( {(row, index) => (
<button <button
@ -94,13 +110,11 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
: 'text-gray-500 hover:text-gray-700' : 'text-gray-500 hover:text-gray-700'
}`} }`}
> >
<Show when={props.roll}>
<span class="mr-1">🎲</span>
</Show>
{row.label} {row.label}
</button> </button>
)} )}
</For> </For>
</div>
<Show when={props.roll}> <Show when={props.roll}>
<button <button
onClick={handleRoll} onClick={handleRoll}
@ -113,7 +127,7 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
</div> </div>
<div class="p-4 prose max-w-none"> <div class="p-4 prose max-w-none">
<Show when={loaded() && rows().length > 0}> <Show when={loaded() && rows().length > 0}>
<div innerHTML={processBody(rows()[activeTab()].body, rows()[activeTab()])} /> <div innerHTML={bodyContent()} />
</Show> </Show>
</div> </div>
</div> </div>