diff options
Diffstat (limited to 'src/static')
-rw-r--r-- | src/static/client.js | 74 | ||||
-rw-r--r-- | src/static/site3.css | 82 |
2 files changed, 156 insertions, 0 deletions
diff --git a/src/static/client.js b/src/static/client.js index 4eb1d2ba..47936d82 100644 --- a/src/static/client.js +++ b/src/static/client.js @@ -622,3 +622,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 c522bc9d..449e6fad 100644 --- a/src/static/site3.css +++ b/src/static/site3.css @@ -1326,6 +1326,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 |