feat: plakat redesign phase 1 (tokens, fonts, poster hero, header)
- New design tokens: signal red, ink and paper as RGB channels; ink and paper swap roles in dark mode so every component inverts cleanly - Fonts via next/font: Bricolage Grotesque (with wdth/opsz axes), Geist, Geist Mono; drop Inter and Playfair - Poster hero: kicker, giant DK0 wordmark that reacts to pointer distance (weight and width through a damped spring, desktop only, off for reduced motion), claim as h1, intro with thesis countdown, marquee strip - Header in poster style: transparent over the red hero, paper strip with ink rule when scrolled or on subpages; drawer menu restyled - Remove wavy SVG separators, CSS shader gradient, background blobs and unused providers that caused the pink/purple bands between sections - Drop the global p/span/div color override so colors inherit properly - New hero texts in de/en, tests and i18n key check updated Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,31 +1,17 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import dynamic from "next/dynamic";
|
||||
import React from "react";
|
||||
import { MotionConfig } from "framer-motion";
|
||||
import { ToastProvider } from "@/components/Toast";
|
||||
import ErrorBoundary from "@/components/ErrorBoundary";
|
||||
import { ConsentProvider } from "./ConsentProvider";
|
||||
import { ThemeProvider } from "./ThemeProvider";
|
||||
|
||||
const BackgroundBlobs = dynamic(
|
||||
() => import("@/components/BackgroundBlobs").catch(() => ({ default: () => null })),
|
||||
{ ssr: false, loading: () => null }
|
||||
);
|
||||
|
||||
export default function ClientProviders({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<ErrorBoundary>
|
||||
@@ -33,7 +19,7 @@ export default function ClientProviders({
|
||||
<ThemeProvider>
|
||||
{/* Respect prefers-reduced-motion in every Framer Motion animation */}
|
||||
<MotionConfig reducedMotion="user">
|
||||
<GatedProviders mounted={mounted}>
|
||||
<GatedProviders>
|
||||
{children}
|
||||
</GatedProviders>
|
||||
</MotionConfig>
|
||||
@@ -44,31 +30,10 @@ export default function ClientProviders({
|
||||
);
|
||||
}
|
||||
|
||||
function GatedProviders({
|
||||
children,
|
||||
mounted,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
mounted: boolean;
|
||||
}) {
|
||||
// Defer animated background blobs until after LCP
|
||||
const [deferredReady, setDeferredReady] = useState(false);
|
||||
useEffect(() => {
|
||||
if (!mounted) return;
|
||||
let id: ReturnType<typeof setTimeout> | number;
|
||||
if (typeof requestIdleCallback !== "undefined") {
|
||||
id = requestIdleCallback(() => setDeferredReady(true), { timeout: 5000 });
|
||||
return () => cancelIdleCallback(id as number);
|
||||
} else {
|
||||
id = setTimeout(() => setDeferredReady(true), 200);
|
||||
return () => clearTimeout(id);
|
||||
}
|
||||
}, [mounted]);
|
||||
|
||||
function GatedProviders({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<ToastProvider>
|
||||
{deferredReady && <BackgroundBlobs />}
|
||||
<div className="relative z-10">{children}</div>
|
||||
</ToastProvider>
|
||||
</ErrorBoundary>
|
||||
|
||||
Reference in New Issue
Block a user