89 lines
2.6 KiB
TypeScript
89 lines
2.6 KiB
TypeScript
|
|
import { customElement, noShadowDOM } from 'solid-element';
|
|||
|
|
import { Show, createEffect, onCleanup } from 'solid-js';
|
|||
|
|
import { resolvePath } from '../utils/path';
|
|||
|
|
import { createDeckStore } from './hooks/deckStore';
|
|||
|
|
import { DeckHeader } from './DeckHeader';
|
|||
|
|
import { DeckContent } from './DeckContent';
|
|||
|
|
import { DataEditorPanel, PropertiesEditorPanel } from './editor-panel';
|
|||
|
|
|
|||
|
|
interface DeckProps {
|
|||
|
|
size?: string;
|
|||
|
|
grid?: string;
|
|||
|
|
bleed?: string;
|
|||
|
|
padding?: string;
|
|||
|
|
layers?: string;
|
|||
|
|
fixed?: boolean | string;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
customElement<DeckProps>('md-deck', {
|
|||
|
|
size: '54x86',
|
|||
|
|
grid: '5x8',
|
|||
|
|
bleed: '1',
|
|||
|
|
padding: '2',
|
|||
|
|
layers: '',
|
|||
|
|
fixed: false
|
|||
|
|
}, (props, { element }) => {
|
|||
|
|
noShadowDOM();
|
|||
|
|
|
|||
|
|
// 从 element 的 textContent 获取 CSV 路径
|
|||
|
|
const csvPath = element?.textContent?.trim() || '';
|
|||
|
|
|
|||
|
|
// 隐藏原始文本内容
|
|||
|
|
if (element) {
|
|||
|
|
element.textContent = '';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 从父节点 article 的 data-src 获取当前 markdown 文件完整路径
|
|||
|
|
const articleEl = element?.closest('article[data-src]');
|
|||
|
|
const articlePath = articleEl?.getAttribute('data-src') || '';
|
|||
|
|
|
|||
|
|
// 解析相对路径
|
|||
|
|
const resolvedSrc = resolvePath(articlePath, csvPath);
|
|||
|
|
|
|||
|
|
// 创建 store 并加载数据
|
|||
|
|
const store = createDeckStore(resolvedSrc, (props.layers as string) || '');
|
|||
|
|
|
|||
|
|
// 初始化 store 属性
|
|||
|
|
store.actions.setSize(props.size || '54x86');
|
|||
|
|
store.actions.setGrid(props.grid || '5x8');
|
|||
|
|
store.actions.setBleed(props.bleed || '1');
|
|||
|
|
store.actions.setPadding(props.padding || '2');
|
|||
|
|
|
|||
|
|
// 加载 CSV 数据
|
|||
|
|
store.actions.loadCardsFromPath(resolvedSrc, (props.layers as string) || '');
|
|||
|
|
|
|||
|
|
// 清理函数
|
|||
|
|
onCleanup(() => {
|
|||
|
|
store.actions.clearError();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div class="md-deck flex gap-4">
|
|||
|
|
{/* 左侧:CSV 数据编辑 */}
|
|||
|
|
<Show when={store.state.isEditing && !store.state.fixed}>
|
|||
|
|
<DataEditorPanel
|
|||
|
|
activeTab={store.state.activeTab}
|
|||
|
|
cards={store.state.cards}
|
|||
|
|
updateCardData={store.actions.updateCardData}
|
|||
|
|
/>
|
|||
|
|
</Show>
|
|||
|
|
|
|||
|
|
{/* 中间:卡牌预览和控制 */}
|
|||
|
|
<div class="flex-1">
|
|||
|
|
{/* Tab 选择器和编辑按钮 */}
|
|||
|
|
<Show when={store.state.cards.length > 0 && !store.state.error}>
|
|||
|
|
<DeckHeader store={store} />
|
|||
|
|
</Show>
|
|||
|
|
|
|||
|
|
{/* 内容区域:错误/加载/卡牌预览/空状态 */}
|
|||
|
|
<DeckContent store={store} isLoading={store.state.isLoading} />
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 右侧:属性编辑表单 */}
|
|||
|
|
<Show when={store.state.isEditing && !store.state.fixed}>
|
|||
|
|
<PropertiesEditorPanel store={store} />
|
|||
|
|
</Show>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
});
|