Add lightbox to snapshot gallery and diff pages
Closes #6

Assisted-by: Claude Opus 4.6 via pi
change ulnrvykuzzqorplmqlzpsllxrunsxkup
commit a4f89fd7b6777dfd59246c6810563024f6d77d6c
author Alpha Chen <alpha@kejadlen.dev>
date
parent opmlkssn
diff --git a/templates/snapshot_diff.erb b/templates/snapshot_diff.erb
index c1853bd..2c6d28d 100644
--- a/templates/snapshot_diff.erb
+++ b/templates/snapshot_diff.erb
@@ -51,6 +51,7 @@
     <% end %>
   </div>
   <% end -%>
+  <div class="lightbox" id="lightbox"><img></div>
   <script>
     document.querySelector(".tab-bar").addEventListener("click", function(e) {
       if (!e.target.matches(".tab")) return;
@@ -58,6 +59,19 @@
       document.querySelectorAll(".tab").forEach(function(t) { t.classList.toggle("active", t.dataset.viewport === viewport); });
       document.querySelectorAll(".viewport-group").forEach(function(g) { g.classList.toggle("hidden", g.dataset.viewport !== viewport); });
     });
+
+    var lightbox = document.getElementById("lightbox");
+    document.addEventListener("click", function(e) {
+      if (e.target.matches(".snapshot img, .side img")) {
+        lightbox.querySelector("img").src = e.target.src;
+        lightbox.classList.add("open");
+      } else if (lightbox.classList.contains("open")) {
+        lightbox.classList.remove("open");
+      }
+    });
+    document.addEventListener("keydown", function(e) {
+      if (e.key === "Escape") lightbox.classList.remove("open");
+    });
   </script>
 </body>
 </html>
diff --git a/templates/snapshot_gallery.erb b/templates/snapshot_gallery.erb
index f585a95..2d85782 100644
--- a/templates/snapshot_gallery.erb
+++ b/templates/snapshot_gallery.erb
@@ -25,6 +25,7 @@
     <% end %>
   </div>
   <% end -%>
+  <div class="lightbox" id="lightbox"><img></div>
   <script>
     document.querySelector(".tab-bar").addEventListener("click", function(e) {
       if (!e.target.matches(".tab")) return;
@@ -32,6 +33,19 @@
       document.querySelectorAll(".tab").forEach(function(t) { t.classList.toggle("active", t.dataset.viewport === viewport); });
       document.querySelectorAll(".viewport-group").forEach(function(g) { g.classList.toggle("hidden", g.dataset.viewport !== viewport); });
     });
+
+    var lightbox = document.getElementById("lightbox");
+    document.addEventListener("click", function(e) {
+      if (e.target.matches(".snapshot img")) {
+        lightbox.querySelector("img").src = e.target.src;
+        lightbox.classList.add("open");
+      } else if (lightbox.classList.contains("open")) {
+        lightbox.classList.remove("open");
+      }
+    });
+    document.addEventListener("keydown", function(e) {
+      if (e.key === "Escape") lightbox.classList.remove("open");
+    });
   </script>
 </body>
 </html>
diff --git a/templates/snapshots.css b/templates/snapshots.css
index 1256ba5..ab32ae4 100644
--- a/templates/snapshots.css
+++ b/templates/snapshots.css
@@ -33,3 +33,11 @@ h1 { margin-bottom: var(--space-l); color: #fff; }
 .side img { max-width: 100%; border: 1px solid #333; border-radius: 4px; display: block; margin-inline: auto; }
 
 .placeholder { padding: var(--space-xl); text-align: center; color: #666; border: 1px dashed #333; border-radius: 4px; }
+
+/* Lightbox */
+
+.snapshot img { cursor: zoom-in; }
+
+.lightbox { display: none; position: fixed; inset: 0; z-index: 1000; background: rgba(0,0,0,0.9); cursor: zoom-out; justify-content: center; align-items: center; padding: var(--space-s); }
+.lightbox.open { display: flex; }
+.lightbox img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 4px; }