Improve scan flow, AI UX, expiry history, and shopping sync.

Manual AI identification replaces auto-fallback; add duplicate-add guard,
AI product match UI, ZBar/Tesseract offline scanning, expiry averages from
last 3 insertions, family sibling hints, and missing i18n keys.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dadaloop82
2026-06-06 09:38:05 +00:00
parent 7eda4a5eb9
commit 34dcb05c05
19 changed files with 3370 additions and 558 deletions
+215 -21
View File
@@ -666,6 +666,118 @@ body.server-offline .bottom-nav {
flex-shrink: 0;
}
/* Family sibling hint (spesa mode) — compact card with thumbnail */
.family-sibling-prompt {
position: fixed;
bottom: 80px;
left: 50%;
transform: translateX(-50%);
z-index: 9998;
background: linear-gradient(145deg, #1e3a5f 0%, #0f2744 100%);
color: #fff;
border-radius: 14px;
padding: 10px 12px;
display: flex;
flex-direction: column;
gap: 8px;
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
max-width: min(440px, calc(100vw - 20px));
width: calc(100% - 20px);
box-sizing: border-box;
border: 1px solid rgba(255, 255, 255, 0.12);
animation: family-sibling-in 0.22s ease-out;
}
@keyframes family-sibling-in {
from { opacity: 0; transform: translateX(-50%) translateY(10px); }
to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
.family-sibling-prompt-body {
display: flex;
gap: 10px;
align-items: flex-start;
}
.family-sibling-prompt-thumb {
flex-shrink: 0;
width: 52px;
height: 52px;
border-radius: 10px;
overflow: hidden;
background: rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
justify-content: center;
}
.family-sibling-prompt-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.family-sibling-prompt-icon {
font-size: 1.6rem;
line-height: 1;
}
.family-sibling-prompt-info {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.family-sibling-prompt-title {
font-size: 0.72rem;
font-weight: 700;
line-height: 1.2;
margin: 0;
text-transform: uppercase;
letter-spacing: 0.03em;
opacity: 0.8;
}
.family-sibling-prompt-name {
font-size: 0.95rem;
font-weight: 700;
line-height: 1.25;
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.family-sibling-prompt-meta {
font-size: 0.8rem;
line-height: 1.3;
margin: 0;
opacity: 0.88;
}
.family-sibling-prompt-question {
font-size: 0.82rem;
line-height: 1.25;
margin: 2px 0 0;
opacity: 0.9;
}
.family-sibling-prompt-actions {
display: flex;
gap: 8px;
}
.family-sibling-prompt-actions button {
flex: 1;
border: none;
border-radius: 10px;
padding: 9px 10px;
font-size: 0.88rem;
font-weight: 700;
cursor: pointer;
min-height: 38px;
}
.family-sibling-prompt-yes {
background: #22c55e;
color: #fff;
}
.family-sibling-prompt-no {
background: #475569;
color: #fff;
}
@keyframes pulse-scan {
0%, 100% { box-shadow: 0 2px 8px rgba(0,0,0,0.2); }
50% { box-shadow: 0 2px 16px rgba(255,255,255,0.4); }
@@ -1845,6 +1957,19 @@ body.server-offline .bottom-nav {
overflow: hidden;
}
/* Spesa mode: hide manual barcode field only — tabs and normal viewport stay */
#page-scan.spesa-scan-layout .barcode-input-row {
display: none !important;
}
.spesa-scan-barcode-hint {
margin: 0;
padding: 6px 4px 2px;
font-size: 0.85rem;
color: var(--text-muted);
text-align: center;
line-height: 1.35;
}
.scanner-viewport video {
width: 100%;
height: 100%;
@@ -2046,21 +2171,25 @@ body.server-offline .bottom-nav {
max-width: 220px;
}
/* — AI retry button (shown below scanner after visual ID fails) — */
.scan-ai-retry-btn {
/* — Manual AI button (user-triggered only) — */
.scan-ai-manual-btn {
width: 100%;
margin-top: 10px;
font-size: 0.95rem;
padding: 12px;
border-radius: var(--radius);
font-size: 1.05rem;
padding: 14px 16px;
border-radius: 14px;
border: 2px solid var(--accent);
background: rgba(124,58,237,0.1);
background: rgba(124,58,237,0.12);
color: var(--accent);
font-weight: 600;
font-weight: 700;
cursor: pointer;
transition: background 0.15s;
transition: background 0.15s, opacity 0.15s;
}
.scan-ai-retry-btn:active { background: rgba(124,58,237,0.22); }
.scan-ai-manual-btn:disabled {
opacity: 0.45;
cursor: not-allowed;
}
.scan-ai-manual-btn:active:not(:disabled) { background: rgba(124,58,237,0.22); }
/* — Viewport overlay controls (torch / zoom / flip) — */
.scan-viewport-controls {
@@ -2115,17 +2244,59 @@ body.server-offline .bottom-nav {
.scan-ai-match-box {
display: flex;
flex-direction: column;
gap: 12px;
gap: 14px;
}
.scan-ai-match-head {
.scan-ai-hero {
display: flex;
flex-direction: column;
gap: 4px;
align-items: center;
gap: 14px;
padding: 14px;
background: linear-gradient(135deg, rgba(124,58,237,0.12), rgba(34,197,94,0.1));
border-radius: 14px;
border: 1px solid var(--border);
}
.scan-ai-hero-icon {
font-size: 2.6rem;
line-height: 1;
flex-shrink: 0;
}
.scan-ai-hero-text {
min-width: 0;
flex: 1;
}
.scan-ai-match-title {
font-size: 1rem;
font-size: 0.82rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--text-muted);
margin-bottom: 4px;
}
.scan-ai-hero-name {
font-size: 1.35rem;
font-weight: 800;
line-height: 1.2;
color: var(--text);
word-break: break-word;
}
.scan-ai-hero-brand {
font-size: 1rem;
color: var(--text-muted);
margin-top: 2px;
}
.scan-ai-action-hint {
margin: -6px 0 0;
font-size: 0.92rem;
line-height: 1.4;
color: var(--text-muted);
text-align: center;
}
.scan-ai-or-divider {
margin: 0;
font-size: 0.88rem;
font-weight: 700;
color: var(--text-muted);
text-align: center;
}
.scan-ai-match-subtitle {
font-size: 0.82rem;
@@ -2137,9 +2308,9 @@ body.server-offline .bottom-nav {
gap: 8px;
}
.scan-ai-match-list-title {
font-size: 0.78rem;
font-size: 0.88rem;
text-transform: uppercase;
letter-spacing: 0.06em;
letter-spacing: 0.04em;
color: var(--text-muted);
font-weight: 700;
}
@@ -2160,6 +2331,22 @@ body.server-offline .bottom-nav {
text-align: left;
}
.scan-ai-candidate-item:active { transform: scale(0.99); }
.scan-ai-candidate-thumb {
width: 44px;
height: 44px;
flex-shrink: 0;
border-radius: 10px;
overflow: hidden;
background: var(--bg-card);
display: flex;
align-items: center;
justify-content: center;
}
.scan-ai-candidate-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.scan-ai-candidate-icon {
font-size: 1.3rem;
flex-shrink: 0;
@@ -2172,26 +2359,27 @@ body.server-offline .bottom-nav {
flex: 1;
}
.scan-ai-candidate-name {
font-size: 0.9rem;
font-weight: 600;
font-size: 1rem;
font-weight: 700;
color: var(--text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.scan-ai-candidate-meta {
font-size: 0.76rem;
font-size: 0.84rem;
color: var(--text-muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.scan-ai-candidate-cta {
font-size: 0.74rem;
font-size: 0.82rem;
font-weight: 700;
color: var(--accent);
border: 1px solid var(--accent);
border-radius: 999px;
padding: 3px 8px;
padding: 6px 10px;
flex-shrink: 0;
}
.scan-ai-match-empty {
@@ -2204,6 +2392,12 @@ body.server-offline .bottom-nav {
}
.scan-ai-add-btn {
width: 100%;
font-size: 1.15rem !important;
font-weight: 800 !important;
padding: 16px 20px !important;
min-height: 54px;
border-radius: 14px !important;
box-shadow: 0 4px 14px rgba(34, 197, 94, 0.35);
}
.scan-ai-detected-label {
font-size: 0.72rem;
+1056 -344
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2
View File
File diff suppressed because one or more lines are too long
+26
View File
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.