diff --git a/src/components/AppShell.tsx b/src/components/AppShell.tsx index dfb8b8be..b53b0091 100644 --- a/src/components/AppShell.tsx +++ b/src/components/AppShell.tsx @@ -36,6 +36,7 @@ import { localeNames } from "../locales"; import type { LocaleCode } from "../locales"; import { mmToUnit } from "../lib/units"; import { useT } from "../lib/useT"; +import { kbd } from "../lib/kbd"; import { useGlobalShortcuts } from "../hooks/useGlobalShortcuts"; import { useDesignFileActions } from "../hooks/useDesignFileActions"; import { useZplImportExport } from "../hooks/useZplImportExport"; @@ -114,7 +115,8 @@ export function AppShell() { diff --git a/src/components/Output/ImportReportModal.tsx b/src/components/Output/ImportReportModal.tsx index bbaa19d3..0b236aa3 100644 --- a/src/components/Output/ImportReportModal.tsx +++ b/src/components/Output/ImportReportModal.tsx @@ -2,6 +2,8 @@ import { useState } from 'react'; import { XMarkIcon, ClipboardDocumentIcon, CheckIcon } from '@heroicons/react/16/solid'; import { partialLoss, formatReportAsText } from '../../lib/importReport'; import type { ImportResult } from '../../lib/importReport'; +import { useT } from '../../lib/useT'; +import { DialogShell } from '../ui/DialogShell'; export type { ImportResult }; @@ -55,6 +57,7 @@ interface Props { } export function ImportReportModal({ result, onClose }: Props) { + const t = useT(); const [copied, setCopied] = useState(false); const handleCopy = () => { @@ -65,41 +68,40 @@ export function ImportReportModal({ result, onClose }: Props) { }; return ( -
{ if (e.target === e.currentTarget) onClose(); }} + -
-
- Import Report - -
+
+ Import Report + +
- + -
- - -
+
+ +
-
+
); } diff --git a/src/components/Output/LabelPreview.tsx b/src/components/Output/LabelPreview.tsx index c7300fca..1a78d2c2 100644 --- a/src/components/Output/LabelPreview.tsx +++ b/src/components/Output/LabelPreview.tsx @@ -5,6 +5,7 @@ import { generateZPL } from '../../lib/zplGenerator'; import { fetchPreview, labelaryErrorMessage } from '../../lib/labelary'; import { triggerDownload } from '../../lib/triggerDownload'; import { useT } from '../../lib/useT'; +import { DialogShell } from '../ui/DialogShell'; interface Props { onClose: () => void; @@ -51,72 +52,65 @@ export function LabelPreviewModal({ onClose }: Props) { }; return ( -
-
e.stopPropagation()} - > -
- - {t.output.previewHeading} - - -
+
+ + {t.output.previewHeading} + + +
- {/* Inset preview area: bg-bg gives a clear edge against the surrounding - surface (especially in light mode where the label image is white). - The outer div scrolls; the inner one stays at least as large as the - viewport so small previews are still centered. */} -
-
- {loading && ( - {t.output.loading} - )} - {!loading && error && ( -
- {error} - -
- )} - {!loading && !error && previewUrl && ( - Label preview - )} -
+ {/* Inset preview area: bg-bg gives a clear edge against the surrounding + surface (especially in light mode where the label image is white). + The outer div scrolls; the inner one stays at least as large as the + viewport so small previews are still centered. */} +
+
+ {loading && ( + {t.output.loading} + )} + {!loading && error && ( +
+ {error} + +
+ )} + {!loading && !error && previewUrl && ( + Label preview + )}
+
-
- - {t.output.previewProvider} - -
+
+ + {t.output.previewProvider} +
-
+ ); } diff --git a/src/components/Output/LabelaryNoticeModal.tsx b/src/components/Output/LabelaryNoticeModal.tsx index 30317e6f..0c109030 100644 --- a/src/components/Output/LabelaryNoticeModal.tsx +++ b/src/components/Output/LabelaryNoticeModal.tsx @@ -1,6 +1,7 @@ import { XMarkIcon } from '@heroicons/react/16/solid'; import { useLabelStore } from '../../store/labelStore'; import { useT } from '../../lib/useT'; +import { DialogShell } from '../ui/DialogShell'; interface Props { /** Called after the modal flipped the store flag, so callers only need @@ -25,48 +26,41 @@ export function LabelaryNoticeModal({ onContinue, onClose }: Props) { }; return ( -
-
e.stopPropagation()} - > -
- - {t.output.previewNoticeTitle} - - -
+
+ + {t.output.previewNoticeTitle} + + +
-
- {t.output.previewNoticeBody} - - {t.output.previewNoticePrivacyLink} - - -
+
+ {t.output.previewNoticeBody} + + {t.output.previewNoticePrivacyLink} + +
-
+ ); } diff --git a/src/components/Output/PrintToZebraDialog.tsx b/src/components/Output/PrintToZebraDialog.tsx index 8fd50fe1..f08489d1 100644 --- a/src/components/Output/PrintToZebraDialog.tsx +++ b/src/components/Output/PrintToZebraDialog.tsx @@ -1,6 +1,7 @@ import { useState } from "react"; import { XMarkIcon } from "@heroicons/react/16/solid"; import { useT } from "../../lib/useT"; +import { DialogShell } from "../ui/DialogShell"; import { discoverBrowserPrintDevices, isConnectionRefused, @@ -107,137 +108,134 @@ export function PrintToZebraDialog({ zpl, onClose }: Props) { }`; return ( -
-
e.stopPropagation()} - > - {/* Header */} -
- - {t.zebraPrint.heading} - - -
+ {/* Header */} +
+ + {t.zebraPrint.heading} + + +
+ + {/* Tabs */} +
+ + +
+ + {/* Network tab */} + {tab === "network" && ( +
+ {window.location.protocol === "https:" && ( +

+ {t.zebraPrint.httpsWarning} +

+ )} +
+
+ + setIp(e.target.value)} + onBlur={persistNetwork} + placeholder="192.168.1.100" + className="bg-bg border border-border rounded px-2 py-1 text-xs font-mono text-text focus:outline-none focus:border-accent" + /> +
+
+ + setPort(e.target.value)} + onBlur={persistNetwork} + className="bg-bg border border-border rounded px-2 py-1 text-xs font-mono text-text focus:outline-none focus:border-accent" + /> +
+
- {/* Tabs */} -
- -
- {/* Network tab */} - {tab === "network" && ( -
- {window.location.protocol === "https:" && ( -

- {t.zebraPrint.httpsWarning} -

- )} -
-
- - setIp(e.target.value)} - onBlur={persistNetwork} - placeholder="192.168.1.100" - className="bg-bg border border-border rounded px-2 py-1 text-xs font-mono text-text focus:outline-none focus:border-accent" - /> -
-
- - setPort(e.target.value)} - onBlur={persistNetwork} - className="bg-bg border border-border rounded px-2 py-1 text-xs font-mono text-text focus:outline-none focus:border-accent" - /> -
+ +
+ )} + + {/* Browser Print tab */} + {tab === "browserprint" && ( +
+
+
+ +
- - -
- )} - - {/* Browser Print tab */} - {tab === "browserprint" && ( -
-
-
- - -
- -
- + - -
- )} -
-
+ +
+ )} + ); } diff --git a/src/components/Output/ZPLOutput.tsx b/src/components/Output/ZPLOutput.tsx index 96df205d..13770d2e 100644 --- a/src/components/Output/ZPLOutput.tsx +++ b/src/components/Output/ZPLOutput.tsx @@ -40,7 +40,8 @@ export function ZPLOutput({ collapsed, onCollapse, onExpand }: Props) { diff --git a/src/components/Output/ZplImportModal.tsx b/src/components/Output/ZplImportModal.tsx index 1dad4d19..67e77935 100644 --- a/src/components/Output/ZplImportModal.tsx +++ b/src/components/Output/ZplImportModal.tsx @@ -5,12 +5,15 @@ import { readFileAsText } from '../../lib/readFile'; import { useLabelStore } from '../../store/labelStore'; import { formatReportAsText, type ImportResult } from '../../lib/importReport'; import { ImportSummaryBody } from './ImportReportModal'; +import { useT } from '../../lib/useT'; +import { DialogShell } from '../ui/DialogShell'; interface Props { onClose: () => void; } export function ZplImportModal({ onClose }: Props) { + const t = useT(); const [zpl, setZpl] = useState(''); const [error, setError] = useState(null); const [result, setResult] = useState(null); @@ -72,99 +75,98 @@ export function ZplImportModal({ onClose }: Props) { }; return ( -
{ if (e.target === e.currentTarget) onClose(); }} + -
-
- Import ZPL - -
+
+ {t.app.importZpl} + +
- {result ? ( - <> - -
- + {result ? ( + <> + +
+ + +
+ + ) : ( + <> +
+

+ Import produces an{' '} + editable reconstruction + , not an exact replica. Simple labels import cleanly; complex or + machine-generated ZPL may lose fidelity. Use{' '} + Save design (.json) as the + lossless source format. +

+