← back to Dot Palette

public/index.html

92 lines

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>dot-palette</title>
<style>
  :root { color-scheme: dark; }
  * { box-sizing: border-box; -webkit-user-select: none; user-select: none; }
  html, body { margin: 0; height: 100%; background: #14161a; overflow: hidden;
    font: 12px -apple-system, system-ui, sans-serif; color: #cbd2da; }
  #bar { display: flex; align-items: center; gap: 6px; height: 100%; padding: 0 8px; }
  /* Left grip: the drag handle (the window is non-activating, so we move it via IPC deltas). */
  #grip { cursor: grab; color: #4a525c; font-size: 13px; letter-spacing: -2px; padding: 0 2px; }
  #grip:active { cursor: grabbing; }
  .chip { width: 30px; height: 30px; border-radius: 50%; border: 2px solid rgba(255,255,255,.14);
    display: flex; align-items: center; justify-content: center; font-size: 15px; cursor: pointer;
    transition: transform .08s ease, box-shadow .12s ease; }
  .chip:hover { transform: scale(1.12); }
  .chip:active { transform: scale(.92); }
  .chip.ok { box-shadow: 0 0 0 3px rgba(255,255,255,.85); }
  .chip.bad { box-shadow: 0 0 0 3px #ff3b30; }
  #x { margin-left: 2px; color: #565e69; cursor: pointer; font-size: 14px; padding: 0 3px; }
  #x:hover { color: #ff5b52; }
</style>
</head>
<body>
  <div id="bar">
    <div id="grip" title="drag to move">⠿</div>
    <div id="chips"></div>
    <div id="x" title="close palette">×</div>
  </div>
  <script>
    const CHIPS = [
      { c: 'green',     bg: '#00c853', em: '🟢', name: 'WORKING' },
      { c: 'yellow',    bg: '#ffcc00', em: '🟡', name: 'DIRECTION?' },
      { c: 'orange',    bg: '#ff8c00', em: '🟠', name: 'PASTE waiting' },
      { c: 'purple',    bg: '#9400d3', em: '🟣', name: 'GATED' },
      { c: 'lightblue', bg: '#00b0f0', em: '🔵', name: 'NEEDS STEVE' },
      { c: 'pink',      bg: '#ff69b4', em: '🩷', name: 'PARKED' },
    ];
    const chipsEl = document.getElementById('chips');
    chipsEl.style.display = 'flex';
    chipsEl.style.gap = '6px';

    for (const k of CHIPS) {
      const el = document.createElement('div');
      el.className = 'chip';
      el.textContent = k.em;
      el.style.background = k.bg + '22';       // faint fill; the ring + emoji carry the colour
      el.style.borderColor = k.bg;
      el.title = k.c + ' — ' + k.name;
      el.addEventListener('click', async () => {
        try {
          const r = await fetch('/api/setdot', {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ color: k.c }),
          });
          const j = await r.json();
          el.classList.remove('ok', 'bad');
          void el.offsetWidth;                 // restart the CSS transition
          el.classList.add(j.ok ? 'ok' : 'bad');
          el.title = j.ok ? (k.c + ' — set on ' + j.tty) : (k.c + ' — ' + (j.error || 'failed'));
          setTimeout(() => el.classList.remove('ok', 'bad'), 650);
        } catch (e) {
          el.classList.add('bad');
          setTimeout(() => el.classList.remove('bad'), 650);
        }
      });
      chipsEl.appendChild(el);
    }

    // Drag-to-move: the panel is focusable:false so native title-bar drag won't fire;
    // track pointer deltas on the grip and nudge the window via the main process.
    const grip = document.getElementById('grip');
    let dragging = false, lastX = 0, lastY = 0;
    grip.addEventListener('pointerdown', (e) => {
      dragging = true; lastX = e.screenX; lastY = e.screenY;
      grip.setPointerCapture(e.pointerId); e.preventDefault();
    });
    grip.addEventListener('pointermove', (e) => {
      if (!dragging) return;
      const dx = e.screenX - lastX, dy = e.screenY - lastY;
      lastX = e.screenX; lastY = e.screenY;
      if (dx || dy) window.palette?.move?.(dx, dy);   // no-op if the IPC bridge is absent (e.g. opened in a plain browser)
    });
    grip.addEventListener('pointerup', (e) => { dragging = false; try { grip.releasePointerCapture(e.pointerId); } catch {} });

    document.getElementById('x').addEventListener('click', () => window.palette?.quit?.());  // guarded: harmless if no IPC bridge
  </script>
</body>
</html>