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> <title>${image.description || `Image ${i + 1}`}</title>
<link rel="stylesheet" href="/styles.css"> <link rel="stylesheet" href="/styles.css">
<link rel="icon" type="image/png" href="/favicon.png"> <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> </head>
<body> <body>
<div class="image-container"> <div class="image-container">
${image?.localPath || 'No image URL available' ${image?.localPath ? `
? `<img src="${image?.localPath || 'No image URL available'}" alt="${image.metadata.description || ''}">` <div class="progressive-image-container">
: '<p>Image not available</p>' <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>` : ''} ${image.description ? `<p class="description">${image.description}</p>` : ''}
<div class="navigation"> <div class="navigation">
<a href="${prevFileName}"></a> <a href="${prevFileName}"></a>
@ -86,11 +121,34 @@ async function generateSite() {
async function serveStaticSite(port = 3000) { async function serveStaticSite(port = 3000) {
const server = http.createServer(async (req, res) => { const server = http.createServer(async (req, res) => {
try { 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 // Convert URL to filesystem path
let filePath; let filePath;
if (req.url.startsWith('/images/')) { if (url.pathname.startsWith('/images/')) {
// Serve directly from images folder // 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 { } else {
// Serve from public folder // Serve from public folder
filePath = path.join('public', req.url === '/' ? 'index.html' : req.url); filePath = path.join('public', req.url === '/' ? 'index.html' : req.url);

View File

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