Sejf
?
QR Kód s aktuální adresou
📺 Fullscreen
Sejf
ZAMČENO
1
2
3
4
5
6
7
8
9
C
0
Potvrdit
Upravit obsah stránky
{% extends "templates/base.html" %} {% set game_name = "Sejf" %} {% block content %} <!-- Fullscreen button --> <button type="button" id="goFullscreen" class="btn btn-light" style="position:fixed; top:8px; right:8px; z-index:2000;">📺 Fullscreen</button> <div class="full-screen"> <!-- Panel with title, state and countdown --> <div class="door-panel card text-center p-3 mb-4 d-flex align-items-center justify-content-between"> <div class="flex-shrink-0"></div> <div> <h1 class="mb-1">Sejf</h1> <p id="safeStatus" class="h4 mb-1">ZAMČENO</p> <p id="safeCountdown" class="h5 mb-0" style="visibility:hidden;"></p> </div> <div class="flex-shrink-0"></div> </div> <!-- Display for code entry --> <input type="text" id="codeDisplay" readonly maxlength="4" class="code-display mb-3" placeholder="____"> <!-- Numeric keypad --> <div class="keypad"> <button type="button" class="key" data-key="1">1</button> <button type="button" class="key" data-key="2">2</button> <button type="button" class="key" data-key="3">3</button> <button type="button" class="key" data-key="4">4</button> <button type="button" class="key" data-key="5">5</button> <button type="button" class="key" data-key="6">6</button> <button type="button" class="key" data-key="7">7</button> <button type="button" class="key" data-key="8">8</button> <button type="button" class="key" data-key="9">9</button> <button type="button" id="clearBtn" class="action-btn">C</button> <button type="button" class="key" data-key="0">0</button> <button type="button" id="confirmBtn" class="action-btn">Potvrdit</button> </div> </div> <style> .full-screen { position: fixed; top:0; left:0; width:100%; height:100%; display:flex; flex-direction:column; align-items:center; background-color:#ff4d4d; padding:2vh 2vw; box-sizing:border-box; overflow:hidden; } .door-panel { width:100%; max-width:400px; background:rgba(255,255,255,0.85); border:2px solid rgba(0,0,0,0.1); border-radius:.5rem; padding:1rem; } .code-display { width:100%; max-width:200px; text-align:center; font-size:2rem; padding:.5rem; border-radius:.3rem; border:2px solid #ccc; } .keypad { display:grid; grid-template-columns: repeat(3, 80px); grid-gap:1rem; } .key { width:80px; height:60px; font-size:1.5rem; background:#fff; border:2px solid #999; border-radius:.3rem; transition: background 0.2s, transform 0.1s; } .key:hover { background: #f0f0f0; } .key:active { transform: scale(0.95); } .action-btn { width:80px; height:60px; font-size:1.2rem; background:#d1e7dd; border:2px solid #9fd3c7; border-radius:.3rem; transition: background 0.2s, transform 0.1s; } .action-btn:hover { background: #b7d9c4; } .action-btn:active { transform: scale(0.95); } body.locked .full-screen { background-color:#ff4d4d; } body.unlocked .full-screen { background-color:#4dff4d; } body.alarm .full-screen { background-color:#660000; } #alarmOverlay { position:absolute; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.9); color:#ff4444; display:flex; align-items:center; justify-content:center; font-size:2rem; text-align:center; z-index:9999; padding:1rem; } @media(max-width:768px) { .keypad { grid-template-columns: repeat(3, 20vw); grid-gap:2vw; } .key, .action-btn { width:100%; height:12vh; font-size:2rem; } .code-display { font-size:1.5rem; padding:.3rem; max-width:60vw; } } </style> <script> // Fullscreen document.getElementById('goFullscreen').addEventListener('click',()=>{ document.getElementById('goFullscreen').style.display='none'; const el=document.documentElement; (el.requestFullscreen||el.webkitRequestFullscreen||el.msRequestFullscreen).call(el); }); (async()=>{ const fh=new ForrestHubLib(); const SAFE_CODE = '1348'; let state='locked', ct, at; let physicalOpened=false, prevTime=0, openTimestamp=0, checkNoOpenTimer; function updateUI(){ document.body.classList.remove('locked','unlocked','alarm'); document.body.classList.add(state); document.getElementById('safeStatus').textContent = state==='locked'? 'ZAMČENO' : state==='unlocked'? 'ODEMČENO' : 'ALARM'; } function clearTimers(){ clearInterval(ct); clearTimeout(at); clearTimeout(checkNoOpenTimer); } async function lockSafe(){ clearTimers(); state='locked'; physicalOpened=false; prevTime=0; openTimestamp=0; await fh.dbVarSetKey('safeCode', SAFE_CODE); await fh.dbVarSetKey('safeState', state); await fh.dbVarSetKey('trezor', 'close'); updateUI(); document.getElementById('safeCountdown').style.visibility='hidden'; document.getElementById('codeDisplay').value=''; } function showCountdown(s){ const el=document.getElementById('safeCountdown'); el.style.visibility='visible'; el.textContent=s+' s'; } async function unlockSafe() { clearTimers(); state='unlocked'; await fh.dbVarSetKey('safeState', state); await fh.dbVarSetKey('trezor', 'open'); updateUI(); let t=10; showCountdown(t); ct = setInterval(() => { if (--t > 0) showCountdown(t); }, 1000); at = setTimeout(lockSafe, 10000); checkNoOpenTimer = setTimeout(async () => { const tSec = await fh.dbVarGetKey('trezor_time') || 0; if (tSec === 0) await fh.dbVarSetKey('trezor', 'close'); }, 10000); } async function alarmLocal(){ clearTimers(); state='alarm'; await fh.dbVarSetKey('safeState','alarm'); await fh.dbVarSetKey('trezor','close'); updateUI(); const ov=document.createElement('div'); ov.id='alarmOverlay'; ov.textContent='!!!! Chyba !!!! Byl aktivován ALARM !!!'; document.body.appendChild(ov); at=setTimeout(()=>{ ov.remove(); lockSafe(); },10000); } // Poll for physical open/close setInterval(async()=>{ const tSeconds = await fh.dbVarGetKey('trezor_time')||0; if(!physicalOpened && tSeconds>0){ physicalOpened = true; openTimestamp = Date.now(); } if(physicalOpened){ if(tSeconds === 0){ physicalOpened=false; await fh.dbVarSetKey('trezor','close'); } else { if(Date.now()-openTimestamp>30000){ alarmLocal(); } } } prevTime = tSeconds; },1000); // Initialize await lockSafe(); updateUI(); // Keypad document.querySelectorAll('.key').forEach(button=>{ button.addEventListener('click',()=>{ const display=document.getElementById('codeDisplay'); if(display.value.length<4) display.value += button.dataset.key; }); }); document.getElementById('clearBtn').addEventListener('click',()=>{ document.getElementById('codeDisplay').value=''; }); document.getElementById('confirmBtn').addEventListener('click', async()=>{ if(state!=='locked') return; const entered=document.getElementById('codeDisplay').value; if(entered===SAFE_CODE) await unlockSafe(); else await alarmLocal(); }); })(); </script> {% endblock %}