From 631547a75142326a7c71bdf123e1475217a5ad73 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Wed, 22 Apr 2026 12:42:56 +0200 Subject: chore: replace with extracted danix.xyz-hacker theme (danix2-hugo-theme) --- assets/js/photo-utils.js | 476 ----------------------------------------------- 1 file changed, 476 deletions(-) delete mode 100644 assets/js/photo-utils.js (limited to 'assets/js/photo-utils.js') diff --git a/assets/js/photo-utils.js b/assets/js/photo-utils.js deleted file mode 100644 index 32ede76..0000000 --- a/assets/js/photo-utils.js +++ /dev/null @@ -1,476 +0,0 @@ -(function() { - 'use strict'; - - // Internal state - let currentPhotoIndex = 0; - let photosData = []; - let isOpen = false; - let exifData = {}; - let options = { - swipeEnabled: true, - keyboardEnabled: true, - extractEXIF: true, - onOpen: null, - onClose: null, - }; - - // Lightbox DOM elements (created on first init) - let lightboxModal = null; - let lightboxImage = null; - let lightboxCaption = null; - let lightboxSidebar = null; - - /** - * Initialize lightbox for a photo collection - * @param {string} containerSelector - CSS selector for photo container - * @param {Array} photos - Array of photo objects: {src, alt, caption, location} - * @param {Object} opts - Options: {swipeEnabled, keyboardEnabled, extractEXIF, onOpen, onClose} - * @returns {Object} - {openLightbox, closeLightbox} - */ - function initLightbox(containerSelector, photos, opts = {}) { - photosData = photos; - options = { ...options, ...opts }; - - // Merge options with defaults - const container = document.querySelector(containerSelector); - if (!container) { - console.error('Photo container not found:', containerSelector); - return { openLightbox: () => {}, closeLightbox: () => {} }; - } - - // Attach click listeners to all figures in the container - const figures = container.querySelectorAll('figure[data-photo-index]'); - figures.forEach((figure) => { - figure.addEventListener('click', () => { - const index = parseInt(figure.dataset.photoIndex, 10); - openLightbox(index); - }); - }); - - // Return public API - return { - openLightbox, - closeLightbox, - }; - } - - /** - * Open lightbox to a specific photo - * @param {number} photoIndex - 0-based index into photosData array - */ - function openLightbox(photoIndex) { - if (photoIndex < 0 || photoIndex >= photosData.length) { - console.warn('Invalid photo index:', photoIndex); - return; - } - - currentPhotoIndex = photoIndex; - isOpen = true; - - // Create lightbox DOM if it doesn't exist - if (!lightboxModal) { - createLightboxDOM(); - } - - // Populate lightbox with current photo - updateLightboxContent(); - - // Show modal - lightboxModal.classList.add('visible'); - document.body.style.overflow = 'hidden'; - - // Extract EXIF if enabled - if (options.extractEXIF) { - extractEXIFForCurrentPhoto(); - } - - // Attach event listeners - attachEventListeners(); - - // Callback - if (options.onOpen) { - options.onOpen(photoIndex); - } - } - - /** - * Close lightbox - */ - function closeLightbox() { - if (!isOpen || !lightboxModal) return; - - isOpen = false; - lightboxModal.classList.remove('visible'); - document.body.style.overflow = ''; - - // Detach event listeners - detachEventListeners(); - - // Callback - if (options.onClose) { - options.onClose(); - } - } - - /** - * Create lightbox HTML structure and inject into DOM - */ - function createLightboxDOM() { - lightboxModal = document.createElement('div'); - lightboxModal.className = 'photo-lightbox'; - - lightboxModal.innerHTML = ` -
-
- - - - -
- -
-
- - - -
-
-
-
- `; - - document.body.appendChild(lightboxModal); - - // Cache element references - lightboxImage = lightboxModal.querySelector('.photo-lightbox-image'); - lightboxCaption = lightboxModal.querySelector('.photo-lightbox-caption'); - lightboxSidebar = lightboxModal.querySelector('.photo-lightbox-sidebar-content'); - - // Attach close button and backdrop click - lightboxModal.querySelector('.photo-lightbox-close').addEventListener('click', closeLightbox); - lightboxModal.querySelector('.photo-lightbox-backdrop').addEventListener('click', closeLightbox); - - // Attach navigation buttons - lightboxModal.querySelector('.photo-lightbox-prev').addEventListener('click', () => navigate(-1)); - lightboxModal.querySelector('.photo-lightbox-next').addEventListener('click', () => navigate(1)); - } - - /** - * Update lightbox content with current photo - */ - function updateLightboxContent() { - const photo = photosData[currentPhotoIndex]; - if (!photo) return; - - lightboxImage.src = photo.src; - lightboxImage.alt = photo.alt || ''; - - // Caption - if (photo.caption) { - lightboxCaption.textContent = photo.caption; - lightboxCaption.style.display = 'block'; - } else { - lightboxCaption.style.display = 'none'; - } - - // Update prev/next button states - const prevBtn = lightboxModal.querySelector('.photo-lightbox-prev'); - const nextBtn = lightboxModal.querySelector('.photo-lightbox-next'); - prevBtn.disabled = currentPhotoIndex === 0; - nextBtn.disabled = currentPhotoIndex === photosData.length - 1; - } - - /** - * Navigate to previous or next photo - * @param {number} direction - -1 for prev, 1 for next - */ - function navigate(direction) { - const newIndex = currentPhotoIndex + direction; - if (newIndex >= 0 && newIndex < photosData.length) { - currentPhotoIndex = newIndex; - updateLightboxContent(); - - // Reset EXIF data and re-extract if enabled - exifData = {}; - if (options.extractEXIF) { - extractEXIFForCurrentPhoto(); - } - } - } - - /** - * Extract EXIF data from current photo image element - */ - function extractEXIFForCurrentPhoto() { - extractEXIF(lightboxImage).then((data) => { - exifData = data; - updateSidebarContent(); - }); - } - - /** - * Update sidebar with EXIF and location data - */ - function updateSidebarContent() { - const photo = photosData[currentPhotoIndex]; - let sidebarHTML = ''; - - // Always show location if provided - if (photo.location) { - sidebarHTML += ` -
- - -
- `; - } - - // Show EXIF fields if available - if (Object.keys(exifData).length > 0) { - sidebarHTML += ` -
-
Camera
- `; - - if (exifData.camera) { - sidebarHTML += ` -
${exifData.camera}
- `; - } - if (exifData.lens) { - sidebarHTML += ` -
- - -
- `; - } - if (exifData.focalLength) { - sidebarHTML += ` -
- - -
- `; - } - if (exifData.aperture) { - sidebarHTML += ` -
- - -
- `; - } - if (exifData.shutterSpeed) { - sidebarHTML += ` -
- - -
- `; - } - if (exifData.iso) { - sidebarHTML += ` -
- - -
- `; - } - if (exifData.dateTaken) { - sidebarHTML += ` -
- - -
- `; - } - } - - // Show or hide sidebar based on whether there's content - const sidebarContainer = lightboxModal.querySelector('.photo-lightbox-sidebar'); - if (sidebarHTML) { - lightboxSidebar.innerHTML = sidebarHTML; - sidebarContainer.classList.add('visible'); - } else { - sidebarContainer.classList.remove('visible'); - } - } - - /** - * Extract EXIF data from an image element using exif-js library - * @param {HTMLImageElement} imageElement - Image to read EXIF from - * @returns {Promise} - Resolves to {camera, lens, iso, aperture, shutterSpeed, focalLength, dateTaken} - */ - function extractEXIF(imageElement) { - return new Promise((resolve) => { - // If exif-js is not loaded, return empty object - if (typeof EXIF === 'undefined') { - console.warn('exif-js library not loaded'); - resolve({}); - return; - } - - EXIF.getData(imageElement, function() { - const data = { - camera: EXIF.getTag(this, 'Model'), - lens: EXIF.getTag(this, 'LensModel'), - iso: EXIF.getTag(this, 'ISOSpeedRatings'), - aperture: formatAperture(EXIF.getTag(this, 'FNumber')), - shutterSpeed: formatShutterSpeed(EXIF.getTag(this, 'ExposureTime')), - focalLength: formatFocalLength(EXIF.getTag(this, 'FocalLength')), - dateTaken: EXIF.getTag(this, 'DateTime'), - }; - - // Filter out undefined values - Object.keys(data).forEach(key => { - if (data[key] === undefined) { - delete data[key]; - } - }); - - resolve(data); - }); - }); - } - - /** - * Format aperture value (f-number) - */ - function formatAperture(value) { - if (!value) return null; - if (typeof value === 'object' && value.numerator !== undefined) { - return `f/${(value.numerator / value.denominator).toFixed(1)}`; - } - return `f/${value}`; - } - - /** - * Format shutter speed (exposure time) - */ - function formatShutterSpeed(value) { - if (!value) return null; - if (typeof value === 'object' && value.numerator !== undefined) { - const speed = value.numerator / value.denominator; - if (speed >= 1) { - return `${speed.toFixed(1)}s`; - } - return `1/${Math.round(1 / speed)}`; - } - return value; - } - - /** - * Format focal length - */ - function formatFocalLength(value) { - if (!value) return null; - if (typeof value === 'object' && value.numerator !== undefined) { - return `${(value.numerator / value.denominator).toFixed(0)}mm`; - } - return `${value}mm`; - } - - /** - * Attach event listeners (swipe, keyboard, etc.) - */ - function attachEventListeners() { - if (options.swipeEnabled) { - attachSwipeListeners(); - } - if (options.keyboardEnabled) { - attachKeyboardListeners(); - } - } - - /** - * Detach event listeners to prevent memory leaks - */ - function detachEventListeners() { - if (options.swipeEnabled) { - detachSwipeListeners(); - } - if (options.keyboardEnabled) { - detachKeyboardListeners(); - } - } - - /** - * Touch swipe event listeners - */ - let swipeStartX = 0; - let swipeStartY = 0; - - function onTouchStart(e) { - swipeStartX = e.touches[0].clientX; - swipeStartY = e.touches[0].clientY; - } - - function onTouchEnd(e) { - const swipeEndX = e.changedTouches[0].clientX; - const swipeEndY = e.changedTouches[0].clientY; - const diffX = swipeEndX - swipeStartX; - const diffY = swipeEndY - swipeStartY; - - // Only consider horizontal swipe if delta-x > delta-y - if (Math.abs(diffX) > Math.abs(diffY) && Math.abs(diffX) > 50) { - if (diffX > 0) { - // Swiped right: go to previous - navigate(-1); - } else { - // Swiped left: go to next - navigate(1); - } - } - } - - function attachSwipeListeners() { - lightboxModal.addEventListener('touchstart', onTouchStart, false); - lightboxModal.addEventListener('touchend', onTouchEnd, false); - } - - function detachSwipeListeners() { - lightboxModal.removeEventListener('touchstart', onTouchStart, false); - lightboxModal.removeEventListener('touchend', onTouchEnd, false); - } - - /** - * Keyboard event listeners - */ - function onKeyDown(e) { - if (!isOpen) return; - - switch (e.key) { - case 'ArrowLeft': - navigate(-1); - e.preventDefault(); - break; - case 'ArrowRight': - navigate(1); - e.preventDefault(); - break; - case 'Escape': - closeLightbox(); - e.preventDefault(); - break; - default: - break; - } - } - - function attachKeyboardListeners() { - document.addEventListener('keydown', onKeyDown); - } - - function detachKeyboardListeners() { - document.removeEventListener('keydown', onKeyDown); - } - - // Expose public API - window.PhotoUtils = { - initLightbox, - extractEXIF, - openLightbox, - closeLightbox, - }; -})(); -- cgit v1.2.3