« get me outta code hell

basic image overlays - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/static
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2023-02-26 17:44:53 -0400
committer(quasar) nebula <qznebula@protonmail.com>2023-02-26 17:59:10 -0400
commitae5f68ba51bbbe308cc56e70e70209652c869843 (patch)
tree87527a981c6131f2a40a07c8e8dbada39548bf2f /src/static
parentf36f93b702729f14021746d56b192b25ac3ed1b7 (diff)
basic image overlays
Diffstat (limited to 'src/static')
-rw-r--r--src/static/client.js74
-rw-r--r--src/static/site3.css82
2 files changed, 156 insertions, 0 deletions
diff --git a/src/static/client.js b/src/static/client.js
index 15f21fdb..9ae5510a 100644
--- a/src/static/client.js
+++ b/src/static/client.js
@@ -547,3 +547,77 @@ function updateStickyHeading() {
 document.addEventListener('scroll', updateStickyHeading);
 
 updateStickyHeading();
+
+// Image overlay ------------------------------------------
+
+function addImageOverlayClickHandlers() {
+  for (const img of document.querySelectorAll('.image-link')) {
+    img.addEventListener('click', handleImageLinkClicked);
+  }
+
+  const container = document.getElementById('image-overlay-container');
+  const actionContainer = document.getElementById('image-overlay-action-container');
+
+  container.addEventListener('click', handleContainerClicked);
+  document.body.addEventListener('keydown', handleKeyDown);
+
+  function handleContainerClicked(evt) {
+    // Only hide the image overlay if actually clicking the background.
+    if (evt.target !== container) {
+      return;
+    }
+
+    // If you clicked anything close to or beneath the action bar, don't hide
+    // the image overlay.
+    const rect = actionContainer.getBoundingClientRect();
+    if (evt.clientY >= rect.top - 40) {
+      return;
+    }
+
+    container.classList.remove('visible');
+  }
+
+  function handleKeyDown(evt) {
+    if (evt.key === 'Escape' || evt.key === 'Esc' || evt.keyCode === 27) {
+      container.classList.remove('visible');
+    }
+  }
+}
+
+function handleImageLinkClicked(evt) {
+  if (evt.metaKey || evt.shiftKey || evt.altKey) {
+    return;
+  }
+  evt.preventDefault();
+
+  const container = document.getElementById('image-overlay-container');
+  container.classList.add('visible');
+  container.classList.remove('loaded');
+  container.classList.remove('errored');
+
+  const viewOriginal = document.getElementById('image-overlay-view-original');
+  const mainImage = document.getElementById('image-overlay-image');
+  const thumbImage = document.getElementById('image-overlay-image-thumb');
+
+  const source = evt.target.closest('a').href;
+  mainImage.src = source.replace(/\.(jpg|png)$/, '.huge.jpg');
+  thumbImage.src = source.replace(/\.(jpg|png)$/, '.small.jpg');
+  viewOriginal.href = source;
+
+  mainImage.addEventListener('load', handleMainImageLoaded);
+  mainImage.addEventListener('error', handleMainImageErrored);
+
+  function handleMainImageLoaded() {
+    mainImage.removeEventListener('load', handleMainImageLoaded);
+    mainImage.removeEventListener('error', handleMainImageErrored);
+    container.classList.add('loaded');
+  }
+
+  function handleMainImageErrored() {
+    mainImage.removeEventListener('load', handleMainImageLoaded);
+    mainImage.removeEventListener('error', handleMainImageErrored);
+    container.classList.add('errored');
+  }
+}
+
+addImageOverlayClickHandlers();
diff --git a/src/static/site3.css b/src/static/site3.css
index cc853b65..7abb5351 100644
--- a/src/static/site3.css
+++ b/src/static/site3.css
@@ -1274,6 +1274,88 @@ main.long-content .content-sticky-heading-container .content-sticky-subheading-r
   contain: paint;
 }
 
+/* Image overlay */
+
+#image-overlay-container {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+
+  background: rgba(0, 0, 0, 0.8);
+  color: white;
+  padding: 20px 40px;
+  box-sizing: border-box;
+
+  opacity: 0;
+  pointer-events: none;
+  transition: opacity 0.4s;
+
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+}
+
+#image-overlay-container.visible {
+  opacity: 1;
+  pointer-events: auto;
+}
+
+#image-overlay-content-container {
+  border-radius: 0 0 8px 8px;
+  border: 2px solid var(--primary-color);
+  background: var(--dim-ghost-color);
+  padding: 3px;
+  overflow: hidden;
+
+  -webkit-backdrop-filter: blur(3px);
+          backdrop-filter: blur(3px);
+}
+
+#image-overlay-image-container {
+  display: block;
+  position: relative;
+  overflow: hidden;
+  width: 80vmin;
+  height: 80vmin;
+}
+
+#image-overlay-image,
+#image-overlay-image-thumb {
+  display: inline-block;
+  object-fit: contain;
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.65);
+}
+
+#image-overlay-image {
+  position: absolute;
+  top: 0;
+  left: 0;
+}
+
+#image-overlay-image-thumb {
+  filter: blur(16px);
+}
+
+#image-overlay-container.loaded #image-overlay-image-thumb {
+  opacity: 0;
+  pointer-events: none;
+  transition: opacity 0.25s;
+}
+
+#image-overlay-action-container {
+  padding: 8px 4px 6px 4px;
+  border-radius: 0 0 5px 5px;
+  background: var(--bg-black-color);
+  color: white;
+  font-style: oblique;
+  text-align: center;
+}
+
 /* important easter egg mode */
 
 html[data-language-code="preview-en"][data-url-key="localized.home"] #content