blog.hangerthem.com/components/content/ImageWrapper.tsx
HangerThem 88c8676d3f perf: image loading, smaller assets, server-rendered code blocks
- Only preload the post cover and latest-post image instead of every image
- Drop in-post image quality from 100 to 90 and add responsive sizes
- Downscale 2940px screenshots to 1800px; convert linkboard-old to WebP
  (3.1 MB -> 60 KB)
- Make CodeWrapper a server component; only CopyButton ships to the client
- Pin the Mermaid CDN script to an exact version for reproducible builds
2026-10-19 14:17:18 +02:00

55 lines
2 KiB
TypeScript

import { cn } from '@/utils/cn'
import Image from 'next/image'
type ImageWrapperProps = {
src: string
alt?: string
/** Visible caption. Falls back to the alt text when omitted. */
caption?: string
isListing?: boolean
/** Preload the image. Only set this for above-the-fold images (covers, latest post). */
priority?: boolean
}
export function ImageWrapper({ src, alt, caption, isListing, priority }: ImageWrapperProps) {
const captionText = caption ?? alt
// When the caption just repeats the alt text, hide it from screen readers so it isn't
// announced twice
const captionIsAlt = caption === undefined
return (
<figure className={cn('flex flex-col items-center gap-1 mb-4 w-full', isListing && 'h-full')}>
<div className="border border-border rounded-xl w-full overflow-hidden flex-1">
<div
className="flex items-center gap-2 px-2 h-6 border-b border-border w-full bg-fg/10"
aria-hidden="true"
>
<div className="space-x-1">
<span className="w-2 h-2 bg-border rounded-full inline-block"></span>
<span className="w-2 h-2 bg-border rounded-full inline-block"></span>
<span className="w-2 h-2 bg-border rounded-full inline-block"></span>
</div>
<span className="text-xs text-fg-dim font-mono">~/{src}</span>
</div>
<Image
src={`/posts/${src}`}
alt={alt ?? ''}
width={isListing ? 400 : 900}
height={isListing ? 240 : 600}
sizes={isListing ? '(min-width: 768px) 400px, 100vw' : '(min-width: 896px) 900px, 100vw'}
quality={isListing ? 75 : 90}
priority={priority}
className="w-full mx-auto object-contain h-full max-h-150"
/>
</div>
{!isListing && captionText && (
<figcaption
className="block text-xs text-fg-dim font-mono text-center"
aria-hidden={captionIsAlt || undefined}
>
{captionText}
</figcaption>
)}
</figure>
)
}