Client: QR print updates

* Added grid borders
* Replaced row height with instead choosing number of rows
* Added support for negative margins
* New QR code content format
* Added number inputs to all sliders
This commit is contained in:
Donkie
2023-08-02 21:00:36 +02:00
parent 0043f536ee
commit 437213c7d4
5 changed files with 335 additions and 141 deletions

View File

@@ -56,16 +56,22 @@
"printing": {
"generic": {
"title": "Printing",
"description": "Tune in the settings below to get the desired print layout. Keep in mind that printers and your OS may apply it's own margins and scaling, so you may need to adjust the settings accordingly. Test it on a piece of regular paper before printing on the actual labels.",
"print": "Print",
"columns": "Columns",
"rows": "Rows",
"paperSize": "Paper Size",
"rowHeight": "Row Height",
"showBorder": "Show Border",
"previewScale": "Preview Scale",
"marginLeft": "Left Margin",
"marginRight": "Right Margin",
"marginTop": "Top Margin",
"marginBottom": "Bottom Margin"
"marginBottom": "Bottom Margin",
"borders": {
"none": "None",
"border": "Border",
"grid": "Grid"
}
},
"qrcode": {
"button": "Print QR Codes",

View File

@@ -56,16 +56,22 @@
"printing": {
"generic": {
"title": "Utskrift",
"description": "Justera inställningarna nedan för att få önskat utskriftslayout. Kom ihåg att skrivare och ditt operativsystem kan tillämpa sina egna marginaler och skalning, så du kan behöva justera inställningarna därefter. Testa på ett vanligt papper innan du skriver ut på de faktiska etiketterna.",
"print": "Skriv ut",
"columns": "Kolumner",
"rows": "Rader",
"paperSize": "Papperstyp",
"rowHeight": "Radhöjd",
"showBorder": "Visa ram",
"previewScale": "Skala förhandsgranskning",
"marginLeft": "Marginal - vänster",
"marginRight": "Marginal - höger",
"marginTop": "Marginal - topp",
"marginBottom": "Marginal - botten"
"marginBottom": "Marginal - botten",
"borders": {
"none": "Ingen",
"border": "Ram",
"grid": "Rutnät"
}
},
"qrcode": {
"button": "Skriv ut QR-koder",

View File

@@ -8,7 +8,9 @@ import {
Col,
Form,
Divider,
Switch,
RadioChangeEvent,
Radio,
InputNumber,
} from "antd";
import ReactToPrint from "react-to-print";
import { useSavedState } from "../../utils/saveload";
@@ -73,72 +75,112 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
10
);
const [itemsPerRow, setItemsPerRow] = useSavedState("print-itemsPerRow", 3);
const [rowsPerPage, setRowsPerPage] = useSavedState("print-rowsPerPage", 8);
const [paperSize, setPaperSize] = useSavedState("print-paperSize", "A4");
const [rowHeight, setRowHeight] = useSavedState("print-rowHeight", 70);
const [previewScale, setPreviewScale] = useSavedState(
"print-previewScale",
0.6
);
const [showBorder, setShowBorder] = useSavedState("print-showBorder", true);
const [borderShowMode, setBorderShowMode] = useSavedState<
"none" | "border" | "grid"
>("print-borderShowMode", "grid");
const paperWidth = paperDimensions[paperSize].width;
const paperHeight = paperDimensions[paperSize].height;
const printRef = useRef<HTMLDivElement>(null);
const itemsPerPage =
itemsPerRow *
Math.floor((paperHeight - marginTop - marginBottom) / rowHeight);
const pageBlocks = [];
for (let i = 0; i < items.length; i += 1) {
if (i % itemsPerPage === 0) {
pageBlocks.push(items.slice(i, i + itemsPerPage));
}
const calculatedRowHeight =
(paperHeight - marginTop - marginBottom) / rowsPerPage;
const rowsOfItems = [];
for (let row_idx = 0; row_idx <= items.length / itemsPerRow; row_idx += 1) {
rowsOfItems.push(
items.slice(row_idx * itemsPerRow, (row_idx + 1) * itemsPerRow)
);
}
const rowBlocks = pageBlocks.map((pageBlock, idx) => (
<div
className="print-page"
key={idx}
style={{
width: `${paperWidth}mm`,
height: `${paperHeight}mm`,
paddingTop: `calc(${marginTop}mm - ${showBorder ? "1px" : "0px"})`,
paddingLeft: `calc(${marginLeft}mm - ${showBorder ? "1px" : "0px"})`,
paddingRight: `calc(${marginRight}mm - ${showBorder ? "1px" : "0px"})`,
paddingBottom: `calc(${marginBottom}mm - ${
showBorder ? "1px" : "0px"
})`,
backgroundColor: "#FFF",
}}
>
<Row
const pageBlocks = [];
for (
let page_idx = 0;
page_idx <= rowsOfItems.length / rowsPerPage;
page_idx += 1
) {
pageBlocks.push(
rowsOfItems.slice(page_idx * rowsPerPage, (page_idx + 1) * rowsPerPage)
);
}
const pages = pageBlocks.map(function (rows, idx) {
const itemRows = rows.map((row, idx) => {
return (
<tr key={idx}>
{row.map((item, index) => (
<td>
<div
key={index}
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
width: `${
(paperWidth - marginLeft - marginRight) / itemsPerRow
}mm`,
height: `${calculatedRowHeight}mm`,
flexDirection: "column",
border: borderShowMode === "grid" ? "1px solid #000" : "none",
}}
>
{item}
</div>
</td>
))}
</tr>
);
});
return (
<div
className="print-page"
key={idx}
style={{
border: showBorder ? "1px solid #000" : "none",
width: "100%",
height: "100%",
alignContent: "flex-start",
width: `${paperWidth}mm`,
height: `${paperHeight}mm`,
backgroundColor: "#FFF",
overflow: "hidden",
}}
>
{pageBlock.map((item, index) => (
<div
key={index}
<div
className="print-page-area"
style={{
marginTop: `calc(${marginTop}mm - ${
borderShowMode !== "none" ? "1px" : "0px"
})`,
marginLeft: `calc(${marginLeft}mm - ${
borderShowMode !== "none" ? "1px" : "0px"
})`,
marginRight: `calc(${marginRight}mm - ${
borderShowMode !== "none" ? "1px" : "0px"
})`,
marginBottom: `calc(${marginBottom}mm - ${
borderShowMode !== "none" ? "1px" : "0px"
})`,
}}
>
<table
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
width: `${
(paperWidth - marginLeft - marginRight - 1) / itemsPerRow
}mm`,
height: `${rowHeight}mm`,
flexDirection: "column",
border: borderShowMode !== "none" ? "1px solid #000" : "none",
width: "100%",
height: "100%",
alignContent: "flex-start",
}}
>
{item}
</div>
))}
</Row>
</div>
));
{itemRows}
</table>
</div>
</div>
);
});
return (
<Modal
@@ -154,10 +196,11 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
content={() => printRef.current}
/>,
]}
width={1000} // Set the modal width to accommodate the preview
width={1200} // Set the modal width to accommodate the preview
>
<Row gutter={16}>
<Col span={16}>
<Col span={24}>{t("printing.generic.description")}</Col>
<Col span={14}>
<div
style={{
transform: "translateZ(0)",
@@ -194,73 +237,179 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
margin-top: 10mm;
}
}
.print-page td {
padding: 0;
}
${style ?? ""}
`}
</style>
{rowBlocks}
{pages}
</div>
</div>
</Col>
<Col span={8}>
<Col span={10}>
<Form
labelAlign="left"
colon={false}
labelCol={{ span: 14 }}
wrapperCol={{ span: 10 }}
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
>
<Form.Item label={t("printing.generic.marginLeft")}>
<Slider
min={0}
max={50}
tooltip={{ formatter: (value) => `${value} mm` }}
value={marginLeft}
onChange={(value) => {
setMarginLeft(value);
}}
/>
<Row>
<Col span={12}>
<Slider
min={-20}
max={50}
step={0.1}
tooltip={{ formatter: (value) => `${value} mm` }}
value={marginLeft}
onChange={(value) => {
setMarginLeft(value);
}}
/>
</Col>
<Col span={12}>
<InputNumber
step={0.1}
style={{ margin: "0 16px" }}
value={marginLeft}
addonAfter="mm"
onChange={(value) => {
setMarginLeft(value ?? 0);
}}
/>
</Col>
</Row>
</Form.Item>
<Form.Item label={t("printing.generic.marginTop")}>
<Slider
min={0}
max={50}
tooltip={{ formatter: (value) => `${value} mm` }}
value={marginTop}
onChange={(value) => {
setMarginTop(value);
}}
/>
<Row>
<Col span={12}>
<Slider
min={-20}
max={50}
step={0.1}
tooltip={{ formatter: (value) => `${value} mm` }}
value={marginTop}
onChange={(value) => {
setMarginTop(value);
}}
/>
</Col>
<Col span={12}>
<InputNumber
step={0.1}
style={{ margin: "0 16px" }}
value={marginTop}
addonAfter="mm"
onChange={(value) => {
setMarginTop(value ?? 0);
}}
/>
</Col>
</Row>
</Form.Item>
<Form.Item label={t("printing.generic.marginRight")}>
<Slider
min={0}
max={50}
tooltip={{ formatter: (value) => `${value} mm` }}
value={marginRight}
onChange={(value) => {
setMarginRight(value);
}}
/>
<Row>
<Col span={12}>
<Slider
min={-20}
max={50}
step={0.1}
tooltip={{ formatter: (value) => `${value} mm` }}
value={marginRight}
onChange={(value) => {
setMarginRight(value);
}}
/>
</Col>
<Col span={12}>
<InputNumber
step={0.1}
style={{ margin: "0 16px" }}
value={marginRight}
addonAfter="mm"
onChange={(value) => {
setMarginRight(value ?? 0);
}}
/>
</Col>
</Row>
</Form.Item>
<Form.Item label={t("printing.generic.marginBottom")}>
<Slider
min={0}
max={50}
tooltip={{ formatter: (value) => `${value} mm` }}
value={marginBottom}
onChange={(value) => {
setMarginBottom(value);
}}
/>
<Row>
<Col span={12}>
<Slider
min={-20}
max={50}
step={0.1}
tooltip={{ formatter: (value) => `${value} mm` }}
value={marginBottom}
onChange={(value) => {
setMarginBottom(value);
}}
/>
</Col>
<Col span={12}>
<InputNumber
step={0.1}
style={{ margin: "0 16px" }}
value={marginBottom}
addonAfter="mm"
onChange={(value) => {
setMarginBottom(value ?? 0);
}}
/>
</Col>
</Row>
</Form.Item>
<Form.Item label={t("printing.generic.columns")}>
<Slider
min={1}
max={5}
value={itemsPerRow}
onChange={(value) => {
setItemsPerRow(value);
}}
/>
<Row>
<Col span={12}>
<Slider
min={1}
max={5}
value={itemsPerRow}
onChange={(value) => {
setItemsPerRow(value);
}}
/>
</Col>
<Col span={12}>
<InputNumber
min={1}
style={{ margin: "0 16px" }}
value={itemsPerRow}
onChange={(value) => {
setItemsPerRow(value ?? 1);
}}
/>
</Col>
</Row>
</Form.Item>
<Form.Item label={t("printing.generic.rows")}>
<Row>
<Col span={12}>
<Slider
min={1}
max={15}
value={rowsPerPage}
onChange={(value) => {
setRowsPerPage(value);
}}
/>
</Col>
<Col span={12}>
<InputNumber
min={1}
style={{ margin: "0 16px" }}
value={rowsPerPage}
onChange={(value) => {
setRowsPerPage(value ?? 1);
}}
/>
</Col>
</Row>
</Form.Item>
<Form.Item label={t("printing.generic.paperSize")}>
<Select
@@ -274,36 +423,53 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
))}
</Select>
</Form.Item>
<Form.Item label={t("printing.generic.rowHeight")}>
<Slider
min={30}
max={200}
tooltip={{ formatter: (value) => `${value} mm` }}
value={rowHeight}
onChange={(value) => {
setRowHeight(value);
}}
/>
</Form.Item>
<Form.Item label={t("printing.generic.showBorder")}>
<Switch
checked={showBorder}
onChange={(checked) => setShowBorder(checked)}
<Radio.Group
options={[
{ label: t("printing.generic.borders.none"), value: "none" },
{
label: t("printing.generic.borders.border"),
value: "border",
},
{ label: t("printing.generic.borders.grid"), value: "grid" },
]}
onChange={(e: RadioChangeEvent) => {
setBorderShowMode(e.target.value);
}}
value={borderShowMode}
optionType="button"
buttonStyle="solid"
/>
</Form.Item>
{extraSettings && <Divider />}
{extraSettings}
<Divider />
<Form.Item label={t("printing.generic.previewScale")}>
<Slider
min={0.1}
max={1}
step={0.01}
value={previewScale}
onChange={(value) => {
setPreviewScale(value);
}}
/>
<Row>
<Col span={12}>
<Slider
min={0.1}
max={1}
step={0.01}
value={previewScale}
onChange={(value) => {
setPreviewScale(value);
}}
/>
</Col>
<Col span={12}>
<InputNumber
min={0.1}
max={1}
step={0.01}
style={{ margin: "0 16px" }}
value={previewScale}
onChange={(value) => {
setPreviewScale(value ?? 0.1);
}}
/>
</Col>
</Row>
</Form.Item>
</Form>
</Col>

View File

@@ -1,4 +1,4 @@
import { Form, QRCode, Slider, Switch } from "antd";
import { Col, Form, InputNumber, QRCode, Row, Slider, Switch } from "antd";
import { useSavedState } from "../../utils/saveload";
import PrintingDialog from "./printingDialog";
import { useTranslate } from "@refinedev/core";
@@ -69,17 +69,34 @@ const QRCodePrintingDialog: React.FC<QRCodePrintingDialogProps> = ({
/>
</Form.Item>
<Form.Item label={t("printing.qrcode.textSize")}>
<Slider
disabled={!showContent}
tooltip={{ formatter: (value) => `${value} mm` }}
min={3}
max={15}
value={textSize}
step={0.1}
onChange={(value) => {
setTextSize(value);
}}
/>
<Row>
<Col span={12}>
<Slider
disabled={!showContent}
tooltip={{ formatter: (value) => `${value} mm` }}
min={3}
max={15}
value={textSize}
step={0.1}
onChange={(value) => {
setTextSize(value);
}}
/>
</Col>
<Col span={12}>
<InputNumber
disabled={!showContent}
min={0.01}
step={0.1}
style={{ margin: "0 16px" }}
value={textSize}
addonAfter="mm"
onChange={(value) => {
setTextSize(value ?? 5);
}}
/>
</Col>
</Row>
</Form.Item>
<Form.Item label={t("printing.qrcode.showSpoolmanIcon")}>
<Switch

View File

@@ -41,9 +41,8 @@ const SelectAndPrint: React.FC = () => {
setStep(1);
}}
items={selectedSpools.map((spool) => ({
value: `S:${spool.id}`,
// value: `https://spoolman.lan/spool/show/${spool.id}`,
// label: `hello`,
value: `web+spoolman:s-${spool.id}`,
label: `s-${spool.id}`,
errorLevel: "H",
}))}
/>