Files
mypage/components/blog/OptimizedImage.tsx
RJ 5f585e2a9f
Some checks failed
Build and Deploy Next.js Blog to Production / 🔍 Code Quality Checks (push) Failing after 31s
Build and Deploy Next.js Blog to Production / 🏗️ Build and Push Docker Image (push) Has been skipped
Build and Deploy Next.js Blog to Production / 🚀 Deploy to Production (push) Has been skipped
🖼️ added support for links to blogposts and support image sizing from .md files
2025-11-24 12:37:52 +00:00

65 lines
1.9 KiB
TypeScript

'use client'
import Image from 'next/image'
import { useState } from 'react'
interface OptimizedImageProps {
src: string
alt: string
caption?: string
width?: number
height?: number
priority?: boolean
className?: string
}
export function OptimizedImage({
src,
alt,
caption,
width = 800,
height = 600,
priority = false,
className = '',
}: OptimizedImageProps) {
const [isLoading, setIsLoading] = useState(true)
const [hasError, setHasError] = useState(false)
if (hasError) {
return (
<div className="my-8 rounded-lg border border-zinc-800 bg-zinc-900/50 p-8 text-center">
<p className="text-zinc-400">Failed to load image</p>
{caption && <p className="mt-2 text-sm text-zinc-500">{caption}</p>}
</div>
)
}
return (
<figure className={`my-8 ${className}`}>
<div className="relative overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900/50">
<Image
src={src}
alt={alt}
width={width}
height={height}
priority={priority}
style={{ maxWidth: '100%', height: 'auto' }}
className={`transition-opacity duration-300 ${isLoading ? 'opacity-0' : 'opacity-100'}`}
onLoad={() => setIsLoading(false)}
onError={() => setHasError(true)}
placeholder="blur"
blurDataURL="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='300'%3E%3Crect width='400' height='300' fill='%2318181b'/%3E%3C/svg%3E"
/>
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center">
<div className="h-8 w-8 animate-spin rounded-full border-2 border-emerald-500 border-t-transparent" />
</div>
)}
</div>
{caption && (
<figcaption className="mt-3 text-center text-sm text-zinc-400">{caption}</figcaption>
)}
</figure>
)
}