Skip to content

Commit c925a25

Browse files
authored
Merge pull request #74 from u8array/feat/zpl-header-commands
Feat/zpl header commands
2 parents eba48db + 1fc38f4 commit c925a25

38 files changed

Lines changed: 1284 additions & 42 deletions

‎src/components/Properties/PropertiesPanel.tsx‎

Lines changed: 232 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ import { AlignButtons } from "./AlignButtons";
2323
import { inputCls, labelCls } from "./styles";
2424
import type { LabelConfig } from "../../types/ObjectType";
2525

26+
/** Built-in alphanumeric font IDs the Zebra firmware ships with. Used as
27+
* suggestions for ^CF — the input stays free-text so user-defined ^CW
28+
* aliases (single letters) can still be entered. */
29+
const ZPL_BUILTIN_FONT_IDS = ['0', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] as const;
30+
2631
interface PropertiesPanelProps {
2732
/** Imperative handle on the canvas — used for actions that need live render
2833
* bboxes (alignment, future zoom-to-selection, etc.). Required so the
@@ -430,7 +435,9 @@ function LabelConfigPanel({
430435
<CollapsibleSection
431436
id="label-output"
432437
title={t.label.outputHeading}
438+
defaultOpen={false}
433439
>
440+
<div className="flex flex-col gap-3">
434441
<div className="flex flex-col gap-1">
435442
<label className={labelCls}>{t.label.mediaMode}</label>
436443
<select
@@ -451,6 +458,61 @@ function LabelConfigPanel({
451458
</select>
452459
</div>
453460

461+
<div className="flex flex-col gap-1">
462+
<label className={labelCls}>
463+
{t.label.offsetsHeading}
464+
<InformationCircleIcon
465+
className="w-3.5 h-3.5 ml-1 inline-block align-text-bottom text-muted cursor-help"
466+
title={t.label.offsetsHint}
467+
/>
468+
</label>
469+
<div className="grid grid-cols-3 gap-2">
470+
<div className="flex flex-col gap-1">
471+
<label className="text-[10px] text-muted">
472+
{t.label.labelHomeX}
473+
</label>
474+
<input
475+
type="number"
476+
className={inputCls}
477+
value={label.labelHomeX ?? ""}
478+
min={0}
479+
onChange={(e) =>
480+
onUpdate({ labelHomeX: parseIntOrUndef(e.target.value) })
481+
}
482+
/>
483+
</div>
484+
<div className="flex flex-col gap-1">
485+
<label className="text-[10px] text-muted">
486+
{t.label.labelHomeY}
487+
</label>
488+
<input
489+
type="number"
490+
className={inputCls}
491+
value={label.labelHomeY ?? ""}
492+
min={0}
493+
onChange={(e) =>
494+
onUpdate({ labelHomeY: parseIntOrUndef(e.target.value) })
495+
}
496+
/>
497+
</div>
498+
<div className="flex flex-col gap-1">
499+
<label className="text-[10px] text-muted">
500+
{t.label.labelTop}
501+
</label>
502+
<input
503+
type="number"
504+
className={inputCls}
505+
value={label.labelTop ?? ""}
506+
min={-120}
507+
max={120}
508+
onChange={(e) =>
509+
onUpdate({ labelTop: parseIntOrUndef(e.target.value) })
510+
}
511+
/>
512+
</div>
513+
</div>
514+
</div>
515+
454516
<div className="flex flex-col gap-1">
455517
<label className={labelCls}>{t.label.labelShift}</label>
456518
<input
@@ -480,51 +542,165 @@ function LabelConfigPanel({
480542
}
481543
/>
482544
</div>
545+
546+
</div>
547+
</CollapsibleSection>
548+
549+
<CollapsibleSection
550+
id="label-quantity-advanced"
551+
title={t.label.quantityAdvancedHeading}
552+
defaultOpen={false}
553+
>
554+
<div className="flex flex-col gap-3">
555+
<div className="flex flex-col gap-1">
556+
<label className={labelCls}>{t.label.pauseCount}</label>
557+
<input
558+
type="number"
559+
className={inputCls}
560+
value={label.pauseCount ?? ""}
561+
min={0}
562+
max={99999999}
563+
onChange={(e) =>
564+
onUpdate({ pauseCount: parseIntOrUndef(e.target.value) })
565+
}
566+
/>
567+
</div>
568+
569+
<div className="flex flex-col gap-1">
570+
<label className={labelCls}>{t.label.replicates}</label>
571+
<input
572+
type="number"
573+
className={inputCls}
574+
value={label.replicates ?? ""}
575+
min={0}
576+
max={99999999}
577+
onChange={(e) =>
578+
onUpdate({ replicates: parseIntOrUndef(e.target.value) })
579+
}
580+
/>
581+
</div>
582+
583+
<label
584+
className="flex items-center gap-2 text-xs"
585+
title={t.label.overridePauseCountHint}
586+
>
587+
<input
588+
type="checkbox"
589+
checked={label.overridePauseCount === "Y"}
590+
onChange={(e) =>
591+
onUpdate({
592+
overridePauseCount: e.target.checked ? "Y" : undefined,
593+
})
594+
}
595+
/>
596+
{t.label.overridePauseCount}
597+
</label>
598+
</div>
483599
</CollapsibleSection>
484600

485601
<CollapsibleSection
486602
id="label-printer-settings"
487603
title={t.label.printerSettingsHeading}
488604
defaultOpen={false}
489605
>
606+
<div className="flex flex-col gap-3">
490607
<div className="flex flex-col gap-1">
491608
<label className={labelCls}>
492-
{t.label.printSpeed}
609+
{t.label.speedHeading}
493610
<InformationCircleIcon
494611
className="w-3.5 h-3.5 ml-1 inline-block align-text-bottom text-muted cursor-help"
495612
title={t.label.printSpeedHint}
496613
/>
497614
</label>
498-
<input
499-
type="number"
500-
className={inputCls}
501-
value={label.printSpeed ?? ""}
502-
min={2}
503-
max={14}
504-
onChange={(e) =>
505-
onUpdate({ printSpeed: parseIntOrUndef(e.target.value) })
506-
}
507-
/>
615+
<div className="grid grid-cols-3 gap-2">
616+
<div className="flex flex-col gap-1">
617+
<label className="text-[10px] text-muted">
618+
{t.label.speedPrint}
619+
</label>
620+
<input
621+
type="number"
622+
className={inputCls}
623+
value={label.printSpeed ?? ""}
624+
min={2}
625+
max={14}
626+
onChange={(e) =>
627+
onUpdate({ printSpeed: parseIntOrUndef(e.target.value) })
628+
}
629+
/>
630+
</div>
631+
<div className="flex flex-col gap-1">
632+
<label className="text-[10px] text-muted">
633+
{t.label.speedSlew}
634+
</label>
635+
<input
636+
type="number"
637+
className={inputCls}
638+
value={label.slewSpeed ?? ""}
639+
min={2}
640+
max={14}
641+
onChange={(e) =>
642+
onUpdate({ slewSpeed: parseIntOrUndef(e.target.value) })
643+
}
644+
/>
645+
</div>
646+
<div className="flex flex-col gap-1">
647+
<label className="text-[10px] text-muted">
648+
{t.label.speedBackfeed}
649+
</label>
650+
<input
651+
type="number"
652+
className={inputCls}
653+
value={label.backfeedSpeed ?? ""}
654+
min={2}
655+
max={14}
656+
onChange={(e) =>
657+
onUpdate({ backfeedSpeed: parseIntOrUndef(e.target.value) })
658+
}
659+
/>
660+
</div>
661+
</div>
508662
</div>
509663

510664
<div className="flex flex-col gap-1">
511665
<label className={labelCls}>
512-
{t.label.darkness}
666+
{t.label.darknessHeading}
513667
<InformationCircleIcon
514668
className="w-3.5 h-3.5 ml-1 inline-block align-text-bottom text-muted cursor-help"
515669
title={t.label.darknessHint}
516670
/>
517671
</label>
518-
<input
519-
type="number"
520-
className={inputCls}
521-
value={label.darkness ?? ""}
522-
min={-30}
523-
max={30}
524-
onChange={(e) =>
525-
onUpdate({ darkness: parseIntOrUndef(e.target.value) })
526-
}
527-
/>
672+
<div className="grid grid-cols-2 gap-2">
673+
<div className="flex flex-col gap-1">
674+
<label className="text-[10px] text-muted">
675+
{t.label.darknessPermanent}
676+
</label>
677+
<input
678+
type="number"
679+
className={inputCls}
680+
value={label.darkness ?? ""}
681+
min={-30}
682+
max={30}
683+
onChange={(e) =>
684+
onUpdate({ darkness: parseIntOrUndef(e.target.value) })
685+
}
686+
/>
687+
</div>
688+
<div className="flex flex-col gap-1">
689+
<label className="text-[10px] text-muted">
690+
{t.label.darknessInstant}
691+
</label>
692+
<input
693+
type="number"
694+
className={inputCls}
695+
value={label.instantDarkness ?? ""}
696+
min={0}
697+
max={30}
698+
onChange={(e) =>
699+
onUpdate({ instantDarkness: parseIntOrUndef(e.target.value) })
700+
}
701+
/>
702+
</div>
703+
</div>
528704
</div>
529705

530706
<div className="flex flex-col gap-1">
@@ -562,11 +738,21 @@ function LabelConfigPanel({
562738
<option value="N">{t.label.printOrientationN}</option>
563739
<option value="I">{t.label.printOrientationI}</option>
564740
</select>
741+
<label className="flex items-center gap-2 text-xs mt-1">
742+
<input
743+
type="checkbox"
744+
checked={label.mirror === "Y"}
745+
onChange={(e) =>
746+
onUpdate({ mirror: e.target.checked ? "Y" : undefined })
747+
}
748+
/>
749+
{t.label.mirror}
750+
</label>
565751
</div>
566752

567753
<div className="flex flex-col gap-1">
568754
<label className={labelCls}>{t.label.defaultFont}</label>
569-
<div className="grid grid-cols-2 gap-2">
755+
<div className="grid grid-cols-3 gap-2">
570756
<div className="flex flex-col gap-1">
571757
<label className="text-[10px] text-muted">
572758
{t.label.defaultFontId}
@@ -575,6 +761,7 @@ function LabelConfigPanel({
575761
type="text"
576762
className={inputCls}
577763
maxLength={2}
764+
list="zpl-default-font-ids"
578765
value={label.defaultFontId ?? ""}
579766
onChange={(e) =>
580767
onUpdate({ defaultFontId: e.target.value || undefined })
@@ -597,10 +784,32 @@ function LabelConfigPanel({
597784
}
598785
/>
599786
</div>
787+
<div className="flex flex-col gap-1">
788+
<label className="text-[10px] text-muted">
789+
{t.label.defaultFontWidth}
790+
</label>
791+
<input
792+
type="number"
793+
className={inputCls}
794+
min={0}
795+
value={label.defaultFontWidth ?? ""}
796+
onChange={(e) =>
797+
onUpdate({
798+
defaultFontWidth: parseIntOrUndef(e.target.value),
799+
})
800+
}
801+
/>
802+
</div>
600803
</div>
601804
</div>
805+
</div>
602806
</CollapsibleSection>
603807
</div>
808+
<datalist id="zpl-default-font-ids">
809+
{ZPL_BUILTIN_FONT_IDS.map((id) => (
810+
<option key={id} value={id} />
811+
))}
812+
</datalist>
604813
</div>
605814
);
606815
}

0 commit comments

Comments
 (0)