<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Tanishq Dubey Photography</title> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Mono:wght@100..900&display=swap" rel="stylesheet"> <style> body { margin: 0; padding: 0; font-family: Arial, sans-serif; background-color: #f0f0f0; display: flex; flex-direction: row; } .main-content { flex-grow: 1; padding: 20px; } .grid-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(10px, 1fr)); grid-auto-rows: 10px; grid-auto-flow: dense; gap: 15px; max-width: 100%; box-sizing: border-box; } .polaroid { position: relative; background-color: #e8e8ea; box-shadow: 0 0 2px 0 #f4f4f6 inset, 1px 5px 5px 0px #99999955; border-radius: 2px; padding: 10px; display: flex; flex-direction: column; align-items: center; transition: background-color 0.3s ease; max-width: 100%; box-sizing: border-box; } .polaroid img { max-width: 100%; height: auto; display: block; flex-grow: 1; object-fit: contain; transition: opacity 0.3s ease; } .date-overlay { position: absolute; bottom: 4rem; font-size: 1rem; right: 1rem; text-align: right; color: #ec5a11; font-family: "Noto Sans Mono", monospace; font-size: 0.7rem; opacity: 0; text-shadow: 0 0 2px #ec5a11; transition: opacity 0.3s ease; } .polaroid:hover .date-overlay { opacity: 0.8; } .polaroid .caption { margin-top: 10px; display: block; flex-grow: 0; flex-shrink: 1; flex-basis: auto; align-self: flex-end; order: 0; text-align: right; line-height: 70%; font-size: 0.75rem; } .noto-sans-mono-font { font-family: "Noto Sans Mono", monospace; font-optical-sizing: auto; font-weight: 400; font-style: normal; font-variation-settings: "wdth" 100; } .sidebar { min-width: 20rem; background-color: #f0f0f0; padding: 20px; box-sizing: border-box; position: sticky; top: 0; height: 100vh; overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; } .sidebar-title { font-size: 1rem; text-align: right; } .sidebar-nav { font-size: 1rem; flex-grow: 1; justify-content: center; text-align: right; } .sidebar-nav ul { list-style-type: none; padding: 0; } .sidebar-nav a { text-decoration: none; color: {{ accent_color }}; } @media (max-width: 768px) { .main-content { padding: 10px; } .grid-container { display: flex; flex-direction: column; gap: 20px; } .polaroid { width: 100%; max-width: 100vw; height: auto; } } @media (max-width: 1024px) { body { flex-direction: column; } .sidebar { width: 100%; height: auto; position: static; padding: 10px; } } </style> </head> <body> <div class="sidebar"> <div class="sidebar-nav noto-sans-mono-font"> <nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> <!-- divider line --> <li><hr></li> <li>Powered by <a href="https://dws.rip">DWS</a></li> </ul> </nav> </div> <div class="sidebar-title noto-sans-mono-font"> <h1>Tanishq Dubey Photography</h1> </div> </div> <div class="main-content"> <div class="grid-container" id="polaroid-grid"></div> <div id="loading">Loading more images...</div> </div> <script> const gridContainer = document.getElementById('polaroid-grid'); const loadingIndicator = document.getElementById('loading'); const baseSize = 110; // Size of one grid cell in pixels let page = 1; let isLoading = false; let hasMore = true; function createPolaroid(polaroid) { const polaroidElement = document.createElement('div'); polaroidElement.className = 'polaroid'; if (polaroid.height > polaroid.width) { polaroidElement.classList.add('vertical'); } polaroidElement.style.backgroundColor = `${polaroid.highlightColor}33`; const img = document.createElement('img'); img.alt = polaroid.caption; img.setAttribute('data-original-width', polaroid.width); img.setAttribute('data-original-height', polaroid.height); img.setAttribute('data-base-src', polaroid.imgSrc); img.src = polaroid.imgSrc; img.onload = () => loadOptimalThumbnail(img); // Load optimal thumbnail after initial load const dateOverlay = document.createElement('div'); dateOverlay.className = 'date-overlay'; dateOverlay.textContent = polaroid.date; const caption = document.createElement('div'); caption.className = 'caption noto-sans-mono-font'; caption.textContent = polaroid.technicalInfo; polaroidElement.appendChild(img); polaroidElement.appendChild(dateOverlay); polaroidElement.appendChild(caption); return polaroidElement; } function calculateGridSpan(dimension) { return Math.ceil(dimension / baseSize); } function positionPolaroid(polaroidElement, polaroid) { const width = calculateGridSpan(polaroid.width + 20); // Add 20px for padding const height = calculateGridSpan(polaroid.height + 40) + 1; // Add 40px for padding and caption polaroidElement.style.gridColumnEnd = `span ${width}`; polaroidElement.style.gridRowEnd = `span ${height}`; } function getOptimalThumbnailSize(width, height) { const sizes = [256, 512, 768, 1024, 1536, 2048]; const maxDimension = Math.max(width, height); return sizes.find(size => size >= maxDimension) || sizes[sizes.length - 1]; } function loadOptimalThumbnail(img) { // Use a small delay to ensure the image has rendered setTimeout(() => { const containerWidth = img.offsetWidth; const containerHeight = img.offsetHeight; const devicePixelRatio = window.devicePixelRatio || 1; // If dimensions are still 0, use the original image dimensions const width = containerWidth || parseInt(img.getAttribute('data-original-width')); const height = containerHeight || parseInt(img.getAttribute('data-original-height')); const optimalSize = getOptimalThumbnailSize( width * devicePixelRatio, height * devicePixelRatio ); const newSrc = img.getAttribute('data-base-src').replace('1536_', `${optimalSize}_`); if (newSrc !== img.src) { const tempImg = new Image(); tempImg.onload = function() { img.src = newSrc; img.style.opacity = 1; }; tempImg.src = newSrc; img.style.opacity = 0.5; } }, 100); // 100ms delay } function handleResize() { const polaroids = document.querySelectorAll('.polaroid'); polaroids.forEach(polaroid => { const img = polaroid.querySelector('img'); const width = parseInt(img.getAttribute('data-original-width')); const height = parseInt(img.getAttribute('data-original-height')); positionPolaroid(polaroid, { width, height }); loadOptimalThumbnail(img); }); } async function loadImages() { if (isLoading || !hasMore) return; isLoading = true; loadingIndicator.style.display = 'block'; try { const response = await fetch(`/api/images?page=${page}`); const data = await response.json(); data.images.forEach(polaroid => { const polaroidElement = createPolaroid(polaroid); positionPolaroid(polaroidElement, polaroid); gridContainer.appendChild(polaroidElement); // loadOptimalThumbnail is now called in the img.onload event }); hasMore = data.hasMore; page++; } catch (error) { console.error('Error loading images:', error); } finally { isLoading = false; loadingIndicator.style.display = 'none'; } } function handleScroll() { if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 500) { loadImages(); } } window.addEventListener('scroll', handleScroll); window.addEventListener('resize', handleResize); loadImages(); // Initial load </script> </body> </html>