wwwfiberdirekt/src/blocks/FDSpecCardsBlock/Component.tsx

192 lines
6.1 KiB
TypeScript

import React from 'react'
import type { FDSpecCardsBlock as Props } from '@/payload-types'
import { FDButton } from '@/components/FDButton'
import {
sectionBg, isExplicitDark, headingColor, bodyColor,
bodySubduedColor, fdCardRadius, fdCardRadiusSm,
} from '@/utilities/fdTheme'
const cardStyleMap: Record<string, {
bg: string; border: string; title: string; body: string
specLabel: string; specValue: string; divider: string; isDark: boolean
}> = {
outlined: {
bg: 'bg-transparent',
border: 'border border-white/15 dark:border-white/15',
title: 'text-white dark:text-white',
body: 'text-white/70 dark:text-white/70',
specLabel: 'text-white/50 dark:text-white/50',
specValue: 'text-white dark:text-white',
divider: 'border-white/10 dark:border-white/10',
isDark: true,
},
navy: {
bg: 'bg-fd-navy dark:bg-white/10',
border: '',
title: 'text-white',
body: 'text-white/70',
specLabel: 'text-white/50',
specValue: 'text-fd-yellow',
divider: 'border-white/10',
isDark: true,
},
gray: {
bg: 'bg-fd-gray-light dark:bg-white/10',
border: '',
title: 'text-fd-navy dark:text-white',
body: 'text-fd-navy/70 dark:text-white/70',
specLabel: 'text-fd-navy/50 dark:text-white/50',
specValue: 'text-fd-navy dark:text-white',
divider: 'border-fd-navy/10 dark:border-white/10',
isDark: false,
},
white: {
bg: 'bg-white dark:bg-white/10 shadow-fd-card dark:shadow-none',
border: '',
title: 'text-fd-navy dark:text-white',
body: 'text-fd-navy/70 dark:text-white/70',
specLabel: 'text-fd-navy/50 dark:text-white/50',
specValue: 'text-fd-navy dark:text-white',
divider: 'border-fd-navy/10 dark:border-white/10',
isDark: false,
},
}
/* Light-section overrides for outlined cards */
const cardStyleMapLight: Record<string, typeof cardStyleMap.outlined> = {
outlined: {
bg: 'bg-transparent',
border: 'border border-gray-200 dark:border-white/15',
title: 'text-fd-navy dark:text-white',
body: 'text-fd-navy/70 dark:text-white/70',
specLabel: 'text-fd-navy/50 dark:text-white/50',
specValue: 'text-fd-navy dark:text-white',
divider: 'border-fd-navy/10 dark:border-white/10',
isDark: false,
},
}
export const FDSpecCardsBlockComponent: React.FC<Props> = ({
heading,
description,
ctaText,
ctaLink,
secondaryCtaText,
secondaryCtaLink,
cards,
layout = 'sideBySide',
cardStyle = 'outlined',
sectionBackground = 'navy',
anchorId,
}) => {
const dark = isExplicitDark(sectionBackground)
const bg = sectionBg(sectionBackground)
const hClr = headingColor(dark)
const bClr = bodySubduedColor(dark)
const style = (!dark && cardStyle === 'outlined')
? cardStyleMapLight.outlined
: (cardStyleMap[cardStyle || 'outlined'] || cardStyleMap.outlined)
const isSideBySide = layout === 'sideBySide' || layout === 'sideBySideReverse'
const isReversed = layout === 'sideBySideReverse'
const cardCount = cards?.length || 1
/* Cards grid: 1 card = 1 col, 2 = 2-col, 3+ = 2-col wrapping */
const cardGridCols = cardCount === 1 ? '' : 'sm:grid-cols-2'
const renderCards = () => (
<div className={`grid grid-cols-1 ${cardGridCols} gap-4 md:gap-5`}>
{cards?.map((card, i) => (
<div
key={i}
className={`${style.bg} ${style.border} ${fdCardRadiusSm} px-7 py-7 md:px-9 md:py-9 flex flex-col gap-4 justify-between`}
>
<div className="flex flex-col gap-3">
<h3 className={`font-joey-bold text-fd-h3 leading-snug ${style.title}`}>
{card.title}
</h3>
{card.description && (
<p className={`font-joey text-fd-body leading-relaxed ${style.body}`}>
{card.description}
</p>
)}
</div>
{(card.specLabel || card.specValue) && (
<div className={`pt-4 mt-auto border-t ${style.divider}`}>
{card.specLabel && (
<span className={`font-joey text-fd-small block mb-1 ${style.specLabel}`}>
{card.specLabel}
</span>
)}
{card.specValue && (
<span className={`font-joey-bold text-fd-h4 ${style.specValue}`}>
{card.specValue}
</span>
)}
</div>
)}
</div>
))}
</div>
)
const renderText = () => (
<div className="flex flex-col gap-5 md:gap-6 justify-center">
<h2 className={`font-joey-heavy text-fd-h1 leading-tight ${hClr}`}>
{heading}
</h2>
{description && (
<p className={`font-joey text-fd-body-lg leading-relaxed ${bClr}`}>
{description}
</p>
)}
{(ctaText || secondaryCtaText) && (
<div className="flex flex-wrap gap-4 pt-2">
{ctaText && (
<FDButton href={ctaLink || '#'} variant="outline" onDark={dark}>
{ctaText}
</FDButton>
)}
{secondaryCtaText && (
<FDButton href={secondaryCtaLink || '#'} variant="primary" onDark={dark}>
{secondaryCtaText}
</FDButton>
)}
</div>
)}
</div>
)
if (!isSideBySide) {
/* Full-width layout — heading on top, cards below */
return (
<section id={anchorId || undefined} className={`w-full py-16 md:py-20 lg:py-[99px] ${bg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
<div className="mb-10 md:mb-14">
{renderText()}
</div>
{renderCards()}
</div>
</section>
)
}
/* Side-by-side layout */
return (
<section id={anchorId || undefined} className={`w-full py-16 md:py-20 lg:py-[99px] ${bg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
<div className={`flex flex-col min-[820px]:flex-row gap-10 min-[820px]:gap-14 items-start ${isReversed ? 'min-[820px]:flex-row-reverse' : ''}`}>
<div className="flex-1 min-w-0 min-[820px]:max-w-[380px]">
{renderText()}
</div>
<div className="flex-[1.5] min-w-0">
{renderCards()}
</div>
</div>
</div>
</section>
)
}