feat(performance): Core Web Vitals optimizations

- Font optimization: Replace @font-face with next/font/google (DM Sans, Inter) for faster font loading and no render-blocking
- Image optimization: Add Unsplash to remotePatterns, configure AVIF/WebP formats, add device/image sizes
- Convert native <img> tags to next/image with proper sizing and priority for LCP images
- Add optimizePackageImports for lucide-react and framer-motion to reduce bundle size
- Fix CLS: Urgency message uses fixed min-height instead of animated height
- Fix CLS: ProductCard quick-add button uses opacity instead of translate for hover
- Convert HeroVideo scroll indicator to CSS animation
- Script loading: Rybbit uses lazyOnload strategy for better INP
This commit is contained in:
Unchained
2026-03-31 12:03:34 +02:00
parent d4039c6e3b
commit 8eb9f24b33
9 changed files with 92 additions and 63 deletions

View File

@@ -245,10 +245,12 @@ export default function ProductDetail({ product, relatedProducts, bundleProducts
: "border-transparent hover:border-[#999999]"
}`}
>
<img
<Image
src={image.url}
alt={image.alt || localized.name}
className="w-full h-full object-cover"
fill
className="object-cover"
sizes="100px"
/>
</button>
))}
@@ -256,10 +258,13 @@ export default function ProductDetail({ product, relatedProducts, bundleProducts
)}
<div className="relative w-full aspect-square bg-[#f8f9fa] overflow-hidden flex-1">
<img
<Image
src={images[selectedImage].url}
alt={images[selectedImage].alt || localized.name}
className="w-full h-full object-cover"
fill
priority
className="object-cover"
sizes="(max-width: 768px) 100vw, 50vw"
/>
{images.length > 1 && (
@@ -307,17 +312,15 @@ export default function ProductDetail({ product, relatedProducts, bundleProducts
transition={{ duration: 0.6, delay: 0.2 }}
className="lg:pl-8"
>
<motion.div
key={urgencyIndex}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 10 }}
transition={{ duration: 0.3 }}
className="bg-white/80 backdrop-blur-sm text-[#1a1a1a] py-3 rounded-lg mb-4 text-sm font-medium text-left"
>
<span className="mr-2">{urgencyMessages[urgencyIndex].icon}</span>
{urgencyMessages[urgencyIndex].text}
</motion.div>
<div className="min-h-[52px] flex items-center">
<div
className="bg-white/80 backdrop-blur-sm text-[#1a1a1a] py-3 px-4 rounded-lg mb-4 text-sm font-medium text-left w-full"
key={urgencyIndex}
>
<span className="mr-2">{urgencyMessages[urgencyIndex].icon}</span>
{urgencyMessages[urgencyIndex].text}
</div>
</div>
<h1 className="text-3xl md:text-4xl font-medium mb-4 tracking-tight">
{localized.name}