Spaces:
Sleeping
Sleeping
Update static/index.html
Browse files- static/index.html +70 -34
static/index.html
CHANGED
|
@@ -9,14 +9,32 @@
|
|
| 9 |
--bg:#0b1220; --panel:#121a2e; --muted:#9fb0cf; --text:#e6edf7;
|
| 10 |
--accent:#3a8dde; --accent2:#6ea8ff; --ok:#2ecc71; --warn:#ffb020; --danger:#ff6b6b;
|
| 11 |
--radius:16px; --shadow:0 12px 30px rgba(0,0,0,.35);
|
|
|
|
| 12 |
}
|
| 13 |
*{box-sizing:border-box}
|
| 14 |
html,body{height:100%; margin:0; background:var(--bg); color:var(--text); font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif}
|
| 15 |
-
#app{display:grid; grid-template-columns: 360px 1fr; height:100%}
|
| 16 |
|
| 17 |
-
/*
|
| 18 |
-
#
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
#panel h2{margin:.3rem 0 1rem; font-size:1.05rem; color:#cfe0ff}
|
| 21 |
fieldset{border:1px solid #2a395f; border-radius:12px; padding:12px; margin:10px 0}
|
| 22 |
legend{font-size:.9rem; color:#bcd0ff; padding:0 6px}
|
|
@@ -35,28 +53,44 @@
|
|
| 35 |
.badge{display:inline-block; padding:2px 8px; border-radius:999px; font-size:.75rem; background:#1b2b54; color:#cfe0ff}
|
| 36 |
.hr{height:1px; background:#203059; margin:12px 0}
|
| 37 |
|
| 38 |
-
/* Panel toggle */
|
| 39 |
-
#toggle{
|
| 40 |
-
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
-
|
| 44 |
-
#stage
|
| 45 |
-
.bgmedia{position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:0}
|
| 46 |
-
#overlay{position:absolute; inset:0; z-index:2}
|
| 47 |
-
#stageMsg{position:absolute; top:12px; right:12px; background:rgba(10,14,30,.55); border:1px solid #2a3a63; padding:8px 12px; border-radius:12px; z-index:4; backdrop-filter: blur(4px); font-size:.9rem}
|
| 48 |
|
| 49 |
-
/* Pins
|
| 50 |
-
.pin{
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
.
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
|
|
|
|
|
|
|
|
|
|
| 60 |
/* Items list */
|
| 61 |
.item{display:grid; grid-template-columns:auto 1fr auto; gap:8px; align-items:center; padding:8px; border:1px solid #21345d; border-radius:10px; margin:8px 0; background:#0e1834}
|
| 62 |
.item .name{font-size:.9rem}
|
|
@@ -139,8 +173,9 @@
|
|
| 139 |
<video id="bgVid" class="bgmedia" autoplay muted loop playsinline style="display:none"></video>
|
| 140 |
<div id="overlay" title="Click to place when in placement mode"></div>
|
| 141 |
<div id="stageMsg" style="display:none"></div>
|
| 142 |
-
<button id="saveState" class="btn-ghost">Saved</button>
|
| 143 |
</main>
|
|
|
|
|
|
|
| 144 |
</div>
|
| 145 |
|
| 146 |
<script>
|
|
@@ -279,13 +314,14 @@
|
|
| 279 |
}
|
| 280 |
|
| 281 |
function adjustPopupPosition(el){
|
|
|
|
| 282 |
const rect = el.getBoundingClientRect();
|
| 283 |
const margin = 8; let dx=0, dy=0;
|
| 284 |
if (rect.left < margin) dx = margin - rect.left;
|
| 285 |
if (rect.right > innerWidth - margin) dx = (innerWidth - margin) - rect.right;
|
| 286 |
if (rect.top < margin) dy = margin - rect.top;
|
| 287 |
if (rect.bottom > innerHeight - margin) dy = (innerHeight - margin) - rect.bottom;
|
| 288 |
-
if (dx || dy) el.style.transform
|
| 289 |
}
|
| 290 |
|
| 291 |
function renderItems(){
|
|
@@ -302,15 +338,19 @@
|
|
| 302 |
if (it.open){
|
| 303 |
const pop = document.createElement('div'); pop.className='popup';
|
| 304 |
pop.style.left = it.x+'%'; pop.style.top = it.y+'%'; pop.style.width = it.widthPct+'vw';
|
|
|
|
| 305 |
const header = document.createElement('header');
|
| 306 |
const h4 = document.createElement('h4'); h4.textContent = it.title || (it.type==='image'?'Image':'Video');
|
| 307 |
const close = document.createElement('button'); close.className='x'; close.innerHTML='×';
|
| 308 |
close.addEventListener('click', e=>{ e.stopPropagation(); it.open=false; renderItems(); });
|
| 309 |
header.append(h4, close); pop.appendChild(header);
|
|
|
|
| 310 |
const wrap = document.createElement('div'); wrap.className='media';
|
| 311 |
if (it.type==='video'){ const v = document.createElement('video'); v.src=it.src; v.controls=true; v.playsInline=true; wrap.appendChild(v); }
|
| 312 |
else { const img = document.createElement('img'); img.src=it.src; img.alt=it.title||'Image'; wrap.appendChild(img); }
|
| 313 |
-
pop.appendChild(wrap);
|
|
|
|
|
|
|
| 314 |
requestAnimationFrame(()=>adjustPopupPosition(pop));
|
| 315 |
}
|
| 316 |
}
|
|
@@ -390,15 +430,11 @@
|
|
| 390 |
});
|
| 391 |
|
| 392 |
// Misc
|
| 393 |
-
function flash(msg){
|
| 394 |
-
stageMsg.textContent = msg;
|
| 395 |
-
stageMsg.style.display='block'; stageMsg.style.opacity='1';
|
| 396 |
-
setTimeout(()=>{ stageMsg.style.transition='opacity .4s'; stageMsg.style.opacity='0';
|
| 397 |
-
setTimeout(()=>{ stageMsg.style.display='none'; stageMsg.style.transition=''; }, 450);
|
| 398 |
-
}, 900);
|
| 399 |
-
}
|
| 400 |
window.addEventListener('resize', ()=>{
|
| 401 |
-
$$('.popup').forEach(el => {
|
|
|
|
|
|
|
|
|
|
| 402 |
});
|
| 403 |
stage.addEventListener('click', e => {
|
| 404 |
if (state.placingId) return; // placement handled on overlay
|
|
|
|
| 9 |
--bg:#0b1220; --panel:#121a2e; --muted:#9fb0cf; --text:#e6edf7;
|
| 10 |
--accent:#3a8dde; --accent2:#6ea8ff; --ok:#2ecc71; --warn:#ffb020; --danger:#ff6b6b;
|
| 11 |
--radius:16px; --shadow:0 12px 30px rgba(0,0,0,.35);
|
| 12 |
+
--panelW:360px; --panelPeek:14px;
|
| 13 |
}
|
| 14 |
*{box-sizing:border-box}
|
| 15 |
html,body{height:100%; margin:0; background:var(--bg); color:var(--text); font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif}
|
|
|
|
| 16 |
|
| 17 |
+
/* App container just hosts overlays; stage lives full-screen behind */
|
| 18 |
+
#app{position:relative; height:100vh; width:100vw; overflow:hidden}
|
| 19 |
+
|
| 20 |
+
/* Stage is full-viewport, underlays everything (so BG truly covers screen) */
|
| 21 |
+
#stage{position:fixed; inset:0; width:100vw; height:100vh; overflow:hidden; background:#000; user-select:none; z-index:0}
|
| 22 |
+
.bgmedia{position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:0}
|
| 23 |
+
#overlay{position:absolute; inset:0; z-index:2}
|
| 24 |
+
#stageMsg{position:absolute; top:12px; right:12px; background:rgba(10,14,30,.55); border:1px solid #2a3a63; padding:8px 12px; border-radius:12px; z-index:4; backdrop-filter: blur(4px); font-size:.9rem}
|
| 25 |
+
|
| 26 |
+
/* Sidebar overlays the stage */
|
| 27 |
+
#panel{
|
| 28 |
+
position:fixed; top:0; left:0; height:100vh; width:var(--panelW);
|
| 29 |
+
background:linear-gradient(180deg,#121a2e,#0e162b);
|
| 30 |
+
border-right:1px solid #1e2844; padding:16px; overflow:auto;
|
| 31 |
+
transition:transform .28s ease; box-shadow:var(--shadow); z-index:5;
|
| 32 |
+
transform:translateX(0);
|
| 33 |
+
}
|
| 34 |
+
#panel.min{
|
| 35 |
+
/* Collapse so only a tiny sliver remains visible */
|
| 36 |
+
transform:translateX(calc(-100% + var(--panelPeek)));
|
| 37 |
+
}
|
| 38 |
#panel h2{margin:.3rem 0 1rem; font-size:1.05rem; color:#cfe0ff}
|
| 39 |
fieldset{border:1px solid #2a395f; border-radius:12px; padding:12px; margin:10px 0}
|
| 40 |
legend{font-size:.9rem; color:#bcd0ff; padding:0 6px}
|
|
|
|
| 53 |
.badge{display:inline-block; padding:2px 8px; border-radius:999px; font-size:.75rem; background:#1b2b54; color:#cfe0ff}
|
| 54 |
.hr{height:1px; background:#203059; margin:12px 0}
|
| 55 |
|
| 56 |
+
/* Panel toggle sits near the left edge whether expanded or collapsed */
|
| 57 |
+
#toggle{
|
| 58 |
+
position:fixed; top:12px; left:calc(var(--panelW) + 8px);
|
| 59 |
+
z-index:6; width:36px; height:36px; border-radius:10px; display:grid; place-items:center;
|
| 60 |
+
background:#0d1a36; border:1px solid #2a395f;
|
| 61 |
+
transition:left .28s ease;
|
| 62 |
+
}
|
| 63 |
+
#panel.min + #toggle{ left:16px; }
|
| 64 |
|
| 65 |
+
#saveState{position:fixed; bottom:12px; left:calc(var(--panelW) + 12px); font-size:.8rem; border-radius:999px; padding:6px 10px; opacity:.9; z-index:4; transition:left .28s ease}
|
| 66 |
+
#panel.min ~ #stage #saveState, #panel.min ~ #saveState { left:28px; }
|
|
|
|
|
|
|
|
|
|
| 67 |
|
| 68 |
+
/* Pins (bigger + more transparent) */
|
| 69 |
+
.pin{
|
| 70 |
+
position:absolute; width:26px; height:26px; border-radius:50%;
|
| 71 |
+
background:rgba(255,255,255,.18); border:2px solid rgba(255,255,255,.45);
|
| 72 |
+
box-shadow:0 2px 10px rgba(0,0,0,.45); transform:translate(-50%, -50%); z-index:3;
|
| 73 |
+
}
|
| 74 |
+
.pin:hover{background:rgba(255,255,255,.26)}
|
| 75 |
+
|
| 76 |
+
/* Popups: centered exactly on the pin midpoint */
|
| 77 |
+
.popup{
|
| 78 |
+
position:absolute; z-index:4;
|
| 79 |
+
transform: translate(-50%, -50%); /* center on pin */
|
| 80 |
+
background:rgba(13,20,40,.92); border:1px solid #2a395f; border-radius:16px; box-shadow:var(--shadow);
|
| 81 |
+
padding:0; min-width:200px; max-width:min(40vw, 520px); backdrop-filter: blur(6px);
|
| 82 |
+
}
|
| 83 |
+
/* Make header overlay so media stays geometrically centered */
|
| 84 |
+
.popup header{
|
| 85 |
+
position:absolute; top:6px; right:6px; left:auto;
|
| 86 |
+
display:flex; align-items:center; gap:8px; margin:0; padding:0;
|
| 87 |
+
}
|
| 88 |
+
.popup h4{margin:0; font-size:.95rem; color:#d9e6ff; background:rgba(0,0,0,.35); padding:6px 10px; border-radius:10px}
|
| 89 |
+
.x{background:rgba(0,0,0,.35); border:1px solid #2a395f; color:#cfe0ff; font-size:16px; padding:6px 8px; border-radius:10px}
|
| 90 |
|
| 91 |
+
.media{display:block; width:100%; height:auto; border-radius:16px; overflow:hidden; background:#000}
|
| 92 |
+
.media video, .media img{display:block; width:100%; height:auto}
|
| 93 |
+
|
| 94 |
/* Items list */
|
| 95 |
.item{display:grid; grid-template-columns:auto 1fr auto; gap:8px; align-items:center; padding:8px; border:1px solid #21345d; border-radius:10px; margin:8px 0; background:#0e1834}
|
| 96 |
.item .name{font-size:.9rem}
|
|
|
|
| 173 |
<video id="bgVid" class="bgmedia" autoplay muted loop playsinline style="display:none"></video>
|
| 174 |
<div id="overlay" title="Click to place when in placement mode"></div>
|
| 175 |
<div id="stageMsg" style="display:none"></div>
|
|
|
|
| 176 |
</main>
|
| 177 |
+
|
| 178 |
+
<button id="saveState" class="btn-ghost">Saved</button>
|
| 179 |
</div>
|
| 180 |
|
| 181 |
<script>
|
|
|
|
| 314 |
}
|
| 315 |
|
| 316 |
function adjustPopupPosition(el){
|
| 317 |
+
// Keep centered popup fully within viewport by nudging
|
| 318 |
const rect = el.getBoundingClientRect();
|
| 319 |
const margin = 8; let dx=0, dy=0;
|
| 320 |
if (rect.left < margin) dx = margin - rect.left;
|
| 321 |
if (rect.right > innerWidth - margin) dx = (innerWidth - margin) - rect.right;
|
| 322 |
if (rect.top < margin) dy = margin - rect.top;
|
| 323 |
if (rect.bottom > innerHeight - margin) dy = (innerHeight - margin) - rect.bottom;
|
| 324 |
+
if (dx || dy) el.style.transform = `translate(calc(-50% + ${dx}px), calc(-50% + ${dy}px))`;
|
| 325 |
}
|
| 326 |
|
| 327 |
function renderItems(){
|
|
|
|
| 338 |
if (it.open){
|
| 339 |
const pop = document.createElement('div'); pop.className='popup';
|
| 340 |
pop.style.left = it.x+'%'; pop.style.top = it.y+'%'; pop.style.width = it.widthPct+'vw';
|
| 341 |
+
|
| 342 |
const header = document.createElement('header');
|
| 343 |
const h4 = document.createElement('h4'); h4.textContent = it.title || (it.type==='image'?'Image':'Video');
|
| 344 |
const close = document.createElement('button'); close.className='x'; close.innerHTML='×';
|
| 345 |
close.addEventListener('click', e=>{ e.stopPropagation(); it.open=false; renderItems(); });
|
| 346 |
header.append(h4, close); pop.appendChild(header);
|
| 347 |
+
|
| 348 |
const wrap = document.createElement('div'); wrap.className='media';
|
| 349 |
if (it.type==='video'){ const v = document.createElement('video'); v.src=it.src; v.controls=true; v.playsInline=true; wrap.appendChild(v); }
|
| 350 |
else { const img = document.createElement('img'); img.src=it.src; img.alt=it.title||'Image'; wrap.appendChild(img); }
|
| 351 |
+
pop.appendChild(wrap);
|
| 352 |
+
|
| 353 |
+
overlay.appendChild(pop);
|
| 354 |
requestAnimationFrame(()=>adjustPopupPosition(pop));
|
| 355 |
}
|
| 356 |
}
|
|
|
|
| 430 |
});
|
| 431 |
|
| 432 |
// Misc
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 433 |
window.addEventListener('resize', ()=>{
|
| 434 |
+
$$('.popup').forEach(el => {
|
| 435 |
+
el.style.transform='translate(-50%, -50%)';
|
| 436 |
+
requestAnimationFrame(()=>adjustPopupPosition(el));
|
| 437 |
+
});
|
| 438 |
});
|
| 439 |
stage.addEventListener('click', e => {
|
| 440 |
if (state.placingId) return; // placement handled on overlay
|