← back to Nova Recolor

draperies/index.html

144 lines

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Novasuede — Drapery Color Library (Reinhard)</title>
  <style>
    *{margin:0;padding:0;box-sizing:border-box}
    body{
      font-family:-apple-system,BlinkMacSystemFont,sans-serif;
      color:#fff;
      min-height:100vh;
      background:#1a1a1a;
      transition:background-image .3s ease;
      background-size:cover;
      background-position:center;
      background-repeat:no-repeat;
      background-attachment:fixed;
    }
    body.has-bg::before{
      content:"";
      position:fixed;inset:0;background:rgba(0,0,0,.35);z-index:-1;pointer-events:none;
    }
    header{padding:24px 28px 12px;background:rgba(0,0,0,.55);backdrop-filter:blur(8px);position:sticky;top:0;z-index:10;border-bottom:1px solid rgba(255,255,255,.08)}
    h1{font-size:22px;font-weight:600;letter-spacing:-.01em}
    .sub{font-size:13px;opacity:.75;margin-top:4px}
    .toolbar{display:flex;gap:12px;align-items:center;margin-top:14px;flex-wrap:wrap}
    .toolbar input{background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.18);color:#fff;padding:8px 12px;border-radius:8px;font:inherit;min-width:240px;outline:none}
    .toolbar input::placeholder{color:rgba(255,255,255,.5)}
    .toolbar button{background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.22);color:#fff;padding:8px 14px;border-radius:8px;font:inherit;cursor:pointer}
    .toolbar button:hover{background:rgba(255,255,255,.22)}
    .grid{
      display:grid;
      grid-template-columns:repeat(auto-fill,minmax(110px,1fr));
      gap:8px;
      padding:18px;
    }
    .chip{
      aspect-ratio:1.4/1;
      border-radius:10px;
      cursor:pointer;
      border:2px solid rgba(255,255,255,.22);
      transition:transform .12s, border-color .12s, box-shadow .15s;
      position:relative;
      overflow:hidden;
      box-shadow:0 1px 4px rgba(0,0,0,.4);
    }
    .chip:hover{transform:translateY(-2px);border-color:rgba(255,255,255,.6);box-shadow:0 6px 18px rgba(0,0,0,.5)}
    .chip.active{border-color:#fff;box-shadow:0 0 0 3px rgba(255,255,255,.55), 0 6px 18px rgba(0,0,0,.6)}
    .chip .label{
      position:absolute;left:0;right:0;bottom:0;padding:6px 8px;
      background:linear-gradient(transparent, rgba(0,0,0,.78));
      font-size:11px;font-weight:600;letter-spacing:.01em;
      text-shadow:0 1px 2px rgba(0,0,0,.7);text-transform:capitalize;
    }
    .status{position:fixed;left:18px;bottom:18px;padding:10px 14px;border-radius:10px;background:rgba(0,0,0,.7);backdrop-filter:blur(6px);font-size:13px;font-weight:600;letter-spacing:.01em;border:1px solid rgba(255,255,255,.18);min-width:180px}
    .status .name{font-size:15px;text-transform:capitalize;margin-bottom:2px}
    .status .meta{font-size:11px;opacity:.65;font-weight:400}
    .reset{position:fixed;right:18px;bottom:18px;padding:10px 16px;border-radius:10px;background:rgba(0,0,0,.7);backdrop-filter:blur(6px);font-size:13px;font-weight:600;border:1px solid rgba(255,255,255,.18);cursor:pointer;color:#fff}
    .reset:hover{background:rgba(0,0,0,.85)}
  </style>
</head>
<body>
  <header>
    <h1>Novasuede™ — Drapery Color Library</h1>
    <div class="sub">Click any color to set the full-bleed drapery as the page background. Reinhard color transfer applied to a single ruby drapery base across <span id="cnt">117</span> Novasuede colors.</div>
    <div class="toolbar">
      <input id="filter" type="search" placeholder="Filter colors…">
      <button id="random">Random</button>
    </div>
  </header>

  <div class="grid" id="grid"></div>

  <div class="status" id="status" style="display:none">
    <div class="name" id="status-name">—</div>
    <div class="meta" id="status-meta"></div>
  </div>

  <button class="reset" onclick="reset()">Reset</button>

  <script>
    let manifest = [];
    const grid = document.getElementById('grid');
    const status = document.getElementById('status');
    const statusName = document.getElementById('status-name');
    const statusMeta = document.getElementById('status-meta');

    fetch('manifest.json').then(r => r.json()).then(m => {
      manifest = m;
      document.getElementById('cnt').textContent = m.length;
      render(m);
    });

    function render(items){
      grid.innerHTML = '';
      items.forEach(it => {
        const chip = document.createElement('div');
        chip.className = 'chip';
        chip.style.background = it.hex;
        chip.dataset.slug = it.slug;
        chip.dataset.hex = it.hex;
        chip.dataset.drapery = it.drapery;
        chip.title = it.slug + ' · ' + it.hex;
        const label = document.createElement('div');
        label.className = 'label';
        label.textContent = it.slug.replace(/-/g, ' ');
        chip.appendChild(label);
        chip.addEventListener('click', () => activate(chip));
        grid.appendChild(chip);
      });
    }

    function activate(chip){
      document.querySelectorAll('.chip.active').forEach(c => c.classList.remove('active'));
      chip.classList.add('active');
      const url = chip.dataset.drapery;
      document.body.classList.add('has-bg');
      document.body.style.backgroundImage = 'url("' + url + '")';
      statusName.textContent = chip.dataset.slug.replace(/-/g, ' ');
      statusMeta.textContent = chip.dataset.hex + ' · ' + url;
      status.style.display = 'block';
    }

    function reset(){
      document.querySelectorAll('.chip.active').forEach(c => c.classList.remove('active'));
      document.body.classList.remove('has-bg');
      document.body.style.backgroundImage = '';
      status.style.display = 'none';
    }

    document.getElementById('filter').addEventListener('input', e => {
      const q = e.target.value.trim().toLowerCase();
      const filtered = !q ? manifest : manifest.filter(m => m.slug.includes(q));
      render(filtered);
    });

    document.getElementById('random').addEventListener('click', () => {
      const chips = document.querySelectorAll('.chip');
      if (chips.length) activate(chips[Math.floor(Math.random()*chips.length)]);
    });
  </script>
</body>
</html>