@@ -2,7 +2,8 @@ import { useRef, useState } from 'react';
22import { XMarkIcon , ClipboardDocumentIcon , CheckIcon , FolderOpenIcon } from '@heroicons/react/16/solid' ;
33import { importZplText } from '../../lib/zplImportService' ;
44import { readFileAsText } from '../../lib/readFile' ;
5- import { useLabelStore } from '../../store/labelStore' ;
5+ import { useLabelStore , type Page } from '../../store/labelStore' ;
6+ import type { LabelConfig } from '../../types/ObjectType' ;
67import { formatReportAsText , type ImportResult } from '../../lib/importReport' ;
78import { ImportSummaryBody } from './ImportReportModal' ;
89import { useT } from '../../lib/useT' ;
@@ -18,9 +19,30 @@ export function ZplImportModal({ onClose }: Props) {
1819 const [ error , setError ] = useState < string | null > ( null ) ;
1920 const [ result , setResult ] = useState < ImportResult | null > ( null ) ;
2021 const [ copied , setCopied ] = useState ( false ) ;
22+ const [ appendMode , setAppendMode ] = useState ( false ) ;
2123 const fileInputRef = useRef < HTMLInputElement > ( null ) ;
2224 const loadDesign = useLabelStore ( ( s ) => s . loadDesign ) ;
25+ const appendPages = useLabelStore ( ( s ) => s . appendPages ) ;
2326 const label = useLabelStore ( ( s ) => s . label ) ;
27+ const pages = useLabelStore ( ( s ) => s . pages ) ;
28+
29+ // Append-mode only makes sense when there is something to append *to*.
30+ // On a fresh designer (one empty page) we hide the toggle entirely
31+ // because the resulting [empty, imported] state would just be clutter
32+ // the user has to clean up manually.
33+ const hasExistingContent =
34+ pages . length > 1 || ( pages [ 0 ] ?. objects . length ?? 0 ) > 0 ;
35+
36+ const applyImport = ( labelConfig : Partial < LabelConfig > , importedPages : Page [ ] ) => {
37+ if ( appendMode && hasExistingContent ) {
38+ // Keep the current label config — the user opted to keep the
39+ // existing design's dimensions, so any imported ^PW/^LL is
40+ // intentionally discarded.
41+ appendPages ( importedPages ) ;
42+ } else {
43+ loadDesign ( { ...label , ...labelConfig } , importedPages ) ;
44+ }
45+ } ;
2446
2547 const handleImport = ( ) => {
2648 setError ( null ) ;
@@ -29,15 +51,15 @@ export function ZplImportModal({ onClose }: Props) {
2951 return ;
3052 }
3153
32- const { labelConfig, pages, report } = importZplText ( zpl , label . dpmm ) ;
33- const totalObjects = pages . reduce ( ( s , p ) => s + p . objects . length , 0 ) ;
54+ const { labelConfig, pages : importedPages , report } = importZplText ( zpl , label . dpmm ) ;
55+ const totalObjects = importedPages . reduce ( ( s , p ) => s + p . objects . length , 0 ) ;
3456
3557 if ( totalObjects === 0 && Object . keys ( labelConfig ) . length === 0 ) {
3658 setError ( 'No supported objects found in the ZPL code.' ) ;
3759 return ;
3860 }
3961
40- loadDesign ( { ... label , ... labelConfig } , pages ) ;
62+ applyImport ( labelConfig , importedPages ) ;
4163 setResult ( { objectCount : totalObjects , report } ) ;
4264 } ;
4365
@@ -60,9 +82,15 @@ export function ZplImportModal({ onClose }: Props) {
6082 return ;
6183 }
6284
63- const { labelConfig, pages, report } = importZplText ( text , label . dpmm ) ;
64- const totalObjects = pages . reduce ( ( s , p ) => s + p . objects . length , 0 ) ;
65- loadDesign ( { ...label , ...labelConfig } , pages ) ;
85+ const { labelConfig, pages : importedPages , report } = importZplText ( text , label . dpmm ) ;
86+ const totalObjects = importedPages . reduce ( ( s , p ) => s + p . objects . length , 0 ) ;
87+
88+ if ( totalObjects === 0 && Object . keys ( labelConfig ) . length === 0 ) {
89+ setError ( 'No supported objects found in the ZPL code.' ) ;
90+ return ;
91+ }
92+
93+ applyImport ( labelConfig , importedPages ) ;
6694 setResult ( { objectCount : totalObjects , report } ) ;
6795 } ;
6896
@@ -142,13 +170,26 @@ export function ZplImportModal({ onClose }: Props) {
142170 </ div >
143171
144172 < div className = "flex items-center justify-between px-4 py-3 border-t border-border shrink-0" >
145- < button
146- onClick = { ( ) => fileInputRef . current ?. click ( ) }
147- className = "flex items-center gap-1.5 font-mono text-[10px] text-muted hover:text-text transition-colors"
148- >
149- < FolderOpenIcon className = "w-3.5 h-3.5" />
150- Choose file
151- </ button >
173+ < div className = "flex items-center gap-4" >
174+ < button
175+ onClick = { ( ) => fileInputRef . current ?. click ( ) }
176+ className = "flex items-center gap-1.5 font-mono text-[10px] text-muted hover:text-text transition-colors"
177+ >
178+ < FolderOpenIcon className = "w-3.5 h-3.5" />
179+ { t . app . chooseFile }
180+ </ button >
181+ { hasExistingContent && (
182+ < label className = "flex items-center gap-1.5 cursor-pointer font-mono text-[10px] text-muted hover:text-text transition-colors" >
183+ < input
184+ type = "checkbox"
185+ className = "accent-accent"
186+ checked = { appendMode }
187+ onChange = { ( e ) => setAppendMode ( e . target . checked ) }
188+ />
189+ { t . app . keepExistingPages }
190+ </ label >
191+ ) }
192+ </ div >
152193 < div className = "flex gap-2" >
153194 < button
154195 onClick = { onClose }
0 commit comments