refactor: svg page

This commit is contained in:
hypercross 2026-02-27 18:19:37 +08:00
parent 1845576b18
commit ec5a00fa94
1 changed files with 121 additions and 109 deletions

View File

@ -179,6 +179,56 @@ export function PrintPreview(props: PrintPreviewProps) {
const visibleLayers = createMemo(() => store.state.layerConfigs.filter((l) => l.visible));
// 渲染单个卡片的 SVG 内容(使用 foreignObject
const renderCardInSvg = (card: { data: typeof store.state.cards[0]; x: number; y: number }, pageIndex: number) => {
const cardWidth = store.state.dimensions?.cardWidth || 56;
const cardHeight = store.state.dimensions?.cardHeight || 88;
const gridOriginX = store.state.dimensions?.gridOriginX || 0;
const gridOriginY = store.state.dimensions?.gridOriginY || 0;
const gridAreaWidth = store.state.dimensions?.gridAreaWidth || cardWidth;
const gridAreaHeight = store.state.dimensions?.gridAreaHeight || cardHeight;
const fontSize = store.state.dimensions?.fontSize || 3;
return (
<g class="card-group">
<foreignObject
x={`${card.x}mm`}
y={`${card.y}mm`}
width={`${cardWidth}mm`}
height={`${cardHeight}mm`}
>
<div xmlns="http://www.w3.org/1999/xhtml" class="w-full h-full bg-white">
{/* 网格区域容器 */}
<div
class="absolute"
style={{
position: 'absolute',
left: `${gridOriginX}mm`,
top: `${gridOriginY}mm`,
width: `${gridAreaWidth}mm`,
height: `${gridAreaHeight}mm`
}}
>
{/* 渲染每个 layer */}
<For each={visibleLayers()}>
{(layer) => (
<div
class="absolute flex items-center justify-center text-center prose prose-sm"
style={{
...getLayerStyle(layer, store.state.dimensions!),
'font-size': `${fontSize}mm`
}}
innerHTML={renderLayerContent(layer, card.data)}
/>
)}
</For>
</div>
</div>
</foreignObject>
</g>
);
};
return (
<div class="fixed inset-0 bg-black/50 z-50 overflow-auto print:overflow-visible print:absolute">
{/* 打印样式:根据方向设置 @page 规则 */}
@ -268,22 +318,20 @@ export function PrintPreview(props: PrintPreviewProps) {
</div>
</div>
{/* A4 纸张预览 */}
{/* A4 纸张预览:每页都是一个完整的 SVG */}
<div class="flex flex-col items-center gap-8 print-root">
<For each={pages()}>
{(page) => (
<div
class="bg-white shadow-xl print:shadow-none print:w-full"
<svg
class="bg-white shadow-xl print:shadow-none"
viewBox={`0 0 ${getA4Size().width}mm ${getA4Size().height}mm`}
style={{
width: `${getA4Size().width}mm`,
height: `${getA4Size().height}mm`
}}
data-page={page.pageIndex + 1}
xmlns="http://www.w3.org/2000/svg"
>
{/* 渲染该页的所有卡牌 */}
<div class="relative w-full h-full">
{/* 裁切线和外围框层 */}
<svg class="absolute inset-0 w-full h-full pointer-events-none" style={{ overflow: 'visible' }}>
{/* 外围边框:黑色 0.2mm */}
<rect
x={`${cropMarks()[page.pageIndex]?.frameBoundsWithMargin.x}mm`}
@ -345,48 +393,12 @@ export function PrintPreview(props: PrintPreviewProps) {
</>
)}
</For>
</svg>
{/* 渲染该页的所有卡牌 */}
<For each={page.cards}>
{(card) => (
<div
class="absolute bg-white"
style={{
left: `${card.x}mm`,
top: `${card.y}mm`,
width: `${store.state.dimensions?.cardWidth}mm`,
height: `${store.state.dimensions?.cardHeight}mm`
}}
>
{/* 网格区域容器 */}
<div
class="absolute"
style={{
left: `${store.state.dimensions?.gridOriginX}mm`,
top: `${store.state.dimensions?.gridOriginY}mm`,
width: `${store.state.dimensions?.gridAreaWidth}mm`,
height: `${store.state.dimensions?.gridAreaHeight}mm`
}}
>
{/* 渲染每个 layer */}
<For each={visibleLayers()}>
{(layer) => (
<div
class="absolute flex items-center justify-center text-center prose prose-sm"
style={{
...getLayerStyle(layer, store.state.dimensions!),
'font-size': `${store.state.dimensions?.fontSize}mm`
}}
innerHTML={renderLayerContent(layer, card.data)}
/>
)}
{(card) => renderCardInSvg(card, page.pageIndex)}
</For>
</div>
</div>
)}
</For>
</div>
</div>
</svg>
)}
</For>
</div>