diff --git a/assets/css/style.css b/assets/css/style.css
index 7f846f5..a8c2084 100644
--- a/assets/css/style.css
+++ b/assets/css/style.css
@@ -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;
diff --git a/assets/js/app.js b/assets/js/app.js
index 8b89ec2..6aadb59 100644
--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -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 ? `
${escapeHtml(item.brand)}
` : ''}
- ${qtyDisplay}
+ ${parts.mainQty} ${parts.unitLabel}
+ ${parts.packageDetail ? `${parts.packageDetail}` : ''}
${expiryLabel ? `${expiryLabel}` : ''}
`;
@@ -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) {
- ${qtyDisplay}
- ${pkgFrac ? `${pkgFrac}` : ''}
+ ${parts.mainQty}
+ ${parts.unitLabel}${parts.packageDetail ? ` ${parts.packageDetail}` : ''}
+ ${parts.fraction ? `${parts.fraction}` : ''}
`;
}
diff --git a/index.html b/index.html
index 46e7d27..e9b398f 100644
--- a/index.html
+++ b/index.html
@@ -9,7 +9,7 @@
🏠 Dispensa Manager
-
+
@@ -750,6 +750,6 @@
-
+