fix(cms): resolve double-root-layout conflict between the site and Payload admin
Next.js 16 requires either one shared root layout for every route, or each top-level route group to be fully self-contained (no ancestor layout.tsx above it). MITHOME-86 added (payload)/layout.tsx — which itself renders Payload's own <html>/<body> via <RootLayout> — while src/app/layout.tsx still existed as a shared ancestor and did the same. The result was two React trees fighting over <html>/<body>/<head>, surfacing in the browser as hydration failures and "You are mounting a new html component" errors on /admin (invisible to curl-based checks in the MITHOME-86 verification, since they only exercise SSR, not client hydration — that verification's "confirmed live" claim was therefore incomplete; caught now with an actual browser). Fix, per Payload's documented multi-root pattern: move every existing site route (page.tsx, globals.css, kapcsolat/szolgaltatasok/rolunk/ adatvedelem/felhasznalasi-feltetelek) into a new (frontend) route group with its own layout.tsx (renamed from src/app/layout.tsx, with relative imports adjusted one level deeper), as a sibling of (payload). No shared layout.tsx remains directly under src/app/. Verified in a real browser (not just curl): /admin/login and the dashboard now render and hydrate cleanly, and all site routes (/, /rolunk, /szolgaltatasok, /kapcsolat, /adatvedelem, /felhasznalasi-feltetelek) are unaffected — same output, just moved. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
2a4f33172b
commit
a661739844
Executable
+305
@@ -0,0 +1,305 @@
|
||||
import { content } from '@/content'
|
||||
import Image from 'next/image'
|
||||
|
||||
const { home: pageContent } = content.pages
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="space-y-0">
|
||||
{/* Hero Section */}
|
||||
<section className="bg-gradient-hero py-20 lg:py-28 relative overflow-hidden">
|
||||
{/* Background decoration */}
|
||||
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
<div
|
||||
className="absolute -top-40 -right-40 w-80 h-80 rounded-full opacity-30 animate-pulse-slow"
|
||||
style={{ background: 'var(--color-primary-200)' }}
|
||||
/>
|
||||
<div
|
||||
className="absolute -bottom-40 -left-40 w-96 h-96 rounded-full opacity-20 animate-pulse-slow"
|
||||
style={{ background: 'var(--color-accent-200)', animationDelay: '1s' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center relative z-10">
|
||||
<h1
|
||||
className="text-4xl md:text-5xl lg:text-6xl font-bold mb-6 leading-tight animate-fade-in-up"
|
||||
style={{ color: 'var(--color-foreground)' }}
|
||||
>
|
||||
{pageContent.hero.title}
|
||||
</h1>
|
||||
<p
|
||||
className="text-lg md:text-xl max-w-4xl mx-auto mb-8 leading-relaxed animate-fade-in-up"
|
||||
style={{ color: 'var(--color-foreground-muted)', animationDelay: '100ms' }}
|
||||
>
|
||||
{pageContent.hero.description}
|
||||
</p>
|
||||
|
||||
{pageContent.hero.trustBullets && (
|
||||
<div
|
||||
className="flex flex-wrap justify-center gap-4 md:gap-8 mb-10 text-sm font-medium animate-fade-in-up"
|
||||
style={{ color: 'var(--color-foreground-secondary)', animationDelay: '150ms' }}
|
||||
>
|
||||
{pageContent.hero.trustBullets.map((bullet: string, i: number) => (
|
||||
<div key={i} className="flex items-center gap-2">
|
||||
<span style={{ color: 'var(--color-primary-500)' }}>✓</span>
|
||||
{bullet}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className="flex flex-col sm:flex-row gap-4 justify-center items-center animate-fade-in-up"
|
||||
style={{ animationDelay: '200ms' }}
|
||||
>
|
||||
<a
|
||||
href={pageContent.hero.cta.primary.href}
|
||||
target={pageContent.hero.cta.primary.external ? '_blank' : undefined}
|
||||
rel={pageContent.hero.cta.primary.external ? 'noopener noreferrer' : undefined}
|
||||
className="btn btn-primary text-lg px-8 py-4 group"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5 transition-transform duration-200 group-hover:scale-110"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10" />
|
||||
</svg>
|
||||
{pageContent.hero.cta.primary.text}
|
||||
</a>
|
||||
{pageContent.hero.cta.secondary && (
|
||||
<a
|
||||
href={pageContent.hero.cta.secondary.href}
|
||||
className="btn btn-secondary text-lg px-8 py-4"
|
||||
>
|
||||
{pageContent.hero.cta.secondary.text}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* USP Section */}
|
||||
<section
|
||||
className="py-20"
|
||||
style={{ background: 'var(--color-background-secondary)' }}
|
||||
>
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center mb-12">
|
||||
<h2
|
||||
className="text-3xl md:text-4xl font-bold mb-4"
|
||||
style={{ color: 'var(--color-foreground)' }}
|
||||
>
|
||||
{pageContent.about.title}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 stagger-children">
|
||||
{pageContent.about.usps.map((usp, index) => (
|
||||
<div
|
||||
key={usp.id}
|
||||
className="group text-center p-6 rounded-xl transition-all duration-300 hover-lift animate-fade-in-up"
|
||||
style={{
|
||||
background: 'var(--color-background)',
|
||||
border: '1px solid var(--color-border)',
|
||||
animationDelay: `${index * 100}ms`
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="icon-container icon-container-lg mx-auto mb-4"
|
||||
>
|
||||
<span className="text-2xl">{usp.icon}</span>
|
||||
</div>
|
||||
<h3
|
||||
className="text-lg font-semibold mb-2 transition-colors duration-200"
|
||||
style={{ color: 'var(--color-foreground)' }}
|
||||
>
|
||||
{usp.title}
|
||||
</h3>
|
||||
<p style={{ color: 'var(--color-foreground-muted)' }}>
|
||||
{usp.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Services Section */}
|
||||
<section
|
||||
className="py-20"
|
||||
style={{ background: 'var(--color-background)' }}
|
||||
>
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center mb-12">
|
||||
<h2
|
||||
className="text-3xl md:text-4xl font-bold mb-4"
|
||||
style={{ color: 'var(--color-foreground)' }}
|
||||
>
|
||||
{pageContent.services.title}
|
||||
</h2>
|
||||
<p
|
||||
className="text-lg max-w-3xl mx-auto"
|
||||
style={{ color: 'var(--color-foreground-muted)' }}
|
||||
>
|
||||
{pageContent.services.subtitle}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-5xl mx-auto">
|
||||
{pageContent.services.items.map((service, index) => (
|
||||
<div
|
||||
key={service.id}
|
||||
className="group card hover-lift"
|
||||
style={{ animationDelay: `${index * 100}ms` }}
|
||||
>
|
||||
<div className="icon-container mb-4">
|
||||
<span className="text-xl">{service.icon}</span>
|
||||
</div>
|
||||
<h3
|
||||
className="text-xl font-semibold mb-3 transition-colors duration-200 group-hover:text-blue-600"
|
||||
style={{ color: 'var(--color-foreground)' }}
|
||||
>
|
||||
{service.title}
|
||||
</h3>
|
||||
<p
|
||||
className="leading-relaxed mb-4"
|
||||
style={{ color: 'var(--color-foreground-muted)' }}
|
||||
>
|
||||
{service.description}
|
||||
</p>
|
||||
<div className="mb-4">
|
||||
<h4
|
||||
className="text-sm font-semibold mb-2"
|
||||
style={{ color: 'var(--color-foreground-secondary)' }}
|
||||
>
|
||||
{pageContent.serviceFeatures.title}
|
||||
</h4>
|
||||
<ul
|
||||
className="text-sm space-y-1.5"
|
||||
style={{ color: 'var(--color-foreground-muted)' }}
|
||||
>
|
||||
{service.features.map((feature, idx) => (
|
||||
<li key={idx} className="flex items-start group/item">
|
||||
<span
|
||||
className="mr-2 transition-transform duration-200 group-hover/item:scale-125"
|
||||
style={{ color: 'var(--color-success-500)' }}
|
||||
>
|
||||
✓
|
||||
</span>
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<a
|
||||
href="/kapcsolat"
|
||||
className="inline-flex items-center font-medium transition-all duration-200 group/link"
|
||||
style={{ color: 'var(--color-primary-600)' }}
|
||||
>
|
||||
{service.ctaText}
|
||||
<svg
|
||||
className="w-4 h-4 ml-1 transition-transform duration-200 group-hover/link:translate-x-1"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Partners Section */}
|
||||
{pageContent.partners.items.length > 0 && (
|
||||
<section className="py-16">
|
||||
<div className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<h2 className="text-3xl font-bold text-center mb-3" style={{ color: 'var(--color-foreground)' }}>
|
||||
{pageContent.partners.title}
|
||||
</h2>
|
||||
<p className="text-center mb-10" style={{ color: 'var(--color-foreground-muted)' }}>
|
||||
{pageContent.partners.subtitle}
|
||||
</p>
|
||||
<div className="flex flex-wrap justify-center items-center gap-10">
|
||||
{pageContent.partners.items.map((partner) => (
|
||||
<a
|
||||
key={partner.name}
|
||||
href={partner.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="group flex flex-col items-center gap-3 opacity-80 hover:opacity-100 transition-opacity duration-200"
|
||||
title={partner.name}
|
||||
>
|
||||
<span className="relative h-12 w-40">
|
||||
<Image
|
||||
src={partner.logo}
|
||||
alt={partner.name}
|
||||
fill
|
||||
sizes="160px"
|
||||
className="object-contain"
|
||||
/>
|
||||
</span>
|
||||
<span className="text-sm" style={{ color: 'var(--color-foreground-muted)' }}>
|
||||
{partner.name}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* CTA Section */}
|
||||
<section
|
||||
className="py-20 relative overflow-hidden"
|
||||
style={{ background: 'var(--color-foreground)' }}
|
||||
>
|
||||
{/* Animated background elements */}
|
||||
<div className="absolute inset-0 overflow-hidden pointer-events-none opacity-10">
|
||||
<div
|
||||
className="absolute top-10 left-10 w-32 h-32 rounded-full animate-float"
|
||||
style={{ background: 'var(--color-primary-500)' }}
|
||||
/>
|
||||
<div
|
||||
className="absolute bottom-10 right-20 w-24 h-24 rounded-full animate-float"
|
||||
style={{ background: 'var(--color-accent-500)', animationDelay: '0.5s' }}
|
||||
/>
|
||||
<div
|
||||
className="absolute top-1/2 right-1/4 w-16 h-16 rounded-full animate-float"
|
||||
style={{ background: 'var(--color-primary-400)', animationDelay: '1s' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center relative z-10">
|
||||
<h2
|
||||
className="text-3xl md:text-4xl font-bold mb-4"
|
||||
style={{ color: 'var(--color-background)' }}
|
||||
>
|
||||
{pageContent.cta.title}
|
||||
</h2>
|
||||
<p
|
||||
className="text-xl mb-8 max-w-2xl mx-auto"
|
||||
style={{ color: 'var(--color-background)', opacity: 0.8 }}
|
||||
>
|
||||
{pageContent.cta.subtitle}
|
||||
</p>
|
||||
<a
|
||||
href="/kapcsolat"
|
||||
className="btn btn-primary text-lg px-8 py-4 hover-glow"
|
||||
>
|
||||
{pageContent.cta.button}
|
||||
<svg
|
||||
className="w-5 h-5 ml-2"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user