feat: image optimization with multiple sizes and lazy loading

- Generate thumbnail (150px), medium (800px), full size on upload
- OptimizedImage component with Intersection Observer lazy loading
- Blur placeholder while loading
- Fetches appropriate size based on props (thumbnail/medium/full)
- Async image loading reduces initial page load time
- Added medium and thumbnail columns to images table
This commit is contained in:
2026-06-30 23:34:23 -05:00
parent 73be5d2f22
commit 81c12ace7b
5 changed files with 196 additions and 25 deletions
+14 -10
View File
@@ -4,6 +4,7 @@ import { useEffect, useState, useRef } from 'react';
import { formatDisplayDate } from '@/lib/date';
import RoomCalendar from '@/components/RoomCalendar';
import LikeButton from '@/components/LikeButton';
import OptimizedImage from '@/components/OptimizedImage';
interface Room {
id: number;
@@ -315,17 +316,14 @@ export default function RoomsPage() {
onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = '0 2px 8px rgba(1,13,30,0.08)'; }}
>
{/* ─── Main Image ─── */}
<div style={{ position: 'relative', width: '100%' }}>
<div style={{ position: 'relative', width: '100%', height: '300px' }}>
{activeSrc ? (
<img
src={activeSrc}
<OptimizedImage
id={parseInt(activeSrc.split('id=')[1])}
alt={room.name}
style={{
width: '100%',
height: '300px',
objectFit: 'cover',
display: 'block',
}}
size="medium"
lazy={true}
style={{ width: '100%', height: '300px' }}
/>
) : (
<div style={{ width: '100%', height: '300px', background: '#ddd', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#999' }}>
@@ -409,7 +407,13 @@ export default function RoomsPage() {
}}
>
{p ? (
<img src={p} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
<OptimizedImage
id={parseInt(p.split('id=')[1])}
alt=""
size="thumbnail"
lazy={true}
style={{ width: '100%', height: '100%' }}
/>
) : (
<div style={{ width: '100%', height: '100%', background: '#ddd' }} />
)}