feat: groupin
This commit is contained in:
parent
cf61c996cc
commit
08f8e0da52
|
|
@ -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}
|
||||
|
||||
### 链接
|
||||
|
||||
|
|
|
|||
|
|
@ -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}},平庸,牧师,高级
|
||||
|
|
|
|||
|
|
|
@ -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,6 +14,7 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
|
|||
noShadowDOM();
|
||||
const [rows, setRows] = createSignal<TableRow[]>([]);
|
||||
const [activeTab, setActiveTab] = createSignal(0);
|
||||
const [activeGroup, setActiveGroup] = createSignal<string | null>(null);
|
||||
const [loaded, setLoaded] = createSignal(false);
|
||||
const [bodyHtml, setBodyHtml] = createSignal('');
|
||||
|
||||
|
|
@ -68,6 +70,33 @@ 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<string>();
|
||||
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;
|
||||
|
|
@ -89,27 +118,68 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
|
|||
|
||||
// 更新 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 (
|
||||
<div class="ttrpg-table">
|
||||
<div class="flex items-center gap-2 border-b border-gray-200">
|
||||
<div class="flex flex-col w-full">
|
||||
{/* 分组 tabs */}
|
||||
<Show when={hasGroup()}>
|
||||
<div class="flex gap-2 border-b border-gray-100 pb-2">
|
||||
<button
|
||||
onClick={() => handleGroupChange(null)}
|
||||
class={`font-medium transition-colors ${
|
||||
activeGroup() === null
|
||||
? 'text-blue-600 border-b-2 border-blue-600'
|
||||
: 'text-gray-500 hover:text-gray-700'
|
||||
}`}
|
||||
>
|
||||
全部
|
||||
</button>
|
||||
<For each={groups()}>
|
||||
{(group) => (
|
||||
<button
|
||||
onClick={() => handleGroupChange(group)}
|
||||
class={`font-medium transition-colors ${
|
||||
activeGroup() === group
|
||||
? 'text-blue-600 border-b-2 border-blue-600'
|
||||
: 'text-gray-500 hover:text-gray-700'
|
||||
}`}
|
||||
>
|
||||
{group}
|
||||
</button>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
{/* 内容 tabs */}
|
||||
<div class="flex gap-2">
|
||||
<Show when={props.roll}>
|
||||
<button
|
||||
onClick={handleRoll}
|
||||
|
|
@ -119,8 +189,7 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
|
|||
🎲
|
||||
</button>
|
||||
</Show>
|
||||
<div class="flex gap-2">
|
||||
<For each={rows()}>
|
||||
<For each={filteredRows()}>
|
||||
{(row, index) => (
|
||||
<button
|
||||
onClick={() => setActiveTab(index())}
|
||||
|
|
@ -136,8 +205,9 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
|
|||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-1 prose max-w-none">
|
||||
<Show when={loaded() && rows().length > 0}>
|
||||
<Show when={loaded() && filteredRows().length > 0}>
|
||||
<div innerHTML={bodyHtml()} />
|
||||
</Show>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue