This commit is contained in:
Ionel Andrei Cataon
2026-02-18 17:07:26 +02:00
parent fad1943b5d
commit fd3686650f

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>NutriAI Elite v19.0</title> <title>NutriAI Elite v20.0</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
@@ -19,7 +19,6 @@
body { background-color: var(--bg); color: var(--text); font-family: 'Outfit', sans-serif; height: 100dvh; overflow: hidden; transition: 0.3s; } body { background-color: var(--bg); color: var(--text); font-family: 'Outfit', sans-serif; height: 100dvh; overflow: hidden; transition: 0.3s; }
/* Mobile Responsive Layout */
.main-wrapper { display: flex; height: 100dvh; flex-direction: row; } .main-wrapper { display: flex; height: 100dvh; flex-direction: row; }
@media (max-width: 991px) { @media (max-width: 991px) {
.main-wrapper { flex-direction: column; overflow-y: auto; height: auto; } .main-wrapper { flex-direction: column; overflow-y: auto; height: auto; }
@@ -28,13 +27,14 @@
body { overflow-y: auto; } body { overflow-y: auto; }
} }
.sidebar { width: 350px; background: var(--sidebar); border-right: 1px solid rgba(255,255,255,0.1); padding: 1.5rem; overflow-y: auto; flex-shrink: 0; } .sidebar { width: 360px; background: var(--sidebar); border-right: 1px solid rgba(255,255,255,0.1); padding: 1.5rem; overflow-y: auto; flex-shrink: 0; }
.chat-section { flex-grow: 1; display: flex; flex-direction: column; background: rgba(0,0,0,0.2); position: relative; } .chat-section { flex-grow: 1; display: flex; flex-direction: column; background: rgba(0,0,0,0.2); position: relative; }
.label-pro { color: var(--accent); font-weight: 800; font-size: 0.75rem; text-transform: uppercase; margin-bottom: 5px; display: block; } .label-pro { color: var(--accent); font-weight: 800; font-size: 0.75rem; text-transform: uppercase; margin-bottom: 5px; display: block; }
.glass-input { background: #fff !important; color: #000 !important; border: 3px solid var(--primary) !important; border-radius: 12px; font-weight: 800 !important; } .glass-input { background: #fff !important; color: #000 !important; border: 3px solid var(--primary) !important; border-radius: 12px; font-weight: 800 !important; }
.stat-panel { background: linear-gradient(145deg, var(--primary), #1e3a8a); border-radius: 20px; padding: 1rem; margin: 10px 0; text-align: center; } .stat-panel { background: linear-gradient(145deg, var(--primary), #1e3a8a); border-radius: 20px; padding: 1rem; margin: 10px 0; text-align: center; }
.water-hub { background: rgba(59, 130, 246, 0.1); border: 2px solid var(--primary); border-radius: 15px; padding: 12px; margin: 10px 0; text-align: center; }
.macro-hub { background: rgba(255,255,255,0.05); border-radius: 20px; padding: 15px; margin-top: 10px; } .macro-hub { background: rgba(255,255,255,0.05); border-radius: 20px; padding: 15px; margin-top: 10px; }
.chat-container { flex-grow: 1; overflow-y: auto; padding: 1.5rem; display: flex; flex-direction: column; } .chat-container { flex-grow: 1; overflow-y: auto; padding: 1.5rem; display: flex; flex-direction: column; }
@@ -43,12 +43,13 @@
.user { background: var(--primary); align-self: flex-end; } .user { background: var(--primary); align-self: flex-end; }
.top-ctrl { padding: 10px; display: flex; justify-content: flex-end; gap: 8px; background: rgba(0,0,0,0.3); } .top-ctrl { padding: 10px; display: flex; justify-content: flex-end; gap: 8px; background: rgba(0,0,0,0.3); }
.input-area { padding: 15px; background: var(--sidebar); border-top: 1px solid rgba(255,255,255,0.1); } .input-area { padding: 15px; background: var(--sidebar); border-top: 1px solid rgba(255,255,255,0.1); display: flex; gap: 10px; }
.btn-shop { background: #f59e0b; color: #000; font-weight: 800; border: none; border-radius: 12px; padding: 0 15px; white-space: nowrap; }
.btn-reset { background: rgba(239, 68, 68, 0.15); color: #fca5a5; border: 1px solid #ef4444; border-radius: 12px; padding: 8px; font-weight: 700; width: 100%; margin-top: 15px; } .btn-reset { background: rgba(239, 68, 68, 0.15); color: #fca5a5; border: 1px solid #ef4444; border-radius: 12px; padding: 8px; font-weight: 700; width: 100%; margin-top: 15px; }
/* Table fixes for mobile */ table { width: 100%; display: block; overflow-x: auto; color: #fff; border-collapse: collapse; margin-top: 10px; }
.msg table { width: 100%; display: block; overflow-x: auto; } th, td { border: 1px solid rgba(255,255,255,0.2); padding: 8px; text-align: left; }
</style> </style>
</head> </head>
<body class="theme-dark"> <body class="theme-dark">
@@ -85,6 +86,11 @@
<p class="text-uppercase fw-bold m-0 opacity-75 small">Target Calories</p> <p class="text-uppercase fw-bold m-0 opacity-75 small">Target Calories</p>
</div> </div>
<div class="water-hub">
<h2 class="fw-bold text-info mb-0" id="h2o">0.0L</h2>
<span class="label-pro"><i class="fas fa-droplet me-1"></i> Daily Hydration</span>
</div>
<div class="macro-hub"> <div class="macro-hub">
<canvas id="mChart" style="max-height: 120px;"></canvas> <canvas id="mChart" style="max-height: 120px;"></canvas>
<div class="row mt-2 text-center fw-bold small"> <div class="row mt-2 text-center fw-bold small">
@@ -114,16 +120,19 @@
<div id="chat" class="chat-container"> <div id="chat" class="chat-container">
<div class="msg ai shadow"> <div class="msg ai shadow">
<h5 class="fw-bold text-primary">Mobile Engine Synced.</h5> <h5 class="fw-bold text-primary">System Unified.</h5>
The dashboard is now fully responsive. Input your data to begin. Shopping list and Water tracker are back. All fields reset on load.
</div> </div>
</div> </div>
<div class="input-area"> <div class="input-area">
<div class="input-group"> <div class="input-group input-group-lg flex-grow-1">
<input type="text" id="uIn" class="form-control bg-dark text-white border-primary" placeholder="Type and press ENTER..." onkeydown="if(event.key === 'Enter') talk()"> <input type="text" id="uIn" class="form-control bg-dark text-white border-primary" placeholder="Type and press ENTER..." onkeydown="if(event.key === 'Enter') talk()">
<button class="btn btn-primary" onclick="talk()"><i class="fas fa-paper-plane"></i></button> <button class="btn btn-primary" onclick="talk()"><i class="fas fa-paper-plane"></i></button>
</div> </div>
<button class="btn-shop shadow-sm" onclick="talk('Generate shopping list for current plan')">
<i class="fas fa-shopping-basket me-1"></i> SHOPPING LIST
</button>
</div> </div>
</div> </div>
</div> </div>
@@ -146,6 +155,7 @@
const total = Math.round((bmr * act) + agg); const total = Math.round((bmr * act) + agg);
document.getElementById('kcal').innerText = total; document.getElementById('kcal').innerText = total;
document.getElementById('h2o').innerText = (wc * 0.035).toFixed(1) + "L";
document.getElementById('aggDisp').innerText = (agg>0?'+':'')+agg+" kcal"; document.getElementById('aggDisp').innerText = (agg>0?'+':'')+agg+" kcal";
const pG = Math.round((total * 0.3)/4), cG = Math.round((total * 0.4)/4), fG = Math.round((total * 0.3)/9); const pG = Math.round((total * 0.3)/4), cG = Math.round((total * 0.4)/4), fG = Math.round((total * 0.3)/9);
document.getElementById('pG').innerText = pG+"g"; document.getElementById('cG').innerText = cG+"g"; document.getElementById('fG').innerText = fG+"g"; document.getElementById('pG').innerText = pG+"g"; document.getElementById('cG').innerText = cG+"g"; document.getElementById('fG').innerText = fG+"g";
@@ -156,15 +166,16 @@
['w','t','h','age','agg'].forEach(id => document.getElementById(id).value = id === 'agg' ? 0 : ""); ['w','t','h','age','agg'].forEach(id => document.getElementById(id).value = id === 'agg' ? 0 : "");
document.getElementById('act').selectedIndex = 0; document.getElementById('act').selectedIndex = 0;
document.getElementById('kcal').innerText = "0"; document.getElementById('kcal').innerText = "0";
document.getElementById('chat').innerHTML = `<div class="msg ai shadow">System reset. All fields cleared.</div>`; document.getElementById('h2o').innerText = "0.0L";
document.getElementById('chat').innerHTML = `<div class="msg ai shadow">System reset. Ready for new inputs.</div>`;
if(mChart) { mChart.data.datasets[0].data = [1,1,1]; mChart.update(); } if(mChart) { mChart.data.datasets[0].data = [1,1,1]; mChart.update(); }
} }
async function talk() { async function talk(custom) {
const box = document.getElementById('chat'), input = document.getElementById('uIn'); const box = document.getElementById('chat'), input = document.getElementById('uIn');
const text = input.value; if(!text) return; const text = custom || input.value; if(!text) return;
box.innerHTML += `<div class="msg user shadow-sm">${text}</div>`; input.value=""; if(!custom) { box.innerHTML += `<div class="msg user shadow-sm">${text}</div>`; input.value=""; }
const id = 'ai-'+Date.now(); box.innerHTML += `<div id="${id}" class="msg ai shadow">Thinking...</div>`; const id = 'ai-'+Date.now(); box.innerHTML += `<div id="${id}" class="msg ai shadow">Processing...</div>`;
box.scrollTop = box.scrollHeight; box.scrollTop = box.scrollHeight;
try { try {
const res = await fetch("https://api.groq.com/openai/v1/chat/completions", { const res = await fetch("https://api.groq.com/openai/v1/chat/completions", {
@@ -176,7 +187,7 @@
}); });
const d = await res.json(); const d = await res.json();
document.getElementById(id).innerHTML = marked.parse(d.choices[0].message.content); document.getElementById(id).innerHTML = marked.parse(d.choices[0].message.content);
} catch(e) { document.getElementById(id).innerText = "Connection Error."; } } catch(e) { document.getElementById(id).innerText = "Error connecting to coach."; }
box.scrollTop = box.scrollHeight; box.scrollTop = box.scrollHeight;
} }
@@ -185,7 +196,7 @@
type: 'doughnut', data: { datasets: [{ data: [1,1,1], backgroundColor: ['#0dcaf0','#dc3545','#ffc107'], borderWeight:0 }] }, type: 'doughnut', data: { datasets: [{ data: [1,1,1], backgroundColor: ['#0dcaf0','#dc3545','#ffc107'], borderWeight:0 }] },
options: { plugins: { legend: { display: false } }, cutout: '75%' } options: { plugins: { legend: { display: false } }, cutout: '75%' }
}); });
resetAll(); // Ensures empty fields on page load resetAll();
} }
</script> </script>
</body> </body>