Загрузка данных


<!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; }
        
        /* Стиль для мини-инструкции под полем веса */
        .form-hint-text {
            font-size: 11px;
            color: rgba(255, 255, 255, 0.6);
            line-height: 1.3;
            margin-top: -2px;
            margin-bottom: 6px;
            padding: 0 4px;
            font-family: 'Segoe UI', Arial, sans-serif;
        }
        .form-hint-text strong { color: #3beed1; }

        .btn-save { width: 100%; background: rgba(43, 192, 180, 0.25); border: 1px solid rgba(43, 192, 180, 0.4); margin-top: 4px; }
        .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 шт (в граммах)">
                        <div class="form-hint-text">
                            БЖУ выше пиши <strong>на 100г</strong>. Если указать вес штуки (н-р, 50 для яйца), в дневник можно будет вводить штуками: <code>яйца 2</code>. Если штук нет — оставь 0.
                        </div>
                        <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>