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

@@ -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",
}))}
/>