← 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>