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:
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
}))}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user