Files
j_kedzierski/src/blocks/Hero/Component.tsx
T

149 lines
5.1 KiB
TypeScript

'use client'
import React from 'react'
import { motion } from 'framer-motion'
import type { Page, Media } from '../../payload-types'
import Link from 'next/link'
import Image from 'next/image'
import { ImagePlaceholder } from '../../components/ImagePlaceholder'
type BaseProps = Extract<NonNullable<Page['layout']>[0], { blockType: 'hero' }>
type Props = BaseProps & { whatsappNumber?: string | null }
const customEase = [0.22, 1, 0.36, 1] as const
const containerVariants = {
hidden: {},
visible: {
transition: {
staggerChildren: 0.14,
delayChildren: 0.2
},
},
}
const itemVariants = {
hidden: { opacity: 0, y: 22 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.7,
ease: customEase,
},
},
}
export const HeroBlock: React.FC<Props> = ({
title,
titleAccent,
subtitle,
primaryCta,
secondaryCta,
image,
whatsappNumber,
}) => {
const whatsappLink = whatsappNumber ? `https://wa.me/${whatsappNumber}` : '#'
const heroMedia = typeof image === 'object' && image !== null ? (image as Media) : null
const imageUrl = heroMedia?.url
const imageAlt = heroMedia?.alt || 'Tło hero'
return (
<motion.section
initial="hidden"
animate="visible"
className="relative w-full min-h-[70vh] lg:min-h-[85vh] flex flex-col justify-end overflow-hidden"
>
{/* Background Layer */}
<div className="absolute inset-0 z-0">
{imageUrl ? (
<>
<Image
src={imageUrl}
alt={imageAlt}
fill
priority
sizes="100vw"
className="object-cover object-center"
/>
{/* Ciemny gradient pod spodem, by biały tekst był świetnie czytelny, a zdjęcie pozostało nasycone */}
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent lg:bg-gradient-to-r lg:from-black/90 lg:via-black/40 lg:to-transparent" />
<div className="absolute inset-0 bg-black/20" />
</>
) : (
<div className="absolute inset-0 bg-card bg-paper-noise border-b border-border/50" />
)}
</div>
{/* Content Layer */}
<div className="container-premium relative z-10 w-full pb-16 lg:pb-24 pt-32">
<div className="flex flex-col lg:flex-row items-end justify-between gap-12">
{/* Main Content (Bottom Left) */}
<motion.div
variants={containerVariants}
className="w-full lg:max-w-3xl flex flex-col"
>
<motion.h1
variants={itemVariants}
className={`font-heading text-4xl sm:text-5xl md:text-6xl lg:text-[4.5rem] font-bold leading-[1.05] mb-6 text-balance break-words hyphens-auto ${imageUrl ? 'text-white drop-shadow-md' : 'text-foreground'}`}
>
<span className="block">{title}</span>
{titleAccent && (
<span className="block text-accent mt-2">
{titleAccent.split(/(po polsku)/i).map((part, i) =>
part.toLowerCase() === 'po polsku' ? <i key={i} className="italic font-medium">{part}</i> : part
)}
</span>
)}
</motion.h1>
<motion.p
variants={itemVariants}
className={`text-lg sm:text-xl md:text-2xl mb-10 leading-relaxed font-medium max-w-[55ch] ${imageUrl ? 'text-white/90 drop-shadow-md' : 'text-foreground/90'}`}
>
{subtitle}
</motion.p>
<motion.div
variants={itemVariants}
className="flex flex-col sm:flex-row items-start sm:items-center gap-6 sm:gap-8"
>
{whatsappNumber && (
<a
href={whatsappLink}
target="_blank"
rel="noopener noreferrer"
className="px-8 py-4 bg-[#25D366] hover:bg-[#20bd5a] text-[#1C1B1A] font-bold text-base sm:text-lg transition-colors flex items-center justify-center rounded-none shadow-md cursor-pointer border border-[#1C1B1A]/10"
>
{primaryCta}
</a>
)}
{secondaryCta?.text && secondaryCta?.url && (
secondaryCta.url.startsWith('#') ? (
<a
href={secondaryCta.url}
className={`${imageUrl ? 'text-white drop-shadow-md' : 'text-foreground'} font-semibold text-lg hover:text-accent hover:underline underline-offset-4 transition-colors`}
>
{secondaryCta.text}
</a>
) : (
<Link
href={secondaryCta.url}
className={`${imageUrl ? 'text-white drop-shadow-md' : 'text-foreground'} font-semibold text-lg hover:text-accent hover:underline underline-offset-4 transition-colors`}
>
{secondaryCta.text}
</Link>
)
)}
</motion.div>
</motion.div>
</div>
</div>
</motion.section>
)
}