@@ -86,6 +86,88 @@ const ogImageUrl = image?.src;
8686
8787 pre.replaceWith(div);
8888 });
89+
90+ // Create lightbox overlay
91+ const lightbox = document.createElement('div');
92+ lightbox.className = 'lightbox-overlay';
93+ lightbox.innerHTML = `
94+ <div class="lightbox-header">
95+ <span class="lightbox-title">Full-size image</span>
96+ <span class="lightbox-hint">Click outside or press Esc to close</span>
97+ </div>
98+ <div class="lightbox-container">
99+ <img src="" alt="" />
100+ </div >
101+ <button class =" lightbox-close" aria-label =" Close" >× </button >
102+ <div class =" lightbox-footer" >
103+ <span >Click anywhere outside the image to close</span >
104+ </div >
105+ `;
106+ document.body.appendChild(lightbox);
107+
108+ const lightboxImg = lightbox.querySelector('.lightbox-container img');
109+ const closeBtn = lightbox.querySelector('.lightbox-close');
110+ const container = lightbox.querySelector('.lightbox-container');
111+
112+ // Close lightbox on overlay click (but not container), close button, or Escape key
113+ lightbox.addEventListener('click', (e) => {
114+ if (e .target === lightbox || e .target === closeBtn || e .target .closest (' .lightbox-header' ) || e .target .closest (' .lightbox-footer' )) {
115+ lightbox .classList .remove (' active' );
116+ }
117+ } );
118+ // Prevent closing when clicking the container
119+ container.addEventListener('click', (e) => e.stopPropagation());
120+ document.addEventListener('keydown', (e) => {
121+ if (e .key === ' Escape' ) lightbox .classList .remove (' active' );
122+ } );
123+
124+ // Get the current post slug from the URL
125+ const pathParts = window.location.pathname.split('/').filter(Boolean);
126+ const slug = pathParts[pathParts.length - 1] || pathParts[pathParts.length - 2];
127+
128+ // Make prose images clickable to open lightbox with original
129+ document.querySelectorAll('.prose img').forEach((img) => {
130+ // Skip if already wrapped in a link
131+ if (img .parentElement ?.tagName === ' A' ) return ;
132+
133+ img .addEventListener (' click' , () => {
134+ // Extract the filename from the optimized src
135+ const src = img .getAttribute (' src' ) || ' ' ;
136+ const alt = img .getAttribute (' alt' ) || ' ' ;
137+
138+ // Try to find the original image
139+ // The optimized path is like /_astro/filename.hash.webp
140+ // We need to map it back to /originals/YEAR/SLUG/filename.png
141+ const match = src .match (/ \/ _astro\/ ([^ . ] + )\. / );
142+ if (match ) {
143+ const baseName = match [1 ];
144+ // Try common extensions
145+ const year = window .location .pathname .match (/ \/ (\d {4} )\/ / )?.[1 ];
146+ if (year && slug ) {
147+ // Try to load the original
148+ const originalPath = ` /originals/${year }/${slug }/${baseName }.png ` ;
149+ lightboxImg .src = originalPath ;
150+ lightboxImg .alt = alt ;
151+ lightbox .classList .add (' active' );
152+
153+ // Fallback to optimized if original fails
154+ lightboxImg .onerror = () => {
155+ // Try jpg
156+ lightboxImg .src = ` /originals/${year }/${slug }/${baseName }.jpg ` ;
157+ lightboxImg .onerror = () => {
158+ // Fall back to optimized version
159+ lightboxImg .src = src ;
160+ };
161+ };
162+ }
163+ } else {
164+ // Use the src as-is if we can't parse it
165+ lightboxImg .src = src ;
166+ lightboxImg .alt = alt ;
167+ lightbox .classList .add (' active' );
168+ }
169+ });
170+ } );
89171 </script >
90172
91173 <blockquote class =" mt-12 border-l-4 border-primary bg-background-2 rounded-r-lg p-6 text-center" >
0 commit comments