refactor: clean up
This commit is contained in:
parent
72285e093f
commit
0aaadea2da
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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,9 +118,30 @@ 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}>
|
||||
<CardPreview store={store}/>
|
||||
<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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
@ -9,25 +10,28 @@ export interface DeckState {
|
|||
padding: string;
|
||||
fixed: boolean;
|
||||
src: string;
|
||||
|
||||
|
||||
// 解析后的尺寸
|
||||
dimensions: Dimensions | null;
|
||||
|
||||
|
||||
// 卡牌数据
|
||||
cards: CardData[];
|
||||
activeTab: number;
|
||||
|
||||
|
||||
// 图层配置
|
||||
layerConfigs: LayerConfig[];
|
||||
|
||||
|
||||
// 编辑状态
|
||||
isEditing: boolean;
|
||||
editingLayer: string | null;
|
||||
|
||||
|
||||
// 框选状态
|
||||
isSelecting: boolean;
|
||||
selectStart: { x: number; y: number } | null;
|
||||
selectEnd: { x: number; y: number } | null;
|
||||
|
||||
// 错误状态
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
export interface DeckActions {
|
||||
|
|
@ -36,31 +40,32 @@ export interface DeckActions {
|
|||
setGrid: (grid: string) => void;
|
||||
setBleed: (bleed: string) => void;
|
||||
setPadding: (padding: string) => void;
|
||||
|
||||
|
||||
// 数据设置
|
||||
setCards: (cards: CardData[]) => void;
|
||||
setActiveTab: (index: number) => void;
|
||||
updateCardData: (index: number, key: string, value: string) => void;
|
||||
|
||||
|
||||
// 图层操作
|
||||
setLayerConfigs: (configs: LayerConfig[]) => void;
|
||||
updateLayerConfig: (prop: string, updates: Partial<LayerConfig>) => void;
|
||||
toggleLayerVisible: (prop: string) => void;
|
||||
|
||||
|
||||
// 编辑状态
|
||||
setIsEditing: (editing: boolean) => void;
|
||||
setEditingLayer: (layer: string | null) => void;
|
||||
updateLayerPosition: (x1: number, y1: number, x2: number, y2: number) => void;
|
||||
|
||||
|
||||
// 框选操作
|
||||
setIsSelecting: (selecting: boolean) => void;
|
||||
setSelectStart: (pos: { x: number; y: number } | null) => void;
|
||||
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;
|
||||
copyCode: () => void;
|
||||
|
|
@ -87,20 +92,44 @@ 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 });
|
||||
|
||||
const setCards = (cards: CardData[]) => setState({ cards });
|
||||
// 更新尺寸并重新计算 dimensions
|
||||
const updateDimensions = () => {
|
||||
const dims = calculateDimensions({
|
||||
size: state.size,
|
||||
grid: state.grid,
|
||||
bleed: state.bleed,
|
||||
padding: state.padding
|
||||
});
|
||||
setState({ dimensions: dims });
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
const setLayerConfigs = (configs: LayerConfig[]) => setState({ layerConfigs: configs });
|
||||
const updateLayerConfig = (prop: string, updates: Partial<LayerConfig>) => {
|
||||
setState('layerConfigs', (prev) => prev.map((config) => config.prop === prop ? { ...config, ...updates } : config));
|
||||
|
|
@ -110,7 +139,7 @@ export function createDeckStore(): DeckStore {
|
|||
config.prop === prop ? { ...config, visible: !config.visible } : config
|
||||
));
|
||||
};
|
||||
|
||||
|
||||
const setIsEditing = (editing: boolean) => setState({ isEditing: editing });
|
||||
const setEditingLayer = (layer: string | null) => setState({ editingLayer: layer });
|
||||
const updateLayerPosition = (x1: number, y1: number, x2: number, y2: number) => {
|
||||
|
|
@ -121,32 +150,34 @@ export function createDeckStore(): DeckStore {
|
|||
));
|
||||
setState({ editingLayer: null });
|
||||
};
|
||||
|
||||
|
||||
const setIsSelecting = (selecting: boolean) => setState({ isSelecting: selecting });
|
||||
const setSelectStart = (pos: { x: number; y: number } | null) => setState({ selectStart: pos });
|
||||
const setSelectEnd = (pos: { x: number; y: number } | null) => setState({ selectEnd: pos });
|
||||
const cancelSelection = () => {
|
||||
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}"}`;
|
||||
};
|
||||
|
||||
|
||||
const copyCode = () => {
|
||||
const code = generateCode();
|
||||
navigator.clipboard.writeText(code).then(() => {
|
||||
|
|
@ -175,7 +206,8 @@ export function createDeckStore(): DeckStore {
|
|||
setSelectStart,
|
||||
setSelectEnd,
|
||||
cancelSelection,
|
||||
initialize,
|
||||
loadCards,
|
||||
setError,
|
||||
generateCode,
|
||||
copyCode
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { DeckStore } from '../stores/deckStore';
|
||||
import type { DeckStore } from './deckStore';
|
||||
|
||||
/**
|
||||
* 框选相关的操作(已整合到 deckStore)
|
||||
Loading…
Reference in New Issue