← back to Domain Landings
wall: add per-chip open-in-new-window control (↗ open button + meta ↗ link)
e79003b9ff3db423d68f1447f5d5650f6fecc310 · 2026-08-17 17:22:27 -0700 · Steve
Files touched
Diff
commit e79003b9ff3db423d68f1447f5d5650f6fecc310
Author: Steve <steve@designerwallcoverings.com>
Date: Mon Aug 17 17:22:27 2026 -0700
wall: add per-chip open-in-new-window control (↗ open button + meta ↗ link)
---
server.js | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/server.js b/server.js
index ad240e0..0533709 100644
--- a/server.js
+++ b/server.js
@@ -214,6 +214,10 @@ input[type=range]{width:150px}
.ph{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#484f58;font-size:12px;text-align:center;padding:8px}
.live{position:absolute;top:6px;right:6px;background:#1f6febcc;color:#fff;font-size:9px;padding:2px 7px;border-radius:999px;opacity:0;transition:.15s}
.frame:hover .live{opacity:1}
+.openbtn{position:absolute;top:6px;left:6px;background:#238636dd;color:#fff;border:0;font-size:9px;font-family:inherit;padding:2px 8px;border-radius:999px;cursor:pointer;opacity:.9;transition:.15s;z-index:3}
+.openbtn:hover{background:#2ea043;opacity:1}
+.meta a.open{color:#8b949e;text-decoration:none;font-size:12px;padding:0 2px;flex:0 0 auto}
+.meta a.open:hover{color:#7ee787}
.meta{padding:9px 11px;display:flex;justify-content:space-between;align-items:center;gap:8px}
.dom{font-weight:600;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dom a{color:#e6edf3;text-decoration:none}.dom a:hover{color:#58a6ff}
@@ -266,11 +270,15 @@ function render(){
grid.innerHTML=list.map(s=>'<div class=card><div class=frame data-dom="'+s.domain+'" data-fr="'+s.fr+'" title="'+(s.fr?'click for live view':'this site blocks embedding — click to open')+'">'+
(s.th?'<img loading=lazy src="/thumbs/'+s.domain+'.jpg" onerror="this.style.display=\\'none\\';this.nextElementSibling.style.display=\\'flex\\'">':'')+
'<div class=ph'+(s.th?' style=display:none':'')+'>'+s.domain+'<br><small>(no preview — click for live)</small></div>'+
- '<span class=live>▶ live</span></div>'+
+ '<span class=live>▶ live</span>'+
+ '<button class=openbtn data-url="https://'+s.domain+'/" title="open '+s.domain+' in a new window">↗ open</button></div>'+
'<div class=meta><span class=dom><a href="https://'+s.domain+'/" target=_blank rel=noopener>'+s.domain+'</a></span>'+
+ '<a class=open href="https://'+s.domain+'/" target=_blank rel=noopener title="open in a new window">↗</a>'+
'<span class="badge b-'+s.type+'">'+s.type+'</span></div></div>').join('');
grid.querySelectorAll('.frame').forEach(f=>{f.addEventListener('click',()=>goLive(f));
if(LIVE.has(f.dataset.dom)){f.dataset.live='';goLive(f);}}); // restore live iframes after re-render
+ // explicit open-in-new-window per chip (bypasses the click-to-iframe hijack; the reliable escape hatch for sites that refuse embedding)
+ grid.querySelectorAll('.openbtn').forEach(b=>b.addEventListener('click',e=>{e.stopPropagation();window.open(b.dataset.url,'_blank','noopener');}));
applyDens();
}
sortEl.onchange=()=>{localStorage.setItem('wall_sort',sortEl.value);render()};
← df81e89 chore: refactor (checkBasicAuth helper), v0.2.0 (session clo
·
back to Domain Landings
·
wall: add liveness-probe report (cert-mismatch = the 'dead s 11a4a85 →