← back to Graphics Agentabrams
index.html
122 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>graphics.agentabrams.com</title>
<style>
* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
display: flex; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
background: #12141a; color: #e8e9ef; overflow: hidden;
}
/* ---- left panel ---- */
#panel {
width: 260px; min-width: 260px; height: 100%; display: flex; flex-direction: column;
background: linear-gradient(180deg, #1a1e28, #14171f);
border-right: 1px solid #2b3140;
}
#brand {
padding: 18px 16px 14px; border-bottom: 1px solid #2b3140;
}
#brand .dot { color: #5eead4; }
#brand h1 {
margin: 0; font-size: 13px; font-weight: 700; letter-spacing: 1.5px;
}
#brand .sub { font-size: 10px; opacity: .45; letter-spacing: 1px; margin-top: 4px; }
#list { flex: 1; overflow-y: auto; padding: 10px 8px; }
#list .dir { font-size: 10px; opacity: .4; letter-spacing: 1px; padding: 4px 8px 8px; }
.item {
display: block; width: 100%; text-align: left; cursor: pointer;
background: none; border: 1px solid transparent; border-radius: 8px;
color: #e8e9ef; font: inherit; padding: 9px 10px; margin-bottom: 2px;
}
.item:hover { background: #222839; }
.item.active { background: #2a3147; border-color: #3d4763; }
.item .fname { font-size: 13px; font-weight: 600; }
.item .fname::before { content: "▸ "; color: #5eead4; }
.item.active .fname::before { content: "▾ "; }
.item .fdesc { font-size: 10.5px; opacity: .5; margin-top: 3px; line-height: 1.4;
display: none; }
.item.active .fdesc { display: block; }
#panel footer {
padding: 12px 16px; border-top: 1px solid #2b3140; font-size: 10px; opacity: .4;
letter-spacing: .5px; line-height: 1.6;
}
/* ---- right panel ---- */
#stage { flex: 1; height: 100%; position: relative; background: #0e1016; }
#frame { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
#empty {
position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
flex-direction: column; gap: 10px; opacity: .35; font-size: 13px; letter-spacing: 1px;
}
#empty .big { font-size: 40px; }
/* ---- mobile ---- */
@media (max-width: 700px) {
body { flex-direction: column; }
#panel { width: 100%; min-width: 0; height: auto; max-height: 45%; }
#panel footer { display: none; }
}
</style>
</head>
<body>
<aside id="panel">
<div id="brand">
<h1><span class="dot">●</span> AGENT ABRAMS GRAPHICS</h1>
<div class="sub">graphics.agentabrams.com</div>
</div>
<nav id="list"><div class="dir">~/graphics/</div></nav>
<footer>zero dependencies · pure browser<br>more graphics landing over time</footer>
</aside>
<main id="stage">
<iframe id="frame" title="graphic" hidden></iframe>
<div id="empty"><div class="big">🎨</div><div>select a graphic</div></div>
</main>
<script>
(function () {
var list = document.getElementById('list');
var frame = document.getElementById('frame');
var empty = document.getElementById('empty');
var items = [], buttons = {};
function select(id, push) {
var g = items.find(function (x) { return x.id === id; });
if (!g) return;
Object.keys(buttons).forEach(function (k) { buttons[k].classList.toggle('active', k === id); });
frame.hidden = false; empty.style.display = 'none';
frame.src = g.path + 'index.html';
document.title = g.file + ' — graphics.agentabrams.com';
try { localStorage.setItem('aa-last-graphic', id); } catch (e) {}
if (push !== false) history.replaceState(null, '', '#' + id);
}
fetch('graphics.json').then(function (r) { return r.json(); }).then(function (data) {
items = data.graphics || [];
items.forEach(function (g) {
var b = document.createElement('button');
b.className = 'item';
b.innerHTML = '<div class="fname"></div><div class="fdesc"></div>';
b.querySelector('.fname').textContent = g.file;
b.querySelector('.fdesc').textContent = g.desc || '';
b.onclick = function () { select(g.id); };
list.appendChild(b);
buttons[g.id] = b;
});
var want = location.hash.replace('#', '');
if (!want) { try { want = localStorage.getItem('aa-last-graphic'); } catch (e) {} }
if (!want || !items.some(function (g) { return g.id === want; })) {
want = items.length ? items[0].id : null;
}
if (want) select(want, false);
});
addEventListener('hashchange', function () {
var id = location.hash.replace('#', '');
if (id) select(id, false);
});
})();
</script>
</body>
</html>