diff --git a/src/components/md-deck/CardList.tsx b/src/components/md-deck/CardList.tsx
new file mode 100644
index 0000000..ac7c45e
--- /dev/null
+++ b/src/components/md-deck/CardList.tsx
@@ -0,0 +1,86 @@
+import { For, Show, createEffect, createSignal, on } from "solid-js";
+import type { DeckStore } from "./hooks/deckStore";
+
+export interface CardListProps {
+ store: DeckStore;
+}
+
+const PAGE_SIZE = 10;
+
+/**
+ * 卡牌列表:左侧垂直导航,每行高度一致,按页分页
+ */
+export function CardList(props: CardListProps) {
+ const { store } = props;
+ const [page, setPage] = createSignal(0);
+
+ const totalPages = () =>
+ Math.max(1, Math.ceil(store.state.cards.length / PAGE_SIZE));
+
+ const pageCards = () => {
+ const start = page() * PAGE_SIZE;
+ return store.state.cards.slice(start, start + PAGE_SIZE);
+ };
+
+ // 当活动卡牌变化时,自动跳转到其所在页(只响应 activeTab,避免与手动翻页互相干扰)
+ createEffect(
+ on(
+ () => store.state.activeTab,
+ (tab) => {
+ setPage(Math.floor(tab / PAGE_SIZE));
+ },
+ ),
+ );
+
+ return (
+
+ );
+}
diff --git a/src/components/md-deck/DeckHeader.tsx b/src/components/md-deck/DeckHeader.tsx
index c7c5479..5c7a0ff 100644
--- a/src/components/md-deck/DeckHeader.tsx
+++ b/src/components/md-deck/DeckHeader.tsx
@@ -1,4 +1,3 @@
-import { For } from "solid-js";
import type { DeckStore } from "./hooks/deckStore";
export interface DeckHeaderProps {
@@ -33,23 +32,13 @@ export function DeckHeader(props: DeckHeaderProps) {
📥 导出 PDF
- {/* Tab 选择器 */}
-
-
- {(card, index) => (
-
- )}
-
-
+ {/* 复制代码按钮 */}
+
);
}
diff --git a/src/components/md-deck/EditorTabs.tsx b/src/components/md-deck/EditorTabs.tsx
new file mode 100644
index 0000000..e27f2c6
--- /dev/null
+++ b/src/components/md-deck/EditorTabs.tsx
@@ -0,0 +1,59 @@
+import { createSignal } from "solid-js";
+import type { DeckStore } from "./hooks/deckStore";
+import { LayerEditorPanel, PropertiesEditorPanel } from "./editor-panel";
+
+export interface EditorTabsProps {
+ store: DeckStore;
+}
+
+type TabKey = "sizing" | "front" | "back";
+
+/**
+ * 编辑面板:尺寸 / 正面图层 / 背面图层 用标签页切换,节省横向空间
+ */
+export function EditorTabs(props: EditorTabsProps) {
+ const { store } = props;
+ const [tab, setTab] = createSignal("sizing");
+
+ const tabs: { key: TabKey; label: string }[] = [
+ { key: "sizing", label: "尺寸" },
+ { key: "front", label: "正面图层" },
+ { key: "back", label: "背面图层" },
+ ];
+
+ const selectTab = (key: TabKey) => {
+ setTab(key);
+ // 切换正/背面标签时,同步预览的显示面
+ if (key === "front") store.actions.setActiveSide("front");
+ if (key === "back") store.actions.setActiveSide("back");
+ };
+
+ return (
+
+ {/* 标签页切换 */}
+
+ {tabs.map((t) => (
+
+ ))}
+
+
+ {tab() === "sizing" ? (
+
+ ) : (
+
+ )}
+
+ );
+}
diff --git a/src/components/md-deck/editor-panel/LayerEditorPanel.tsx b/src/components/md-deck/editor-panel/LayerEditorPanel.tsx
index 3960d1b..be1792b 100644
--- a/src/components/md-deck/editor-panel/LayerEditorPanel.tsx
+++ b/src/components/md-deck/editor-panel/LayerEditorPanel.tsx
@@ -6,11 +6,13 @@ import {
closestCenter,
} from "@thisbeyond/solid-dnd";
import type { DeckStore } from "../hooks/deckStore";
+import type { CardSide } from "../types";
import { toSortableId } from "../hooks/layer-crud";
import { LayerRow } from "./LayerRow";
export interface LayerEditorPanelProps {
store: DeckStore;
+ side?: CardSide;
}
function LayerEditorPanel(props: LayerEditorPanelProps) {
@@ -20,7 +22,7 @@ function LayerEditorPanel(props: LayerEditorPanelProps) {
const [addMenuOpen, setAddMenuOpen] = createSignal(false);
let addMenuRef: HTMLDivElement | undefined;
- const side = () => store.state.activeSide;
+ const side = () => props.side || "front";
const layers = () =>
side() === "front"
? store.state.frontLayerConfigs
@@ -143,15 +145,6 @@ function LayerEditorPanel(props: LayerEditorPanelProps) {
-
-
-
);
}
diff --git a/src/components/md-deck/editor-panel/PropertiesEditorPanel.tsx b/src/components/md-deck/editor-panel/PropertiesEditorPanel.tsx
index c513c34..7267747 100644
--- a/src/components/md-deck/editor-panel/PropertiesEditorPanel.tsx
+++ b/src/components/md-deck/editor-panel/PropertiesEditorPanel.tsx
@@ -1,49 +1,32 @@
-import type { DeckStore } from '../hooks/deckStore';
-import type { CardShape } from '../types';
+import type { DeckStore } from "../hooks/deckStore";
+import type { CardShape } from "../types";
export interface PropertiesEditorPanelProps {
store: DeckStore;
}
/**
- * 卡牌属性编辑面板:尺寸、网格、出血、内边距、正背面切换
+ * 卡牌尺寸编辑面板:尺寸、网格、出血、内边距、形状
*/
export function PropertiesEditorPanel(props: PropertiesEditorPanelProps) {
const { store } = props;
- return (
-
-
卡牌属性
+ const shapeOptions: { value: CardShape; label: string }[] = [
+ { value: "rectangle", label: "矩形" },
+ { value: "circle", label: "圆形" },
+ { value: "triangle", label: "三角形" },
+ { value: "hexagon", label: "六边形" },
+ ];
- {/* 正面/背面切换标签页 */}
-
-
-
-
-
-
+ return (
+
+
尺寸
-
+
-
-
- {(['rectangle', 'circle', 'triangle', 'hexagon'] as CardShape[]).map((shape) => (
-
+
+
+
diff --git a/src/components/md-deck/index.tsx b/src/components/md-deck/index.tsx
index 32c54e9..3d87f4c 100644
--- a/src/components/md-deck/index.tsx
+++ b/src/components/md-deck/index.tsx
@@ -6,13 +6,11 @@ import { createDeckStore } from "./hooks/deckStore";
import { registerDeck, unregisterDeck } from "./hooks/deck-registry";
import type { CardShape } from "./types";
import { DeckHeader } from "./DeckHeader";
+import { CardList } from "./CardList";
import { DeckContent } from "./DeckContent";
+import { EditorTabs } from "./EditorTabs";
import { PrintPreview } from "./PrintPreview";
-import {
- DataEditorPanel,
- LayerEditorPanel,
- PropertiesEditorPanel,
-} from "./editor-panel";
+import { DataEditorPanel } from "./editor-panel";
interface DeckProps {
size?: string;
@@ -139,29 +137,19 @@ customElement
(
- {/* 内容区域:错误/加载/卡牌预览/空状态 */}
- {/* 左侧:CSV 数据编辑 */}
- {/*
*/}
- {/* */}
- {/**/}
-
-
-
+ {/* 左侧:卡牌列表导航 */}
+ 0 && !store.state.error}>
+
-
+ {/* 中间:内容区域(错误/加载/卡牌预览/空状态) */}
+
+
+
- {/* 右侧:属性/图层编辑面板 */}
+ {/* 右侧:属性/图层编辑面板(标签页切换) */}
-
-
-
+