filter labels
This commit is contained in:
@ -267,3 +267,52 @@ ul {
|
|||||||
.mt-4 { margin-top: 1rem; }
|
.mt-4 { margin-top: 1rem; }
|
||||||
.mb-4 { margin-bottom: 1rem; }
|
.mb-4 { margin-bottom: 1rem; }
|
||||||
.text-center { text-align: center; }
|
.text-center { text-align: center; }
|
||||||
|
|
||||||
|
/* Print Styles */
|
||||||
|
@media print {
|
||||||
|
/* Remove scroll contexts to allow thead to repeat */
|
||||||
|
.table-container {
|
||||||
|
overflow: visible !important;
|
||||||
|
overflow-x: visible !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead {
|
||||||
|
display: table-header-group;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
page-break-inside: avoid;
|
||||||
|
break-inside: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glass {
|
||||||
|
box-shadow: none !important;
|
||||||
|
border: none !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide UI elements unnecessary for print */
|
||||||
|
.btn, .input-field, .navbar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: white !important;
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table th {
|
||||||
|
color: black !important;
|
||||||
|
border-bottom: 2px solid black !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table td {
|
||||||
|
border-bottom: 1px solid #ccc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-muted {
|
||||||
|
color: #555 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import QRCode from "react-qr-code";
|
import QRCode from "react-qr-code";
|
||||||
import { Printer, AlertCircle } from "lucide-react";
|
import { Printer, AlertCircle, Filter, Search, Tag, CheckCircle2 } from "lucide-react";
|
||||||
|
|
||||||
export default function PrintPage() {
|
export default function PrintPage() {
|
||||||
const [items, setItems] = useState([]);
|
const [items, setItems] = useState([]);
|
||||||
const [selectedIds, setSelectedIds] = useState(new Set());
|
const [selectedIds, setSelectedIds] = useState(new Set());
|
||||||
|
const [selectedCategory, setSelectedCategory] = useState("");
|
||||||
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
@ -27,6 +29,21 @@ export default function PrintPage() {
|
|||||||
fetchItems();
|
fetchItems();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const uniqueCategories = [
|
||||||
|
...new Set(items.map(item => item.category?.trim() || "Uncategorized"))
|
||||||
|
].filter(Boolean).sort();
|
||||||
|
|
||||||
|
const filteredItems = items.filter(item => {
|
||||||
|
const itemCat = item.category?.trim() || "Uncategorized";
|
||||||
|
const matchesCategory = selectedCategory === "" || itemCat === selectedCategory;
|
||||||
|
const matchesSearch = searchQuery === "" ||
|
||||||
|
item.name?.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
|
(item.qrCodeId && item.qrCodeId.toLowerCase().includes(searchQuery.toLowerCase()));
|
||||||
|
return matchesCategory && matchesSearch;
|
||||||
|
});
|
||||||
|
|
||||||
|
const isAllFilteredSelected = filteredItems.length > 0 && filteredItems.every(i => selectedIds.has(i.id));
|
||||||
|
|
||||||
const handlePrint = () => {
|
const handlePrint = () => {
|
||||||
if (selectedIds.size === 0) return alert("Please select at least one label to print.");
|
if (selectedIds.size === 0) return alert("Please select at least one label to print.");
|
||||||
window.print();
|
window.print();
|
||||||
@ -39,12 +56,32 @@ export default function PrintPage() {
|
|||||||
setSelectedIds(next);
|
setSelectedIds(next);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleAll = () => {
|
const toggleFilteredAll = () => {
|
||||||
if (selectedIds.size === items.length) setSelectedIds(new Set());
|
const next = new Set(selectedIds);
|
||||||
else setSelectedIds(new Set(items.map(i => i.id)));
|
if (isAllFilteredSelected) {
|
||||||
|
filteredItems.forEach(i => next.delete(i.id));
|
||||||
|
} else {
|
||||||
|
filteredItems.forEach(i => next.add(i.id));
|
||||||
|
}
|
||||||
|
setSelectedIds(next);
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectOnlyCurrentFiltered = () => {
|
||||||
|
const next = new Set();
|
||||||
|
filteredItems.forEach(i => next.add(i.id));
|
||||||
|
setSelectedIds(next);
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectAll = () => {
|
||||||
|
setSelectedIds(new Set(items.map(i => i.id)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const deselectAll = () => {
|
||||||
|
setSelectedIds(new Set());
|
||||||
};
|
};
|
||||||
|
|
||||||
const itemsToPrint = items.filter(i => selectedIds.has(i.id));
|
const itemsToPrint = items.filter(i => selectedIds.has(i.id));
|
||||||
|
const sheetCount = Math.ceil(itemsToPrint.length / 30);
|
||||||
|
|
||||||
if (loading) return <div className="p-8 text-center">Loading inventory codes...</div>;
|
if (loading) return <div className="p-8 text-center">Loading inventory codes...</div>;
|
||||||
if (error) return <div className="p-8 text-danger">Error: {error}</div>;
|
if (error) return <div className="p-8 text-danger">Error: {error}</div>;
|
||||||
@ -52,8 +89,8 @@ export default function PrintPage() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* On-screen Controls (Hidden in Print) */}
|
{/* On-screen Controls (Hidden in Print) */}
|
||||||
<div className="glass no-print" style={{ padding: "2rem", marginBottom: "2rem" }}>
|
<div className="glass no-print" style={{ padding: "2rem", marginBottom: "1.5rem" }}>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center flex-wrap gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="flex items-center gap-2 mb-2">
|
<h2 className="flex items-center gap-2 mb-2">
|
||||||
<Printer size={24} className="text-primary" />
|
<Printer size={24} className="text-primary" />
|
||||||
@ -63,10 +100,21 @@ export default function PrintPage() {
|
|||||||
Designed for <strong>Avery 5160</strong> standard labels (1" x 2-5/8", 30 per sheet).
|
Designed for <strong>Avery 5160</strong> standard labels (1" x 2-5/8", 30 per sheet).
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<button className="btn btn-primary" onClick={handlePrint}>
|
<div className="flex items-center gap-3">
|
||||||
<Printer size={18} /> Print Now
|
<div className="text-right" style={{ fontSize: "0.9rem" }}>
|
||||||
</button>
|
<div style={{ fontWeight: 600, color: itemsToPrint.length > 0 ? "var(--text-main)" : "var(--danger)" }}>
|
||||||
|
{itemsToPrint.length} of {items.length} selected
|
||||||
|
</div>
|
||||||
|
<div className="text-muted" style={{ fontSize: "0.8rem" }}>
|
||||||
|
{sheetCount} {sheetCount === 1 ? "sheet" : "sheets"} required
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button className="btn btn-primary" onClick={handlePrint} disabled={itemsToPrint.length === 0}>
|
||||||
|
<Printer size={18} /> Print Now
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-start gap-4 mt-4" style={{ backgroundColor: "rgba(59, 130, 246, 0.1)", padding: "1rem", borderRadius: "8px", border: "1px solid var(--primary)" }}>
|
<div className="flex items-start gap-4 mt-4" style={{ backgroundColor: "rgba(59, 130, 246, 0.1)", padding: "1rem", borderRadius: "8px", border: "1px solid var(--primary)" }}>
|
||||||
<AlertCircle size={24} className="text-primary flex-shrink-0" />
|
<AlertCircle size={24} className="text-primary flex-shrink-0" />
|
||||||
<div style={{ fontSize: "0.9rem" }}>
|
<div style={{ fontSize: "0.9rem" }}>
|
||||||
@ -81,73 +129,245 @@ export default function PrintPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Filter and Category Selection Toolbar (Hidden in Print) */}
|
||||||
|
<div className="glass no-print mb-6" style={{ padding: "1.5rem" }}>
|
||||||
|
<div className="flex justify-between items-center flex-wrap gap-4 mb-4">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Filter size={18} className="text-primary" />
|
||||||
|
<h3 style={{ fontSize: "1.1rem", margin: 0 }}>Filter & Select Labels</h3>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
|
{selectedCategory && (
|
||||||
|
<button
|
||||||
|
className="btn btn-secondary"
|
||||||
|
style={{ padding: "0.4rem 0.8rem", fontSize: "0.85rem", borderColor: "var(--primary)" }}
|
||||||
|
onClick={selectOnlyCurrentFiltered}
|
||||||
|
title={`Select only items in "${selectedCategory}"`}
|
||||||
|
>
|
||||||
|
<CheckCircle2 size={15} className="text-primary" />
|
||||||
|
Select Only "{selectedCategory}" ({filteredItems.length})
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
className="btn btn-secondary"
|
||||||
|
style={{ padding: "0.4rem 0.8rem", fontSize: "0.85rem" }}
|
||||||
|
onClick={selectAll}
|
||||||
|
>
|
||||||
|
Select All ({items.length})
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn-secondary"
|
||||||
|
style={{ padding: "0.4rem 0.8rem", fontSize: "0.85rem" }}
|
||||||
|
onClick={deselectAll}
|
||||||
|
>
|
||||||
|
Deselect All
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Filter Inputs */}
|
||||||
|
<div className="flex gap-4 flex-wrap" style={{ alignItems: "center" }}>
|
||||||
|
<div style={{ position: "relative", flex: 1, minWidth: "220px" }}>
|
||||||
|
<Search size={16} className="text-muted" style={{ position: "absolute", left: "12px", top: "50%", transform: "translateY(-50%)" }} />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Search by name or QR..."
|
||||||
|
className="input-field"
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
style={{ width: "100%", paddingLeft: "36px" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ display: "flex", alignItems: "center", gap: "0.5rem", minWidth: "220px" }}>
|
||||||
|
<Tag size={16} className="text-muted flex-shrink-0" />
|
||||||
|
<select
|
||||||
|
className="input-field"
|
||||||
|
value={selectedCategory}
|
||||||
|
onChange={(e) => setSelectedCategory(e.target.value)}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
>
|
||||||
|
<option value="">All Categories ({items.length})</option>
|
||||||
|
{uniqueCategories.map(cat => {
|
||||||
|
const count = items.filter(i => (i.category?.trim() || "Uncategorized") === cat).length;
|
||||||
|
return (
|
||||||
|
<option key={cat} value={cat}>
|
||||||
|
{cat} ({count})
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Quick Category Badges */}
|
||||||
|
{uniqueCategories.length > 1 && (
|
||||||
|
<div className="flex gap-2 mt-3 flex-wrap" style={{ alignItems: "center" }}>
|
||||||
|
<span className="text-muted" style={{ fontSize: "0.8rem", marginRight: "4px" }}>Quick Category Filter:</span>
|
||||||
|
<button
|
||||||
|
onClick={() => setSelectedCategory("")}
|
||||||
|
className="btn btn-secondary"
|
||||||
|
style={{
|
||||||
|
padding: "0.2rem 0.6rem",
|
||||||
|
fontSize: "0.78rem",
|
||||||
|
borderRadius: "20px",
|
||||||
|
background: selectedCategory === "" ? "var(--primary)" : "rgba(255, 255, 255, 0.05)",
|
||||||
|
color: selectedCategory === "" ? "white" : "var(--text-muted)",
|
||||||
|
border: "1px solid " + (selectedCategory === "" ? "var(--primary)" : "var(--border)")
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
All ({items.length})
|
||||||
|
</button>
|
||||||
|
{uniqueCategories.map(cat => {
|
||||||
|
const count = items.filter(i => (i.category?.trim() || "Uncategorized") === cat).length;
|
||||||
|
const isSelected = selectedCategory === cat;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={cat}
|
||||||
|
onClick={() => setSelectedCategory(isSelected ? "" : cat)}
|
||||||
|
className="btn btn-secondary"
|
||||||
|
style={{
|
||||||
|
padding: "0.2rem 0.6rem",
|
||||||
|
fontSize: "0.78rem",
|
||||||
|
borderRadius: "20px",
|
||||||
|
background: isSelected ? "var(--primary)" : "rgba(255, 255, 255, 0.05)",
|
||||||
|
color: isSelected ? "white" : "var(--text-muted)",
|
||||||
|
border: "1px solid " + (isSelected ? "var(--primary)" : "var(--border)")
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{cat} ({count})
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Item Selection Table (Hidden in Print) */}
|
{/* Item Selection Table (Hidden in Print) */}
|
||||||
<div className="glass no-print mb-6">
|
<div className="glass no-print mb-6">
|
||||||
<div className="flex justify-between items-center mb-4" style={{ padding: "0 1rem" }}>
|
<div className="flex justify-between items-center mb-3" style={{ padding: "1rem 1rem 0" }}>
|
||||||
<h3 className="text-muted">Select Labels to Print ({selectedIds.size} selected)</h3>
|
<div className="flex items-center gap-2">
|
||||||
<button className="btn btn-secondary" style={{ padding: "0.25rem 0.75rem", fontSize: "0.85rem" }} onClick={toggleAll}>
|
<span className="text-muted" style={{ fontSize: "0.9rem" }}>
|
||||||
{selectedIds.size === items.length ? "Deselect All" : "Select All"}
|
Showing {filteredItems.length} of {items.length} items
|
||||||
|
{selectedCategory && ` in "${selectedCategory}"`}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
className="btn btn-secondary"
|
||||||
|
style={{ padding: "0.25rem 0.75rem", fontSize: "0.85rem" }}
|
||||||
|
onClick={toggleFilteredAll}
|
||||||
|
>
|
||||||
|
{isAllFilteredSelected ? "Deselect Visible" : "Select Visible"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="table-container" style={{ maxHeight: "300px", overflowY: "auto" }}>
|
|
||||||
|
<div className="table-container" style={{ maxHeight: "380px", overflowY: "auto" }}>
|
||||||
<table className="data-table">
|
<table className="data-table">
|
||||||
<thead style={{ position: "sticky", top: 0, zIndex: 1, backgroundColor: "var(--bg-card)" }}>
|
<thead style={{ position: "sticky", top: 0, zIndex: 1, backgroundColor: "var(--bg-card)" }}>
|
||||||
<tr>
|
<tr>
|
||||||
<th style={{ width: "50px", textAlign: "center" }}>
|
<th style={{ width: "50px", textAlign: "center" }}>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={selectedIds.size === items.length && items.length > 0}
|
checked={isAllFilteredSelected}
|
||||||
onChange={toggleAll}
|
onChange={toggleFilteredAll}
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>QR ID</th>
|
<th>QR ID</th>
|
||||||
<th>Category</th>
|
<th>Category</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th>Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{items.map(item => (
|
{filteredItems.length === 0 ? (
|
||||||
<tr key={item.id} style={{ cursor: "pointer", opacity: selectedIds.has(item.id) ? 1 : 0.6 }} onClick={() => toggleSelection(item.id)}>
|
<tr>
|
||||||
<td style={{ textAlign: "center" }}>
|
<td colSpan="6" style={{ textAlign: "center", padding: "2rem", color: "var(--text-muted)" }}>
|
||||||
<input
|
No items found matching the selected filters.
|
||||||
type="checkbox"
|
|
||||||
checked={selectedIds.has(item.id)}
|
|
||||||
onChange={() => {}} /* Handled by row click */
|
|
||||||
/>
|
|
||||||
</td>
|
</td>
|
||||||
<td style={{ fontWeight: 500 }}>{item.name}</td>
|
|
||||||
<td><code className="text-muted">{item.qrCodeId}</code></td>
|
|
||||||
<td>{item.category || "-"}</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
) : (
|
||||||
|
filteredItems.map(item => {
|
||||||
|
const isSelected = selectedIds.has(item.id);
|
||||||
|
return (
|
||||||
|
<tr
|
||||||
|
key={item.id}
|
||||||
|
style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
backgroundColor: isSelected ? "rgba(59, 130, 246, 0.08)" : "transparent",
|
||||||
|
opacity: isSelected ? 1 : 0.6
|
||||||
|
}}
|
||||||
|
onClick={() => toggleSelection(item.id)}
|
||||||
|
>
|
||||||
|
<td style={{ textAlign: "center" }} onClick={(e) => e.stopPropagation()}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={isSelected}
|
||||||
|
onChange={() => toggleSelection(item.id)}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td style={{ fontWeight: 500 }}>{item.name}</td>
|
||||||
|
<td><code className="text-muted" style={{ background: "rgba(255,255,255,0.05)", padding: "2px 6px", borderRadius: "4px" }}>{item.qrCodeId}</code></td>
|
||||||
|
<td>
|
||||||
|
<span style={{
|
||||||
|
padding: "2px 8px",
|
||||||
|
borderRadius: "12px",
|
||||||
|
fontSize: "0.8rem",
|
||||||
|
background: "rgba(255, 255, 255, 0.07)",
|
||||||
|
border: "1px solid var(--border)"
|
||||||
|
}}>
|
||||||
|
{item.category || "Uncategorized"}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td className="text-muted">{item.location || "-"}</td>
|
||||||
|
<td>
|
||||||
|
{isSelected ? (
|
||||||
|
<span className="text-success" style={{ fontSize: "0.8rem", fontWeight: 500 }}>
|
||||||
|
To Print
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-muted" style={{ fontSize: "0.8rem" }}>
|
||||||
|
Excluded
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Printable Sheet Area */}
|
{/* Printable Sheet Area */}
|
||||||
{/* Printable Sheet Area */}
|
{itemsToPrint.length === 0 ? (
|
||||||
{Array.from({ length: Math.ceil(itemsToPrint.length / 30) }, (_, pageIndex) => (
|
<div className="glass text-center p-8 no-print" style={{ padding: "3rem", color: "var(--text-muted)" }}>
|
||||||
<div key={pageIndex} className="print-container">
|
<p>No labels selected to print. Select items above to generate printable sheets.</p>
|
||||||
{itemsToPrint.slice(pageIndex * 30, (pageIndex + 1) * 30).map((item) => (
|
|
||||||
<div key={item.id} className="label-cell">
|
|
||||||
<div className="qr-wrapper">
|
|
||||||
<QRCode
|
|
||||||
value={item.qrCodeId || item.id}
|
|
||||||
size={64}
|
|
||||||
level="H"
|
|
||||||
style={{ height: "auto", maxWidth: "100%", width: "100%" }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="label-text">
|
|
||||||
<div className="item-name">{item.name}</div>
|
|
||||||
<div className="item-sku">{item.qrCodeId}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
) : (
|
||||||
|
Array.from({ length: Math.ceil(itemsToPrint.length / 30) }, (_, pageIndex) => (
|
||||||
|
<div key={pageIndex} className="print-container">
|
||||||
|
{itemsToPrint.slice(pageIndex * 30, (pageIndex + 1) * 30).map((item) => (
|
||||||
|
<div key={item.id} className="label-cell">
|
||||||
|
<div className="qr-wrapper">
|
||||||
|
<QRCode
|
||||||
|
value={item.qrCodeId || item.id}
|
||||||
|
size={64}
|
||||||
|
level="H"
|
||||||
|
style={{ height: "auto", maxWidth: "100%", width: "100%" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="label-text">
|
||||||
|
<div className="item-name">{item.name}</div>
|
||||||
|
<div className="item-sku">{item.qrCodeId}</div>
|
||||||
|
{item.category && <div className="item-category">{item.category}</div>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
|
||||||
<style>{`
|
<style>{`
|
||||||
/* Standard View Adjustments */
|
/* Standard View Adjustments */
|
||||||
@ -160,6 +380,7 @@ export default function PrintPage() {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
min-height: 50vh;
|
min-height: 50vh;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-cell {
|
.label-cell {
|
||||||
@ -203,6 +424,15 @@ export default function PrintPage() {
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-category {
|
||||||
|
font-size: 0.5rem;
|
||||||
|
color: #777;
|
||||||
|
margin-top: 0.05rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
@page {
|
@page {
|
||||||
size: letter;
|
size: letter;
|
||||||
@ -232,7 +462,8 @@ export default function PrintPage() {
|
|||||||
background: white;
|
background: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
break-after:page;
|
break-after: page;
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.print-container {
|
.print-container {
|
||||||
|
|||||||
Reference in New Issue
Block a user