diff --git a/src/components/md-deck/DeckHeader.tsx b/src/components/md-deck/DeckHeader.tsx
index 304fe40..b0b2a64 100644
--- a/src/components/md-deck/DeckHeader.tsx
+++ b/src/components/md-deck/DeckHeader.tsx
@@ -25,6 +25,14 @@ export function DeckHeader(props: DeckHeaderProps) {
{store.state.isEditing ? '✓ 编辑中' : '✏️ 编辑'}
+ {/* 打印按钮 */}
+
+
{/* Tab 选择器 */}
diff --git a/src/components/md-deck/PrintPreview.tsx b/src/components/md-deck/PrintPreview.tsx
new file mode 100644
index 0000000..18c6c54
--- /dev/null
+++ b/src/components/md-deck/PrintPreview.tsx
@@ -0,0 +1,165 @@
+import { Show, For, createMemo } from 'solid-js';
+import { marked } from '../../markdown';
+import { getLayerStyle } from './hooks/dimensions';
+import type { DeckStore } from './hooks/deckStore';
+
+export interface PrintPreviewProps {
+ store: DeckStore;
+ onClose: () => void;
+ onPrint: () => void;
+}
+
+/**
+ * 渲染 layer 内容
+ */
+function renderLayerContent(layer: { prop: string }, cardData: { [key: string]: string }): string {
+ const content = cardData[layer.prop] || '';
+ return marked.parse(content) as string;
+}
+
+/**
+ * 打印预览组件:在 A4 纸张上排列所有卡牌
+ */
+export function PrintPreview(props: PrintPreviewProps) {
+ const { store } = props;
+
+ // A4 纸张尺寸(mm):210 x 297
+ const A4_WIDTH = 210;
+ const A4_HEIGHT = 297;
+ const PRINT_MARGIN = 5; // 打印边距
+
+ // 计算每张卡牌在 A4 纸上的位置
+ const pages = createMemo(() => {
+ const cards = store.state.cards;
+ const cardWidth = store.state.dimensions?.cardWidth || 56;
+ const cardHeight = store.state.dimensions?.cardHeight || 88;
+
+ // 每行可容纳的卡牌数量
+ const usableWidth = A4_WIDTH - PRINT_MARGIN * 2;
+ const cardsPerRow = Math.floor(usableWidth / cardWidth);
+
+ // 每页可容纳的行数
+ const usableHeight = A4_HEIGHT - PRINT_MARGIN * 2;
+ const rowsPerPage = Math.floor(usableHeight / cardHeight);
+
+ // 每页的卡牌数量
+ const cardsPerPage = cardsPerRow * rowsPerPage;
+
+ // 分页
+ const result: { pageIndex: number; cards: Array<{ data: typeof cards[0]; x: number; y: number }> }[] = [];
+ let currentPage: typeof result[0] = { pageIndex: 0, cards: [] };
+
+ for (let i = 0; i < cards.length; i++) {
+ const pageIndex = Math.floor(i / cardsPerPage);
+ const indexInPage = i % cardsPerPage;
+ const row = Math.floor(indexInPage / cardsPerRow);
+ const col = indexInPage % cardsPerRow;
+
+ if (pageIndex !== currentPage.pageIndex) {
+ result.push(currentPage);
+ currentPage = { pageIndex, cards: [] };
+ }
+
+ currentPage.cards.push({
+ data: cards[i],
+ x: PRINT_MARGIN + col * cardWidth,
+ y: PRINT_MARGIN + row * cardHeight
+ });
+ }
+
+ if (currentPage.cards.length > 0) {
+ result.push(currentPage);
+ }
+
+ return result;
+ });
+
+ const visibleLayers = createMemo(() => store.state.layerConfigs.filter((l) => l.visible));
+
+ return (
+
+
+ {/* 打印预览控制栏 */}
+
+
+
打印预览
+
共 {pages().length} 页,{store.state.cards.length} 张卡牌
+
+
+
+
+
+
+
+ {/* A4 纸张预览 */}
+
+
+ {(page) => (
+
+ {/* 渲染该页的所有卡牌 */}
+
+
+ {(card) => (
+
+ {/* 网格区域容器 */}
+
+ {/* 渲染每个 layer */}
+
+ {(layer) => (
+
+ )}
+
+
+
+ )}
+
+
+
+ )}
+
+
+
+
+ );
+}
diff --git a/src/components/md-deck/hooks/deckStore.ts b/src/components/md-deck/hooks/deckStore.ts
index 75833a1..3f7bb5e 100644
--- a/src/components/md-deck/hooks/deckStore.ts
+++ b/src/components/md-deck/hooks/deckStore.ts
@@ -53,6 +53,9 @@ export interface DeckState {
// 错误状态
error: string | null;
+
+ // 打印状态
+ isPrinting: boolean;
}
export interface DeckActions {
@@ -94,6 +97,10 @@ export interface DeckActions {
// 生成代码
generateCode: () => string;
copyCode: () => Promise;
+
+ // 打印操作
+ setPrinting: (printing: boolean) => void;
+ printDeck: () => void;
}
export interface DeckStore {
@@ -128,7 +135,8 @@ export function createDeckStore(
selectStart: null,
selectEnd: null,
isLoading: false,
- error: null
+ error: null,
+ isPrinting: false
});
// 更新尺寸并重新计算 dimensions
@@ -265,6 +273,12 @@ export function createDeckStore(
}
};
+ const setPrinting = (printing: boolean) => setState({ isPrinting: printing });
+
+ const printDeck = () => {
+ setState({ isPrinting: true });
+ };
+
const actions: DeckActions = {
setSizeW,
setSizeH,
@@ -290,7 +304,9 @@ export function createDeckStore(
setError,
clearError,
generateCode,
- copyCode
+ copyCode,
+ setPrinting,
+ printDeck
};
return { state, actions };
diff --git a/src/components/md-deck/index.tsx b/src/components/md-deck/index.tsx
index 04932b7..4551c70 100644
--- a/src/components/md-deck/index.tsx
+++ b/src/components/md-deck/index.tsx
@@ -4,6 +4,7 @@ import { resolvePath } from '../utils/path';
import { createDeckStore } from './hooks/deckStore';
import { DeckHeader } from './DeckHeader';
import { DeckContent } from './DeckContent';
+import { PrintPreview } from './PrintPreview';
import {DataEditorPanel, LayerEditorPanel, PropertiesEditorPanel} from './editor-panel';
interface DeckProps {
@@ -102,6 +103,15 @@ customElement('md-deck', {
return (
+ {/* 打印预览弹窗 */}
+
+ store.actions.setPrinting(false)}
+ onPrint={() => window.print()}
+ />
+
+
{/* Tab 选择器和编辑按钮 */}
0 && !store.state.error}>
diff --git a/src/styles.css b/src/styles.css
index 3571db7..b585f83 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1,2 +1,20 @@
@import "tailwindcss";
@plugin "@tailwindcss/typography";
+
+/* 打印样式 */
+@media print {
+ body {
+ visibility: hidden;
+ }
+
+ body .in-print {
+ visibility: visible;
+ -webkit-print-color-adjust: exact !important;
+ print-color-adjust: exact !important;
+ }
+
+ @page {
+ size: A4;
+ margin: 0;
+ }
+}
\ No newline at end of file