Загрузка данных
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; user-select: none; }
body, html {
width: 100%; height: 100%; font-family: 'Segoe UI', Arial, sans-serif; overflow: hidden;
background-image: url('images/bg.png'); background-size: cover; background-position: center;
}
.tabs-header { display: flex; width: 100%; background: transparent; position: relative; z-index: 10; }
.tab-btn {
width: 33.33%; padding: 14px 0; text-align: center; color: #888888;
font-family: 'Consolas', monospace; font-size: 15px; font-weight: 500;
letter-spacing: 2px; cursor: pointer; border-bottom: 2px solid transparent;
line-height: 1.2; background: rgba(0, 0, 0, 0); opacity: 0.6;
transition: color 0.2s ease, background 0.2s ease, opacity 0.2s ease;
}
.tab-btn:hover { color: #dddddd; background: rgba(0, 0, 0, 0.2); }
.tab-btn.active {
color: #ffffff; border-bottom: 3px solid #2bc0b4; opacity: 1;
text-shadow: 0 0 10px rgba(43, 192, 180, 0.8), 0 0 20px rgba(43, 192, 180, 0.4);
background: rgba(0, 0, 0, 0.55);
}
.tabs-content { width: 100%; height: calc(100% - 49px); padding: 20px; }
.tab-page { display: none; width: 100%; height: 100%; }
.tab-page.active { display: flex; flex-direction: column; }
.input-row { display: flex; gap: 15px; margin-bottom: 20px; width: 100%; }
input[type="text"], input[type="number"] {
height: 44px; background: rgba(0, 0, 0, 0.4); border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 22px; padding: 2px 20px 0px 20px; color: #ffffff; font-size: 14px;
line-height: 40px; outline: none; display: inline-block; transform: translateZ(0);
}
input[type="text"]:focus, input[type="number"]:focus { background: rgba(0, 0, 0, 0.5); border: 1px solid rgba(43, 192, 180, 0.5); }
.btn-ok {
width: 120px; height: 44px; background: rgba(0, 0, 0, 0.4); border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 22px; color: #ffffff; font-size: 14px; font-weight: bold; line-height: 42px;
cursor: pointer; outline: none; transition: all 0.2s ease; display: inline-block; transform: translateZ(0);
letter-spacing: 2px; text-align: center;
}
.btn-ok:hover { background: rgba(0, 0, 0, 0.6); border: 1px solid rgba(255, 255, 255, 0.3); }
.glass-panel {
flex: 1; background-color: rgba(0, 0, 0, 0.35); backdrop-filter: blur(12px) !important;
-webkit-backdrop-filter: blur(12px) !important; border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 16px; padding: 20px 0px 20px 20px; color: #ffffff; font-family: 'Consolas', 'Courier New', monospace;
font-size: 14px; line-height: 1.5; overflow: hidden; position: relative;
}
.scroll-content {
width: calc(100% - 45px); height: 100%; overflow-y: auto; white-space: normal; padding-right: 5px;
}
.scroll-content::-webkit-scrollbar { display: none !important; }
.magnetic-track-zone {
position: absolute; right: 0; top: 0; width: 45px; height: 100%; cursor: pointer; z-index: 9998;
}
.split-layout { display: flex; width: 100%; height: 100%; gap: 20px; }
.buttons-column { display: flex; flex-direction: column; gap: 15px; width: 130px; }
.side-btn {
width: 100%; height: 40px; background: rgba(0, 0, 0, 0.4); border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px; color: #ffffff; font-family: 'Consolas', monospace; font-size: 15px;
font-weight: 500; line-height: 38px; cursor: pointer; outline: none; transition: all 0.2s ease;
display: inline-block; transform: translateZ(0); letter-spacing: 3px; padding: 0 10px; text-align: center;
}
.side-btn:hover { background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); }
.side-btn.btn-clear { background: rgba(150, 40, 40, 0.4); border: 1px solid rgba(255, 100, 100, 0.15); }
.side-btn.btn-clear:hover { background: rgba(180, 50, 50, 0.5); border: 1px solid rgba(255, 100, 100, 0.3); }
.db-table-wrapper { flex: 1; display: flex; flex-direction: column; height: 100%; }
.db-form-panel { width: 260px; display: flex; flex-direction: column; gap: 12px; }
.form-title { font-size: 13px; font-weight: bold; color: #2bc0b4; letter-spacing: 1px; margin-bottom: 4px; font-family: 'Consolas', monospace; }
.form-input { width: 100%; height: 38px; border-radius: 19px; font-size: 13px; line-height: 34px; margin-bottom: 2px; }
.btn-save { width: 100%; background: rgba(43, 192, 180, 0.25); border: 1px solid rgba(43, 192, 180, 0.4); }
.btn-save:hover { background: rgba(43, 192, 180, 0.4); }
.btn-cancel { width: 100%; background: rgba(0,0,0,0.3); border: 1px solid rgba(255,255,255,0.1); margin-top: 5px; }
.product-item, .diary-item {
display: flex; flex-direction: column; justify-content: center; align-items: flex-start;
padding: 8px 10px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); white-space: normal;
}
.product-item { flex-direction: row; justify-content: space-between; align-items: center; }
.product-info { flex: 1; min-height: 38px; display: flex; flex-direction: column; justify-content: center; }
.product-macros { color: #2bc0b4; font-size: 12px; margin-top: 2px; font-family: 'Consolas', monospace; }
.actions-zone { display: inline-flex; align-items: center; justify-content: center; gap: 14px; height: 38px; padding-right: 5px; }
.btn-action-icon {
background: transparent; border: none; cursor: pointer; outline: none;
display: inline-flex; align-items: center; justify-content: center;
height: 38px; width: 22px; padding: 0; margin: 0; box-sizing: border-box;
transition: color 0.2s ease, transform 0.2s ease;
}
.btn-edit { color: #2bc0b4; }
.btn-edit:hover { color: #3beed1; transform: rotate(90deg) scale(1.1); }
.btn-delete { color: #ff6464; }
.btn-delete:hover { color: #ff3333; transform: scale(1.2); }
.btn-action-icon svg { width: 16px; height: 16px; display: block; fill: currentColor; }
.custom-scroll-thumb {
position: absolute; right: 18px; width: 8px; height: 8px; background-color: rgba(43, 192, 180, 0.5);
border: 1px solid rgba(43, 192, 180, 0.7); border-radius: 50%; cursor: pointer; z-index: 9999;
transition: background-color 0.2s, transform 0.2s; display: none;
}
.custom-scroll-thumb:hover, .custom-scroll-thumb.dragging {
background-color: rgba(43, 192, 180, 0.9); transform: scale(1.2); box-shadow: 0 0 10px rgba(43, 192, 180, 0.8);
}
</style>
</head>
<body>
<div class="tabs-header">
<div class="tab-btn active" id="btn-0" onclick="switchTab(0)">ДНЕВНИК</div>
<div class="tab-btn" id="btn-1" onclick="switchTab(1)">ИСТОРИЯ</div>
<div class="tab-btn" id="btn-2" onclick="switchTab(2)">ПРОДУКТЫ</div>
</div>
<div class="tabs-content">
<div class="tab-page active" id="page-0">
<div class="input-row">
<input type="text" id="meal-input" style="flex:1;" placeholder="Введите прием пищи..." onkeydown="if(event.key==='Enter') sendData()">
<button class="btn-ok" onclick="sendData()">OK</button>
</div>
<div class="glass-panel" id="diary-panel">
<div class="scroll-content" id="diary-box">Загрузка дневника...</div>
<div class="magnetic-track-zone" id="diary-track"></div>
<div class="custom-scroll-thumb" id="diary-thumb"></div>
</div>
</div>
<div class="tab-page" id="page-1">
<div class="split-layout">
<div class="glass-panel" id="history-panel">
<div class="scroll-content" id="history-box">Загрузка истории...</div>
<div class="magnetic-track-zone" id="history-track"></div>
<div class="custom-scroll-thumb" id="history-thumb"></div>
</div>
<div class="buttons-column">
<button class="side-btn" onclick="triggerAction('open')">OPEN</button>
<button class="side-btn" onclick="triggerAction('save')">SAVE</button>
<button class="side-btn btn-clear" onclick="triggerAction('clear')">CLEAR</button>
</div>
</div>
</div>
<div class="tab-page" id="page-2">
<div class="split-layout">
<div class="db-table-wrapper">
<div class="input-row">
<input type="text" id="search-input" style="flex:1;" placeholder="Поиск продукта..." oninput="filterProducts()">
</div>
<div class="glass-panel" id="db-panel" style="padding:10px 0px 10px 10px;">
<div class="scroll-content" id="db-box">Загрузка базы данных...</div>
<div class="magnetic-track-zone" id="db-track"></div>
<div class="custom-scroll-thumb" id="db-thumb"></div>
</div>
</div>
<div class="db-form-panel">
<div class="glass-panel" style="flex:none; width:100%; padding:15px; display:flex; flex-direction:column; gap:10px; border-radius:16px;">
<div class="form-title" id="form-action-title">НОВЫЙ ПРОДУКТ</div>
<input type="text" id="f-name" class="form-input" placeholder="Название продукта">
<input type="number" id="f-kcal" class="form-input" placeholder="Калории (авто)" disabled style="opacity: 0.6; background: rgba(0, 0, 0, 0.45); border: 1px dashed rgba(255,255,255,0.15);">
<input type="number" id="f-b" class="form-input" placeholder="Белки (на 100г)" step="0.1" oninput="recalcKcal()">
<input type="number" id="f-j" class="form-input" placeholder="Жиры (на 100г)" step="0.1" oninput="recalcKcal()">
<input type="number" id="f-u" class="form-input" placeholder="Углеводы (на 100г)" step="0.1" oninput="recalcKcal()">
<input type="number" id="f-w" class="form-input" placeholder="Вес 1 шт (0 если нет порции)" value="0">
<button class="side-btn btn-save" id="form-submit-btn" onclick="saveNewProduct()">ДОБАВИТЬ</button>
<button class="side-btn btn-cancel" id="form-cancel-btn" style="display:none;" onclick="resetForm()">ОТМЕНА</button>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('contextmenu', function(e) { e.preventDefault(); });
var isEditMode = false; var oldEditName = "";
function switchTab(i) {
document.getElementById('btn-0').classList.toggle('active', i === 0);
document.getElementById('btn-1').classList.toggle('active', i === 1);
document.getElementById('btn-2').classList.toggle('active', i === 2);
document.getElementById('page-0').classList.toggle('active', i === 0);
document.getElementById('page-1').classList.toggle('active', i === 1);
document.getElementById('page-2').classList.toggle('active', i === 2);
document.title = "tab:" + i;
}
function sendData() {
var i = document.getElementById('meal-input'); if (!i.value.trim()) return;
document.title = "add:" + i.value.trim(); i.value = "";
}
function triggerAction(n) { document.title = "btn:" + n; }
function recalcKcal() {
var b = parseFloat(document.getElementById('f-b').value) || 0;
var j = parseFloat(document.getElementById('f-j').value) || 0;
var u = parseFloat(document.getElementById('f-u').value) || 0;
var kcal = Math.round((b * 4) + (j * 9) + (u * 4));
document.getElementById('f-kcal').value = kcal;
}
function saveNewProduct() {
var n = document.getElementById('f-name').value.trim();
var kc = document.getElementById('f-kcal').value.trim() || "0";
var b = document.getElementById('f-b').value.trim() || "0";
var j = document.getElementById('f-j').value.trim() || "0";
var u = document.getElementById('f-u').value.trim() || "0";
var w = document.getElementById('f-w').value.trim() || "0";
if (!n) return;
n = n.replace(/:/g, ' ');
if (isEditMode) {
document.title = "dbadd:" + n + ":" + kc + ":" + b + ":" + j + ":" + u + ":" + w + "___del:" + oldEditName;
} else {
document.title = "dbadd:" + n + ":" + kc + ":" + b + ":" + j + ":" + u + ":" + w;
}
resetForm();
}
function resetForm() {
document.getElementById('f-name').value = ""; document.getElementById('f-kcal').value = "";
document.getElementById('f-b').value = ""; document.getElementById('f-j').value = "";
document.getElementById('f-u').value = ""; document.getElementById('f-w').value = "0";
cancelEdit();
}
function clickSettings(n, kc, b, j, u, w) {
isEditMode = true; oldEditName = n;
document.getElementById('form-action-title').innerText = "РЕДАКТИРОВАНИЕ";
document.getElementById('form-submit-btn').innerText = "ИЗМЕНИТЬ";
document.getElementById('form-cancel-btn').style.display = "block";
document.getElementById('f-name').value = n; document.getElementById('f-kcal').value = kc;
document.getElementById('f-b').value = b; document.getElementById('f-j').value = j;
document.getElementById('f-u').value = u; document.getElementById('f-w').value = w;
}
function cancelEdit() {
isEditMode = false; oldEditName = "";
document.getElementById('form-action-title').innerText = "НОВЫЙ ПРОДУКТ";
document.getElementById('form-submit-btn').innerText = "ДОБАВИТЬ";
document.getElementById('form-cancel-btn').style.display = "none";
}
function deleteProduct(n) {
if(confirm("Удалить продукт '" + n + "'?")) { document.title = "dbdel:" + n; }
}
function filterProducts() {
var q = document.getElementById('search-input').value.toLowerCase().trim();
var items = document.getElementsByClassName('product-item');
for(var i=0; i<items.length; i++){
var pN = items[i].getAttribute('data-name'); items[i].style.display = pN.includes(q) ? "flex" : "none";
}
var box = document.getElementById('db-box');
if(box.onscroll) box.onscroll();
}
function updateDiary(h) {
document.getElementById('diary-box').innerHTML = h;
setupCustomScroll('diary-box', 'diary-thumb', 'diary-panel', 'diary-track');
}
function setupCustomScroll(boxId, thumbId, panelId, trackId) {
var box = document.getElementById(boxId);
var thumb = document.getElementById(thumbId);
var panel = document.getElementById(panelId);
var track = document.getElementById(trackId);
if (!box || !thumb || !panel || !track) return;
var padding = 12;
var smoothScrollAnimation = null;
var isMouseDownOnTrack = false;
var currentMouseY = 0;
function syncScroll() {
var visibleHeight = box.clientHeight;
var totalHeight = box.scrollHeight;
var scrollTop = box.scrollTop;
if (totalHeight <= visibleHeight + 2) {
thumb.style.display = 'none';
return;
}
thumb.style.display = 'block';
var availableTrack = visibleHeight - thumb.clientHeight - (padding * 2);
var scrollPercent = scrollTop / (totalHeight - visibleHeight);
thumb.style.top = (padding + (scrollPercent * availableTrack)) + 'px';
}
box.onscroll = syncScroll;
syncScroll();
setTimeout(syncScroll, 50);
var isDown = false;
var startY, startScrollTop;
box.addEventListener('mousedown', function(e) {
if (e.target.closest('.actions-zone') || e.target.closest('button')) return;
if (e.button !== 0) return;
isDown = true;
box.style.cursor = 'grabbing';
startY = e.pageY - box.offsetTop;
startScrollTop = box.scrollTop;
});
window.addEventListener('mouseup', function() {
if (isDown) { isDown = false; box.style.cursor = 'default'; }
});
box.addEventListener('mousemove', function(e) {
if (!isDown) return;
e.preventDefault();
var y = e.pageY - box.offsetTop;
var walk = (y - startY) * 1.5;
box.scrollTop = startScrollTop - walk;
});
track.onmousedown = function(e) {
if (e.target === thumb) return;
if (e.button !== 0) return;
isMouseDownOnTrack = true;
currentMouseY = e.clientY;
thumb.classList.add('dragging');
function onGlobalTrackMove(moveEvent) {
currentMouseY = moveEvent.clientY;
}
window.addEventListener('mousemove', onGlobalTrackMove);
function animate() {
if (!isMouseDownOnTrack) return;
var visibleHeight = box.clientHeight;
var totalHeight = box.scrollHeight;
var maxScroll = totalHeight - visibleHeight;
var availableTrack = visibleHeight - thumb.clientHeight - (padding * 2);
var rect = track.getBoundingClientRect();
var clickY = currentMouseY - rect.top;
var targetTop = clickY - (thumb.clientHeight / 2);
var targetPercent = targetTop / availableTrack;
if (targetPercent < 0) targetPercent = 0;
if (targetPercent > 1) targetPercent = 1;
var targetScrollTop = targetPercent * maxScroll;
var diff = targetScrollTop - box.scrollTop;
if (Math.abs(diff) < 1) {
box.scrollTop = targetScrollTop;
} else {
box.scrollTop += diff * 0.18;
}
smoothScrollAnimation = requestAnimationFrame(animate);
}
smoothScrollAnimation = requestAnimationFrame(animate);
window.addEventListener('mouseup', function onGlobalTrackUp() {
isMouseDownOnTrack = false;
thumb.classList.remove('dragging');
cancelAnimationFrame(smoothScrollAnimation);
window.removeEventListener('mousemove', onGlobalTrackMove);
}, { once: true });
};
thumb.onmousedown = function(e) {
e.preventDefault(); e.stopPropagation();
if (e.button !== 0) return;
thumb.classList.add('dragging');
var startY = e.clientY;
var startScrollTop = box.scrollTop;
var visibleHeight = box.clientHeight;
var totalHeight = box.scrollHeight;
var availableTrack = visibleHeight - thumb.clientHeight - (padding * 2);
function onGlobalThumbMove(moveEvent) {
var deltaY = moveEvent.clientY - startY;
var scrollDelta = (deltaY / availableTrack) * (totalHeight - visibleHeight);
box.scrollTop = startScrollTop + scrollDelta;
}
window.addEventListener('mousemove', onGlobalThumbMove);
window.addEventListener('mouseup', function onGlobalThumbUp() {
thumb.classList.remove('dragging');
window.removeEventListener('mousemove', onGlobalThumbMove);
}, { once: true });
};
}
function updateHistory(h) {
document.getElementById('history-box').innerHTML = h;
setupCustomScroll('history-box', 'history-thumb', 'history-panel', 'history-track');
}
function updateProductList(h) {
document.getElementById('db-box').innerHTML = h;
setupCustomScroll('db-box', 'db-thumb', 'db-panel', 'db-track');
filterProducts();
}
window.onload = function() { document.title = "ui_ready:true"; };
</script>
</body>
</html>