Skip to content

Commit dd4d445

Browse files
Andyyesiyuclaude
andauthored
Add click-to-zoom lightbox for article figures (#21)
Clicking a figure on the survey or RSIHub page opens it full-screen on a dark backdrop; a click or Escape closes, and Enter/Space work from the keyboard with focus returned to the figure. The enlarged image keeps the white plate padding so transparent SVGs stay legible. Claude-Session: https://claude.ai/code/session_01HZxZsJ6KCnffNAfu8WxquU Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5aea1fa commit dd4d445

2 files changed

Lines changed: 81 additions & 0 deletions

File tree

‎assets/site.js‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,58 @@
7474

7575
setLanguage(root.dataset.lang === "zh" ? "zh" : "en", false);
7676
setTheme(root.dataset.theme === "dark" ? "dark" : "light", false);
77+
78+
var zoomableImages = document.querySelectorAll(
79+
".project-page figure img, .showcase-grid figure img"
80+
);
81+
var lightbox = null;
82+
var lightboxTrigger = null;
83+
84+
function closeLightbox() {
85+
if (!lightbox) return;
86+
lightbox.remove();
87+
lightbox = null;
88+
document.body.style.overflow = "";
89+
if (lightboxTrigger) lightboxTrigger.focus();
90+
lightboxTrigger = null;
91+
}
92+
93+
function openLightbox(image) {
94+
closeLightbox();
95+
lightboxTrigger = image;
96+
lightbox = document.createElement("div");
97+
lightbox.className = "lightbox";
98+
lightbox.setAttribute("role", "dialog");
99+
lightbox.setAttribute("aria-modal", "true");
100+
lightbox.setAttribute("aria-label", image.alt || "Enlarged image");
101+
lightbox.tabIndex = -1;
102+
103+
var enlarged = document.createElement("img");
104+
enlarged.src = image.currentSrc || image.src;
105+
enlarged.alt = image.alt || "";
106+
lightbox.appendChild(enlarged);
107+
108+
lightbox.addEventListener("click", closeLightbox);
109+
document.body.appendChild(lightbox);
110+
document.body.style.overflow = "hidden";
111+
lightbox.focus();
112+
}
113+
114+
Array.prototype.forEach.call(zoomableImages, function (image) {
115+
image.tabIndex = 0;
116+
image.setAttribute("role", "button");
117+
image.addEventListener("click", function () {
118+
openLightbox(image);
119+
});
120+
image.addEventListener("keydown", function (event) {
121+
if (event.key === "Enter" || event.key === " ") {
122+
event.preventDefault();
123+
openLightbox(image);
124+
}
125+
});
126+
});
127+
128+
document.addEventListener("keydown", function (event) {
129+
if (event.key === "Escape") closeLightbox();
130+
});
77131
})();

‎assets/styles.css‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,3 +455,30 @@ footer a:hover { color: var(--fg); }
455455
html { scroll-behavior: auto; }
456456
.masthead-mark { animation: none; }
457457
}
458+
459+
/* Click-to-zoom lightbox: article figures open full-screen; a click or
460+
Escape closes. The white padding keeps transparent-background SVGs
461+
legible on the dark backdrop, matching the .plate treatment. */
462+
.project-page figure img,
463+
.showcase-grid figure img { cursor: zoom-in; }
464+
.lightbox {
465+
position: fixed;
466+
inset: 0;
467+
z-index: 100;
468+
display: flex;
469+
align-items: center;
470+
justify-content: center;
471+
padding: 24px;
472+
background: rgba(10, 12, 11, 0.85);
473+
cursor: zoom-out;
474+
}
475+
.lightbox img {
476+
max-width: 100%;
477+
max-height: 100%;
478+
width: auto;
479+
height: auto;
480+
padding: 12px;
481+
background: #fff;
482+
border-radius: 10px;
483+
box-shadow: 0 18px 60px rgba(0, 0, 0, 0.45);
484+
}

0 commit comments

Comments
 (0)