feat: draggable nav panel in web runtime (universal-runtime)
This commit is contained in:
@@ -42,7 +42,8 @@ cat > /opt/portal/index.html <<'HTML'
|
|||||||
.nav-panel{
|
.nav-panel{
|
||||||
position:fixed;left:16px;top:64px;z-index:99;display:flex;gap:10px;
|
position:fixed;left:16px;top:64px;z-index:99;display:flex;gap:10px;
|
||||||
background:linear-gradient(180deg,rgba(15,24,36,.78),rgba(9,14,22,.86));border:1px solid rgba(255,255,255,.22);backdrop-filter: blur(5px);
|
background:linear-gradient(180deg,rgba(15,24,36,.78),rgba(9,14,22,.86));border:1px solid rgba(255,255,255,.22);backdrop-filter: blur(5px);
|
||||||
box-shadow:0 10px 28px rgba(0,0,0,.36);padding:9px 10px;border-radius:14px
|
box-shadow:0 10px 28px rgba(0,0,0,.36);padding:9px 10px;border-radius:14px;
|
||||||
|
cursor:grab;user-select:none;touch-action:none
|
||||||
}
|
}
|
||||||
.nav-btn{
|
.nav-btn{
|
||||||
border:1px solid rgba(255,255,255,.26);border-radius:999px;padding:9px 14px;cursor:pointer;letter-spacing:.01em;
|
border:1px solid rgba(255,255,255,.26);border-radius:999px;padding:9px 14px;cursor:pointer;letter-spacing:.01em;
|
||||||
@@ -50,6 +51,7 @@ cat > /opt/portal/index.html <<'HTML'
|
|||||||
}
|
}
|
||||||
.nav-btn:hover{filter:brightness(1.08)}
|
.nav-btn:hover{filter:brightness(1.08)}
|
||||||
.nav-btn:active{transform:translateY(1px)}
|
.nav-btn:active{transform:translateY(1px)}
|
||||||
|
.nav-panel.dragging{cursor:grabbing;opacity:.85}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -253,6 +255,33 @@ cat > /opt/portal/index.html <<'HTML'
|
|||||||
document.getElementById('btn-home').addEventListener('click', goHome);
|
document.getElementById('btn-home').addEventListener('click', goHome);
|
||||||
document.addEventListener('contextmenu', (e) => e.preventDefault());
|
document.addEventListener('contextmenu', (e) => e.preventDefault());
|
||||||
|
|
||||||
|
(function(){
|
||||||
|
const p = document.querySelector('.nav-panel');
|
||||||
|
const SK = 'portal_nav_pos';
|
||||||
|
try { const s = JSON.parse(localStorage.getItem(SK)); if(s){p.style.left=s.x+'px';p.style.top=s.y+'px';} } catch(e){}
|
||||||
|
let ox, oy, dragged = false;
|
||||||
|
p.addEventListener('pointerdown', e => {
|
||||||
|
if (e.target.closest('button')) return;
|
||||||
|
dragged = false;
|
||||||
|
ox = e.clientX - p.getBoundingClientRect().left;
|
||||||
|
oy = e.clientY - p.getBoundingClientRect().top;
|
||||||
|
p.setPointerCapture(e.pointerId);
|
||||||
|
p.classList.add('dragging');
|
||||||
|
});
|
||||||
|
p.addEventListener('pointermove', e => {
|
||||||
|
if (!p.hasPointerCapture(e.pointerId)) return;
|
||||||
|
dragged = true;
|
||||||
|
const x = Math.max(0, Math.min(window.innerWidth - p.offsetWidth, e.clientX - ox));
|
||||||
|
const y = Math.max(0, Math.min(window.innerHeight - p.offsetHeight, e.clientY - oy));
|
||||||
|
p.style.left = x + 'px';
|
||||||
|
p.style.top = y + 'px';
|
||||||
|
});
|
||||||
|
p.addEventListener('pointerup', () => {
|
||||||
|
p.classList.remove('dragging');
|
||||||
|
if (dragged) try { localStorage.setItem(SK, JSON.stringify({x: parseInt(p.style.left), y: parseInt(p.style.top)})); } catch(e){}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
connectRfb('Подключение к слоту...');
|
connectRfb('Подключение к слоту...');
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user