TipTap (ProseMirror) was causing: - chunks 1007 (85 KiB) and 3207 (58 KiB) in the initial bundle - Array.prototype.at/flat/flatMap, Object.fromEntries/hasOwn polyfills (ProseMirror bundles core-js for these — the 12 KiB legacy JS flag) - 2+ seconds of main thread blocking on mobile Fix: move HTML conversion to the server (API route) and pass the resulting HTML string to the client, eliminating the need to import richTextToSafeHtml (and transitively TipTap) in any client component. Changes: - app/api/content/page/route.ts: call richTextToSafeHtml server-side, add html: string to response alongside existing content - app/components/RichTextClient.tsx: accept html string, remove all TipTap imports — TipTap/ProseMirror now has zero client bundle cost - app/components/About.tsx, Contact.tsx: use cmsHtml from API - app/legal-notice/page.tsx, privacy-policy/page.tsx: same - app/components/ClientWrappers.tsx: change static imports of About, Projects, Contact, Footer to next/dynamic so their JS is in separate lazy-loaded chunks, not in the initial bundle Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
144 lines
6.5 KiB
TypeScript
144 lines
6.5 KiB
TypeScript
"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";
|
|
import Link from "next/link";
|
|
import { useLocale, useTranslations } from "next-intl";
|
|
import { useEffect, useState } from "react";
|
|
import RichTextClient from "../components/RichTextClient";
|
|
|
|
export default function LegalNotice() {
|
|
const locale = useLocale();
|
|
const t = useTranslations("common");
|
|
const [cmsHtml, setCmsHtml] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
(async () => {
|
|
try {
|
|
const res = await fetch(
|
|
`/api/content/page?key=${encodeURIComponent("legal-notice")}&locale=${encodeURIComponent(locale)}`,
|
|
);
|
|
const data = await res.json();
|
|
if (data?.content?.html && data?.content?.locale === locale) {
|
|
setCmsHtml(data.content.html as string);
|
|
}
|
|
} catch {}
|
|
})();
|
|
}, [locale]);
|
|
|
|
return (
|
|
<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"
|
|
>
|
|
<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"
|
|
>
|
|
<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>
|
|
|
|
{/* 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"
|
|
>
|
|
{cmsHtml ? (
|
|
<div className="prose prose-stone dark:prose-invert max-w-none text-lg md:text-xl font-light leading-relaxed">
|
|
<RichTextClient html={cmsHtml} />
|
|
</div>
|
|
) : (
|
|
<div className="space-y-16">
|
|
<section>
|
|
<h2 className="text-3xl font-black text-stone-900 dark:text-stone-100 mb-8 uppercase tracking-tight flex items-center gap-3">
|
|
<Scale className="text-liquid-mint" size={28} /> Angaben gemäß § 5 TMG
|
|
</h2>
|
|
<div className="text-xl font-light leading-relaxed text-stone-600 dark:text-stone-400 space-y-4">
|
|
<p className="font-bold text-stone-900 dark:text-stone-100">Dennis Konkol</p>
|
|
<p>Auf dem Ziegenbrink 2B</p>
|
|
<p>49082 Osnabrück, Deutschland</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<h2 className="text-3xl font-black text-stone-900 dark:text-stone-100 mb-8 uppercase tracking-tight flex items-center gap-3">
|
|
<ShieldCheck className="text-liquid-sky" size={28} /> Haftungsausschluss
|
|
</h2>
|
|
<p className="text-xl font-light leading-relaxed text-stone-600 dark:text-stone-400">
|
|
Die Inhalte dieser Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität der Inhalte kann ich jedoch keine Gewähr übernehmen.
|
|
</p>
|
|
</section>
|
|
</div>
|
|
)}
|
|
</motion.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>
|
|
<div className="space-y-6">
|
|
<div className="flex items-center gap-4">
|
|
<div className="w-12 h-12 rounded-2xl bg-white/10 flex items-center justify-center border border-white/10">
|
|
<Mail className="text-liquid-mint" size={20} />
|
|
</div>
|
|
<div>
|
|
<p className="text-[10px] font-black uppercase tracking-widest text-stone-500">Email</p>
|
|
<Link href="mailto:info@dk0.dev" className="font-bold hover:text-liquid-mint transition-colors">info@dk0.dev</Link>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-4">
|
|
<div className="w-12 h-12 rounded-2xl bg-white/10 flex items-center justify-center border border-white/10">
|
|
<MapPin className="text-liquid-sky" size={20} />
|
|
</div>
|
|
<div>
|
|
<p className="text-[10px] font-black uppercase tracking-widest text-stone-500">Location</p>
|
|
<p className="font-bold">Osnabrück, GER</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Meta Info Box */}
|
|
<div className="bg-liquid-purple/5 dark:bg-stone-900 rounded-[3rem] p-10 border border-liquid-purple/20 dark:border-stone-800/60">
|
|
<div className="flex items-center gap-4 mb-6">
|
|
<Clock className="text-liquid-purple" size={20} />
|
|
<div>
|
|
<p className="text-[10px] font-black uppercase tracking-widest text-stone-400">Last Review</p>
|
|
<p className="font-bold text-stone-900 dark:text-stone-100 text-sm">February 15, 2025</p>
|
|
</div>
|
|
</div>
|
|
<p className="text-xs text-stone-500 leading-relaxed">
|
|
This legal notice applies to all contents on dk0.dev and related social media profiles.
|
|
</p>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</main>
|
|
<Footer />
|
|
</div>
|
|
);
|
|
}
|