| <script type="text/javascript"> |
| var gk_isXlsx = false; |
| var gk_xlsxFileLookup = {}; |
| var gk_fileData = {}; |
| function filledCell(cell) { |
| return cell !== '' && cell != null; |
| } |
| function loadFileData(filename) { |
| if (gk_isXlsx && gk_xlsxFileLookup[filename]) { |
| try { |
| var workbook = XLSX.read(gk_fileData[filename], { type: 'base64' }); |
| var firstSheetName = workbook.SheetNames[0]; |
| var worksheet = workbook.Sheets[firstSheetName]; |
| |
| |
| var jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1, blankrows: false, defval: '' }); |
| |
| var filteredData = jsonData.filter(row => row.some(filledCell)); |
| |
| |
| var headerRowIndex = filteredData.findIndex((row, index) => |
| row.filter(filledCell).length >= filteredData[index + 1]?.filter(filledCell).length |
| ); |
| |
| if (headerRowIndex === -1 || headerRowIndex > 25) { |
| headerRowIndex = 0; |
| } |
| |
| |
| var csv = XLSX.utils.aoa_to_sheet(filteredData.slice(headerRowIndex)); |
| csv = XLSX.utils.sheet_to_csv(csv, { header: 1 }); |
| return csv; |
| } catch (e) { |
| console.error(e); |
| return ""; |
| } |
| } |
| return gk_fileData[filename] || ""; |
| } |
| </script> |
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>SnapCal AI - Real-time Food Analysis</title> |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> |
| <script src="https://unpkg.com/feather-icons"></script> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:wght@400;700&family=Noto+Sans+Devanagari:wght@400;700&family=Noto+Sans+Hebrew:wght@400;700&family=Noto+Sans+JP:wght@400;700&family=Noto+Sans+KR:wght@400;700&family=Noto+Sans+SC:wght@400;700&family=Noto+Sans+Thai:wght@400;700&family=Noto+Serif:wght@400;700&display=swap'); |
| |
| @media screen and (max-width: 767px) { |
| |
| .neu { |
| border-radius: 12px; |
| box-shadow: 5px 5px 10px #171717, -5px -5px 10px #252525; |
| } |
| body.light .neu { |
| box-shadow: 5px 5px 10px #D9D9D9, -5px -5px 10px #FFFFFF; |
| } |
| .neu-inset { |
| border-radius: 12px; |
| box-shadow: inset 5px 5px 10px #171717, inset -5px -5px 10px #252525; |
| } |
| body.light .neu-inset { |
| box-shadow: inset 5px 5px 10px #D9D9D9, inset -5px -5px 10px #FFFFFF; |
| } |
| } |
| |
| body { |
| font-family: 'Noto Sans', 'Noto Sans Arabic', 'Noto Sans Devanagari', 'Noto Sans Hebrew', 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans SC', 'Noto Sans Thai', sans-serif; |
| background: #1E1E1E; |
| color: #E0E0E0; |
| margin: 0; |
| padding: 0; |
| overflow-x: hidden; |
| transition: background 0.3s ease-in-out, color 0.3s ease-in-out; |
| text-align: center; |
| } |
| |
| body.light { |
| background: #F0F0F0; |
| color: #333; |
| } |
| .neu { |
| background: #1E1E1E; |
| border-radius: 20px; |
| box-shadow: 10px 10px 20px #171717, -10px -10px 20px #252525; |
| transition: all 0.3s ease-in-out; |
| } |
| |
| @media screen and (max-width: 767px) { |
| .neu { |
| border-radius: 12px; |
| } |
| } |
| body.light .neu { |
| background: #F0F0F0; |
| box-shadow: 10px 10px 20px #D9D9D9, -10px -10px 20px #FFFFFF; |
| } |
| .neu-inset { |
| background: #1E1E1E; |
| border-radius: 20px; |
| box-shadow: inset 10px 10px 20px #171717, inset -10px -10px 20px #252525; |
| } |
| |
| @media screen and (max-width: 767px) { |
| .neu-inset { |
| border-radius: 12px; |
| } |
| } |
| body.light .neu-inset { |
| background: #F0F0F0; |
| box-shadow: inset 10px 10px 20px #D9D9D9, inset -10px -10px 20px #FFFFFF; |
| } |
| |
| .neu-button { |
| background: #1E1E1E; |
| border: none; |
| border-radius: 50px; |
| padding: 12px 24px; |
| color: #E0E0E0; |
| font-weight: bold; |
| box-shadow: 5px 5px 10px #171717, -5px -5px 10px #252525; |
| transition: all 0.3s ease-in-out; |
| } |
| |
| .neu-button:hover { |
| box-shadow: inset 5px 5px 10px #171717, inset -5px -5px 10px #252525; |
| } |
| |
| body.light .neu-button { |
| background: #F0F0F0; |
| color: #333; |
| box-shadow: 5px 5px 10px #D9D9D9, -5px -5px 10px #FFFFFF; |
| } |
| |
| body.light .neu-button:hover { |
| box-shadow: inset 5px 5px 10px #D9D9D9, inset -5px -5px 10px #FFFFFF; |
| } |
| |
| .accent { |
| background: linear-gradient(45deg, #FF5722, #FF9800); |
| color: #FFF; |
| } |
| |
| body.light .accent { |
| background: linear-gradient(45deg, #00E676, #4CAF50); |
| } |
| |
| .camera-feed { |
| background: #000; |
| border: none; |
| position: relative; |
| overflow: hidden; |
| border-radius: 20px; |
| } |
| |
| .scan-line { |
| position: absolute; |
| width: 100%; |
| height: 3px; |
| background: linear-gradient(90deg, transparent, #FF5722, transparent); |
| box-shadow: 0 0 10px #FF5722; |
| animation: scan 2s linear infinite; |
| z-index: 10; |
| } |
| |
| body.light .scan-line { |
| background: linear-gradient(90deg, transparent, #00E676, transparent); |
| box-shadow: 0 0 10px #00E676; |
| } |
| |
| @keyframes scan { |
| 0% { |
| top: 0; |
| } |
| |
| 100% { |
| top: 100%; |
| } |
| } |
| |
| .detection-item { |
| background: #1E1E1E; |
| border-radius: 12px; |
| padding: 8px; |
| z-index: 20; |
| text-align: center; |
| box-shadow: 5px 5px 10px #171717, -5px -5px 10px #252525; |
| } |
| |
| body.light .detection-item { |
| background: #F0F0F0; |
| box-shadow: 5px 5px 10px #D9D9D9, -5px -5px 10px #FFFFFF; |
| } |
| |
| .calorie-badge { |
| background: linear-gradient(45deg, #FF5722, #FF9800); |
| color: #FFF; |
| padding: 2px 8px; |
| border-radius: 12px; |
| font-size: 12px; |
| } |
| |
| body.light .calorie-badge { |
| background: linear-gradient(45deg, #00E676, #4CAF50); |
| } |
| |
| .progress-bar { |
| height: 4px; |
| background: #252525; |
| border-radius: 2px; |
| overflow: hidden; |
| } |
| |
| body.light .progress-bar { |
| background: #E0E0E0; |
| } |
| |
| .progress-fill { |
| height: 100%; |
| background: linear-gradient(90deg, #FF5722, #FF9800); |
| width: 0%; |
| transition: width 0.3s ease-in-out; |
| } |
| |
| body.light .progress-fill { |
| background: linear-gradient(90deg, #00E676, #4CAF50); |
| } |
| |
| .component-highlight { |
| animation: pulse 1.5s infinite ease-in-out; |
| border: 2px solid #FF5722; |
| } |
| |
| body.light .component-highlight { |
| border: 2px solid #00E676; |
| } |
| |
| @keyframes pulse { |
| 0% { |
| opacity: 0.6; |
| } |
| |
| 50% { |
| opacity: 1; |
| } |
| |
| 100% { |
| opacity: 0.6; |
| } |
| } |
| |
| .processing-overlay { |
| background: rgba(30, 30, 30, 0.9); |
| z-index: 30; |
| transition: opacity 0.5s ease-in-out; |
| } |
| |
| body.light .processing-overlay { |
| background: rgba(240, 240, 240, 0.9); |
| } |
| |
| .nav-button { |
| transition: all 0.6s ease-in-out; |
| position: relative; |
| } |
| |
| .fade-in { |
| opacity: 0; |
| transform: translateY(20px); |
| transition: opacity 0.8s ease-in-out, transform 0.8s ease-in-out; |
| } |
| |
| .fade-in.visible { |
| opacity: 1; |
| transform: translateY(0); |
| } |
| |
| #cameraContainer { |
| transition: height 0.5s ease-in-out; |
| } |
| |
| #analysisResults, #navButtons, #footer, #header { |
| transition: opacity 0.5s ease-in-out; |
| } |
| |
| .nav-menu { |
| display: none; |
| position: absolute; |
| bottom: 100%; |
| left: 50%; |
| transform: translateX(-50%); |
| background: #1E1E1E; |
| border-radius: 12px; |
| padding: 8px; |
| min-width: 150px; |
| z-index: 40; |
| text-align: center; |
| box-shadow: 5px 5px 10px #171717, -5px -5px 10px #252525; |
| } |
| |
| body.light .nav-menu { |
| background: #F0F0F0; |
| box-shadow: 5px 5px 10px #D9D9D9, -5px -5px 10px #FFFFFF; |
| } |
| |
| .nav-button:hover .nav-menu { |
| display: block; |
| } |
| |
| .nav-menu li { |
| padding: 4px 8px; |
| cursor: pointer; |
| transition: box-shadow 0.3s ease-in-out; |
| text-align: center; |
| border-radius: 8px; |
| } |
| |
| .nav-menu li:hover { |
| box-shadow: inset 2px 2px 5px #171717, inset -2px -2px 5px #252525; |
| } |
| |
| body.light .nav-menu li:hover { |
| box-shadow: inset 2px 2px 5px #D9D9D9, inset -2px -2px 5px #FFFFFF; |
| } |
| |
| .modal { |
| display: none; |
| position: fixed; |
| z-index: 50; |
| left: 0; |
| top: 0; |
| width: 100%; |
| height: 100%; |
| overflow: auto; |
| background-color: rgba(0,0,0,0.4); |
| animation: fadeIn 0.3s ease-in-out; |
| transition: opacity 0.3s ease-in-out; |
| } |
| |
| .modal.closing { |
| opacity: 0; |
| } |
| |
| @keyframes fadeIn { |
| from { |
| opacity: 0; |
| } |
| |
| to { |
| opacity: 1; |
| } |
| } |
| |
| .modal-content { |
| background: #1E1E1E; |
| margin: 15% auto; |
| padding: 20px; |
| width: 80%; |
| max-width: 600px; |
| border-radius: 20px; |
| text-align: center; |
| animation: slideDown 0.3s ease-in-out; |
| transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out; |
| box-shadow: 10px 10px 20px #171717, -10px -10px 20px #252525; |
| } |
| |
| .modal-content.closing { |
| transform: translateY(20px); |
| opacity: 0; |
| } |
| |
| @keyframes slideDown { |
| from { |
| transform: translateY(-20px); |
| opacity: 0; |
| } |
| |
| to { |
| transform: translateY(0); |
| opacity: 1; |
| } |
| } |
| |
| body.light .modal-content { |
| background: #F0F0F0; |
| box-shadow: 10px 10px 20px #D9D9D9, -10px -10px 20px #FFFFFF; |
| } |
| |
| .close { |
| color: #aaa; |
| float: right; |
| font-size: 28px; |
| font-weight: bold; |
| transition: color 0.3s ease-in-out; |
| } |
| |
| .close:hover, |
| .close:focus { |
| color: #FF5722; |
| text-decoration: none; |
| cursor: pointer; |
| } |
| |
| .theme-toggle { |
| cursor: pointer; |
| transition: transform 0.3s ease-in-out; |
| } |
| |
| .theme-toggle:hover { |
| transform: scale(1.1); |
| } |
| |
| .border-black { |
| border-color: #000; |
| } |
| |
| body.light .border-black { |
| border-color: #333; |
| } |
| |
| .bg-white { |
| background: #1E1E1E; |
| } |
| |
| body.light .bg-white { |
| background: #F0F0F0; |
| } |
| |
| .text-gray-600 { |
| color: #A0A0A0; |
| } |
| |
| body.light .text-gray-600 { |
| color: #666; |
| } |
| |
| .text-gray-500 { |
| color: #808080; |
| } |
| |
| body.light .text-gray-500 { |
| color: #999; |
| } |
| |
| .hover\:bg-gray-100:hover { |
| background: #252525; |
| } |
| |
| body.light .hover\:bg-gray-100:hover { |
| background: #E0E0E0; |
| } |
| |
| .bg-black { |
| background: #252525; |
| } |
| |
| body.light .bg-black { |
| background: #E0E0E0; |
| } |
| |
| .text-white { |
| color: #E0E0E0; |
| } |
| |
| body.light .text-white { |
| color: #333; |
| } |
| |
| .text-black { |
| color: #E0E0E0; |
| } |
| |
| body.light .text-black { |
| color: #333; |
| } |
| |
| .upgrade-progress { |
| height: 10px; |
| background: #252525; |
| border-radius: 5px; |
| overflow: hidden; |
| margin-top: 10px; |
| } |
| |
| .upgrade-progress-fill { |
| height: 100%; |
| background: linear-gradient(90deg, #FF5722, #FF9800); |
| width: 0%; |
| transition: width 1s ease-in-out; |
| } |
| |
| body.light .upgrade-progress-fill { |
| background: linear-gradient(90deg, #00E676, #4CAF50); |
| } |
| |
| .btn-primary { |
| background: #1E1E1E; |
| color: #E0E0E0; |
| padding: 10px 20px; |
| border-radius: 50px; |
| cursor: pointer; |
| transition: all 0.3s ease-in-out; |
| box-shadow: 5px 5px 10px #171717, -5px -5px 10px #252525; |
| } |
| |
| .btn-primary:hover { |
| box-shadow: inset 5px 5px 10px #171717, inset -5px -5px 10px #252525; |
| } |
| |
| body.light .btn-primary { |
| background: #F0F0F0; |
| color: #333; |
| box-shadow: 5px 5px 10px #D9D9D9, -5px -5px 10px #FFFFFF; |
| } |
| |
| body.light .btn-primary:hover { |
| box-shadow: inset 5px 5px 10px #D9D9D9, inset -5px -5px 10px #FFFFFF; |
| } |
| |
| .success-message { |
| color: #FF9800; |
| margin-top: 10px; |
| animation: fadeInMessage 0.5s ease-in-out; |
| } |
| |
| @keyframes fadeInMessage { |
| from { |
| opacity: 0; |
| transform: translateY(10px); |
| } |
| |
| to { |
| opacity: 1; |
| transform: translateY(0); |
| } |
| } |
| |
| |
| select { |
| appearance: none; |
| background-image: url('data:image/svg+xml;utf8,<svg fill="%23E0E0E0" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'); |
| background-repeat: no-repeat; |
| background-position-x: calc(100% - 8px); |
| background-position-y: center; |
| padding-right: 2rem !important; |
| cursor: pointer; |
| transition: all 0.3s ease-in-out; |
| } |
| |
| body.light select { |
| background-image: url('data:image/svg+xml;utf8,<svg fill="%23333" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'); |
| } |
| |
| select:focus { |
| outline: none; |
| box-shadow: 0 0 0 2px rgba(255, 87, 34, 0.5); |
| } |
| |
| body.light select:focus { |
| box-shadow: 0 0 0 2px rgba(0, 230, 118, 0.5); |
| } |
| |
| select option { |
| background-color: #1E1E1E; |
| color: #E0E0E0; |
| padding: 0.5rem; |
| } |
| |
| body.light select option { |
| background-color: #F0F0F0; |
| color: #333; |
| } |
| |
| |
| body.rtl { |
| direction: rtl; |
| text-align: right; |
| } |
| |
| body.rtl .flex { |
| flex-direction: row-reverse; |
| } |
| |
| body.rtl .space-x-2 > :not([hidden]) ~ :not([hidden]) { |
| --tw-space-x-reverse: 1; |
| } |
| |
| body.rtl .space-x-4 > :not([hidden]) ~ :not([hidden]) { |
| --tw-space-x-reverse: 1; |
| } |
| |
| body.rtl .justify-between { |
| flex-direction: row-reverse; |
| } |
| |
| body.rtl .text-right { |
| text-align: left; |
| } |
| |
| body.rtl .text-left { |
| text-align: right; |
| } |
| |
| body.rtl .float-right { |
| float: left; |
| } |
| |
| body.rtl .nav-menu { |
| text-align: right; |
| } |
| |
| body.rtl select { |
| background-position-x: 8px; |
| padding-left: 2rem; |
| padding-right: 1rem; |
| } |
| |
| body.rtl .absolute.right-2 { |
| right: auto; |
| left: 2rem; |
| } |
| </style> |
| </head> |
| <body class="min-h-screen"> |
| |
| <header id="header" class="p-4 flex justify-between items-center neu hidden" style="opacity: 0;"> |
| <div class="flex items-center space-x-2"> |
| <i data-feather="camera" class="text-white"></i> |
| <h1 class="text-xl font-bold text-white">SnapCal AI</h1> |
| </div> |
| <div class="flex space-x-4 items-center"> |
| <div class="relative flex items-center"> |
| <select id="languageSelect" class="p-2 pr-8 rounded neu-inset text-white"> |
| <option value="en">🇺🇸 English</option> |
| <option value="fa">🇮🇷 فارسی</option> |
| <option value="fr">🇫🇷 Français</option> |
| <option value="it">🇮🇹 Italiano</option> |
| <option value="de">🇩🇪 Deutsch</option> |
| </select> |
| <i data-feather="globe" class="absolute right-2 top-1/2 transform -translate-y-1/2 text-white pointer-events-none"></i> |
| </div> |
| <div id="themeToggle" class="p-2 rounded-full neu flex items-center justify-center theme-toggle"> |
| <i data-feather="sun" class="text-white" id="themeIcon"></i> |
| </div> |
| <button class="p-2 rounded-full neu"> |
| <i data-feather="user" class="text-white"></i> |
| </button> |
| </div> |
| </header> |
| <main class="container mx-auto px-4 py-8"> |
| <div class="neu rounded-2xl overflow-hidden"> |
| |
| <div id="cameraContainer" class="relative w-full h-screen camera-feed flex items-center justify-center"> |
| |
| <video id="videoFeed" class="absolute inset-0 w-full h-full object-cover" autoplay playsinline></video> |
| |
| <div id="cameraPlaceholder" class="absolute inset-0 flex items-center justify-center z-5"> |
| <div class="text-center"> |
| <i data-feather="camera" class="w-16 h-16 mx-auto mb-4 text-white"></i> |
| <p class="text-lg text-white" data-lang-en="Live Camera Feed" data-lang-fa="فید دوربین زنده" data-lang-fr="Flux de caméra en direct" data-lang-it="Feed della telecamera dal vivo" data-lang-de="Live-Kamera-Feed">Live Camera Feed</p> |
| <p class="text-sm text-gray-300" data-lang-en="Point at your food to begin analysis" data-lang-fa="دوربین را به سمت غذای خود بگیرید تا تحلیل آغاز شود" data-lang-fr="Pointez la caméra vers votre nourriture pour commencer l'analyse" data-lang-it="Punta la fotocamera verso il cibo per iniziare l'analisi" data-lang-de="Richten Sie die Kamera auf Ihr Essen, um die Analyse zu starten">Point at your food to begin analysis</p> |
| </div> |
| </div> |
| |
| <div class="scan-line"></div> |
| |
| <div id="processingOverlay" class="processing-overlay absolute inset-0 hidden flex-col items-center justify-center"> |
| <div class="text-center mb-4 md:mb-6 z-20"> |
| <div class="w-12 h-12 md:w-16 md:h-16 border-4 border-white border-t-transparent rounded-full animate-spin mx-auto mb-2 md:mb-4"></div> |
| <h3 class="text-xl font-bold" data-lang-en="Analyzing Food..." data-lang-fa="در حال تحلیل غذا..." data-lang-fr="Analyse de la nourriture..." data-lang-it="Analisi del cibo in corso..." data-lang-de="Lebensmittel werden analysiert...">Analyzing Food...</h3> |
| <p class="text-gray-600" data-lang-en="Processing image to detect components" data-lang-fa="پردازش تصویر برای تشخیص اجزا" data-lang-fr="Traitement de l'image pour détecter les composants" data-lang-it="Elaborazione dell'immagine per rilevare i componenti" data-lang-de="Verarbeitung des Bildes zur Erkennung der Bestandteile">Processing image to detect components</p> |
| </div> |
| <div class="w-48 md:w-64 progress-bar"> |
| <div id="progressFill" class="progress-fill"></div> |
| </div> |
| </div> |
| |
| <div id="detectionResults" class="absolute inset-0 hidden flex items-center justify-center"> |
| <div class="text-center z-20"> |
| <div class="absolute top-1/3 left-1/4 w-16 h-16 md:w-24 md:h-24 border-2 border-white rounded-lg component-highlight"></div> |
| <div class="absolute bottom-1/3 right-1/3 w-14 h-14 md:w-20 md:h-20 border-2 border-white rounded-lg component-highlight"></div> |
| <div class="absolute top-1/3 left-1/4 transform -translate-x-1/2 -translate-y-1/2"> |
| <div class="detection-item flex items-center space-x-2 neu-inset"> |
| <span class="font-semibold" data-lang-en="Pancake" data-lang-fa="پنکیک" data-lang-fr="Crêpe" data-lang-it="Pancake" data-lang-de="Pfannkuchen">Pancake</span> |
| <span class="calorie-badge">220 cal</span> |
| </div> |
| </div> |
| <div class="absolute bottom-1/3 right-1/3 transform translate-x-1/2 translate-y-1/2"> |
| <div class="detection-item flex items-center space-x-2 neu-inset"> |
| <span class="font-semibold" data-lang-en="Maple Syrup" data-lang-fa="شربت افرا" data-lang-fr="Sirop d'érable" data-lang-it="Sciroppo d'acero" data-lang-de="Ahornsirup">Maple Syrup</span> |
| <span class="calorie-badge">52 cal</span> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="analysisResults" class="p-6 hidden" style="opacity: 0;"> |
| <div class="flex justify-between items-center mb-4 md:mb-6"> |
| <h2 class="text-xl md:text-2xl font-bold" data-lang-en="Food Analysis" data-lang-fa="تحلیل غذا" data-lang-fr="Analyse alimentaire" data-lang-it="Analisi del cibo" data-lang-de="Lebensmittelanalyse">Food Analysis</h2> |
| <div class="flex items-center space-x-2"> |
| <span class="px-3 py-1 rounded-full text-sm font-medium neu-inset">Live</span> |
| <span class="text-sm text-gray-500" data-lang-en="Updated just now" data-lang-fa="بهروزرسانی شده همین حالا" data-lang-fr="Mis à jour à l'instant" data-lang-it="Aggiornato proprio ora" data-lang-de="Gerade jetzt aktualisiert">Updated just now</span> |
| </div> |
| </div> |
|
|
| |
| <div class="neu rounded-2xl p-4 md:p-6 mb-4 md:mb-6"> |
| <div class="flex justify-between items-center"> |
| <div> |
| <p class="text-lg text-gray-600" data-lang-en="Total Calories" data-lang-fa="کالری کل" data-lang-fr="Calories totales" data-lang-it="Calorie totali" data-lang-de="Gesamtkalorien">Total Calories</p> |
| <p class="text-3xl md:text-4xl font-bold">272 kcal</p> |
| </div> |
| <div class="text-right"> |
| <p class="text-lg text-gray-600" data-lang-en="Components" data-lang-fa="اجزا" data-lang-fr="Composants" data-lang-it="Componenti" data-lang-de="Komponenten">Components</p> |
| <p class="text-3xl md:text-4xl font-bold">2</p> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="space-y-4"> |
| <h3 class="text-lg font-semibold" data-lang-en="Detected Components" data-lang-fa="اجزای تشخیص داده شده" data-lang-fr="Composants détectés" data-lang-it="Componenti rilevati" data-lang-de="Erkannte Komponenten">Detected Components</h3> |
|
|
| <div class="flex items-center justify-between p-4 rounded-xl neu"> |
| <div class="flex items-center space-x-4"> |
| <div class="w-10 h-10 md:w-12 md:h-12 rounded-lg flex items-center justify-center neu-inset"> |
| <i data-feather="circle" class="text-white"></i> |
| </div> |
| <div> |
| <h4 class="font-medium" data-lang-en="Pancake" data-lang-fa="پنکیک" data-lang-fr="Crêpe" data-lang-it="Pancake" data-lang-de="Pfannkuchen">Pancake</h4> |
| <p class="text-sm text-gray-600" data-lang-en="Flour, egg, milk, butter" data-lang-fa="آرد، تخممرغ، شیر، کره" data-lang-fr="Farine, œuf, lait, beurre" data-lang-it="Farina, uovo, latte, burro" data-lang-de="Mehl, Ei, Milch, Butter">Flour, egg, milk, butter</p> |
| </div> |
| </div> |
| <div class="text-right"> |
| <p class="font-semibold">220 kcal</p> |
| <p class="text-sm text-gray-600" data-lang-en="1 serving" data-lang-fa="1 وعده" data-lang-fr="1 portion" data-lang-it="1 porzione" data-lang-de="1 Portion">1 serving</p> |
| </div> |
| </div> |
|
|
| <div class="flex items-center justify-between p-4 rounded-xl neu"> |
| <div class="flex items-center space-x-4"> |
| <div class="w-12 h-12 rounded-lg flex items-center justify-center neu-inset"> |
| <i data-feather="droplet" class="text-white"></i> |
| </div> |
| <div> |
| <h4 class="font-medium" data-lang-en="Maple Syrup" data-lang-fa="شربت افرا" data-lang-fr="Sirop d'érable" data-lang-it="Sciroppo d'acero" data-lang-de="Ahornsirup">Maple Syrup</h4> |
| <p class="text-sm text-gray-600" data-lang-en="Natural sweetener" data-lang-fa="شیرینکننده طبیعی" data-lang-fr="Édulcorant naturel" data-lang-it="Edulcorante naturale" data-lang-de="Natürlicher Süßstoff">Natural sweetener</p> |
| </div> |
| </div> |
| <div class="text-right"> |
| <p class="font-semibold">52 kcal</p> |
| <p class="text-sm text-gray-600" data-lang-en="1 tbsp" data-lang-fa="1 قاشق غذاخوری" data-lang-fr="1 cuillère à soupe" data-lang-it="1 cucchiaio" data-lang-de="1 Esslöffel">1 tbsp</p> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="mt-8 flex flex-col sm:flex-row space-y-4 sm:space-y-0 sm:space-x-4"> |
| <button id="saveMealButton" class="flex-1 neu-button accent flex items-center justify-center space-x-2"> |
| <i data-feather="save"></i> |
| <span data-lang-en="Save Meal" data-lang-fa="ذخیره وعده غذایی" data-lang-fr="Enregistrer le repas" data-lang-it="Salva pasto" data-lang-de="Mahlzeit speichern">Save Meal</span> |
| </button> |
| <button id="rescanButton" class="flex-1 neu-button flex items-center justify-center space-x-2"> |
| <i data-feather="refresh-ccw"></i> |
| <span data-lang-en="Rescan" data-lang-fa="اسکن مجدد" data-lang-fr="Rescanner" data-lang-it="Riscansiona" data-lang-de="Erneut scannen">Rescan</span> |
| </button> |
| </div> |
| </div> |
| </div> |
| </main> |
|
|
| |
| <div id="navButtons" class="fixed bottom-0 left-0 right-0 p-2 md:p-4 hidden neu" style="opacity: 0;"> |
| <div class="flex justify-around items-center"> |
| <button class="nav-button flex flex-col items-center space-y-1 fade-in neu-button"> |
| <i data-feather="home" class="w-5 h-5 md:w-6 md:h-6"></i> |
| <span class="text-xs" data-lang-en="Home" data-lang-fa="خانه" data-lang-fr="Accueil" data-lang-it="Home" data-lang-de="Startseite">Home</span> |
| </button> |
| <div class="nav-button flex flex-col items-center space-y-1 fade-in relative neu-button"> |
| <i data-feather="book" class="w-6 h-6"></i> |
| <span class="text-xs" data-lang-en="Dishes" data-lang-fa="غذاها" data-lang-fr="Plats" data-lang-it="Piatti" data-lang-de="Gerichte">Dishes</span> |
| <ul class="nav-menu"> |
| <li data-lang-en="Soup" data-lang-fa="سوپ" data-lang-fr="Soupe" data-lang-it="Zuppa" data-lang-de="Suppe">Soup</li> |
| <li data-lang-en="Sandwich" data-lang-fa="ساندویچ" data-lang-fr="Sandwich" data-lang-it="Panino" data-lang-de="Sandwich">Sandwich</li> |
| <li data-lang-en="Khoresht" data-lang-fa="خورش" data-lang-fr="Khoresht" data-lang-it="Khoresht" data-lang-de="Khoresht">Khoresht</li> |
| <li data-lang-en="Polo" data-lang-fa="پلو" data-lang-fr="Polo" data-lang-it="Polo" data-lang-de="Polo">Polo</li> |
| <li data-lang-en="Salad" data-lang-fa="سالاد" data-lang-fr="Salade" data-lang-it="Insalata" data-lang-de="Salat">Salad</li> |
| <li data-lang-en="Dessert" data-lang-fa="دسر" data-lang-fr="Dessert" data-lang-it="Dessert" data-lang-de="Dessert">Dessert</li> |
| </ul> |
| </div> |
| <div class="nav-button flex flex-col items-center space-y-1 fade-in relative neu-button"> |
| <i data-feather="user" class="w-6 h-6"></i> |
| <span class="text-xs" data-lang-en="Account" data-lang-fa="حساب کاربری" data-lang-fr="Compte" data-lang-it="Account" data-lang-de="Konto">Account</span> |
| <ul class="nav-menu"> |
| <li onclick="openModal('profileModal')" data-lang-en="Profile" data-lang-fa="پروفایل" data-lang-fr="Profil" data-lang-it="Profilo" data-lang-de="Profil">Profile</li> |
| <li onclick="openModal('premiumModal')" data-lang-en="Upgrade to Premium" data-lang-fa="ارتقا به پرمیوم" data-lang-fr="Passer à Premium" data-lang-it="Passa a Premium" data-lang-de="Auf Premium upgraden">Upgrade to Premium</li> |
| <li onclick="openModal('historyModal')" data-lang-en="Meal History" data-lang-fa="تاریخچه وعدهها" data-lang-fr="Historique des repas" data-lang-it="Cronologia pasti" data-lang-de="Mahlzeitenverlauf">Meal History</li> |
| <li onclick="openModal('accountSettingsModal')" data-lang-en="Settings" data-lang-fa="تنظیمات" data-lang-fr="Paramètres" data-lang-it="Impostazioni" data-lang-de="Einstellungen">Settings</li> |
| <li onclick="confirmLogout()" data-lang-en="Logout" data-lang-fa="خروج" data-lang-fr="Déconnexion" data-lang-it="Disconnessione" data-lang-de="Abmelden">Logout</li> |
| </ul> |
| </div> |
| <div class="nav-button flex flex-col items-center space-y-1 fade-in relative neu-button"> |
| <i data-feather="settings" class="w-6 h-6"></i> |
| <span class="text-xs" data-lang-en="Settings" data-lang-fa="تنظیمات" data-lang-fr="Paramètres" data-lang-it="Impostazioni" data-lang-de="Einstellungen">Settings</span> |
| <ul class="nav-menu"> |
| <li onclick="openModal('languageModal')" data-lang-en="Language" data-lang-fa="زبان" data-lang-fr="Langue" data-lang-it="Lingua" data-lang-de="Sprache">Language</li> |
| <li onclick="openModal('notificationsModal')" data-lang-en="Notifications" data-lang-fa="اعلانها" data-lang-fr="Notifications" data-lang-it="Notifiche" data-lang-de="Benachrichtigungen">Notifications</li> |
| <li onclick="openModal('privacyModal')" data-lang-en="Privacy" data-lang-fa="حریم خصوصی" data-lang-fr="Confidentialité" data-lang-it="Privacy" data-lang-de="Datenschutz">Privacy</li> |
| <li onclick="openModal('supportModal')" data-lang-en="Help & Support" data-lang-fa="کمک و پشتیبانی" data-lang-fr="Aide & Support" data-lang-it="Aiuto & Supporto" data-lang-de="Hilfe & Support">Help & Support</li> |
| <li onclick="openModal('aboutModal')" data-lang-en="About" data-lang-fa="درباره ما" data-lang-fr="À propos" data-lang-it="Informazioni" data-lang-de="Über">About</li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| |
| <footer id="footer" class="py-8 text-center text-gray-600 hidden neu" style="opacity: 0;"> |
| <p data-lang-en="© 2023 SnapCal AI by Team Nora. All rights reserved." data-lang-fa="© ۲۰۲۳ SnapCal AI توسط تیم نورا. همه حقوق محفوظ است." data-lang-fr="© 2023 SnapCal AI par Team Nora. Tous droits réservés." data-lang-it="© 2023 SnapCal AI da Team Nora. Tutti i diritti riservati." data-lang-de="© 2023 SnapCal AI von Team Nora. Alle Rechte vorbehalten.">© 2023 SnapCal AI by Team Nora. All rights reserved.</p> |
| <p data-lang-en="Trademark of Team Nora. Rights reserved." data-lang-fa="علامت تجاری تیم نورا. حقوق محفوظ." data-lang-fr="Marque de Team Nora. Droits réservés." data-lang-it="Marchio di Team Nora. Diritti riservati." data-lang-de="Marke von Team Nora. Rechte vorbehalten.">Trademark of Team Nora. Rights reserved.</p> |
| </footer> |
|
|
| |
| <div id="aboutModal" class="modal"> |
| <div class="modal-content neu" style="width: 90%; margin: 10% auto;"> |
| <span class="close" onclick="closeModal('aboutModal')">×</span> |
| <h2 data-lang-en="About Us" data-lang-fa="درباره ما" data-lang-fr="À propos de nous" data-lang-it="Chi siamo" data-lang-de="Über uns">About Us</h2> |
| <p data-lang-en="SnapCal AI is developed by Team Nora, a group of passionate developers focused on making healthy eating easier through AI technology." data-lang-fa="SnapCal AI توسط تیم نورا توسعه یافته است، گروهی از توسعهدهندگان مشتاق که بر روی آسان کردن خوردن سالم از طریق فناوری هوش مصنوعی تمرکز دارند." data-lang-fr="SnapCal AI est développé par Team Nora, un groupe de développeurs passionnés axés sur la simplification de l'alimentation saine grâce à la technologie IA." data-lang-it="SnapCal AI è sviluppato da Team Nora, un gruppo di sviluppatori appassionati focalizzati sul rendere più facile una dieta sana tramite la tecnologia AI." data-lang-de="SnapCal AI wird von Team Nora entwickelt, einer Gruppe leidenschaftlicher Entwickler, die sich darauf konzentrieren, gesundes Essen durch KI-Technologie zu erleichtern.">SnapCal AI is developed by Team Nora, a group of passionate developers focused on making healthy eating easier through AI technology.</p> |
| </div> |
| </div> |
|
|
| <div id="supportModal" class="modal"> |
| <div class="modal-content neu"> |
| <span class="close" onclick="closeModal('supportModal')">×</span> |
| <h2 data-lang-en="Help & Support" data-lang-fa="کمک و پشتیبانی" data-lang-fr="Aide & Support" data-lang-it="Aiuto & Supporto" data-lang-de="Hilfe & Support">Help & Support</h2> |
| <p data-lang-en="Contact us at support@teamnora.com or call +1-123-456-7890 for assistance." data-lang-fa="با ما تماس بگیرید در support@teamnora.com یا شماره +۱-۱۲۳-۴۵۶-۷۸۹۰ برای کمک." data-lang-fr="Contactez-nous à support@teamnora.com ou appelez le +1-123-456-7890 pour de l'aide." data-lang-it="Contattaci a support@teamnora.com o chiama il +1-123-456-7890 per assistenza." data-lang-de="Kontaktiere uns unter support@teamnora.com oder ruf +1-123-456-7890 an für Hilfe.">Contact us at support@teamnora.com or call +1-123-456-7890 for assistance.</p> |
| <button class="neu-button mt-4" onclick="sendSupportEmail()">Send Email</button> |
| <p id="supportStatus" class="success-message hidden">Email sent successfully!</p> |
| </div> |
| </div> |
|
|
| <div id="privacyModal" class="modal"> |
| <div class="modal-content neu"> |
| <span class="close" onclick="closeModal('privacyModal')">×</span> |
| <h2 data-lang-en="Privacy Policy" data-lang-fa="سیاست حریم خصوصی" data-lang-fr="Politique de confidentialité" data-lang-it="Politica sulla privacy" data-lang-de="Datenschutzrichtlinie">Privacy Policy</h2> |
| <p data-lang-en="We value your privacy. Your data is secure and not shared without consent. For more details, read our full policy." data-lang-fa="ما به حریم خصوصی شما اهمیت میدهیم. دادههای شما امن است و بدون رضایت به اشتراک گذاشته نمیشود. برای جزئیات بیشتر، سیاست کامل ما را بخوانید." data-lang-fr="Nous valorisons votre vie privée. Vos données sont sécurisées et ne sont pas partagées sans consentement. Pour plus de détails, lisez notre politique complète." data-lang-it="Valorizziamo la tua privacy. I tuoi dati sono sicuri e non vengono condivisi senza consenso. Per maggiori dettagli, leggi la nostra politica completa." data-lang-de="Wir schätzen Ihre Privatsphäre. Ihre Daten sind sicher und werden ohne Zustimmung nicht geteilt. Lesen Sie unsere vollständige Richtlinie für weitere Details.">We value your privacy. Your data is secure and not shared without consent. For more details, read our full policy.</p> |
| </div> |
| </div> |
|
|
| <div id="notificationsModal" class="modal"> |
| <div class="modal-content neu"> |
| <span class="close" onclick="closeModal('notificationsModal')">×</span> |
| <h2 data-lang-en="Notifications Settings" data-lang-fa="تنظیمات اعلانها" data-lang-fr="Paramètres des notifications" data-lang-it="Impostazioni notifiche" data-lang-de="Benachrichtigungseinstellungen">Notifications Settings</h2> |
| <label> |
| <input type="checkbox" id="silentMode" onchange="updateNotificationSettings()"> |
| <span data-lang-en="Silent Mode" data-lang-fa="حالت سایلنت" data-lang-fr="Mode silencieux" data-lang-it="Modalità silenziosa" data-lang-de="Stiller Modus">Silent Mode</span> |
| </label> |
| <br> |
| <label> |
| <input type="checkbox" id="dailyReminders" onchange="updateNotificationSettings()"> |
| <span data-lang-en="Daily Reminders" data-lang-fa="یادآوری روزانه" data-lang-fr="Rappels quotidiens" data-lang-it="Promemoria giornalieri" data-lang-de="Tägliche Erinnerungen">Daily Reminders</span> |
| </label> |
| <p id="notificationStatus" class="text-gray-600 mt-2 success-message"></p> |
| </div> |
| </div> |
|
|
| <div id="profileModal" class="modal"> |
| <div class="modal-content neu"> |
| <span class="close" onclick="closeModal('profileModal')">×</span> |
| <h2 data-lang-en="Profile" data-lang-fa="پروفایل" data-lang-fr="Profil" data-lang-it="Profilo" data-lang-de="Profil">Profile</h2> |
| <form id="profileForm" onsubmit="saveProfile(event)"> |
| <label data-lang-en="Name:" data-lang-fa="نام:" data-lang-fr="Nom:" data-lang-it="Nome:" data-lang-de="Name:">Name:</label> |
| <input type="text" id="profileName" class="p-2 mt-2 rounded neu-inset bg-transparent text-white w-full" placeholder="Enter your name"> |
| <br><br> |
| <label data-lang-en="Email:" data-lang-fa="ایمیل:" data-lang-fr="Email:" data-lang-it="Email:" data-lang-de="E-Mail:">Email:</label> |
| <input type="email" id="profileEmail" class="p-2 mt-2 rounded neu-inset bg-transparent text-white w-full" placeholder="Enter your email"> |
| <br><br> |
| <button type="submit" class="neu-button mt-4">Save</button> |
| </form> |
| <p id="profileStatus" class="success-message hidden">Profile saved successfully!</p> |
| </div> |
| </div> |
|
|
| <div id="premiumModal" class="modal"> |
| <div class="modal-content neu"> |
| <span class="close" onclick="closeModal('premiumModal')">×</span> |
| <h2 data-lang-en="Upgrade to Premium" data-lang-fa="ارتقا به پرمیوم" data-lang-fr="Passer à Premium" data-lang-it="Passa a Premium" data-lang-de="Auf Premium upgraden">Upgrade to Premium</h2> |
| <p data-lang-en="Get unlimited scans and more features." data-lang-fa="اسکنهای نامحدود و ویژگیهای بیشتر دریافت کنید." data-lang-fr="Obtenez des scans illimités et plus de fonctionnalités." data-lang-it="Ottieni scansioni illimitate e più funzionalità." data-lang-de="Erhalte unbegrenzte Scans und mehr Funktionen.">Get unlimited scans and more features.</p> |
| <button onclick="upgradeToPremium()" class="neu-button accent mt-4">Upgrade</button> |
| <div id="upgradeProgress" class="upgrade-progress mt-2 hidden"> |
| <div id="upgradeProgressFill" class="upgrade-progress-fill"></div> |
| </div> |
| <p id="upgradeStatus" class="success-message mt-2"></p> |
| </div> |
| </div> |
|
|
| <div id="historyModal" class="modal"> |
| <div class="modal-content neu"> |
| <span class="close" onclick="closeModal('historyModal')">×</span> |
| <h2 data-lang-en="Meal History" data-lang-fa="تاریخچه وعدهها" data-lang-fr="Historique des repas" data-lang-it="Cronologia pasti" data-lang-de="Mahlzeitenverlauf">Meal History</h2> |
| <ul id="mealHistoryList" class="text-left mt-4 space-y-2"> |
| <li class="p-2 neu-inset">2023-10-01: Salad (150 kcal)</li> |
| <li class="p-2 neu-inset">2023-10-02: Sandwich (300 kcal)</li> |
| </ul> |
| <button onclick="clearHistory()" class="neu-button mt-4">Clear History</button> |
| <p id="historyStatus" class="success-message hidden">History cleared!</p> |
| </div> |
| </div> |
|
|
| <div id="accountSettingsModal" class="modal"> |
| <div class="modal-content neu"> |
| <span class="close" onclick="closeModal('accountSettingsModal')">×</span> |
| <h2 data-lang-en="Account Settings" data-lang-fa="تنظیمات حساب" data-lang-fr="Paramètres du compte" data-lang-it="Impostazioni account" data-lang-de="Kontoeinstellungen">Account Settings</h2> |
| <p data-lang-en="Manage your account settings." data-lang-fa="مدیریت تنظیمات حساب شما." data-lang-fr="Gérez les paramètres de votre compte." data-lang-it="Gestisci le impostazioni del tuo account." data-lang-de="Verwalten Sie Ihre Kontoeinstellungen.">Manage your account settings.</p> |
| <button onclick="deleteAccount()" class="neu-button mt-4 accent bg-red-500">Delete Account</button> |
| <p id="accountStatus" class="success-message hidden">Account deleted!</p> |
| </div> |
| </div> |
|
|
| <div id="languageModal" class="modal"> |
| <div class="modal-content neu"> |
| <span class="close" onclick="closeModal('languageModal')">×</span> |
| <h2 data-lang-en="Language Settings" data-lang-fa="تنظیمات زبان" data-lang-fr="Paramètres de langue" data-lang-it="Impostazioni lingua" data-lang-de="Spracheinstellungen">Language Settings</h2> |
| <select id="modalLanguageSelect" class="p-2 rounded neu-inset bg-transparent text-white"> |
| <option value="en">🇺🇸 English</option> |
| <option value="fa">🇮🇷 فارسی</option> |
| <option value="fr">🇫🇷 Français</option> |
| <option value="it">🇮🇹 Italiano</option> |
| <option value="de">🇩🇪 Deutsch</option> |
| </select> |
| <button onclick="changeLanguage(document.getElementById('modalLanguageSelect').value)" class="neu-button mt-4">Apply</button> |
| <p id="languageStatus" class="success-message hidden">Language changed!</p> |
| </div> |
| </div> |
|
|
| <script> |
| feather.replace(); |
| |
| |
| async function initCamera() { |
| const video = document.getElementById('videoFeed'); |
| const placeholder = document.getElementById('cameraPlaceholder'); |
| if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { |
| try { |
| const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } }); |
| video.srcObject = stream; |
| video.play(); |
| placeholder.style.display = 'none'; |
| } catch (error) { |
| console.error('Error accessing camera:', error); |
| |
| try { |
| const stream = await navigator.mediaDevices.getUserMedia({ video: true }); |
| video.srcObject = stream; |
| video.play(); |
| placeholder.style.display = 'none'; |
| } catch (fallbackError) { |
| console.error('Fallback error:', fallbackError); |
| |
| alert('Unable to access camera. Please check permissions.'); |
| } |
| } |
| } else { |
| alert('getUserMedia is not supported in this browser.'); |
| } |
| } |
| |
| |
| const themeToggle = document.getElementById('themeToggle'); |
| const themeIcon = document.getElementById('themeIcon'); |
| themeToggle.addEventListener('click', () => { |
| document.body.classList.toggle('light'); |
| if (document.body.classList.contains('light')) { |
| themeIcon.setAttribute('data-feather', 'moon'); |
| } else { |
| themeIcon.setAttribute('data-feather', 'sun'); |
| } |
| feather.replace(); |
| }); |
| |
| |
| function changeLanguage(lang) { |
| document.querySelectorAll('[data-lang-en]').forEach(el => { |
| el.textContent = el.getAttribute(`data-lang-${lang}`); |
| }); |
| if (lang === 'fa') { |
| document.body.classList.add('rtl'); |
| document.documentElement.dir = 'rtl'; |
| } else { |
| document.body.classList.remove('rtl'); |
| document.documentElement.dir = 'ltr'; |
| } |
| } |
| |
| const languageSelect = document.getElementById('languageSelect'); |
| languageSelect.addEventListener('change', () => { |
| changeLanguage(languageSelect.value); |
| }); |
| |
| |
| function openModal(modalId) { |
| const modal = document.getElementById(modalId); |
| modal.style.display = 'block'; |
| modal.focus(); |
| } |
| |
| function closeModal(modalId) { |
| const modal = document.getElementById(modalId); |
| const modalContent = modal.querySelector('.modal-content'); |
| modal.classList.add('closing'); |
| modalContent.classList.add('closing'); |
| setTimeout(() => { |
| modal.style.display = 'none'; |
| modal.classList.remove('closing'); |
| modalContent.classList.remove('closing'); |
| }, 300); |
| } |
| |
| |
| window.onclick = function (event) { |
| if (event.target.classList.contains('modal')) { |
| closeModal(event.target.id); |
| } |
| } |
| |
| |
| document.addEventListener('keydown', (e) => { |
| if (e.key === 'Escape') { |
| document.querySelectorAll('.modal').forEach(modal => { |
| if (modal.style.display === 'block') { |
| closeModal(modal.id); |
| } |
| }); |
| } |
| }); |
| |
| |
| function confirmLogout() { |
| if (confirm("Are you sure you want to logout?")) { |
| alert("Logged out successfully!"); |
| |
| } |
| } |
| |
| function updateNotificationSettings() { |
| const status = document.getElementById('notificationStatus'); |
| status.textContent = "Settings updated!"; |
| status.classList.remove('hidden'); |
| setTimeout(() => { |
| status.classList.add('hidden'); |
| }, 2000); |
| } |
| |
| function saveProfile(event) { |
| event.preventDefault(); |
| const status = document.getElementById('profileStatus'); |
| status.classList.remove('hidden'); |
| setTimeout(() => { |
| status.classList.add('hidden'); |
| }, 2000); |
| |
| } |
| |
| function upgradeToPremium() { |
| const progress = document.getElementById('upgradeProgress'); |
| const fill = document.getElementById('upgradeProgressFill'); |
| const status = document.getElementById('upgradeStatus'); |
| progress.classList.remove('hidden'); |
| fill.style.width = '100%'; |
| setTimeout(() => { |
| status.textContent = "Upgrade complete!"; |
| progress.classList.add('hidden'); |
| fill.style.width = '0%'; |
| }, 1000); |
| } |
| |
| function clearHistory() { |
| const list = document.getElementById('mealHistoryList'); |
| const status = document.getElementById('historyStatus'); |
| list.innerHTML = ''; |
| status.classList.remove('hidden'); |
| setTimeout(() => { |
| status.classList.add('hidden'); |
| }, 2000); |
| } |
| |
| function deleteAccount() { |
| if (confirm("Are you sure you want to delete your account? This action cannot be undone.")) { |
| const status = document.getElementById('accountStatus'); |
| status.classList.remove('hidden'); |
| setTimeout(() => { |
| closeModal('accountSettingsModal'); |
| }, 2000); |
| |
| } |
| } |
| |
| function sendSupportEmail() { |
| const status = document.getElementById('supportStatus'); |
| status.classList.remove('hidden'); |
| setTimeout(() => { |
| status.classList.add('hidden'); |
| }, 2000); |
| |
| } |
| |
| |
| function startScan() { |
| const cameraContainer = document.getElementById('cameraContainer'); |
| const processingOverlay = document.getElementById('processingOverlay'); |
| const detectionResults = document.getElementById('detectionResults'); |
| const progressFill = document.getElementById('progressFill'); |
| const header = document.getElementById('header'); |
| const analysisResults = document.getElementById('analysisResults'); |
| const navButtons = document.getElementById('navButtons'); |
| const footer = document.getElementById('footer'); |
| const navItems = document.querySelectorAll('.fade-in'); |
| |
| |
| cameraContainer.style.height = '100vh'; |
| detectionResults.classList.add('hidden'); |
| analysisResults.style.opacity = '0'; |
| analysisResults.classList.add('hidden'); |
| header.style.opacity = '0'; |
| header.classList.add('hidden'); |
| navButtons.style.opacity = '0'; |
| navButtons.classList.add('hidden'); |
| footer.style.opacity = '0'; |
| footer.classList.add('hidden'); |
| |
| setTimeout(() => { |
| processingOverlay.classList.remove('hidden'); |
| processingOverlay.classList.add('flex'); |
| processingOverlay.style.opacity = '1'; |
| |
| let progress = 0; |
| const progressInterval = setInterval(() => { |
| progress += Math.random() * 15; |
| if (progress >= 100) { |
| progress = 100; |
| clearInterval(progressInterval); |
| |
| setTimeout(() => { |
| processingOverlay.style.opacity = '0'; |
| setTimeout(() => { |
| processingOverlay.classList.add('hidden'); |
| processingOverlay.classList.remove('flex'); |
| }, 500); |
| |
| detectionResults.classList.remove('hidden'); |
| cameraContainer.style.height = '50vh'; |
| header.classList.remove('hidden'); |
| header.style.opacity = '1'; |
| analysisResults.classList.remove('hidden'); |
| analysisResults.style.opacity = '1'; |
| navButtons.classList.remove('hidden'); |
| navButtons.style.opacity = '1'; |
| footer.classList.remove('hidden'); |
| footer.style.opacity = '1'; |
| |
| setTimeout(() => { |
| navItems.forEach((item, index) => { |
| setTimeout(() => { |
| item.classList.add('visible'); |
| }, index * 200); |
| }); |
| }, 500); |
| }, 500); |
| } |
| progressFill.style.width = progress + '%'; |
| }, 100); |
| }, 1000); |
| } |
| |
| |
| document.addEventListener('DOMContentLoaded', function () { |
| initCamera(); |
| startScan(); |
| }); |
| |
| |
| document.getElementById('rescanButton').addEventListener('click', startScan); |
| |
| |
| document.getElementById('saveMealButton').addEventListener('click', () => { |
| alert('Meal saved successfully!'); |
| |
| }); |
| </script> |
| </body> |
| </html> |