ui: riorganizza quantità in lista inventario
- Numero grande e visibile (es. '10') - Sotto: unità + dettaglio confezione (es. 'conf da 36g') - Sotto: proporzione rimasta in piccolo (es. '¼') - Stesso layout per dashboard compact items - Frazione esclusa per unit=conf (dove default_quantity è il peso) - Cache-busting v=20260311c
This commit is contained in:
+48
-13
@@ -1700,7 +1700,7 @@ body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
gap: 1px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -1711,6 +1711,19 @@ body {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.inv-qty-value small {
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.inv-qty-pkg-detail {
|
||||
font-size: 0.65rem;
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.inv-expiry-small {
|
||||
font-size: 0.7rem;
|
||||
color: var(--text-muted);
|
||||
@@ -2598,27 +2611,49 @@ body {
|
||||
background: #ea580c;
|
||||
}
|
||||
|
||||
/* ===== LARGER QUANTITY IN INVENTORY ===== */
|
||||
/* ===== STRUCTURED QUANTITY IN INVENTORY ===== */
|
||||
.inv-qty-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
min-width: 56px;
|
||||
background: #ecfdf5;
|
||||
border-radius: 14px;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.inv-qty-prominent {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 800;
|
||||
.inv-qty-number {
|
||||
font-size: 1.55rem;
|
||||
font-weight: 900;
|
||||
color: var(--primary);
|
||||
white-space: nowrap;
|
||||
background: #d1fae5;
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
flex-shrink: 0;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Package fraction indicators */
|
||||
.inv-qty-unit {
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
color: #4b5563;
|
||||
white-space: nowrap;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.inv-qty-pkg {
|
||||
font-weight: 500;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.inv-qty-frac {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
color: #9ca3af;
|
||||
line-height: 1;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
/* Package fraction indicators (used elsewhere) */
|
||||
.pkg-fraction {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
|
||||
+40
-6
@@ -763,7 +763,7 @@ function renderDashItem(item) {
|
||||
const days = daysUntilExpiry(item.expiry_date);
|
||||
const isExpired = days < 0;
|
||||
const isExpiring = !isExpired && days <= 7;
|
||||
const qtyDisplay = formatQuantity(item.quantity, item.unit, item.default_quantity, item.package_unit);
|
||||
const parts = formatQuantityParts(item.quantity, item.unit, item.default_quantity, item.package_unit);
|
||||
|
||||
let expiryLabel = '';
|
||||
if (item.expiry_date) {
|
||||
@@ -784,7 +784,8 @@ function renderDashItem(item) {
|
||||
${item.brand ? `<div class="inv-brand">${escapeHtml(item.brand)}</div>` : ''}
|
||||
</div>
|
||||
<div class="inv-qty-right">
|
||||
<span class="inv-qty-value">${qtyDisplay}</span>
|
||||
<span class="inv-qty-value">${parts.mainQty} <small>${parts.unitLabel}</small></span>
|
||||
${parts.packageDetail ? `<span class="inv-qty-pkg-detail">${parts.packageDetail}</span>` : ''}
|
||||
${expiryLabel ? `<span class="inv-expiry-small ${isExpired ? 'expired' : isExpiring ? 'expiring' : ''}">${expiryLabel}</span>` : ''}
|
||||
</div>
|
||||
</div>`;
|
||||
@@ -823,6 +824,39 @@ function formatQuantity(qty, unit, defaultQty, packageUnit) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Structured quantity display for inventory cards.
|
||||
// Returns { mainQty: '10', unitLabel: 'conf', packageDetail: 'da 36g', fraction: '¼' }
|
||||
function formatQuantityParts(qty, unit, defaultQty, packageUnit) {
|
||||
const n = parseFloat(qty) || 0;
|
||||
const unitLabels = { 'pz': 'pz', 'kg': 'kg', 'g': 'g', 'l': 'L', 'ml': 'ml', 'conf': 'conf' };
|
||||
const label = unitLabels[unit] || unit || 'pz';
|
||||
let mainQty;
|
||||
if (n === Math.floor(n)) mainQty = `${Math.floor(n)}`;
|
||||
else if (unit === 'pz' || unit === 'conf') mainQty = `${Math.round(n)}`;
|
||||
else mainQty = `${n.toFixed(1)}`;
|
||||
|
||||
let packageDetail = '';
|
||||
if (unit === 'conf' && packageUnit && defaultQty > 0) {
|
||||
const pkgLabel = unitLabels[packageUnit] || packageUnit;
|
||||
packageDetail = `da ${defaultQty}${pkgLabel}`;
|
||||
}
|
||||
|
||||
let fraction = '';
|
||||
// For conf, defaultQty is the package SIZE (e.g. 300g), not a count; fraction doesn't apply
|
||||
if (unit !== 'conf' && defaultQty && defaultQty > 1) {
|
||||
const d = parseFloat(defaultQty);
|
||||
const ratio = n / d;
|
||||
const remainder = ratio - Math.floor(ratio);
|
||||
if (remainder >= 0.1 && remainder <= 0.9) {
|
||||
if (remainder < 0.38) fraction = '¼';
|
||||
else if (remainder < 0.62) fraction = '½';
|
||||
else fraction = '¾';
|
||||
}
|
||||
}
|
||||
|
||||
return { mainQty, unitLabel: label, packageDetail, fraction };
|
||||
}
|
||||
|
||||
// Show package fraction: only ¼, ½, ¾ when there's a partial package.
|
||||
// Returns '' if quantity maps to whole packages or fraction is not meaningful.
|
||||
function formatPackageFraction(qty, defaultQty) {
|
||||
@@ -862,8 +896,7 @@ function renderInventoryItem(item) {
|
||||
const days = daysUntilExpiry(item.expiry_date);
|
||||
const isExpired = days < 0;
|
||||
const isExpiring = !isExpired && days <= 7;
|
||||
const qtyDisplay = formatQuantity(item.quantity, item.unit, item.default_quantity, item.package_unit);
|
||||
const pkgFrac = formatPackageFraction(item.quantity, item.default_quantity);
|
||||
const parts = formatQuantityParts(item.quantity, item.unit, item.default_quantity, item.package_unit);
|
||||
|
||||
let expiryBadge = '';
|
||||
if (item.expiry_date) {
|
||||
@@ -890,8 +923,9 @@ function renderInventoryItem(item) {
|
||||
</div>
|
||||
</div>
|
||||
<div class="inv-qty-col">
|
||||
<span class="inv-qty-prominent">${qtyDisplay}</span>
|
||||
${pkgFrac ? `<span class="inv-pkg-frac">${pkgFrac}</span>` : ''}
|
||||
<span class="inv-qty-number">${parts.mainQty}</span>
|
||||
<span class="inv-qty-unit">${parts.unitLabel}${parts.packageDetail ? ` <span class="inv-qty-pkg">${parts.packageDetail}</span>` : ''}</span>
|
||||
${parts.fraction ? `<span class="inv-qty-frac">${parts.fraction}</span>` : ''}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@
|
||||
<title>🏠 Dispensa Manager</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🏠</text></svg>">
|
||||
<link rel="stylesheet" href="assets/css/style.css?v=20260311b">
|
||||
<link rel="stylesheet" href="assets/css/style.css?v=20260311c">
|
||||
<!-- QuaggaJS for barcode scanning -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.8.4/dist/quagga.min.js"></script>
|
||||
</head>
|
||||
@@ -750,6 +750,6 @@
|
||||
<div class="modal-content" id="modal-content" onclick="event.stopPropagation()"></div>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/app.js?v=20260311b"></script>
|
||||
<script src="assets/js/app.js?v=20260311c"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user