refactor: clean up

This commit is contained in:
hypercross 2026-02-27 14:32:43 +08:00
parent 72285e093f
commit 0aaadea2da
5 changed files with 133 additions and 112 deletions

View File

@ -1,7 +1,7 @@
import { Show, For } from 'solid-js';
import { marked } from '../markdown';
import { getLayerStyle } from './utils/dimensions';
import {getSelectionBoxStyle, useSelection} from './hooks/use-selection';
import {getSelectionBoxStyle, useSelection} from './stores/use-selection';
import {DeckStore} from "./stores/deckStore";
export interface CardPreviewProps {

View File

@ -1,58 +0,0 @@
/**
* Schema
*/
export type FieldType = 'string' | 'number' | 'boolean' | 'text' | 'select';
export interface FieldSchema {
/** 字段名 */
key: string;
/** 字段类型 */
type: FieldType;
/** 显示标签 */
label?: string;
/** 占位符文本 */
placeholder?: string;
/** 描述/提示文本 */
description?: string;
/** 是否必需 */
required?: boolean;
/** 最小值(用于 number 类型) */
min?: number;
/** 最大值(用于 number 类型) */
max?: number;
/** 选项(用于 select 类型) */
options?: { label: string; value: string }[];
/** 行数(用于 text 类型) */
rows?: number;
/** 默认值 */
default?: string | number | boolean;
}
export interface Schema {
/** Schema 名称 */
name?: string;
/** 字段定义列表 */
fields: FieldSchema[];
}
/**
*
*/
export type PropertyValues = Record<string, string | number | boolean>;
/**
* usePropertyEditor hook
*/
export interface UsePropertyEditorReturn<T extends PropertyValues> {
/** 获取属性值 */
get: <K extends keyof T>(key: K) => T[K];
/** 设置属性值 */
set: <K extends keyof T>(key: K, value: T[K]) => void;
/** 获取所有属性值 */
getAll: () => T;
/** 设置所有属性值 */
setAll: (values: T) => void;
/** 重置为默认值 */
reset: () => void;
}

View File

@ -1,5 +1,5 @@
import { customElement, noShadowDOM } from 'solid-element';
import { Show, createEffect, createResource, For } from 'solid-js';
import { Show, createEffect, createResource, For, onCleanup } from 'solid-js';
import { resolvePath } from './utils/path';
import { loadCSV } from './utils/csv-loader';
import { initLayerConfigs } from './utils/layer-parser';
@ -7,7 +7,16 @@ import { createDeckStore } from './stores/deckStore';
import { CardPreview } from './card-preview';
import { DataEditorPanel, PropertiesEditorPanel } from './editor-panel';
customElement('md-deck', {
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',
@ -21,7 +30,7 @@ customElement('md-deck', {
const store = createDeckStore();
// 从 element 的 textContent 获取 CSV 路径
const src = element?.textContent?.trim() || '';
const csvPath = element?.textContent?.trim() || '';
// 隐藏原始文本内容
if (element) {
@ -33,20 +42,37 @@ customElement('md-deck', {
const articlePath = articleEl?.getAttribute('data-src') || '';
// 解析相对路径
const resolvedSrc = resolvePath(articlePath, src);
const resolvedSrc = resolvePath(articlePath, csvPath);
// 初始化 store
store.initialize(props, src);
// 初始化 store 属性
store.setSize(props.size || '54x86');
store.setGrid(props.grid || '5x8');
store.setBleed(props.bleed || '1');
store.setPadding(props.padding || '2');
// 加载 CSV 文件
const [csvData] = createResource(() => resolvedSrc, loadCSV);
const [csvData, { refetch }] = createResource(() => resolvedSrc, loadCSV);
// 处理 CSV 数据加载结果
createEffect(() => {
const data = !csvData.loading && csvData();
if (data) {
store.setCards(data);
store.setLayerConfigs(initLayerConfigs(data, props.layers as string || ''));
const data = csvData();
const loading = csvData.loading;
const error = csvData.error;
if (error) {
store.setError(`加载 CSV 失败:${error.message}`);
return;
}
if (!loading && data) {
store.loadCards(data);
store.setLayerConfigs(initLayerConfigs(data, (props.layers as string) || ''));
}
});
// 清理函数
onCleanup(() => {
// 可以在这里清理资源
});
return (
@ -92,10 +118,31 @@ customElement('md-deck', {
</div>
</div>
{/* 错误提示 */}
<Show when={store.error}>
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded mb-4">
{store.error}
</div>
</Show>
{/* 加载状态 */}
<Show when={csvData.loading}>
<div class="text-center text-gray-500 py-8">
...
</div>
</Show>
{/* 卡牌预览 */}
<Show when={!csvData.loading && store.cards.length > 0}>
<Show when={!csvData.loading && store.cards.length > 0 && !store.error}>
<CardPreview store={store} />
</Show>
{/* 空状态 */}
<Show when={!csvData.loading && store.cards.length === 0 && !store.error}>
<div class="text-center text-gray-500 py-8">
</div>
</Show>
</div>
{/* 右侧:属性编辑表单 */}

View File

@ -1,4 +1,5 @@
import { createStore, produce } from 'solid-js/store';
import { createStore } from 'solid-js/store';
import { calculateDimensions } from '../utils/dimensions';
import type { CardData, LayerConfig, Dimensions } from '../types';
export interface DeckState {
@ -28,6 +29,9 @@ export interface DeckState {
isSelecting: boolean;
selectStart: { x: number; y: number } | null;
selectEnd: { x: number; y: number } | null;
// 错误状态
error: string | null;
}
export interface DeckActions {
@ -58,8 +62,9 @@ export interface DeckActions {
setSelectEnd: (pos: { x: number; y: number } | null) => void;
cancelSelection: () => void;
// 初始化
initialize: (props: Record<string, any>, csvPath: string) => void;
// 初始化和数据加载
loadCards: (cards: CardData[]) => void;
setError: (error: string | null) => void;
// 生成代码
generateCode: () => string;
@ -87,15 +92,39 @@ export function createDeckStore(): DeckStore {
editingLayer: null,
isSelecting: false,
selectStart: null,
selectEnd: null
selectEnd: null,
error: null
});
const setSize = (size: string) => setState({ size });
const setGrid = (grid: string) => setState({ grid });
const setBleed = (bleed: string) => setState({ bleed });
const setPadding = (padding: string) => setState({ padding });
// 更新尺寸并重新计算 dimensions
const updateDimensions = () => {
const dims = calculateDimensions({
size: state.size,
grid: state.grid,
bleed: state.bleed,
padding: state.padding
});
setState({ dimensions: dims });
};
const setCards = (cards: CardData[]) => setState({ cards });
const setSize = (size: string) => {
setState({ size });
updateDimensions();
};
const setGrid = (grid: string) => {
setState({ grid });
updateDimensions();
};
const setBleed = (bleed: string) => {
setState({ bleed });
updateDimensions();
};
const setPadding = (padding: string) => {
setState({ padding });
updateDimensions();
};
const setCards = (cards: CardData[]) => setState({ cards, activeTab: 0 });
const setActiveTab = (index: number) => setState({ activeTab: index });
const updateCardData = (index: number, key: string, value: string) => {
setState('cards', index, key, value);
@ -129,21 +158,23 @@ export function createDeckStore(): DeckStore {
setState({ isSelecting: false, selectStart: null, selectEnd: null });
};
const initialize = (props: Record<string, any>, csvPath: string) => {
setState({
size: props.size as string || '54x86',
grid: props.grid as string || '5x8',
bleed: props.bleed as string || '1',
padding: props.padding as string || '2',
fixed: props.fixed === true || props.fixed === 'true',
src: csvPath
});
// 加载卡牌数据并初始化 dimensions 和 layerConfigs
const loadCards = (cards: CardData[]) => {
if (cards.length === 0) {
setState({ error: 'CSV 文件为空或格式不正确' });
return;
}
setState({ cards, activeTab: 0, error: null });
updateDimensions();
};
const setError = (error: string | null) => setState({ error });
const generateCode = () => {
const layersStr = state.layerConfigs
.map(l => `${l.prop}=${l.x1},${l.y1},${l.x2},${l.y2}`)
.join('|');
.filter(l => l.visible)
.map(l => `${l.prop}:${l.x1},${l.y1}-${l.x2},${l.y2}`)
.join(' ');
return `:md-deck[${state.src}]{size="${state.size}" grid="${state.grid}" bleed="${state.bleed}" padding="${state.padding}" layers="${layersStr}"}`;
};
@ -175,7 +206,8 @@ export function createDeckStore(): DeckStore {
setSelectStart,
setSelectEnd,
cancelSelection,
initialize,
loadCards,
setError,
generateCode,
copyCode
};

View File

@ -1,4 +1,4 @@
import type { DeckStore } from '../stores/deckStore';
import type { DeckStore } from './deckStore';
/**
* deckStore