Implement progressive image loading in generateSite.js and enhance image serving with quality and width parameters. Added sharp dependency for image processing. Updated image display logic to improve user experience.

This commit is contained in:
Knight 2024-12-28 10:58:05 -05:00
parent ba39cb4af7
commit d575fd58e2
2 changed files with 66 additions and 7 deletions

View File

@ -47,13 +47,48 @@ async function generateSite() {
<title>${image.description || `Image ${i + 1}`}</title>
<link rel="stylesheet" href="/styles.css">
<link rel="icon" type="image/png" href="/favicon.png">
<style>
.progressive-image-container {
position: relative;
overflow: hidden;
}
.progressive-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: opacity 0.5s ease-in-out;
}
.thumbnail {
filter: blur(10px);
transform: scale(1.1);
}
.full-image {
opacity: 0;
}
.full-image.loaded {
opacity: 1;
}
</style>
</head>
<body>
<div class="image-container">
${image?.localPath || 'No image URL available'
? `<img src="${image?.localPath || 'No image URL available'}" alt="${image.metadata.description || ''}">`
: '<p>Image not available</p>'
}
${image?.localPath ? `
<div class="progressive-image-container">
<img
class="progressive-image thumbnail"
src="${image.localPath}?quality=10&width=50"
alt="${image.metadata.description || ''}"
>
<img
class="progressive-image full-image"
src="${image.localPath}"
alt="${image.metadata.description || ''}"
onload="this.classList.add('loaded')"
>
</div>
` : '<p>Image not available</p>'}
${image.description ? `<p class="description">${image.description}</p>` : ''}
<div class="navigation">
<a href="${prevFileName}"></a>
@ -86,11 +121,34 @@ async function generateSite() {
async function serveStaticSite(port = 3000) {
const server = http.createServer(async (req, res) => {
try {
// Parse URL and query parameters
const url = new URL(req.url, `http://localhost:${port}`);
const quality = url.searchParams.get('quality');
const width = url.searchParams.get('width');
// Convert URL to filesystem path
let filePath;
if (req.url.startsWith('/images/')) {
if (url.pathname.startsWith('/images/')) {
// Serve directly from images folder
filePath = req.url.slice(1); // Remove leading slash
filePath = url.pathname.slice(1); // Remove leading slash
// If quality parameter is present, serve a resized version
if (quality && width && (filePath.endsWith('.jpg') || filePath.endsWith('.jpeg') || filePath.endsWith('.png'))) {
try {
const Sharp = (await import('sharp')).default;
const image = await Sharp(filePath)
.resize(parseInt(width))
.jpeg({ quality: parseInt(quality) })
.toBuffer();
res.writeHead(200, { 'Content-Type': 'image/jpeg' });
res.end(image);
return;
} catch (error) {
console.error('Error processing image:', error);
// Fall through to serve original image
}
}
} else {
// Serve from public folder
filePath = path.join('public', req.url === '/' ? 'index.html' : req.url);

View File

@ -9,6 +9,7 @@
},
"dependencies": {
"axios": "^1.7.9",
"node-fetch": "^3.3.2"
"node-fetch": "^3.3.2",
"sharp": "^0.32.0"
}
}