Files
portfolio/app/components/ThemeProvider.tsx
denshooter dacec18956
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
perf: eliminate next-themes and framer-motion from initial JS bundle
- 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>
2026-03-06 17:39:29 +01:00

39 lines
1.0 KiB
TypeScript

"use client";
import React, { createContext, useContext, useEffect, useState } from "react";
type Theme = "light" | "dark";
const ThemeCtx = createContext<{ theme: Theme; setTheme: (t: Theme) => void }>({
theme: "light",
setTheme: () => {},
});
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setThemeState] = useState<Theme>("light");
useEffect(() => {
try {
const stored = localStorage.getItem("theme") as Theme | null;
if (stored === "dark" || stored === "light") {
setThemeState(stored);
document.documentElement.classList.toggle("dark", stored === "dark");
}
} catch {}
}, []);
const setTheme = (t: Theme) => {
setThemeState(t);
try {
localStorage.setItem("theme", t);
} catch {}
document.documentElement.classList.toggle("dark", t === "dark");
};
return <ThemeCtx.Provider value={{ theme, setTheme }}>{children}</ThemeCtx.Provider>;
}
export function useTheme() {
return useContext(ThemeCtx);
}