perf: eliminate next-themes and framer-motion from initial JS bundle
All checks were successful
CI / CD / test-build (push) Successful in 10m10s
CI / CD / deploy-dev (push) Successful in 1m46s
CI / CD / deploy-production (push) Has been skipped

- Replace next-themes (38 KiB) with a tiny custom ThemeProvider (~< 1 KiB)
  using localStorage + classList.toggle for theme management
- Add FOUC-prevention inline script in layout.tsx to apply saved theme
  before React hydrates
- Remove framer-motion from Header.tsx: nav entry now uses CSS slideDown
  keyframe, mobile menu uses CSS opacity/translate transitions
- Remove framer-motion from ThemeToggle.tsx: use Tailwind hover/active scale
- Remove framer-motion from legal-notice and privacy-policy pages
- Update useTheme import in ThemeToggle to use custom ThemeProvider
- Add slideDown keyframe to tailwind.config.ts
- Update tests to mock custom ThemeProvider instead of next-themes

Result: framer-motion moves from "First Load JS shared by all" to lazy
chunks; next-themes chunk eliminated entirely; -38 KiB from initial bundle

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 17:39:29 +01:00
parent 7f7ed39b0e
commit dacec18956
11 changed files with 94 additions and 91 deletions

View File

@@ -1,7 +1,6 @@
"use client";
import React from "react";
import { motion } from 'framer-motion';
import { ArrowLeft, Mail, MapPin, Scale, ShieldCheck, Clock } from 'lucide-react';
import Header from "../components/Header";
import Footer from "../components/Footer";
@@ -33,13 +32,9 @@ export default function LegalNotice() {
<div className="min-h-screen bg-[#fdfcf8] dark:bg-stone-950 transition-colors duration-500">
<Header />
<main className="max-w-7xl mx-auto px-6 pt-40 pb-20">
{/* Editorial Header */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
className="mb-20"
>
<div className="animate-fade-in mb-20">
<Link
href={`/${locale}`}
className="inline-flex items-center gap-2 text-stone-500 hover:text-stone-900 dark:hover:text-white transition-colors mb-10 group"
@@ -47,22 +42,17 @@ export default function LegalNotice() {
<ArrowLeft size={20} className="group-hover:-translate-x-1 transition-transform" />
<span className="font-bold uppercase tracking-widest text-xs">{t("backToHome")}</span>
</Link>
<h1 className="text-6xl md:text-[10rem] font-black tracking-tighter text-stone-900 dark:text-stone-50 leading-[0.85] uppercase">
Legal<span className="text-liquid-mint">.</span>
</h1>
</motion.div>
</div>
{/* Bento Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8">
{/* Main Legal Content (Large Box) */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 }}
className="lg:col-span-8 bg-white dark:bg-stone-900 rounded-[3rem] p-10 md:p-16 border border-stone-200/60 dark:border-stone-800/60 shadow-sm"
>
<div className="animate-[fadeIn_0.5s_ease-out_0.1s_both] lg:col-span-8 bg-white dark:bg-stone-900 rounded-[3rem] p-10 md:p-16 border border-stone-200/60 dark:border-stone-800/60 shadow-sm">
{cmsHtml ? (
<div className="prose prose-stone dark:prose-invert max-w-none text-lg md:text-xl font-light leading-relaxed">
<RichTextClient html={cmsHtml} />
@@ -90,11 +80,11 @@ export default function LegalNotice() {
</section>
</div>
)}
</motion.div>
</div>
{/* Sidebar Widgets */}
<div className="lg:col-span-4 space-y-8">
{/* Quick Contact Box */}
<div className="bg-stone-900 rounded-[3rem] p-10 border border-stone-800 shadow-2xl text-white">
<h3 className="text-xl font-black mb-8 uppercase tracking-widest text-liquid-mint">Direct Contact</h3>