fix: state tracking
This commit is contained in:
parent
0aaadea2da
commit
8ddc2a672a
|
|
@ -1,8 +1,8 @@
|
||||||
import { Show, For } from 'solid-js';
|
import { Show, For } from 'solid-js';
|
||||||
import { marked } from '../markdown';
|
import { marked } from '../markdown';
|
||||||
import { getLayerStyle } from './utils/dimensions';
|
import { getLayerStyle } from './utils/dimensions';
|
||||||
import {getSelectionBoxStyle, useSelection} from './stores/use-selection';
|
import { getSelectionBoxStyle, useSelection } from './stores/use-selection';
|
||||||
import {DeckStore} from "./stores/deckStore";
|
import type { DeckStore } from "./stores/deckStore";
|
||||||
|
|
||||||
export interface CardPreviewProps {
|
export interface CardPreviewProps {
|
||||||
store: DeckStore;
|
store: DeckStore;
|
||||||
|
|
@ -11,30 +11,30 @@ export interface CardPreviewProps {
|
||||||
/**
|
/**
|
||||||
* 渲染 layer 内容
|
* 渲染 layer 内容
|
||||||
*/
|
*/
|
||||||
function renderLayer(layer: { prop: string }, cardData: DeckStore['cards'][number]): string {
|
function renderLayer(layer: { prop: string }, cardData: DeckStore['state']['cards'][number]): string {
|
||||||
const content = cardData[layer.prop] || '';
|
const content = cardData[layer.prop] || '';
|
||||||
return marked.parse(content) as string;
|
return marked.parse(content) as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CardPreview(props: CardPreviewProps) {
|
export function CardPreview(props: CardPreviewProps) {
|
||||||
const currentCard = () => props.store.cards[props.store.activeTab];
|
const currentCard = () => props.store.state.cards[props.store.state.activeTab];
|
||||||
const visibleLayers = () => props.store.layerConfigs.filter((l) => l.visible);
|
const visibleLayers = () => props.store.state.layerConfigs.filter((l) => l.visible);
|
||||||
const selectionStyle = () =>
|
const selectionStyle = () =>
|
||||||
getSelectionBoxStyle(props.store.selectStart, props.store.selectEnd, props.store.dimensions);
|
getSelectionBoxStyle(props.store.state.selectStart, props.store.state.selectEnd, props.store.state.dimensions);
|
||||||
|
|
||||||
const selection = useSelection(props.store);
|
const selection = useSelection(props.store);
|
||||||
|
|
||||||
let cardRef: HTMLDivElement | undefined;
|
let cardRef: HTMLDivElement | undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<Show when={props.store.activeTab < props.store.cards.length}>
|
<Show when={props.store.state.activeTab < props.store.state.cards.length}>
|
||||||
<div
|
<div
|
||||||
ref={cardRef}
|
ref={cardRef}
|
||||||
class="relative bg-white border border-gray-300 shadow-lg"
|
class="relative bg-white border border-gray-300 shadow-lg"
|
||||||
style={{
|
style={{
|
||||||
width: `${props.store.dimensions?.cardWidth}mm`,
|
width: `${props.store.state.dimensions?.cardWidth}mm`,
|
||||||
height: `${props.store.dimensions?.cardHeight}mm`
|
height: `${props.store.state.dimensions?.cardHeight}mm`
|
||||||
}}
|
}}
|
||||||
onMouseDown={(e) => selection.onMouseDown(e, cardRef!)}
|
onMouseDown={(e) => selection.onMouseDown(e, cardRef!)}
|
||||||
onMouseMove={(e) => selection.onMouseMove(e, cardRef!)}
|
onMouseMove={(e) => selection.onMouseMove(e, cardRef!)}
|
||||||
|
|
@ -42,7 +42,7 @@ export function CardPreview(props: CardPreviewProps) {
|
||||||
onMouseLeave={selection.onMouseLeave}
|
onMouseLeave={selection.onMouseLeave}
|
||||||
>
|
>
|
||||||
{/* 框选遮罩 */}
|
{/* 框选遮罩 */}
|
||||||
<Show when={props.store.isSelecting && selectionStyle()}>
|
<Show when={props.store.state.isSelecting && selectionStyle()}>
|
||||||
<div
|
<div
|
||||||
class="absolute bg-blue-500/30 border-2 border-blue-500 pointer-events-none"
|
class="absolute bg-blue-500/30 border-2 border-blue-500 pointer-events-none"
|
||||||
style={selectionStyle()!}
|
style={selectionStyle()!}
|
||||||
|
|
@ -53,28 +53,28 @@ export function CardPreview(props: CardPreviewProps) {
|
||||||
<div
|
<div
|
||||||
class="absolute"
|
class="absolute"
|
||||||
style={{
|
style={{
|
||||||
left: `${props.store.dimensions?.gridOriginX}mm`,
|
left: `${props.store.state.dimensions?.gridOriginX}mm`,
|
||||||
top: `${props.store.dimensions?.gridOriginY}mm`,
|
top: `${props.store.state.dimensions?.gridOriginY}mm`,
|
||||||
width: `${props.store.dimensions?.gridAreaWidth}mm`,
|
width: `${props.store.state.dimensions?.gridAreaWidth}mm`,
|
||||||
height: `${props.store.dimensions?.gridAreaHeight}mm`
|
height: `${props.store.state.dimensions?.gridAreaHeight}mm`
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* 编辑模式下的网格线 */}
|
{/* 编辑模式下的网格线 */}
|
||||||
<Show when={props.store.isEditing && !props.store.fixed}>
|
<Show when={props.store.state.isEditing && !props.store.state.fixed}>
|
||||||
<div class="absolute inset-0 pointer-events-none">
|
<div class="absolute inset-0 pointer-events-none">
|
||||||
<For each={Array.from({ length: (props.store.dimensions?.gridW || 0) - 1 })}>
|
<For each={Array.from({ length: (props.store.state.dimensions?.gridW || 0) - 1 })}>
|
||||||
{(_, i) => (
|
{(_, i) => (
|
||||||
<div
|
<div
|
||||||
class="absolute top-0 bottom-0 border-r border-dashed border-gray-300"
|
class="absolute top-0 bottom-0 border-r border-dashed border-gray-300"
|
||||||
style={{ left: `${(i() + 1) * (props.store.dimensions?.cellWidth || 0)}mm` }}
|
style={{ left: `${(i() + 1) * (props.store.state.dimensions?.cellWidth || 0)}mm` }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
<For each={Array.from({ length: (props.store.dimensions?.gridH || 0) - 1 })}>
|
<For each={Array.from({ length: (props.store.state.dimensions?.gridH || 0) - 1 })}>
|
||||||
{(_, i) => (
|
{(_, i) => (
|
||||||
<div
|
<div
|
||||||
class="absolute left-0 right-0 border-b border-dashed border-gray-300"
|
class="absolute left-0 right-0 border-b border-dashed border-gray-300"
|
||||||
style={{ top: `${(i() + 1) * (props.store.dimensions?.cellHeight || 0)}mm` }}
|
style={{ top: `${(i() + 1) * (props.store.state.dimensions?.cellHeight || 0)}mm` }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
|
|
@ -84,12 +84,12 @@ export function CardPreview(props: CardPreviewProps) {
|
||||||
{/* 渲染每个 layer */}
|
{/* 渲染每个 layer */}
|
||||||
<For each={visibleLayers()}>
|
<For each={visibleLayers()}>
|
||||||
{(layer) => {
|
{(layer) => {
|
||||||
const style = getLayerStyle(layer, props.store.dimensions!);
|
const style = getLayerStyle(layer, props.store.state.dimensions!);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
class={`absolute flex items-center justify-center text-center prose prose-sm ${
|
class={`absolute flex items-center justify-center text-center prose prose-sm ${
|
||||||
props.store.isEditing ? 'bg-blue-500/20 ring-2 ring-blue-500' : ''
|
props.store.state.isEditing ? 'bg-blue-500/20 ring-2 ring-blue-500' : ''
|
||||||
}`}
|
}`}
|
||||||
style={style}
|
style={style}
|
||||||
innerHTML={renderLayer(layer, currentCard())}
|
innerHTML={renderLayer(layer, currentCard())}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { For } from 'solid-js';
|
import { For } from 'solid-js';
|
||||||
import { DeckStore } from './stores/deckStore';
|
import type { DeckStore } from './stores/deckStore';
|
||||||
|
|
||||||
export interface DataEditorPanelProps {
|
export interface DataEditorPanelProps {
|
||||||
activeTab: number;
|
activeTab: number;
|
||||||
cards: DeckStore['cards'];
|
cards: DeckStore['state']['cards'];
|
||||||
updateCardData: DeckStore['updateCardData'];
|
updateCardData: DeckStore['actions']['updateCardData'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PropertiesEditorPanelProps {
|
export interface PropertiesEditorPanelProps {
|
||||||
|
|
@ -42,7 +42,7 @@ export function DataEditorPanel(props: DataEditorPanelProps) {
|
||||||
*/
|
*/
|
||||||
export function PropertiesEditorPanel(props: PropertiesEditorPanelProps) {
|
export function PropertiesEditorPanel(props: PropertiesEditorPanelProps) {
|
||||||
const { store } = props;
|
const { store } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="w-64 flex-shrink-0">
|
<div class="w-64 flex-shrink-0">
|
||||||
<h3 class="font-bold mb-2">卡牌属性</h3>
|
<h3 class="font-bold mb-2">卡牌属性</h3>
|
||||||
|
|
@ -53,8 +53,8 @@ export function PropertiesEditorPanel(props: PropertiesEditorPanelProps) {
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
|
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
|
||||||
value={store.size}
|
value={store.state.size}
|
||||||
onInput={(e) => store.setSize(e.target.value)}
|
onInput={(e) => store.actions.setSize(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -63,8 +63,8 @@ export function PropertiesEditorPanel(props: PropertiesEditorPanelProps) {
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
|
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
|
||||||
value={store.grid}
|
value={store.state.grid}
|
||||||
onInput={(e) => store.setGrid(e.target.value)}
|
onInput={(e) => store.actions.setGrid(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -73,8 +73,8 @@ export function PropertiesEditorPanel(props: PropertiesEditorPanelProps) {
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
|
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
|
||||||
value={store.bleed}
|
value={store.state.bleed}
|
||||||
onInput={(e) => store.setBleed(e.target.value)}
|
onInput={(e) => store.actions.setBleed(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -83,33 +83,33 @@ export function PropertiesEditorPanel(props: PropertiesEditorPanelProps) {
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
|
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
|
||||||
value={store.padding}
|
value={store.state.padding}
|
||||||
onInput={(e) => store.setPadding(e.target.value)}
|
onInput={(e) => store.actions.setPadding(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-4" />
|
<hr class="my-4" />
|
||||||
|
|
||||||
<h4 class="font-medium text-sm text-gray-700">图层</h4>
|
<h4 class="font-medium text-sm text-gray-700">图层</h4>
|
||||||
<For each={store.layerConfigs}>
|
<For each={store.state.layerConfigs}>
|
||||||
{(layer) => (
|
{(layer) => (
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={layer.visible}
|
checked={layer.visible}
|
||||||
onChange={() => store.toggleLayerVisible(layer.prop)}
|
onChange={() => store.actions.toggleLayerVisible(layer.prop)}
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
/>
|
/>
|
||||||
<span class="text-sm flex-1">{layer.prop}</span>
|
<span class="text-sm flex-1">{layer.prop}</span>
|
||||||
<button
|
<button
|
||||||
onClick={() => store.setEditingLayer(layer.prop)}
|
onClick={() => store.actions.setEditingLayer(layer.prop)}
|
||||||
class={`text-xs px-2 py-0.5 rounded cursor-pointer ${
|
class={`text-xs px-2 py-0.5 rounded cursor-pointer ${
|
||||||
store.editingLayer === layer.prop
|
store.state.editingLayer === layer.prop
|
||||||
? 'bg-blue-500 text-white'
|
? 'bg-blue-500 text-white'
|
||||||
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{store.editingLayer === layer.prop ? '✓ 框选' : '编辑位置'}
|
{store.state.editingLayer === layer.prop ? '✓ 框选' : '编辑位置'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -118,7 +118,7 @@ export function PropertiesEditorPanel(props: PropertiesEditorPanelProps) {
|
||||||
<hr class="my-4" />
|
<hr class="my-4" />
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={store.copyCode}
|
onClick={store.actions.copyCode}
|
||||||
class="w-full bg-blue-600 hover:bg-blue-700 text-white px-3 py-2 rounded text-sm font-medium cursor-pointer"
|
class="w-full bg-blue-600 hover:bg-blue-700 text-white px-3 py-2 rounded text-sm font-medium cursor-pointer"
|
||||||
>
|
>
|
||||||
📋 复制代码
|
📋 复制代码
|
||||||
|
|
|
||||||
|
|
@ -45,10 +45,10 @@ customElement<DeckProps>('md-deck', {
|
||||||
const resolvedSrc = resolvePath(articlePath, csvPath);
|
const resolvedSrc = resolvePath(articlePath, csvPath);
|
||||||
|
|
||||||
// 初始化 store 属性
|
// 初始化 store 属性
|
||||||
store.setSize(props.size || '54x86');
|
store.actions.setSize(props.size || '54x86');
|
||||||
store.setGrid(props.grid || '5x8');
|
store.actions.setGrid(props.grid || '5x8');
|
||||||
store.setBleed(props.bleed || '1');
|
store.actions.setBleed(props.bleed || '1');
|
||||||
store.setPadding(props.padding || '2');
|
store.actions.setPadding(props.padding || '2');
|
||||||
|
|
||||||
// 加载 CSV 文件
|
// 加载 CSV 文件
|
||||||
const [csvData, { refetch }] = createResource(() => resolvedSrc, loadCSV);
|
const [csvData, { refetch }] = createResource(() => resolvedSrc, loadCSV);
|
||||||
|
|
@ -60,13 +60,13 @@ customElement<DeckProps>('md-deck', {
|
||||||
const error = csvData.error;
|
const error = csvData.error;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
store.setError(`加载 CSV 失败:${error.message}`);
|
store.actions.setError(`加载 CSV 失败:${error.message}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loading && data) {
|
if (!loading && data) {
|
||||||
store.loadCards(data);
|
store.actions.loadCards(data);
|
||||||
store.setLayerConfigs(initLayerConfigs(data, (props.layers as string) || ''));
|
store.actions.setLayerConfigs(initLayerConfigs(data, (props.layers as string) || ''));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -78,11 +78,11 @@ customElement<DeckProps>('md-deck', {
|
||||||
return (
|
return (
|
||||||
<div class="md-deck flex gap-4">
|
<div class="md-deck flex gap-4">
|
||||||
{/* 左侧:CSV 数据编辑 */}
|
{/* 左侧:CSV 数据编辑 */}
|
||||||
<Show when={store.isEditing && !store.fixed}>
|
<Show when={store.state.isEditing && !store.state.fixed}>
|
||||||
<DataEditorPanel
|
<DataEditorPanel
|
||||||
activeTab={store.activeTab}
|
activeTab={store.state.activeTab}
|
||||||
cards={store.cards}
|
cards={store.state.cards}
|
||||||
updateCardData={store.updateCardData}
|
updateCardData={store.actions.updateCardData}
|
||||||
/>
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
|
@ -91,22 +91,22 @@ customElement<DeckProps>('md-deck', {
|
||||||
{/* Tab 选择器 */}
|
{/* Tab 选择器 */}
|
||||||
<div class="flex items-center gap-2 border-b border-gray-200 pb-2 mb-4">
|
<div class="flex items-center gap-2 border-b border-gray-200 pb-2 mb-4">
|
||||||
<button
|
<button
|
||||||
onClick={() => store.setIsEditing(!store.isEditing)}
|
onClick={() => store.actions.setIsEditing(!store.state.isEditing)}
|
||||||
class={`px-3 py-1 rounded text-sm font-medium transition-colors ${
|
class={`px-3 py-1 rounded text-sm font-medium transition-colors ${
|
||||||
store.isEditing && !store.fixed
|
store.state.isEditing && !store.state.fixed
|
||||||
? 'bg-blue-100 text-blue-600'
|
? 'bg-blue-100 text-blue-600'
|
||||||
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
|
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
|
||||||
} cursor-pointer`}
|
} cursor-pointer`}
|
||||||
>
|
>
|
||||||
{store.isEditing ? '✓ 编辑中' : '✏️ 编辑'}
|
{store.state.isEditing ? '✓ 编辑中' : '✏️ 编辑'}
|
||||||
</button>
|
</button>
|
||||||
<div class="flex gap-1 overflow-x-auto flex-1 min-w-0 flex-wrap">
|
<div class="flex gap-1 overflow-x-auto flex-1 min-w-0 flex-wrap">
|
||||||
<For each={store.cards}>
|
<For each={store.state.cards}>
|
||||||
{(card, index) => (
|
{(card, index) => (
|
||||||
<button
|
<button
|
||||||
onClick={() => store.setActiveTab(index())}
|
onClick={() => store.actions.setActiveTab(index())}
|
||||||
class={`font-medium transition-colors flex-shrink-0 min-w-[1.6em] cursor-pointer px-2 py-1 rounded ${
|
class={`font-medium transition-colors flex-shrink-0 min-w-[1.6em] cursor-pointer px-2 py-1 rounded ${
|
||||||
store.activeTab === index()
|
store.state.activeTab === index()
|
||||||
? 'bg-blue-100 text-blue-600 border-b-2 border-blue-600'
|
? 'bg-blue-100 text-blue-600 border-b-2 border-blue-600'
|
||||||
: 'text-gray-500 hover:text-gray-700 hover:bg-gray-100'
|
: 'text-gray-500 hover:text-gray-700 hover:bg-gray-100'
|
||||||
}`}
|
}`}
|
||||||
|
|
@ -119,9 +119,9 @@ customElement<DeckProps>('md-deck', {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 错误提示 */}
|
{/* 错误提示 */}
|
||||||
<Show when={store.error}>
|
<Show when={store.state.error}>
|
||||||
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded mb-4">
|
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded mb-4">
|
||||||
{store.error}
|
{store.state.error}
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
|
@ -133,12 +133,12 @@ customElement<DeckProps>('md-deck', {
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
{/* 卡牌预览 */}
|
{/* 卡牌预览 */}
|
||||||
<Show when={!csvData.loading && store.cards.length > 0 && !store.error}>
|
<Show when={!csvData.loading && store.state.cards.length > 0 && !store.state.error}>
|
||||||
<CardPreview store={store} />
|
<CardPreview store={store} />
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
{/* 空状态 */}
|
{/* 空状态 */}
|
||||||
<Show when={!csvData.loading && store.cards.length === 0 && !store.error}>
|
<Show when={!csvData.loading && store.state.cards.length === 0 && !store.state.error}>
|
||||||
<div class="text-center text-gray-500 py-8">
|
<div class="text-center text-gray-500 py-8">
|
||||||
暂无卡牌数据
|
暂无卡牌数据
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -146,7 +146,7 @@ customElement<DeckProps>('md-deck', {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 右侧:属性编辑表单 */}
|
{/* 右侧:属性编辑表单 */}
|
||||||
<Show when={store.isEditing && !store.fixed}>
|
<Show when={store.state.isEditing && !store.state.fixed}>
|
||||||
<PropertiesEditorPanel store={store} />
|
<PropertiesEditorPanel store={store} />
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,10 @@ export interface DeckActions {
|
||||||
copyCode: () => void;
|
copyCode: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DeckStore extends DeckState, DeckActions {}
|
export interface DeckStore {
|
||||||
|
state: DeckState;
|
||||||
|
actions: DeckActions;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建 deck store
|
* 创建 deck store
|
||||||
|
|
@ -187,8 +190,7 @@ export function createDeckStore(): DeckStore {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
const actions: DeckActions = {
|
||||||
...state,
|
|
||||||
setSize,
|
setSize,
|
||||||
setGrid,
|
setGrid,
|
||||||
setBleed,
|
setBleed,
|
||||||
|
|
@ -211,4 +213,6 @@ export function createDeckStore(): DeckStore {
|
||||||
generateCode,
|
generateCode,
|
||||||
copyCode
|
copyCode
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import type { DeckStore } from './deckStore';
|
||||||
* 此 hook 保留用于向后兼容或提取特定逻辑
|
* 此 hook 保留用于向后兼容或提取特定逻辑
|
||||||
*/
|
*/
|
||||||
export function useSelection(store: DeckStore) {
|
export function useSelection(store: DeckStore) {
|
||||||
const calculateGridCoords = (e: MouseEvent, cardEl: HTMLElement, dimensions: DeckStore['dimensions']) => {
|
const calculateGridCoords = (e: MouseEvent, cardEl: HTMLElement, dimensions: DeckStore['state']['dimensions']) => {
|
||||||
if (!dimensions) return { gridX: 1, gridY: 1 };
|
if (!dimensions) return { gridX: 1, gridY: 1 };
|
||||||
|
|
||||||
const rect = cardEl.getBoundingClientRect();
|
const rect = cardEl.getBoundingClientRect();
|
||||||
|
|
||||||
const offsetX = (e.clientX - rect.left) / rect.width * dimensions.cardWidth;
|
const offsetX = (e.clientX - rect.left) / rect.width * dimensions.cardWidth;
|
||||||
|
|
@ -23,36 +23,36 @@ export function useSelection(store: DeckStore) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseDown = (e: MouseEvent, cardEl: HTMLElement) => {
|
const handleMouseDown = (e: MouseEvent, cardEl: HTMLElement) => {
|
||||||
if (!store.isEditing || !store.editingLayer) return;
|
if (!store.state.isEditing || !store.state.editingLayer) return;
|
||||||
|
|
||||||
const { gridX, gridY } = calculateGridCoords(e, cardEl, store.dimensions);
|
const { gridX, gridY } = calculateGridCoords(e, cardEl, store.state.dimensions);
|
||||||
|
|
||||||
store.setSelectStart({ x: gridX, y: gridY });
|
store.actions.setSelectStart({ x: gridX, y: gridY });
|
||||||
store.setSelectEnd({ x: gridX, y: gridY });
|
store.actions.setSelectEnd({ x: gridX, y: gridY });
|
||||||
store.setIsSelecting(true);
|
store.actions.setIsSelecting(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseMove = (e: MouseEvent, cardEl: HTMLElement) => {
|
const handleMouseMove = (e: MouseEvent, cardEl: HTMLElement) => {
|
||||||
if (!store.isSelecting) return;
|
if (!store.state.isSelecting) return;
|
||||||
|
|
||||||
const { gridX, gridY } = calculateGridCoords(e, cardEl, store.dimensions);
|
const { gridX, gridY } = calculateGridCoords(e, cardEl, store.state.dimensions);
|
||||||
|
|
||||||
store.setSelectEnd({ x: gridX, y: gridY });
|
store.actions.setSelectEnd({ x: gridX, y: gridY });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseUp = () => {
|
const handleMouseUp = () => {
|
||||||
if (!store.isSelecting || !store.editingLayer) return;
|
if (!store.state.isSelecting || !store.state.editingLayer) return;
|
||||||
|
|
||||||
const start = store.selectStart!;
|
const start = store.state.selectStart!;
|
||||||
const end = store.selectEnd!;
|
const end = store.state.selectEnd!;
|
||||||
|
|
||||||
const x1 = Math.min(start.x, end.x);
|
const x1 = Math.min(start.x, end.x);
|
||||||
const y1 = Math.min(start.y, end.y);
|
const y1 = Math.min(start.y, end.y);
|
||||||
const x2 = Math.max(start.x, end.x);
|
const x2 = Math.max(start.x, end.x);
|
||||||
const y2 = Math.max(start.y, end.y);
|
const y2 = Math.max(start.y, end.y);
|
||||||
|
|
||||||
store.updateLayerPosition(x1, y1, x2, y2);
|
store.actions.updateLayerPosition(x1, y1, x2, y2);
|
||||||
store.cancelSelection();
|
store.actions.cancelSelection();
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue