import { Link } from 'react-router-dom'; import type { HeroSectionPayload } from '@homaroma/types'; import { useTranslation } from 'react-i18next'; import { getLocalizedField } from '../utils/localization'; interface DynamicHeroProps { payload: HeroSectionPayload; } // Map 9-box grid position to mobile flex classes export const getHeroMobilePositionClasses = (pos: string) => { switch (pos) { case 'top-left': return { wrapper: 'justify-start items-start text-left pt-20 pb-12 pl-6 pr-6', content: 'items-start text-left', actions: 'items-start justify-start' }; case 'top-center': return { wrapper: 'justify-start items-center text-center pt-20 pb-12 px-6', content: 'items-center text-center', actions: 'items-center justify-center' }; case 'top-right': return { wrapper: 'justify-start items-end text-right pt-20 pb-12 pr-6 pl-6', content: 'items-end text-right', actions: 'items-end justify-end' }; case 'center-left': return { wrapper: 'justify-center items-start text-left py-16 pl-6 pr-6', content: 'items-start text-left', actions: 'items-start justify-start' }; case 'center-right': return { wrapper: 'justify-center items-end text-right py-16 pr-6 pl-6', content: 'items-end text-right', actions: 'items-end justify-end' }; case 'bottom-left': return { wrapper: 'justify-end items-start text-left pt-12 pb-16 pl-6 pr-6', content: 'items-start text-left', actions: 'items-start justify-start' }; case 'bottom-center': return { wrapper: 'justify-end items-center text-center pt-12 pb-16 px-6', content: 'items-center text-center', actions: 'items-center justify-center' }; case 'bottom-right': return { wrapper: 'justify-end items-end text-right pt-12 pb-16 pr-6 pl-6', content: 'items-end text-right', actions: 'items-end justify-end' }; case 'center': default: return { wrapper: 'justify-center items-center text-center py-16 px-6', content: 'items-center text-center', actions: 'items-center justify-center' }; } }; // Map 9-box grid position to desktop (md:) flex classes export const getHeroDesktopPositionClasses = (pos: string) => { switch (pos) { case 'top-left': return { wrapper: 'md:justify-start md:items-start md:text-left md:pt-28 md:pb-12 md:pl-16 md:pr-6', content: 'md:items-start md:text-left', actions: 'md:items-start md:justify-start' }; case 'top-center': return { wrapper: 'md:justify-start md:items-center md:text-center md:pt-28 md:pb-12 md:px-6', content: 'md:items-center md:text-center', actions: 'md:items-center md:justify-center' }; case 'top-right': return { wrapper: 'md:justify-start md:items-end md:text-right md:pt-28 md:pb-12 md:pr-16 md:pl-6', content: 'md:items-end md:text-right', actions: 'md:items-end md:justify-end' }; case 'center-left': return { wrapper: 'md:justify-center md:items-start md:text-left md:py-16 md:pl-16 md:pr-6', content: 'md:items-start md:text-left', actions: 'md:items-start md:justify-start' }; case 'center-right': return { wrapper: 'md:justify-center md:items-end md:text-right md:py-16 md:pr-16 md:pl-6', content: 'md:items-end md:text-right', actions: 'md:items-end md:justify-end' }; case 'bottom-left': return { wrapper: 'md:justify-end md:items-start md:text-left md:pt-12 md:pb-24 md:pl-16 md:pr-6', content: 'md:items-start md:text-left', actions: 'md:items-start md:justify-start' }; case 'bottom-center': return { wrapper: 'md:justify-end md:items-center md:text-center md:pt-12 md:pb-24 md:px-6', content: 'md:items-center md:text-center', actions: 'md:items-center md:justify-center' }; case 'bottom-right': return { wrapper: 'md:justify-end md:items-end md:text-right md:pt-12 md:pb-24 md:pr-16 md:pl-6', content: 'md:items-end md:text-right', actions: 'md:items-end md:justify-end' }; case 'center': default: return { wrapper: 'md:justify-center md:items-center md:text-center md:py-16 md:px-6', content: 'md:items-center md:text-center', actions: 'md:items-center md:justify-center' }; } }; export function getHeroPositionClasses(mobilePos: string, desktopPos: string) { const mClasses = getHeroMobilePositionClasses(mobilePos); const dClasses = getHeroDesktopPositionClasses(desktopPos); return { wrapperClasses: `${mClasses.wrapper} ${dClasses.wrapper}`, contentClasses: `${mClasses.content} ${dClasses.content}`, actionsClasses: `${mClasses.actions} ${dClasses.actions}`, }; } export 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'; } } export function getHeroTitleSizeClass(titleSize?: string): string { switch (titleSize) { case 'sm': return 'ui-hero-title-sm'; case 'md': return 'ui-hero-title-md'; case 'lg': return 'ui-hero-title-lg'; case 'xl': default: return 'ui-hero-title-xl'; } } export default function DynamicHero({ payload }: DynamicHeroProps) { const { t, i18n } = useTranslation(); const lang = i18n.language; const { imageUrl, buttonLink } = payload; const desktopPosition = (payload as any).buttonPosition || 'center'; const mobilePosition = (payload as any).mobileButtonPosition || desktopPosition; const contentWidth = (payload as any).contentWidth || 'standard'; const focalPoint = typeof payload.focalPoint === 'object' && payload.focalPoint ? (payload.focalPoint as { x: string, y: string }) : undefined; // Localized values const rawTagline = getLocalizedField(payload.tagline, lang); const rawTitle = getLocalizedField(payload.title, lang); const rawDescription = getLocalizedField(payload.description, lang); const rawButtonText = getLocalizedField(payload.buttonText, lang); // If fields are explicitly defined as empty strings, respect them as empty const hasTagline = payload.tagline !== undefined && payload.tagline !== null ? !!rawTagline?.trim() : true; const tagline = hasTagline ? (rawTagline || t('hero.defaultTagline')) : ''; const hasTitle = payload.title !== undefined && payload.title !== null ? !!rawTitle?.trim() : true; const title = hasTitle ? (rawTitle || t('hero.defaultTitle')) : ''; const hasDescription = payload.description !== undefined && payload.description !== null ? !!rawDescription?.trim() : false; const description = hasDescription ? rawDescription : ''; const buttonText = rawButtonText !== undefined && rawButtonText !== null ? rawButtonText.trim() : t('hero.exploreCollection'); const textColorScheme = (payload as any).textColorScheme || 'light'; const isDarkText = textColorScheme === 'dark'; const renderTitle = (text: string) => { if (!text) return null; return text.split('[').map((part, i) => { if (part.includes(']')) { const [accent, rest] = part.split(']'); return ( {accent} {rest} ); } return {part}; }); }; const { wrapperClasses, contentClasses, actionsClasses } = getHeroPositionClasses(mobilePosition, desktopPosition); const overlayStyle = (payload as any).overlayStyle || 'gradient'; const overlayOpacity = (payload as any).overlayOpacity !== undefined ? (payload as any).overlayOpacity : 45; const renderOverlay = () => { if (overlayStyle === 'none' || overlayOpacity === 0) { return null; } const opacityRatio = overlayOpacity / 100; if (overlayStyle === 'solid') { return (
); } // Gradient style (default): smooth vertical gradient scaled by opacity const bottomAlpha = Math.min(0.95, opacityRatio * 1.85); const midAlpha = opacityRatio; const topAlpha = Math.max(0, opacityRatio * 0.65); const rgb = isDarkText ? '255, 255, 255' : '0, 0, 0'; return (
); }; const containerClasses = getHeroContainerWidthClasses(contentWidth); const titleSize = (payload as any).titleSize || 'xl'; const titleSizeClass = getHeroTitleSizeClass(titleSize); const textWrapperWidthClass = titleSize === 'sm' || contentWidth === 'compact' ? 'max-w-xl' : titleSize === 'md' ? 'max-w-2xl' : 'max-w-3xl'; const aspectRatio = (payload as any).aspectRatio; const mobileAspectRatio = (payload as any).mobileAspectRatio; const mobileImageUrl = (payload as any).mobileImageUrl; const isFullScreen = !aspectRatio || aspectRatio === 'full_screen'; const getAspectClass = () => { switch (aspectRatio) { case '21/6': return 'md:aspect-[21/6]'; case '21/7': return 'md:aspect-[21/7]'; case '21/9': return 'md:aspect-[21/9]'; case '16/5': return 'md:aspect-[16/5]'; case '16/6': return 'md:aspect-[16/6]'; case '4/1': return 'md:aspect-[4/1]'; case '5/1': return 'md:aspect-[5/1]'; case 'full_screen': return 'md:h-[90vh] md:aspect-[21/9]'; default: return 'md:aspect-[21/7]'; } }; const getMobileAspectClass = () => { switch (mobileAspectRatio) { case '16/9': return 'aspect-[16/9]'; case '4/3': return 'aspect-[4/3]'; case '1/1': return 'aspect-[1/1]'; case '21/9': return 'aspect-[21/9]'; case 'full_screen': return 'min-h-[85vh]'; default: return 'aspect-[16/9]'; } }; const sectionHeightClass = isFullScreen ? 'min-h-[85vh] sm:min-h-[90vh] md:h-[90vh] md:aspect-[21/9]' : `${getMobileAspectClass()} ${getAspectClass()}`; const innerHeightClass = isFullScreen ? 'min-h-[85vh] sm:min-h-[90vh] md:min-h-full' : 'h-full justify-center'; return (
Hero Background { (e.target as HTMLImageElement).style.display = 'none'; }} /> {mobileImageUrl && ( Hero Background Mobile { (e.target as HTMLImageElement).style.display = 'none'; }} /> )} {/* Dynamic Dark / Light Gradient / Solid Overlay */} {renderOverlay()}
{tagline && (

{tagline}

)} {title && (

{renderTitle(title)}

)} {description && (

{description}

)}
{buttonText && ( {buttonText} )} {t('hero.learnMore')} →
); }