x
This commit is contained in:
1 parent
e349ef5b84
commit
8d415ecef7
14 files changed
+372
-119
No files matched your search
@@ -227,6 +227,18 @@ function getHeroPositionClasses(mobilePos: string, desktopPos: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function getHeroContainerWidthClasses(contentWidth?: string) {
|
||||
switch (contentWidth) {
|
||||
case 'full':
|
||||
return 'w-full max-w-none px-6 md:px-12 lg:px-16'
|
||||
case 'compact':
|
||||
return 'w-full max-w-4xl mx-auto px-6'
|
||||
case 'standard':
|
||||
default:
|
||||
return 'w-full max-w-7xl mx-auto px-6 md:px-10 lg:px-12'
|
||||
}
|
||||
}
|
||||
|
||||
function HeroSection({ payload, lang }: { payload: Record<string, unknown>, lang: string }) {
|
||||
const { t } = useTranslation()
|
||||
const i18nLang = useLang()
|
||||
@@ -239,6 +251,9 @@ function HeroSection({ payload, lang }: { payload: Record<string, unknown>, lang
|
||||
const buttonLink = typeof payload.buttonLink === 'string' ? payload.buttonLink : '/shop'
|
||||
const desktopPosition = typeof payload.buttonPosition === 'string' ? payload.buttonPosition : 'center'
|
||||
const mobilePosition = typeof payload.mobileButtonPosition === 'string' ? payload.mobileButtonPosition : desktopPosition
|
||||
const contentWidth = typeof payload.contentWidth === 'string' ? payload.contentWidth : 'standard'
|
||||
const textColorScheme = typeof payload.textColorScheme === 'string' ? payload.textColorScheme : 'light'
|
||||
const isDarkText = textColorScheme === 'dark'
|
||||
const focalPoint = typeof payload.focalPoint === 'object' && payload.focalPoint ? (payload.focalPoint as { x: string, y: string }) : undefined
|
||||
|
||||
// If fields are explicitly defined as empty strings, respect them as empty
|
||||
@@ -256,6 +271,7 @@ function HeroSection({ payload, lang }: { payload: Record<string, unknown>, lang
|
||||
: 'Explore Collection'
|
||||
|
||||
const { wrapperClasses, contentClasses, actionsClasses } = getHeroPositionClasses(mobilePosition, desktopPosition)
|
||||
const containerClasses = getHeroContainerWidthClasses(contentWidth)
|
||||
|
||||
const overlayStyle = typeof payload.overlayStyle === 'string' ? payload.overlayStyle : 'gradient'
|
||||
const overlayOpacity = typeof payload.overlayOpacity === 'number' ? payload.overlayOpacity : 45
|
||||
@@ -266,12 +282,13 @@ function HeroSection({ payload, lang }: { payload: Record<string, unknown>, lang
|
||||
}
|
||||
|
||||
const opacityRatio = overlayOpacity / 100
|
||||
const rgb = isDarkText ? '255, 255, 255' : '0, 0, 0'
|
||||
|
||||
if (overlayStyle === 'solid') {
|
||||
return (
|
||||
<div
|
||||
className="absolute inset-0 transition-opacity duration-300"
|
||||
style={{ backgroundColor: `rgba(0, 0, 0, ${opacityRatio})` }}
|
||||
style={{ backgroundColor: `rgba(${rgb}, ${opacityRatio})` }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -285,14 +302,14 @@ function HeroSection({ payload, lang }: { payload: Record<string, unknown>, lang
|
||||
<div
|
||||
className="absolute inset-0 transition-opacity duration-300"
|
||||
style={{
|
||||
background: `linear-gradient(to top, rgba(0, 0, 0, ${bottomAlpha}) 0%, rgba(0, 0, 0, ${midAlpha}) 50%, rgba(0, 0, 0, ${topAlpha}) 100%)`,
|
||||
background: `linear-gradient(to top, rgba(${rgb}, ${bottomAlpha}) 0%, rgba(${rgb}, ${midAlpha}) 50%, rgba(${rgb}, ${topAlpha}) 100%)`,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="relative w-full min-h-[85vh] sm:min-h-[90vh] md:h-[90vh] md:aspect-[21/9] flex bg-night-950 overflow-hidden">
|
||||
<section className={`relative w-full min-h-[85vh] sm:min-h-[90vh] md:h-[90vh] md:aspect-[21/9] flex overflow-hidden ${isDarkText ? 'bg-surface-page' : 'bg-night-950'}`}>
|
||||
<div className="absolute inset-0 w-full h-full z-0">
|
||||
<Image
|
||||
src={imageUrl}
|
||||
@@ -302,23 +319,23 @@ function HeroSection({ payload, lang }: { payload: Record<string, unknown>, lang
|
||||
className="object-cover md:scale-[1.02]"
|
||||
style={{ objectPosition: focalPoint ? `${focalPoint.x} ${focalPoint.y}` : undefined }}
|
||||
/>
|
||||
{/* Dynamic Dark Gradient / Solid Overlay */}
|
||||
{/* Dynamic Dark / Light Gradient / Solid Overlay */}
|
||||
{renderOverlay()}
|
||||
</div>
|
||||
<div className={`relative z-10 w-full min-h-[85vh] sm:min-h-[90vh] md:min-h-full flex flex-col ${wrapperClasses}`}>
|
||||
<div className={`relative z-10 min-h-[85vh] sm:min-h-[90vh] md:min-h-full flex flex-col ${containerClasses} ${wrapperClasses}`}>
|
||||
<div className={`w-full max-w-3xl flex flex-col space-y-5 ${contentClasses}`}>
|
||||
{tagline && (
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-brand-accent drop-shadow-md md:text-sm">
|
||||
<p className={`text-xs font-semibold uppercase tracking-[0.3em] drop-shadow-md md:text-sm ${isDarkText ? 'text-brand-primary' : 'text-brand-accent'}`}>
|
||||
{tagline}
|
||||
</p>
|
||||
)}
|
||||
{title && (
|
||||
<h1 className="ui-hero-title !text-white drop-shadow-lg">
|
||||
{renderAccentTitle(title, 'ui-accent-text font-medium')}
|
||||
<h1 className={`ui-hero-title ${isDarkText ? '!text-text-main' : '!text-white'} drop-shadow-lg`}>
|
||||
{renderAccentTitle(title, isDarkText ? 'text-brand-primary font-medium' : 'ui-accent-text font-medium')}
|
||||
</h1>
|
||||
)}
|
||||
{description && (
|
||||
<p className={`ui-hero-copy !text-white/90 drop-shadow-md !pb-2 ${contentClasses.includes('text-left') ? '!mx-0' : contentClasses.includes('text-right') ? '!ml-auto !mr-0' : '!mx-auto'}`}>
|
||||
<p className={`ui-hero-copy ${isDarkText ? '!text-text-main/80' : '!text-white/90'} drop-shadow-md !pb-2 ${contentClasses.includes('text-left') ? '!mx-0' : contentClasses.includes('text-right') ? '!ml-auto !mr-0' : '!mx-auto'}`}>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
@@ -333,7 +350,7 @@ function HeroSection({ payload, lang }: { payload: Record<string, unknown>, lang
|
||||
)}
|
||||
<a
|
||||
href="#categories"
|
||||
className="ui-hero-link group flex items-center gap-1.5 drop-shadow-md hover:underline"
|
||||
className={`group flex items-center gap-1.5 drop-shadow-md hover:underline ${isDarkText ? '!text-text-main hover:!text-brand-primary' : 'ui-hero-link'}`}
|
||||
>
|
||||
<span>{t('dynamic.heroLearnMore', { lng: resolvedLang })}</span>
|
||||
<span className="transition-transform group-hover:translate-x-1">→</span>
|
||||
@@ -438,19 +455,25 @@ function HeroCarouselSection({ payload, lang }: { payload: Record<string, unknow
|
||||
{(title || subtitle || buttonText) && (() => {
|
||||
const slideDesktopPos = typeof slide.buttonPosition === 'string' ? slide.buttonPosition : 'bottom-left'
|
||||
const slideMobilePos = typeof slide.mobileButtonPosition === 'string' ? slide.mobileButtonPosition : slideDesktopPos
|
||||
const slideWidth = typeof slide.contentWidth === 'string' ? slide.contentWidth : 'standard'
|
||||
const slideColor = typeof slide.textColorScheme === 'string' ? slide.textColorScheme : 'light'
|
||||
const isDarkSlide = slideColor === 'dark'
|
||||
const { wrapperClasses: sWrap, contentClasses: sContent, actionsClasses: sActions } = getHeroPositionClasses(slideMobilePos, slideDesktopPos)
|
||||
const sContainer = getHeroContainerWidthClasses(slideWidth)
|
||||
return (
|
||||
<div className={`absolute inset-0 z-10 bg-gradient-to-t from-black/70 via-black/20 to-transparent flex flex-col p-6 md:p-10 ${sWrap}`}>
|
||||
<div className={`max-w-xl space-y-1.5 md:space-y-2 flex flex-col ${sContent}`}>
|
||||
{subtitle && <p className="text-[10px] md:text-xs uppercase font-bold tracking-widest text-brand-accent drop-shadow-md">{subtitle}</p>}
|
||||
{title && <h3 className="text-lg md:text-3xl font-bold text-white drop-shadow-md leading-tight">{renderAccentTitle(title)}</h3>}
|
||||
{buttonText && (
|
||||
<div className={`flex ${sActions}`}>
|
||||
<span className="inline-block mt-2 px-4 py-1.5 bg-brand-primary text-white text-xs font-bold rounded-full shadow-lg hover:bg-brand-primary-hover transition-all">
|
||||
{buttonText}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className={`absolute inset-0 z-10 flex flex-col py-6 md:py-10 ${isDarkSlide ? 'bg-gradient-to-t from-white/80 via-white/30 to-transparent' : 'bg-gradient-to-t from-black/70 via-black/20 to-transparent'} ${sWrap}`}>
|
||||
<div className={`w-full ${sContainer} flex flex-col ${sContent}`}>
|
||||
<div className={`space-y-1.5 md:space-y-2 flex flex-col ${sContent} ${slideWidth === 'full' ? 'max-w-2xl' : 'max-w-xl'}`}>
|
||||
{subtitle && <p className={`text-[10px] md:text-xs uppercase font-bold tracking-widest drop-shadow-md ${isDarkSlide ? 'text-brand-primary' : 'text-brand-accent'}`}>{subtitle}</p>}
|
||||
{title && <h3 className={`text-lg md:text-3xl font-bold drop-shadow-md leading-tight ${isDarkSlide ? 'text-text-main' : 'text-white'}`}>{renderAccentTitle(title)}</h3>}
|
||||
{buttonText && (
|
||||
<div className={`flex ${sActions}`}>
|
||||
<span className="inline-block mt-2 px-4 py-1.5 bg-brand-primary text-white text-xs font-bold rounded-full shadow-lg hover:bg-brand-primary-hover transition-all">
|
||||
{buttonText}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -505,10 +528,14 @@ function HeroVideoSection({ payload, lang }: { payload: Record<string, unknown>,
|
||||
|
||||
const desktopPosition = typeof payload.buttonPosition === 'string' ? payload.buttonPosition : 'center'
|
||||
const mobilePosition = typeof payload.mobileButtonPosition === 'string' ? payload.mobileButtonPosition : desktopPosition
|
||||
const contentWidth = typeof payload.contentWidth === 'string' ? payload.contentWidth : 'standard'
|
||||
const textColorScheme = typeof payload.textColorScheme === 'string' ? payload.textColorScheme : 'light'
|
||||
const isDarkText = textColorScheme === 'dark'
|
||||
const { wrapperClasses, contentClasses, actionsClasses } = getHeroPositionClasses(mobilePosition, desktopPosition)
|
||||
const containerClasses = getHeroContainerWidthClasses(contentWidth)
|
||||
|
||||
return (
|
||||
<section className={`relative w-full ${getHeightClass(height)} overflow-hidden flex bg-[#0B0F17] text-white`}>
|
||||
<section className={`relative w-full ${getHeightClass(height)} overflow-hidden flex ${isDarkText ? 'bg-surface-page text-text-main' : 'bg-[#0B0F17] text-white'}`}>
|
||||
{videoUrl ? (
|
||||
<video
|
||||
autoPlay={payload.autoplay !== false}
|
||||
@@ -543,22 +570,22 @@ function HeroVideoSection({ payload, lang }: { payload: Record<string, unknown>,
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<div className="absolute inset-0 z-10 bg-black transition-opacity" style={{ opacity: overlayOpacity / 100 }}></div>
|
||||
<div className={`absolute inset-0 z-10 transition-opacity ${isDarkText ? 'bg-white' : 'bg-black'}`} style={{ opacity: overlayOpacity / 100 }}></div>
|
||||
|
||||
<div className={`relative z-20 mx-auto px-6 py-16 w-full max-w-5xl h-full flex flex-col ${wrapperClasses}`}>
|
||||
<div className={`relative z-20 py-16 h-full flex flex-col ${containerClasses} ${wrapperClasses}`}>
|
||||
<div className={`flex flex-col space-y-6 max-w-3xl ${contentClasses}`}>
|
||||
{tagline && (
|
||||
<p className="text-xs md:text-sm font-semibold uppercase tracking-[0.35em] text-brand-accent drop-shadow-md">
|
||||
<p className={`text-xs md:text-sm font-semibold uppercase tracking-[0.35em] drop-shadow-md ${isDarkText ? 'text-brand-primary' : 'text-brand-accent'}`}>
|
||||
{tagline}
|
||||
</p>
|
||||
)}
|
||||
{title && (
|
||||
<h1 className="font-serif text-4xl md:text-6xl lg:text-7xl font-light leading-tight tracking-wide drop-shadow-lg text-white">
|
||||
{renderAccentTitle(title)}
|
||||
<h1 className={`font-serif text-4xl md:text-6xl lg:text-7xl font-light leading-tight tracking-wide drop-shadow-lg ${isDarkText ? 'text-text-main' : 'text-white'}`}>
|
||||
{renderAccentTitle(title, isDarkText ? 'text-brand-primary font-medium' : undefined)}
|
||||
</h1>
|
||||
)}
|
||||
{description && (
|
||||
<p className="max-w-2xl text-sm md:text-lg font-light leading-relaxed opacity-90 drop-shadow">
|
||||
<p className={`max-w-2xl text-sm md:text-lg font-light leading-relaxed drop-shadow ${isDarkText ? 'text-text-main/80' : 'opacity-90'}`}>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
@@ -567,7 +594,11 @@ function HeroVideoSection({ payload, lang }: { payload: Record<string, unknown>,
|
||||
{buttonText && buttonLink && (
|
||||
<Link
|
||||
href={buttonLink}
|
||||
className="px-8 py-3.5 bg-white text-neutral-900 font-medium text-xs uppercase tracking-widest hover:bg-brand-primary hover:text-white transition-all shadow-lg rounded-sm"
|
||||
className={`px-8 py-3.5 font-medium text-xs uppercase tracking-widest transition-all shadow-lg rounded-sm ${
|
||||
isDarkText
|
||||
? 'bg-brand-primary text-white hover:bg-brand-primary-hover'
|
||||
: 'bg-white text-neutral-900 hover:bg-brand-primary hover:text-white'
|
||||
}`}
|
||||
>
|
||||
{buttonText}
|
||||
</Link>
|
||||
@@ -575,7 +606,11 @@ function HeroVideoSection({ payload, lang }: { payload: Record<string, unknown>,
|
||||
{secondaryButtonText && secondaryButtonLink && (
|
||||
<Link
|
||||
href={secondaryButtonLink}
|
||||
className="px-8 py-3.5 bg-transparent border border-white/40 text-white font-medium text-xs uppercase tracking-widest hover:bg-white/10 hover:border-white transition-all rounded-sm backdrop-blur-sm"
|
||||
className={`px-8 py-3.5 bg-transparent border font-medium text-xs uppercase tracking-widest transition-all rounded-sm backdrop-blur-sm ${
|
||||
isDarkText
|
||||
? 'border-neutral-900/40 text-neutral-900 hover:bg-neutral-900/10 hover:border-neutral-900'
|
||||
: 'border-white/40 text-white hover:bg-white/10 hover:border-white'
|
||||
}`}
|
||||
>
|
||||
{secondaryButtonText}
|
||||
</Link>
|
||||
@@ -1123,10 +1158,19 @@ function BannerSection({ payload, lang }: { payload: Record<string, unknown>, la
|
||||
|
||||
const desktopPosition = typeof payload.buttonPosition === 'string' ? payload.buttonPosition : 'center-left'
|
||||
const mobilePosition = typeof payload.mobileButtonPosition === 'string' ? payload.mobileButtonPosition : desktopPosition
|
||||
const contentWidth = typeof payload.contentWidth === 'string' ? payload.contentWidth : 'standard'
|
||||
const textColorScheme = typeof payload.textColorScheme === 'string' ? payload.textColorScheme : 'light'
|
||||
const isDarkText = textColorScheme === 'dark'
|
||||
const { wrapperClasses: bWrap, contentClasses: bContent, actionsClasses: bActions } = getHeroPositionClasses(mobilePosition, desktopPosition)
|
||||
|
||||
const shellWidthClass = contentWidth === 'full'
|
||||
? '!max-w-none !rounded-none md:!rounded-3xl mx-4 md:mx-8'
|
||||
: contentWidth === 'compact'
|
||||
? '!max-w-4xl'
|
||||
: '!max-w-7xl'
|
||||
|
||||
const content = (
|
||||
<div className={`ui-banner-shell flex flex-col ${bWrap}`}>
|
||||
<div className={`ui-banner-shell flex flex-col ${shellWidthClass} ${bWrap}`}>
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt={title || 'Banner'}
|
||||
@@ -1135,13 +1179,17 @@ function BannerSection({ payload, lang }: { payload: Record<string, unknown>, la
|
||||
className="absolute inset-0 h-full w-full object-cover"
|
||||
style={{ objectPosition: focalPoint ? `${focalPoint.x} ${focalPoint.y}` : undefined }}
|
||||
/>
|
||||
<div className="ui-banner-overlay" />
|
||||
<div className={isDarkText ? "absolute inset-0 bg-white/40 backdrop-blur-[1px]" : "ui-banner-overlay"} />
|
||||
<div className={`ui-banner-content flex flex-col space-y-4 max-w-2xl ${bContent}`}>
|
||||
{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>}
|
||||
{title && <h2 className={`text-3xl font-semibold drop-shadow-md md:text-5xl ${isDarkText ? '!text-text-main' : 'text-brand-primary'}`}>{title}</h2>}
|
||||
{description && <p className={`drop-shadow-sm ${isDarkText ? '!text-text-main/80' : 'text-surface-page/90'}`}>{description}</p>}
|
||||
{buttonText && (
|
||||
<div className={`flex ${bActions}`}>
|
||||
<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>
|
||||
<span className={`inline-flex cursor-pointer rounded-full px-6 py-3 font-semibold transition-colors ${
|
||||
isDarkText
|
||||
? 'bg-brand-primary text-white hover:bg-brand-primary-hover shadow-md'
|
||||
: 'bg-surface-card text-text-main hover:bg-brand-primary hover:text-surface-card'
|
||||
}`}>{buttonText}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user