fix: table roll
This commit is contained in:
parent
3098328a27
commit
ceaf5f23d0
2
QWEN.md
2
QWEN.md
|
|
@ -36,7 +36,7 @@ cli应当搜索目录下的所有`.md`文件,并为每个文件创建一条路
|
||||||
|
|
||||||
另外,支持一些可选属性:
|
另外,支持一些可选属性:
|
||||||
|
|
||||||
- `{roll=true}`:添加一个骰子图标在标签页前,点击会随机切换到一个tab。
|
- `{roll=true}`:添加一个骰子标签,点击会随机切换到一个tab。
|
||||||
- `{remix=true}`:`body`的内容每次引用`{{prop}}`时,使用随机行的内容,而不是同一行。
|
- `{remix=true}`:`body`的内容每次引用`{{prop}}`时,使用随机行的内容,而不是同一行。
|
||||||
|
|
||||||
## 样式
|
## 样式
|
||||||
|
|
|
||||||
|
|
@ -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,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,14 +13,15 @@ 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() || '';
|
||||||
|
|
||||||
// 从父节点 article 的 data-src 获取当前 markdown 文件完整路径
|
// 从父节点 article 的 data-src 获取当前 markdown 文件完整路径
|
||||||
const articleEl = element?.closest('article[data-src]');
|
const articleEl = element?.closest('article[data-src]');
|
||||||
const articlePath = articleEl?.getAttribute('data-src') || '';
|
const articlePath = articleEl?.getAttribute('data-src') || '';
|
||||||
|
|
||||||
// 解析相对路径(相对于 markdown 文件所在目录)
|
// 解析相对路径(相对于 markdown 文件所在目录)
|
||||||
const resolvePath = (base: string, relative: string): string => {
|
const resolvePath = (base: string, relative: string): string => {
|
||||||
if (relative.startsWith('/')) {
|
if (relative.startsWith('/')) {
|
||||||
|
|
@ -29,7 +30,7 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
|
||||||
const baseDir = base.substring(0, base.lastIndexOf('/') + 1);
|
const baseDir = base.substring(0, base.lastIndexOf('/') + 1);
|
||||||
return baseDir + relative;
|
return baseDir + relative;
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolvedSrc = resolvePath(articlePath, src);
|
const resolvedSrc = resolvePath(articlePath, src);
|
||||||
|
|
||||||
// 解析 CSV 内容
|
// 解析 CSV 内容
|
||||||
|
|
@ -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,26 +76,45 @@ 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">
|
||||||
<For each={rows()}>
|
<div class="flex gap-2">
|
||||||
{(row, index) => (
|
<For each={rows()}>
|
||||||
<button
|
{(row, index) => (
|
||||||
onClick={() => setActiveTab(index())}
|
<button
|
||||||
class={`px-4 py-2 font-medium transition-colors ${
|
onClick={() => setActiveTab(index())}
|
||||||
activeTab() === index()
|
class={`px-4 py-2 font-medium transition-colors ${
|
||||||
? 'text-blue-600 border-b-2 border-blue-600'
|
activeTab() === index()
|
||||||
: 'text-gray-500 hover:text-gray-700'
|
? 'text-blue-600 border-b-2 border-blue-600'
|
||||||
}`}
|
: 'text-gray-500 hover:text-gray-700'
|
||||||
>
|
}`}
|
||||||
<Show when={props.roll}>
|
>
|
||||||
<span class="mr-1">🎲</span>
|
{row.label}
|
||||||
</Show>
|
</button>
|
||||||
{row.label}
|
)}
|
||||||
</button>
|
</For>
|
||||||
)}
|
</div>
|
||||||
</For>
|
|
||||||
<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>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue