Back

cull.papp

All 47 lines. No libraries, nothing hidden. Read it before you run it.

cull.papp
<!doctype html>
<meta charset="utf-8">
<meta name="papp-write" content=".">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect x='14' y='26' width='46' height='34' rx='5' fill='%23c4c7d4'/><rect x='4' y='16' width='46' height='36' rx='5' fill='%23111114'/><path d='M9 47l12-14 8 9 6-6 10 11z' fill='%23fff'/><circle cx='36' cy='26' r='4.5' fill='%23ff4f00'/></svg>">
<title>Cull</title>
<style>
  html, body { height: 100%; margin: 0; background: #0f0f11; color: #f2f2f3; font: 13px/1.4 system-ui, sans-serif; }
  img { display: block; width: 100%; height: 100%; object-fit: contain; }
  #bar { position: fixed; inset: 0 auto auto 0; height: 3px; background: #ff4f00; transition: width 0.2s; }
  p { position: fixed; bottom: 16px; margin: 0; padding: 7px 12px; border-radius: 99px; background: rgb(15 15 17 / 0.7); backdrop-filter: blur(12px); }
  #progress { left: 16px; font-variant-numeric: tabular-nums; }
  #keys { right: 16px; color: #9b9ba4; }
  kbd { padding: 0 5px; border: 1px solid #3a3a42; border-radius: 4px; color: #f2f2f3; font: 12px ui-monospace, monospace; }
</style>
<img id="photo" alt="">
<div id="bar"></div>
<p id="progress"></p>
<p id="keys"><kbd>→</kbd> keep · <kbd>←</kbd> reject · <kbd>Z</kbd> undo</p>
<script type="module">
  // → keeps the photo, ← moves it to ./rejects, Z takes back the last choice.
  const photos = (await papp.readdir('.')).filter(name => /\.(jpe?g|png|gif|webp)$/i.test(name)).sort();
  const choices = [];
  await papp.mkdir('rejects');
  show();

  addEventListener('keydown', async ({ key }) => {
    const name = photos[choices.length];
    if (key === 'ArrowRight' && name) {
      choices.push({ name, kept: true });
    } else if (key === 'ArrowLeft' && name) {
      choices.push({ name, kept: false });
      await papp.rename(name, `rejects/${name}`);
    } else if (key === 'z' && choices.length) {
      const last = choices.pop();
      if (!last.kept) await papp.rename(`rejects/${last.name}`, last.name);
    }
    show();
  });

  function show() {
    const name = photos[choices.length];
    const kept = choices.filter(choice => choice.kept).length;
    photo.src = name ? encodeURIComponent(name) : '';
    bar.style.width = `${(choices.length / photos.length) * 100}%`;
    progress.textContent = name ? `${choices.length + 1} / ${photos.length}, kept ${kept} · ${name}` : `Done. Kept ${kept} of ${photos.length}.`;
  }
</script>
Download cull.papp