x
This commit is contained in:
1 parent
1a13b3624a
commit
4454b860c1
9 files changed
+381
-105
No files matched your search
@@ -290,9 +290,9 @@ function BannerSection({ payload, lang }: { payload: Record<string, unknown>, la
|
||||
<Image src={imageUrl} alt={title || 'Banner'} fill unoptimized className="absolute inset-0 h-full w-full object-cover" />
|
||||
<div className="ui-banner-overlay" />
|
||||
<div className="ui-banner-content">
|
||||
{title && <h2 className="text-3xl font-semibold md:text-5xl">{title}</h2>}
|
||||
{description && <p className="text-surface-card">{description}</p>}
|
||||
{buttonText && <span className="inline-flex rounded-full bg-surface-card px-6 py-3 font-semibold text-text-main">{buttonText}</span>}
|
||||
{title && <h2 className="text-3xl font-semibold text-brand-primary drop-shadow-md md:text-5xl">{title}</h2>}
|
||||
{description && <p className="text-surface-page/90 drop-shadow-sm">{description}</p>}
|
||||
{buttonText && <span className="inline-flex cursor-pointer rounded-full bg-surface-card px-6 py-3 font-semibold text-text-main transition-colors hover:bg-brand-primary hover:text-surface-card">{buttonText}</span>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -399,56 +399,82 @@ function EditorialCarouselSection({ payload, lang }: { payload: Record<string, u
|
||||
const slides = Array.isArray(payload.slides) ? payload.slides.map(toRecord) : []
|
||||
const backgroundColor = typeof payload.backgroundColor === 'string' ? payload.backgroundColor : undefined
|
||||
const textColor = typeof payload.textColor === 'string' ? payload.textColor : undefined
|
||||
const bgClass = backgroundColor ? `bg-pop-${backgroundColor}` : 'bg-surface-page'
|
||||
const textClass = textColor ? `text-pop-${textColor}` : 'text-text-main'
|
||||
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null)
|
||||
const scrollBy = (offset: number) => {
|
||||
if (scrollContainerRef.current) {
|
||||
scrollContainerRef.current.scrollBy({ left: offset, behavior: 'smooth' })
|
||||
}
|
||||
}
|
||||
|
||||
if (!slides.length) return null
|
||||
|
||||
return (
|
||||
<section className="ui-section-dark py-16 md:py-24" style={{ backgroundColor, color: textColor }}>
|
||||
<section className={`px-6 py-16 md:py-24 ${bgClass} ${textClass}`}>
|
||||
<div className="mx-auto max-w-7xl space-y-12">
|
||||
{title && (
|
||||
<div className="mx-auto max-w-3xl space-y-4 text-center">
|
||||
<h2 className="text-4xl font-semibold text-surface-card md:text-5xl" style={{ color: textColor }}>{renderAccentTitle(title)}</h2>
|
||||
<h2 className={`text-4xl font-semibold md:text-5xl ${textClass}`}>{renderAccentTitle(title)}</h2>
|
||||
<div className="mx-auto h-px w-16 bg-brand-accent" />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex overflow-x-auto snap-x snap-mandatory hide-scrollbar gap-6 pb-8">
|
||||
{slides.map((slide, index) => {
|
||||
const slideTitle = localizedFromRecord(slide, 'title', resolvedLang)
|
||||
const description = localizedFromRecord(slide, 'description', resolvedLang)
|
||||
const category = localizedFromRecord(slide, 'category', resolvedLang)
|
||||
const buttonText = localizedFromRecord(slide, 'buttonText', resolvedLang)
|
||||
const buttonLink = typeof slide.buttonLink === 'string' ? slide.buttonLink : ''
|
||||
const imageUrl = typeof slide.imageUrl === 'string' ? slide.imageUrl : ''
|
||||
<div className="relative">
|
||||
<button
|
||||
onClick={() => scrollBy(-400)}
|
||||
className="hidden md:flex bg-surface-card rounded-full shadow-card hover:text-brand-primary h-10 w-10 items-center justify-center absolute z-10 top-1/2 -translate-y-1/2 -left-5"
|
||||
aria-label="Scroll left"
|
||||
>
|
||||
<ChevronLeft className="h-6 w-6 text-brand-primary" />
|
||||
</button>
|
||||
<div ref={scrollContainerRef} className="flex overflow-x-auto snap-x snap-mandatory hide-scrollbar gap-6 pb-8">
|
||||
{slides.map((slide, index) => {
|
||||
const slideTitle = localizedFromRecord(slide, 'title', resolvedLang)
|
||||
const description = localizedFromRecord(slide, 'description', resolvedLang)
|
||||
const category = localizedFromRecord(slide, 'category', resolvedLang)
|
||||
const buttonText = localizedFromRecord(slide, 'buttonText', resolvedLang)
|
||||
const buttonLink = typeof slide.buttonLink === 'string' ? slide.buttonLink : ''
|
||||
const imageUrl = typeof slide.imageUrl === 'string' ? slide.imageUrl : ''
|
||||
|
||||
return (
|
||||
<article key={index} className="ui-section-dark-card group w-[85vw] md:w-[350px] flex-none snap-start">
|
||||
{imageUrl ? (
|
||||
<div className="relative aspect-[4/3] overflow-hidden">
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt={slideTitle || 'Editorial slide'}
|
||||
fill
|
||||
unoptimized
|
||||
className="h-full w-full object-cover transition duration-700 group-hover:scale-105"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="space-y-4 p-6 flex flex-col flex-1 justify-between">
|
||||
<div>
|
||||
{category && <p className="text-[10px] font-bold uppercase tracking-[0.24em] text-brand-accent mb-2">{category}</p>}
|
||||
{slideTitle && <h3 className="ui-section-dark-card-title text-xl mb-3">{renderAccentTitle(slideTitle)}</h3>}
|
||||
{description && <p className="ui-section-dark-card-copy text-sm line-clamp-3">{description}</p>}
|
||||
</div>
|
||||
{buttonText && buttonLink && (
|
||||
<div className="pt-2">
|
||||
<Link href={buttonLink} className="ui-section-dark-link inline-flex items-center gap-2 text-xs font-bold uppercase tracking-widest transition-colors group/link">
|
||||
{buttonText} <span className="group-hover/link:translate-x-1 transition-transform">→</span>
|
||||
</Link>
|
||||
return (
|
||||
<article key={index} className="ui-card overflow-hidden group w-[85vw] md:w-[350px] flex-none snap-start">
|
||||
{imageUrl ? (
|
||||
<div className="relative aspect-[4/3] overflow-hidden">
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt={slideTitle || 'Editorial slide'}
|
||||
fill
|
||||
unoptimized
|
||||
className="h-full w-full object-cover transition duration-700 group-hover:scale-105"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</article>
|
||||
)
|
||||
})}
|
||||
) : null}
|
||||
<div className="space-y-4 p-6 flex flex-col flex-1 justify-between">
|
||||
<div>
|
||||
{category && <span className="text-[10px] font-bold uppercase tracking-[0.24em] text-brand-primary block">{category}</span>}
|
||||
{slideTitle && <h3 className="text-xl font-bold text-text-main mt-6 group-hover:text-brand-primary transition-colors">{renderAccentTitle(slideTitle)}</h3>}
|
||||
{description && <p className="text-base text-muted-text mt-3 whitespace-pre-wrap">{description}</p>}
|
||||
</div>
|
||||
{buttonText && buttonLink && (
|
||||
<div className="pt-2">
|
||||
<Link href={buttonLink} className="ui-section-dark-link inline-flex items-center gap-2 text-xs font-bold uppercase tracking-widest transition-colors group/link">
|
||||
{buttonText} <span className="group-hover/link:translate-x-1 transition-transform">→</span>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</article>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => scrollBy(400)}
|
||||
className="hidden md:flex bg-surface-card rounded-full shadow-card hover:text-brand-primary h-10 w-10 items-center justify-center absolute z-10 top-1/2 -translate-y-1/2 -right-5"
|
||||
aria-label="Scroll right"
|
||||
>
|
||||
<ChevronRight className="h-6 w-6 text-brand-primary" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -560,9 +586,12 @@ function AccordionSection({ payload, lang }: { payload: Record<string, unknown>,
|
||||
const categories = Array.isArray(payload.categories) ? payload.categories.map(toRecord) : []
|
||||
if (!categories.length) return null
|
||||
const sectionTitle = localizedFromRecord(payload, 'title', resolvedLang)
|
||||
const backgroundColor = typeof payload.backgroundColor === 'string' ? payload.backgroundColor : undefined
|
||||
const textColor = typeof payload.textColor === 'string' ? payload.textColor : undefined
|
||||
const iconColor = typeof payload.iconColor === 'string' ? payload.iconColor : undefined
|
||||
|
||||
return (
|
||||
<section className="bg-surface-page ui-section-band">
|
||||
<section className="ui-section-band" style={{ backgroundColor, color: textColor }}>
|
||||
<div className="mx-auto max-w-4xl space-y-10">
|
||||
{sectionTitle && <h2 className="ui-section-title">{sectionTitle}</h2>}
|
||||
{categories.map((category, categoryIndex) => {
|
||||
@@ -573,8 +602,8 @@ function AccordionSection({ payload, lang }: { payload: Record<string, unknown>,
|
||||
return (
|
||||
<div key={categoryIndex} className="space-y-5">
|
||||
{name && (
|
||||
<h2 className="flex items-center gap-3 text-2xl font-semibold text-text-main">
|
||||
{icon && <span className="text-brand-primary">{icon}</span>}
|
||||
<h2 className="flex items-center gap-3 text-2xl font-semibold">
|
||||
{icon && <span style={{ color: iconColor }}>{icon}</span>}
|
||||
{name}
|
||||
</h2>
|
||||
)}
|
||||
@@ -586,7 +615,7 @@ function AccordionSection({ payload, lang }: { payload: Record<string, unknown>,
|
||||
|
||||
return (
|
||||
<details key={itemIndex} className="group rounded-2xl bg-surface-card p-5 shadow-card">
|
||||
<summary className="cursor-pointer list-none text-lg font-semibold text-text-main marker:hidden">
|
||||
<summary className="cursor-pointer list-none text-lg font-semibold marker:hidden">
|
||||
{question}
|
||||
</summary>
|
||||
<p className="mt-4 whitespace-pre-wrap leading-relaxed text-muted-text">{answer}</p>
|
||||
|
||||
Reference in new issue
Block a user