Move 36 root-level audit/analysis documents and 7 web app audit documents into docs/audits/ directory to declutter the project root. Remove stale EXPLORATION_SUMMARY.txt. Co-Authored-By: Paperclip <noreply@paperclip.ing>
4.9 KiB
4.9 KiB
Image Usage - Quick Reference Card
🎯 At a Glance
| Item | Status | Details |
|---|---|---|
HTML <img> Tags |
✅ 0 found | All replaced with next/image |
| next/image Used | ✅ 8 files | Proper implementation across app |
| Image Components | ✅ 3 specialized | Gallery, Lightbox, Upload |
| Configuration | ✅ Configured | remotePatterns + CSP headers |
| Accessibility | ✅ Full support | Alt text, keyboard nav, ARIA |
| Security | ✅ HTTPS only | CSP configured, blob URLs for preview |
📁 Where Images Are Used
Core Image Components
components/listings/image-gallery.tsx ← Main gallery viewer
components/listings/image-lightbox.tsx ← Fullscreen view
components/listings/image-upload.tsx ← Upload with preview
Components That Display Images
components/search/property-card.tsx → Thumbnail in search results
components/agents/agent-profile-client.tsx → Avatar + agent's listings
components/comparison/comparison-table.tsx → Comparison images
components/listings/listing-detail-client.tsx → Integrates ImageGallery
Page Components
app/[locale]/(public)/listings/[id]/page.tsx → Listing detail (uses ImageGallery)
app/[locale]/(public)/search/page.tsx → Search results (uses PropertyCard)
app/[locale]/(public)/agents/[id]/page.tsx → Agent profile
app/[locale]/(dashboard)/listings/page.tsx → Dashboard listings
app/[locale]/(dashboard)/listings/new/page.tsx → Upload new listing
🔧 Configuration
next.config.js
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**',
},
],
}
CSP Headers
img-src 'self' data: blob: https://*.mapbox.com https://*.tiles.mapbox.com https:
- ✅ Allows blob: (file preview)
- ✅ Allows data: (inline images)
- ✅ Allows all HTTPS
📊 Image Component Details
ImageGallery
<ImageGallery
media={propertyMedia} // PropertyMedia[]
className="w-full"
/>
Features: Main + thumbnails, navigation, counter, lightbox integration
ImageLightbox
<ImageLightbox
images={images}
initialIndex={0}
open={isOpen}
onClose={() => setIsOpen(false)}
/>
Features: Keyboard nav, swipe, preloading, focus trap
ImageUpload
<ImageUpload
images={uploadedImages}
onChange={setUploadedImages}
maxFiles={20}
/>
Features: Drag-drop, validation (JPEG/PNG/WebP), preview, cleanup
🎨 Image Data Types
interface PropertyMedia {
id: string;
url: string; // Image URL
type: 'image' | 'video'; // Media type
order: number; // Display order
caption?: string; // Optional caption
}
interface ImageFile {
file: File; // Browser File
preview: string; // blob: URL
}
⚡ Performance Features
| Feature | Status |
|---|---|
Responsive sizing (sizes prop) |
✅ Implemented |
| Priority loading for above-fold | ✅ Implemented |
| Image preloading in lightbox | ✅ Implemented |
| Blob URL cleanup (memory) | ✅ Implemented |
| Skeleton placeholders | ⚠️ Not implemented |
| Image compression on upload | ⚠️ Not implemented |
♿ Accessibility Features
| Feature | Status |
|---|---|
| Alt text on images | ✅ Vietnamese |
| ARIA labels | ✅ Implemented |
| Keyboard navigation | ✅ Arrow keys + Escape |
| Focus trap in modal | ✅ Implemented |
| Tab trapping | ✅ Implemented |
🔒 Security Checklist
- ✅ HTTPS-only remote patterns
- ✅ CSP headers configured
- ✅ blob: URLs only for client-side preview
- ⚠️ API image URL validation - TO DO
- ⚠️ User upload scanning - TO DO
📝 Common Tasks
Adding Images to a Component
import Image from 'next/image';
<Image
src={imageUrl}
alt="Descriptive text in Vietnamese"
fill
sizes="(max-width: 768px) 100vw, 50vw"
className="object-cover"
/>
Showing Image Gallery
import { ImageGallery } from '@/components/listings/image-gallery';
<ImageGallery
media={property.media}
/>
File Upload
import { ImageUpload } from '@/components/listings/image-upload';
const [images, setImages] = useState<ImageFile[]>([]);
<ImageUpload
images={images}
onChange={setImages}
maxFiles={20}
/>
🚨 Important Notes
- Never use HTML
<img>tags - Usenext/imageinstead - Exception: Blob URL preview in image-upload is OK
- Always provide alt text - Use Vietnamese text
- Use
sizesprop - For responsive images - Set
priority- For above-fold images - Revoke blob URLs - On unmount to prevent memory leaks
- Validate image URLs - At API layer before returning
📞 Questions?
See IMAGE_AUDIT_REPORT.md for complete details and recommendations.