feat: dark mode across all blocks

This commit is contained in:
Jeffrey 2026-02-20 11:17:18 +01:00
parent 097615569b
commit 576ecf1e97
22 changed files with 397 additions and 259 deletions

View File

@ -14,12 +14,24 @@ export const FDAlternateHeroBlockComponent: React.FC<Props> = ({
imageCaption,
sectionBackground = 'white',
}) => {
const media = image as Media | undefined
const media = image as Media | undefined
const hasImage = media && typeof media === 'object' && media.url
const isDark = sectionBackground === 'navy'
const bgClass = isDark ? 'bg-fd-navy' : sectionBackground === 'gray' ? 'bg-fd-gray-light' : 'bg-white'
const titleClass = isDark ? 'text-fd-yellow' : 'text-fd-navy'
const bodyClass = isDark ? 'text-white' : 'text-fd-navy'
const isDark = sectionBackground === 'navy'
const bgClass =
isDark
? 'bg-fd-navy'
: sectionBackground === 'gray'
? 'bg-fd-gray-light dark:bg-fd-navy'
: 'bg-white dark:bg-fd-navy'
const titleClass = isDark
? 'text-fd-yellow'
: 'text-fd-navy dark:text-fd-yellow'
const bodyClass = isDark
? 'text-white'
: 'text-fd-navy dark:text-white'
return (
<section className={`w-full pt-16 md:pt-20 lg:pt-[99px] ${bgClass}`}>
@ -49,7 +61,7 @@ export const FDAlternateHeroBlockComponent: React.FC<Props> = ({
)}
</div>
{/* FIX: Full-width image using FDImage with fill, replacing raw <img> */}
{/* Full-width image — no border radius, bleeds edge to edge */}
{hasImage && (
<div className="w-full">
<div className="relative w-full" style={{ maxHeight: '620px', height: '45vw', minHeight: '220px' }}>

View File

@ -1,42 +1,44 @@
// @ts-nocheck
import React from 'react'
import type { FDCtaBannerBlock as FDCtaBannerBlockProps } from '@/payload-types'
const bgMap: Record<string, { section: string; heading: string; sub: string; primaryBtn: string; secondaryBtn: string }> = {
const bgMap: Record<string, {
section: string; heading: string; sub: string
primaryBtn: string; secondaryBtn: string
}> = {
yellow: {
section: 'bg-fd-yellow',
heading: 'text-fd-navy',
sub: 'text-fd-navy/70',
primaryBtn: 'bg-fd-navy hover:bg-fd-navy/90 text-white',
section: 'bg-fd-yellow',
heading: 'text-fd-navy',
sub: 'text-fd-navy/70',
primaryBtn: 'bg-fd-navy hover:bg-fd-navy/90 text-white',
secondaryBtn: 'border-2 border-fd-navy text-fd-navy hover:bg-fd-navy/10',
},
navy: {
section: 'bg-fd-navy',
heading: 'text-fd-yellow',
sub: 'text-white/70',
primaryBtn: 'bg-fd-yellow hover:bg-fd-yellow/90 text-fd-navy',
section: 'bg-fd-navy',
heading: 'text-fd-yellow',
sub: 'text-white/70',
primaryBtn: 'bg-fd-yellow hover:bg-fd-yellow/90 text-fd-navy',
secondaryBtn: 'border-2 border-white text-white hover:bg-white/10',
},
gray: {
section: 'bg-[#e5e5e5]',
heading: 'text-fd-navy',
sub: 'text-fd-navy/70',
primaryBtn: 'bg-fd-navy hover:bg-fd-navy/90 text-white',
secondaryBtn: 'border-2 border-fd-navy text-fd-navy hover:bg-fd-navy/10',
section: 'bg-fd-gray-light dark:bg-fd-navy',
heading: 'text-fd-navy dark:text-fd-yellow',
sub: 'text-fd-navy/70 dark:text-white/70',
primaryBtn: 'bg-fd-navy hover:bg-fd-navy/90 text-white dark:bg-fd-yellow dark:hover:bg-fd-yellow/90 dark:text-fd-navy',
secondaryBtn: 'border-2 border-fd-navy text-fd-navy hover:bg-fd-navy/10 dark:border-white dark:text-white dark:hover:bg-white/10',
},
white: {
section: 'bg-white',
heading: 'text-fd-navy',
sub: 'text-fd-navy/70',
primaryBtn: 'bg-fd-navy hover:bg-fd-navy/90 text-white',
secondaryBtn: 'border-2 border-fd-navy text-fd-navy hover:bg-fd-navy/10',
section: 'bg-white dark:bg-fd-navy',
heading: 'text-fd-navy dark:text-fd-yellow',
sub: 'text-fd-navy/70 dark:text-white/70',
primaryBtn: 'bg-fd-navy hover:bg-fd-navy/90 text-white dark:bg-fd-yellow dark:hover:bg-fd-yellow/90 dark:text-fd-navy',
secondaryBtn: 'border-2 border-fd-navy text-fd-navy hover:bg-fd-navy/10 dark:border-white dark:text-white dark:hover:bg-white/10',
},
}
const sizeMap: Record<string, { py: string; heading: string; sub: string }> = {
small: { py: 'py-10 md:py-14', heading: 'text-2xl md:text-3xl lg:text-4xl', sub: 'text-base md:text-lg' },
medium: { py: 'py-14 md:py-20 lg:py-[80px]', heading: 'text-3xl md:text-4xl lg:text-5xl', sub: 'text-lg md:text-xl' },
large: { py: 'py-16 md:py-24 lg:py-[99px]', heading: 'text-4xl md:text-5xl lg:text-[64px]', sub: 'text-xl md:text-2xl' },
small: { py: 'py-10 md:py-14', heading: 'text-fd-h2', sub: 'text-fd-body' },
medium: { py: 'py-14 md:py-20 lg:py-[80px]', heading: 'text-fd-h1', sub: 'text-fd-body-lg' },
large: { py: 'py-16 md:py-24 lg:py-[99px]', heading: 'text-fd-display', sub: 'text-fd-body-lg' },
}
export const FDCtaBannerBlockComponent: React.FC<FDCtaBannerBlockProps> = ({
@ -50,8 +52,8 @@ export const FDCtaBannerBlockComponent: React.FC<FDCtaBannerBlockProps> = ({
alignment = 'center',
size = 'medium',
}) => {
const theme = bgMap[sectionBackground] || bgMap.yellow
const sizing = sizeMap[size] || sizeMap.medium
const theme = bgMap[sectionBackground ?? 'yellow'] || bgMap.yellow
const sizing = sizeMap[size ?? 'medium'] || sizeMap.medium
const isCenter = alignment === 'center'
return (
@ -75,7 +77,7 @@ export const FDCtaBannerBlockComponent: React.FC<FDCtaBannerBlockProps> = ({
{ctaText && (
<a
href={ctaLink || '#'}
className={`inline-flex items-center justify-center px-8 py-3 rounded-full font-joey-bold text-lg transition-colors ${theme.primaryBtn}`}
className={`inline-flex items-center justify-center px-8 py-3 rounded-full font-joey-bold text-fd-btn transition-colors ${theme.primaryBtn}`}
>
{ctaText}
</a>
@ -83,7 +85,7 @@ export const FDCtaBannerBlockComponent: React.FC<FDCtaBannerBlockProps> = ({
{secondaryCtaText && secondaryCtaLink && (
<a
href={secondaryCtaLink}
className={`inline-flex items-center justify-center px-8 py-3 rounded-full font-joey-bold text-lg transition-colors ${theme.secondaryBtn}`}
className={`inline-flex items-center justify-center px-8 py-3 rounded-full font-joey-bold text-fd-btn transition-colors ${theme.secondaryBtn}`}
>
{secondaryCtaText}
</a>

View File

@ -16,26 +16,32 @@ export const FDCtaSideImageBlockComponent: React.FC<FDCtaSideImageBlockProps> =
const isDark = theme === 'dark'
const hasImage = !!image
// Light theme adapts to OS dark preference → becomes navy bg
const sectionBg = isDark
? 'bg-fd-navy'
: 'bg-white dark:bg-fd-navy'
const headingClass = isDark
? 'text-fd-yellow'
: 'text-fd-navy dark:text-fd-yellow'
const bodyClass = isDark
? 'text-white'
: 'text-fd-navy dark:text-white'
const textContent = (
<div className={`flex flex-col flex-1 items-start gap-8 lg:gap-[41px] ${!hasImage ? 'max-w-2xl' : ''}`}>
<div className="flex flex-col items-start gap-4 w-full">
<h2
className={`w-full font-joey-heavy text-fd-h1 leading-tight ${
isDark ? 'text-fd-yellow' : 'text-fd-navy'
}`}
>
<h2 className={`w-full font-joey-heavy text-fd-h1 leading-tight ${headingClass}`}>
{heading}
</h2>
<p
className={`w-full font-joey text-fd-body-lg leading-relaxed ${
isDark ? 'text-white' : 'text-fd-navy'
}`}
>
<p className={`w-full font-joey text-fd-body-lg leading-relaxed ${bodyClass}`}>
{body}
</p>
</div>
{ctaText && (
// onDark — either explicit dark theme, or dark: mode makes it navy anyway
<FDButton href={ctaLink || '#'} variant="primary" onDark={isDark}>
{ctaText}
</FDButton>
@ -56,19 +62,12 @@ export const FDCtaSideImageBlockComponent: React.FC<FDCtaSideImageBlockProps> =
) : null
return (
// FIX: added md:py-20 so tablet gets correct spacing
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${isDark ? 'bg-fd-navy' : 'bg-white'}`}>
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${sectionBg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8 flex flex-col lg:flex-row items-center gap-10 lg:gap-16">
{imagePosition === 'left' ? (
<>
{imageContent}
{textContent}
</>
<>{imageContent}{textContent}</>
) : (
<>
{textContent}
{imageContent}
</>
<>{textContent}{imageContent}</>
)}
</div>
</section>

View File

@ -10,16 +10,29 @@ export const FDFaqBlockComponent: React.FC<FDFaqBlockProps> = ({
}) => {
const [openIndex, setOpenIndex] = useState<number | null>(null)
// dark theme = always navy. gray/white adapt via dark: OS preference
const bgClass =
theme === 'dark'
? 'bg-fd-navy'
: theme === 'gray'
? 'bg-fd-gray-light'
: 'bg-white'
const headingColor = theme === 'dark' ? 'text-fd-yellow' : 'text-fd-navy'
const textColor = theme === 'dark' ? 'text-white' : 'text-fd-navy'
const borderColor = theme === 'dark' ? 'border-white/20' : 'border-fd-navy/10'
const proseColor = theme === 'dark' ? 'text-white/80' : 'text-fd-navy/80'
? 'bg-fd-gray-light dark:bg-fd-navy'
: 'bg-white dark:bg-fd-navy'
const headingColor = theme === 'dark'
? 'text-fd-yellow'
: 'text-fd-navy dark:text-fd-yellow'
const textColor = theme === 'dark'
? 'text-white'
: 'text-fd-navy dark:text-white'
const borderColor = theme === 'dark'
? 'border-white/20'
: 'border-fd-navy/10 dark:border-white/20'
const proseColor = theme === 'dark'
? 'text-white/80'
: 'text-fd-navy/80 dark:text-white/80'
return (
<section className={`w-full py-16 md:py-20 lg:py-[130px] ${bgClass}`}>

View File

@ -11,21 +11,36 @@ export const FDFeatureAnnouncementBlockComponent: React.FC<FDFeatureAnnouncement
}) => {
const isDark = theme === 'dark'
const bgClass = isDark ? 'bg-fd-navy' : theme === 'gray' ? 'bg-fd-gray' : 'bg-white'
const headingColor = isDark ? 'text-fd-yellow' : 'text-fd-navy'
const bodyColor = isDark ? 'text-white' : 'text-fd-navy'
// Light themes pick up dark: variants from OS preference
const bgClass =
isDark
? 'bg-fd-navy'
: theme === 'gray'
? 'bg-fd-gray-light dark:bg-fd-navy'
: 'bg-white dark:bg-fd-navy'
const headingColor = isDark
? 'text-fd-yellow'
: 'text-fd-navy dark:text-fd-yellow'
const bodyColor = isDark
? 'text-white'
: 'text-fd-navy dark:text-white'
// In dark mode the section is always navy, so onDark=true for the button
const onDark = isDark || true // once dark: kicks in bg is navy anyway
return (
<section className={`w-full py-20 md:py-28 lg:py-[173px] ${bgClass}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8 flex flex-col items-center gap-8">
<h2
className={`w-full max-w-[696px] font-joey-bold text-3xl md:text-4xl lg:text-[54px] text-center leading-tight lg:leading-[64.8px] ${headingColor}`}
className={`w-full max-w-[696px] font-joey-bold text-fd-h1 text-center leading-tight ${headingColor}`}
>
{heading}
</h2>
<p
className={`w-full max-w-[1112px] font-joey text-xl md:text-2xl lg:text-4xl text-center leading-relaxed lg:leading-[44px] ${bodyColor}`}
className={`w-full max-w-[1112px] font-joey text-xl md:text-2xl lg:text-4xl text-center leading-relaxed ${bodyColor}`}
>
{body}
</p>

View File

@ -3,31 +3,38 @@ import type { FDHeaderTextImageBlock as FDHeaderTextImageBlockProps, Media } fro
import { FDImage } from '@/components/FDImage'
const bgMap: Record<string, string> = {
white: 'bg-white',
gray: 'bg-fd-gray-light',
navy: 'bg-fd-navy',
white: 'bg-white dark:bg-fd-navy',
gray: 'bg-fd-gray-light dark:bg-fd-navy',
navy: 'bg-fd-navy',
}
const textMap: Record<string, string> = {
navy: 'text-fd-navy',
// Heading: navy→yellow in dark, white stays white
const headingMap: Record<string, string> = {
navy: 'text-fd-navy dark:text-fd-yellow',
white: 'text-white',
}
// Body: navy→white in dark, white stays white
const bodyMap: Record<string, string> = {
navy: 'text-fd-navy dark:text-white',
white: 'text-white',
}
const overlayMap: Record<string, string> = {
none: '',
navyLight: 'bg-fd-navy/20',
navyMedium: 'bg-fd-navy/40',
none: '',
navyLight: 'bg-fd-navy/20',
navyMedium: 'bg-fd-navy/40',
yellowLight: 'bg-fd-yellow/20',
yellowMedium: 'bg-fd-yellow/40',
sepia: 'bg-[#8B7D3C]/30',
blackLight: 'bg-black/20',
yellowMedium:'bg-fd-yellow/40',
sepia: 'bg-[#8B7D3C]/30',
blackLight: 'bg-black/20',
blackMedium: 'bg-black/40',
}
const roundedMap: Record<string, string> = {
none: '',
none: '',
medium: 'rounded-[24px]',
large: 'rounded-[40px]',
large: 'rounded-[40px]',
}
export const FDHeaderTextImageBlockComponent: React.FC<FDHeaderTextImageBlockProps> = ({
@ -40,23 +47,24 @@ export const FDHeaderTextImageBlockComponent: React.FC<FDHeaderTextImageBlockPro
sectionBackground = 'white',
textColor = 'navy',
}) => {
const bg = bgMap[sectionBackground || 'white']
const txt = textMap[textColor || 'navy']
const bg = bgMap[sectionBackground || 'white']
const headClr = headingMap[textColor || 'navy']
const bodyClr = bodyMap[textColor || 'navy']
const overlay = overlayMap[imageOverlay || 'none']
const rounded = roundedMap[imageRounded || 'large']
const align = textAlign === 'center' ? 'text-center' : 'text-left'
const media = image as Media
const align = textAlign === 'center' ? 'text-center' : 'text-left'
const media = image as Media
return (
<section className={`w-full py-12 md:py-16 lg:py-20 ${bg}`}>
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${bg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8 flex flex-col gap-8 md:gap-10">
{(heading || body) && (
<div className={`flex flex-col gap-4 md:gap-6 ${align} ${textAlign === 'center' ? 'max-w-[900px] mx-auto' : ''}`}>
{heading && (
<h2 className={`font-joey-heavy text-fd-h1 ${txt}`}>{heading}</h2>
<h2 className={`font-joey-heavy text-fd-h1 ${headClr}`}>{heading}</h2>
)}
{body && (
<p className={`font-joey text-fd-body ${txt} opacity-80`}>{body}</p>
<p className={`font-joey text-fd-body-lg ${bodyClr} opacity-80`}>{body}</p>
)}
</div>
)}

View File

@ -3,22 +3,28 @@ import type { FDIconBarBlock as FDIconBarBlockProps, Media } from '@/payload-typ
import { FDImage } from '@/components/FDImage'
const bgMap: Record<string, string> = {
white: 'bg-white',
gray: 'bg-fd-gray-light',
navy: 'bg-fd-navy',
white: 'bg-white dark:bg-fd-navy',
gray: 'bg-fd-gray-light dark:bg-fd-navy',
navy: 'bg-fd-navy',
yellow: 'bg-fd-yellow',
}
const textColorMap: Record<string, string> = {
navy: 'text-fd-navy',
const headingMap: Record<string, string> = {
navy: 'text-fd-navy dark:text-fd-yellow',
white: 'text-white',
}
const labelMap: Record<string, string> = {
navy: 'text-fd-navy dark:text-white',
white: 'text-white',
}
// Icon circle bg — navy circles become yellow-tinted in dark when on a now-navy section
const iconBgMap: Record<string, string> = {
navy: 'bg-fd-navy',
navy: 'bg-fd-navy dark:bg-white/10',
yellow: 'bg-fd-yellow',
gray: 'bg-[#e5e5e5]',
none: '',
gray: 'bg-fd-gray-light dark:bg-white/10',
none: '',
}
export const FDIconBarBlockComponent: React.FC<FDIconBarBlockProps> = ({
@ -28,16 +34,17 @@ export const FDIconBarBlockComponent: React.FC<FDIconBarBlockProps> = ({
sectionBackground = 'gray',
textColor = 'navy',
}) => {
const bg = bgMap[sectionBackground || 'gray']
const txtColor = textColorMap[textColor || 'navy']
const iconBg = iconBgMap[iconStyle || 'navy']
const bg = bgMap[sectionBackground || 'gray']
const headClr = headingMap[textColor || 'navy']
const labelClr = labelMap[textColor || 'navy']
const iconBg = iconBgMap[iconStyle || 'navy']
const hasCircle = iconStyle !== 'none'
return (
<section className={`w-full py-12 md:py-16 lg:py-20 ${bg}`}>
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${bg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
{heading && (
<h2 className={`font-joey-heavy text-fd-h1 mb-10 md:mb-14 ${txtColor}`}>
<h2 className={`font-joey-heavy text-fd-h1 mb-10 md:mb-14 ${headClr}`}>
{heading}
</h2>
)}
@ -61,7 +68,7 @@ export const FDIconBarBlockComponent: React.FC<FDIconBarBlockProps> = ({
/>
)}
</div>
<span className={`font-joey-bold text-fd-body text-center ${txtColor}`}>
<span className={`font-joey-bold text-fd-body text-center ${labelClr}`}>
{item.label}
</span>
</div>

View File

@ -12,18 +12,24 @@ export const FDLocationsGridBlockComponent: React.FC<Props> = ({
}) => {
const bgClass =
sectionBackground === 'navy' ? 'bg-fd-navy' :
sectionBackground === 'gray' ? 'bg-fd-surface-alt' : 'bg-white'
sectionBackground === 'gray' ? 'bg-fd-gray-light dark:bg-fd-navy' :
'bg-white dark:bg-fd-navy'
const titleClass = sectionBackground === 'navy' ? 'text-fd-yellow' : 'text-fd-navy'
const bodyClass = sectionBackground === 'navy' ? 'text-white' : 'text-fd-navy'
const titleClass = sectionBackground === 'navy'
? 'text-fd-yellow'
: 'text-fd-navy dark:text-fd-yellow'
const bodyClass = sectionBackground === 'navy'
? 'text-white'
: 'text-fd-navy dark:text-white'
const hoverBgClass =
hoverColor === 'yellow' ? 'bg-fd-yellow' :
hoverColor === 'mint' ? 'bg-fd-mint' : 'bg-fd-navy'
hoverColor === 'mint' ? 'bg-fd-mint' : 'bg-fd-navy'
const hoverTextClass =
hoverColor === 'yellow' ? 'text-fd-navy' :
hoverColor === 'mint' ? 'text-fd-navy' : 'text-white'
hoverColor === 'mint' ? 'text-fd-navy' : 'text-white'
return (
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${bgClass}`}>
@ -51,8 +57,8 @@ export const FDLocationsGridBlockComponent: React.FC<Props> = ({
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6">
{(cards ?? []).map((card, i) => {
const media = card.image as Media | undefined
const isLink = Boolean(card.link)
const media = card.image as Media | undefined
const isLink = Boolean(card.link)
const className = `group relative overflow-hidden rounded-[30px] md:rounded-[50px] aspect-[4/3] block ${isLink ? 'cursor-pointer' : ''}`
const inner = (

View File

@ -8,22 +8,23 @@ export const FDPartnersLogosBlockComponent: React.FC<FDPartnersLogosBlockProps>
sectionBackground = 'gray',
}) => {
const bgClass =
sectionBackground === 'navy'
? 'bg-fd-navy'
: sectionBackground === 'gray'
? 'bg-fd-surface-alt'
: 'bg-white'
sectionBackground === 'navy' ? 'bg-fd-navy' :
sectionBackground === 'gray' ? 'bg-fd-gray-light dark:bg-fd-navy' :
'bg-white dark:bg-fd-navy'
const titleClass = sectionBackground === 'navy' ? 'text-fd-yellow' : 'text-fd-navy'
const titleClass = sectionBackground === 'navy'
? 'text-fd-yellow'
: 'text-fd-navy dark:text-fd-yellow'
// In dark mode, monochrome logos invert to be visible on navy bg
const imgFilter =
displayMode === 'monochrome'
? 'grayscale opacity-40 hover:grayscale-0 hover:opacity-100 transition-all duration-500'
? 'grayscale opacity-40 hover:grayscale-0 hover:opacity-100 dark:invert dark:opacity-50 dark:hover:opacity-100 transition-all duration-500'
: 'hover:opacity-80 transition-opacity duration-300'
return (
<section className={`fd-section ${bgClass}`}>
<div className="fd-container">
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${bgClass}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
{heading && (
<h2 className={`font-joey-medium text-fd-h2 text-center mb-10 md:mb-14 ${titleClass}`}>
{heading}

View File

@ -3,14 +3,14 @@ import type { FDPricingCardBlock as FDPricingCardBlockProps } from '@/payload-ty
import { FDButton } from '@/components/FDButton'
const sectionBgMap: Record<string, string> = {
white: 'bg-white',
white: 'bg-white dark:bg-fd-navy',
navy: 'bg-fd-navy',
gray: 'bg-fd-gray-light',
gray: 'bg-fd-gray-light dark:bg-fd-navy',
yellow: 'bg-fd-yellow',
}
const titleColorMap: Record<string, string> = {
navy: 'text-fd-navy',
navy: 'text-fd-navy dark:text-fd-yellow',
white: 'text-white',
yellow: 'text-fd-yellow',
}
@ -19,11 +19,41 @@ const cardStyleMap: Record<string, {
bg: string; border: string; title: string
subtitle: string; body: string; bullet: string; isDark: boolean
}> = {
outlined: { bg: 'bg-white', border: 'border-[2px] border-[#d1d5db]', title: 'text-fd-navy', subtitle: 'text-fd-navy', body: 'text-fd-navy/80', bullet: 'text-fd-navy', isDark: false },
navy: { bg: 'bg-fd-navy', border: '', title: 'text-fd-yellow', subtitle: 'text-white', body: 'text-white/80', bullet: 'text-white', isDark: true },
gray: { bg: 'bg-fd-gray-light', border: '', title: 'text-fd-navy', subtitle: 'text-fd-navy', body: 'text-fd-navy/80', bullet: 'text-fd-navy', isDark: false },
yellow: { bg: 'bg-fd-yellow', border: '', title: 'text-fd-navy', subtitle: 'text-fd-navy', body: 'text-fd-navy/80', bullet: 'text-fd-navy', isDark: false },
white: { bg: 'bg-white shadow-lg', border: '', title: 'text-fd-navy', subtitle: 'text-fd-navy', body: 'text-fd-navy/80', bullet: 'text-fd-navy', isDark: false },
outlined: {
bg: 'bg-white dark:bg-white/10',
border: 'border-[2px] border-gray-200 dark:border-white/20',
title: 'text-fd-navy dark:text-fd-yellow',
subtitle: 'text-fd-navy dark:text-white',
body: 'text-fd-navy/80 dark:text-white/80',
bullet: 'text-fd-navy dark:text-white',
isDark: false,
},
navy: {
bg: 'bg-fd-navy', border: '', title: 'text-fd-yellow',
subtitle: 'text-white', body: 'text-white/80', bullet: 'text-white', isDark: true,
},
gray: {
bg: 'bg-fd-gray-light dark:bg-white/10',
border: '',
title: 'text-fd-navy dark:text-white',
subtitle: 'text-fd-navy dark:text-white',
body: 'text-fd-navy/80 dark:text-white/80',
bullet: 'text-fd-navy dark:text-white',
isDark: false,
},
yellow: {
bg: 'bg-fd-yellow', border: '', title: 'text-fd-navy',
subtitle: 'text-fd-navy', body: 'text-fd-navy/80', bullet: 'text-fd-navy', isDark: false,
},
white: {
bg: 'bg-white dark:bg-white/10 shadow-lg dark:shadow-none',
border: '',
title: 'text-fd-navy dark:text-fd-yellow',
subtitle: 'text-fd-navy dark:text-white',
body: 'text-fd-navy/80 dark:text-white/80',
bullet: 'text-fd-navy dark:text-white',
isDark: false,
},
}
const buttonVariantMap: Record<string, { variant: 'primary' | 'outline' }> = {
@ -47,13 +77,13 @@ export const FDPricingCardBlockComponent: React.FC<FDPricingCardBlockProps> = ({
sectionBackground = 'white',
titleColor = 'navy',
}) => {
const sectionBg = sectionBgMap[sectionBackground || 'white']
const sectionBg = sectionBgMap[sectionBackground || 'white']
const sectionTitleColor = titleColorMap[titleColor || 'navy']
const style = cardStyleMap[cardStyle || 'outlined']
const { variant } = buttonVariantMap[buttonColor || 'yellow']
const cardCount = cards?.length || 1
const gridCols = gridColsMap[cardCount] || gridColsMap[3]
const outlineOnDark = style.isDark
const style = cardStyleMap[cardStyle || 'outlined']
const { variant } = buttonVariantMap[buttonColor || 'yellow']
const cardCount = cards?.length || 1
const gridCols = gridColsMap[cardCount] || gridColsMap[3]
const outlineOnDark = style.isDark
return (
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${sectionBg}`}>
@ -63,7 +93,6 @@ export const FDPricingCardBlockComponent: React.FC<FDPricingCardBlockProps> = ({
{sectionTitle}
</h2>
)}
{/* FIX: rounded-[32px] → rounded-[70px] per design system */}
<div className={`grid grid-cols-1 ${gridCols} gap-6 md:gap-8`}>
{cards?.map((card, index) => (
<div

View File

@ -14,10 +14,9 @@ export const FDServicesGridBlockComponent: React.FC<FDServicesGridBlockProps> =
columns = '4',
}) => {
return (
// FIX: lg:py-24 → lg:py-[99px] (standard section padding)
<section className="relative w-full bg-white py-16 md:py-20 lg:py-[99px]">
<section className="relative w-full bg-white dark:bg-fd-navy py-16 md:py-20 lg:py-[99px]">
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
<h2 className="font-joey-heavy text-fd-h1 text-fd-navy mb-8 lg:mb-12">
<h2 className="font-joey-heavy text-fd-h1 text-fd-navy dark:text-fd-yellow mb-8 lg:mb-12">
{heading}
</h2>
@ -27,7 +26,7 @@ export const FDServicesGridBlockComponent: React.FC<FDServicesGridBlockProps> =
const content = (
<div className="flex flex-col gap-4 md:gap-6 lg:gap-[30px]">
<h3 className="font-joey-bold text-fd-navy text-fd-h2">
<h3 className="font-joey-bold text-fd-navy dark:text-white text-fd-h2">
{service.title}
</h3>
@ -41,7 +40,7 @@ export const FDServicesGridBlockComponent: React.FC<FDServicesGridBlockProps> =
/>
)}
<p className="font-joey text-fd-navy text-fd-body">
<p className="font-joey text-fd-navy dark:text-white/80 text-fd-body">
{service.description}
</p>
</div>

View File

@ -9,10 +9,10 @@ const heightMap: Record<string, string> = {
}
const bgMap: Record<string, string> = {
white: 'bg-white',
navy: 'bg-fd-navy',
gray: 'bg-fd-gray-light',
yellow: 'bg-fd-yellow',
white: 'bg-white dark:bg-fd-navy',
navy: 'bg-fd-navy',
gray: 'bg-fd-gray-light dark:bg-fd-navy',
yellow: 'bg-fd-yellow',
transparent: 'bg-transparent',
}

View File

@ -22,17 +22,24 @@ export const FDStatisticsBlockComponent: React.FC<Props> = ({
const bgClass =
sectionBackground === 'navy' ? 'bg-fd-navy' :
sectionBackground === 'gray' ? 'bg-fd-surface-alt' : 'bg-white'
sectionBackground === 'gray' ? 'bg-fd-gray-light dark:bg-fd-navy' :
'bg-white dark:bg-fd-navy'
const titleClass = sectionBackground === 'navy' ? 'text-fd-yellow' : 'text-fd-navy'
const labelClass = sectionBackground === 'navy' ? 'text-white' : 'text-fd-navy'
const titleClass = sectionBackground === 'navy'
? 'text-fd-yellow'
: 'text-fd-navy dark:text-fd-yellow'
const labelClass = sectionBackground === 'navy'
? 'text-white'
: 'text-fd-navy dark:text-white'
const getNumberClass = () => {
if (numberColor === 'gradient') return 'bg-gradient-to-r from-fd-yellow to-fd-mint bg-clip-text text-transparent'
if (numberColor === 'yellow') return 'text-fd-yellow'
if (numberColor === 'mint') return 'text-fd-mint'
if (numberColor === 'white') return 'text-white'
return 'text-fd-navy'
if (numberColor === 'mint') return 'text-fd-mint'
if (numberColor === 'white') return 'text-white'
// navy number adapts in dark mode
return 'text-fd-navy dark:text-white'
}
return (
@ -52,7 +59,6 @@ export const FDStatisticsBlockComponent: React.FC<Props> = ({
}`}
style={{ transitionDelay: `${i * 120}ms` }}
>
{/* Intentionally oversized for visual impact — not mapped to fd-* token */}
<span className={`font-joey-heavy text-5xl md:text-7xl lg:text-[96px] leading-none ${getNumberClass()}`}>
{stat.number}
</span>

View File

@ -2,10 +2,10 @@ import React from 'react'
import type { FDTagsBlock as FDTagsBlockProps } from '@/payload-types'
const tagStyleMap: Record<string, { bg: string; text: string; border: string }> = {
navy: { bg: 'bg-fd-navy', text: 'text-fd-yellow', border: '' },
yellow: { bg: 'bg-fd-yellow', text: 'text-fd-navy', border: '' },
outlined: { bg: 'bg-transparent', text: 'text-fd-navy', border: 'border-2 border-fd-navy' },
gray: { bg: 'bg-fd-surface-alt', text: 'text-fd-navy', border: '' },
navy: { bg: 'bg-fd-navy', text: 'text-fd-yellow', border: '' },
yellow: { bg: 'bg-fd-yellow', text: 'text-fd-navy', border: '' },
outlined: { bg: 'bg-transparent', text: 'text-fd-navy dark:text-white', border: 'border-2 border-fd-navy dark:border-white' },
gray: { bg: 'bg-fd-gray-light dark:bg-white/10', text: 'text-fd-navy dark:text-white', border: '' },
}
const tagSizeMap: Record<string, string> = {
@ -15,15 +15,15 @@ const tagSizeMap: Record<string, string> = {
}
const sectionBgMap: Record<string, string> = {
white: 'bg-white',
white: 'bg-white dark:bg-fd-navy',
navy: 'bg-fd-navy',
gray: 'bg-fd-gray-light',
gray: 'bg-fd-gray-light dark:bg-fd-navy',
}
const headingColorMap: Record<string, string> = {
white: 'text-fd-navy',
white: 'text-fd-navy dark:text-fd-yellow',
navy: 'text-fd-yellow',
gray: 'text-fd-navy',
gray: 'text-fd-navy dark:text-fd-yellow',
}
export const FDTagsBlockComponent: React.FC<FDTagsBlockProps> = ({
@ -34,14 +34,14 @@ export const FDTagsBlockComponent: React.FC<FDTagsBlockProps> = ({
alignment = 'left',
sectionBackground = 'white',
}) => {
const style = tagStyleMap[tagStyle ?? 'navy'] || tagStyleMap.navy
const size = tagSizeMap[tagSize ?? 'large'] || tagSizeMap.large
const sectionBg = sectionBgMap[sectionBackground || 'white']
const style = tagStyleMap[tagStyle ?? 'navy'] || tagStyleMap.navy
const size = tagSizeMap[tagSize ?? 'large'] || tagSizeMap.large
const sectionBg = sectionBgMap[sectionBackground || 'white']
const headingColor = headingColorMap[sectionBackground || 'white']
const justify = alignment === 'center' ? 'justify-center' : 'justify-start'
const justify = alignment === 'center' ? 'justify-center' : 'justify-start'
return (
<section className={`w-full py-12 md:py-16 lg:py-20 ${sectionBg}`}>
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${sectionBg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
{heading && (
<h2

View File

@ -3,15 +3,33 @@ import type { FDTeamBlock as FDTeamBlockProps, Media } from '@/payload-types'
import { FDImage } from '@/components/FDImage'
const sectionBgMap: Record<string, string> = {
white: 'bg-white',
gray: 'bg-fd-gray-light',
white: 'bg-white dark:bg-fd-navy',
gray: 'bg-fd-gray-light dark:bg-fd-navy',
navy: 'bg-fd-navy',
}
const cardMap: Record<string, { bg: string; name: string; role: string; bio: string; icon: string }> = {
navy: { bg: 'bg-fd-navy', name: 'text-fd-yellow', role: 'text-white/70', bio: 'text-white/60', icon: 'text-white/40 hover:text-fd-yellow' },
white: { bg: 'bg-white', name: 'text-fd-navy', role: 'text-fd-navy/60', bio: 'text-fd-navy/60', icon: 'text-fd-navy/40 hover:text-fd-navy' },
gray: { bg: 'bg-fd-gray-light', name: 'text-fd-navy', role: 'text-fd-navy/60', bio: 'text-fd-navy/60', icon: 'text-fd-navy/40 hover:text-fd-navy' },
navy: {
bg: 'bg-fd-navy',
name: 'text-fd-yellow',
role: 'text-white/70',
bio: 'text-white/60',
icon: 'text-white/40 hover:text-fd-yellow',
},
white: {
bg: 'bg-white dark:bg-white/10',
name: 'text-fd-navy dark:text-white',
role: 'text-fd-navy/60 dark:text-white/60',
bio: 'text-fd-navy/60 dark:text-white/60',
icon: 'text-fd-navy/40 hover:text-fd-navy dark:text-white/40 dark:hover:text-white',
},
gray: {
bg: 'bg-fd-gray-light dark:bg-white/10',
name: 'text-fd-navy dark:text-white',
role: 'text-fd-navy/60 dark:text-white/60',
bio: 'text-fd-navy/60 dark:text-white/60',
icon: 'text-fd-navy/40 hover:text-fd-navy dark:text-white/40 dark:hover:text-white',
},
}
const colsMap: Record<string, string> = {
@ -28,42 +46,38 @@ export const FDTeamBlockComponent: React.FC<FDTeamBlockProps> = ({
cardStyle = 'navy',
sectionBackground = 'white',
}) => {
const sectionBg = sectionBgMap[sectionBackground ?? 'white'] || sectionBgMap.white
const card = cardMap[cardStyle ?? 'navy'] || cardMap.navy
const gridCols = colsMap[columns ?? '3'] || colsMap['3']
const sectionBg = sectionBgMap[sectionBackground ?? 'white'] || sectionBgMap.white
const card = cardMap[cardStyle ?? 'navy'] || cardMap.navy
const gridCols = colsMap[columns ?? '3'] || colsMap['3']
const isNavySection = sectionBackground === 'navy'
return (
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${sectionBg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
{/* Header */}
{(heading || subheading) && (
<div className="flex flex-col gap-3 mb-10 md:mb-14">
{heading && (
<h2 className={`font-joey-heavy text-fd-h1 ${isNavySection ? 'text-fd-yellow' : 'text-fd-navy'}`}>
<h2 className={`font-joey-heavy text-fd-h1 ${isNavySection ? 'text-fd-yellow' : 'text-fd-navy dark:text-fd-yellow'}`}>
{heading}
</h2>
)}
{subheading && (
<p className={`font-joey text-fd-body-lg ${isNavySection ? 'text-white/70' : 'text-fd-navy/60'}`}>
<p className={`font-joey text-fd-body-lg ${isNavySection ? 'text-white/70' : 'text-fd-navy/60 dark:text-white/70'}`}>
{subheading}
</p>
)}
</div>
)}
{/* Grid */}
<div className={`grid grid-cols-1 ${gridCols} gap-6`}>
{members?.map((member, i) => {
// FIX: cast photo properly as Media and pass full object to FDImage
const photo = member.photo as Media | undefined
const photo = member.photo as Media | undefined
const hasPhoto = photo && typeof photo === 'object' && photo.url
return (
<div key={i} className={`${card.bg} rounded-[70px] overflow-hidden flex flex-col`}>
{/* Photo */}
<div className="aspect-[4/3] w-full overflow-hidden">
{hasPhoto ? (
<FDImage
@ -74,7 +88,7 @@ export const FDTeamBlockComponent: React.FC<FDTeamBlockProps> = ({
fallbackAlt={member.name}
/>
) : (
<div className={`w-full h-full flex items-center justify-center ${cardStyle === 'navy' ? 'bg-fd-navy/50' : 'bg-fd-navy/10'}`}>
<div className={`w-full h-full flex items-center justify-center ${cardStyle === 'navy' ? 'bg-fd-navy/50' : 'bg-fd-navy/10 dark:bg-white/5'}`}>
<svg viewBox="0 0 80 80" className="w-20 h-20 opacity-30" fill="currentColor">
<circle cx="40" cy="30" r="18" />
<path d="M10 72c0-16.6 13.4-30 30-30s30 13.4 30 30H10z" />
@ -83,7 +97,6 @@ export const FDTeamBlockComponent: React.FC<FDTeamBlockProps> = ({
)}
</div>
{/* Info */}
<div className="flex flex-col gap-2 px-8 py-8 flex-1">
<p className={`font-joey-bold text-fd-h3 ${card.name}`}>{member.name}</p>
<p className={`font-joey text-fd-small ${card.role}`}>{member.role}</p>
@ -94,28 +107,17 @@ export const FDTeamBlockComponent: React.FC<FDTeamBlockProps> = ({
</p>
)}
{/* Links */}
{(member.email || member.linkedin) && (
<div className="flex items-center gap-4 mt-4">
{member.email && (
<a
href={`mailto:${member.email}`}
aria-label={`E-post till ${member.name}`}
className={`transition-colors ${card.icon}`}
>
<a href={`mailto:${member.email}`} aria-label={`E-post till ${member.name}`} className={`transition-colors ${card.icon}`}>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</a>
)}
{member.linkedin && (
<a
href={member.linkedin}
target="_blank"
rel="noopener noreferrer"
aria-label={`LinkedIn för ${member.name}`}
className={`transition-colors ${card.icon}`}
>
<a href={member.linkedin} target="_blank" rel="noopener noreferrer" aria-label={`LinkedIn för ${member.name}`} className={`transition-colors ${card.icon}`}>
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
</svg>

View File

@ -3,20 +3,22 @@ import type { FDTechPropertiesBlock as FDTechPropertiesBlockProps } from '@/payl
const bgMap: Record<string, string> = {
navy: 'bg-fd-navy',
white: 'bg-white',
gray: 'bg-fd-gray-light',
white: 'bg-white dark:bg-fd-navy',
gray: 'bg-fd-gray-light dark:bg-fd-navy',
yellow: 'bg-fd-yellow',
}
// Category label (small text above value)
const catColorMap: Record<string, string> = {
white: 'text-white',
navy: 'text-fd-navy',
navy: 'text-fd-navy dark:text-white/70',
}
// Value (large number/text)
const valColorMap: Record<string, string> = {
yellow: 'text-fd-yellow',
white: 'text-white',
navy: 'text-fd-navy',
navy: 'text-fd-navy dark:text-fd-yellow',
}
export const FDTechPropertiesBlockComponent: React.FC<FDTechPropertiesBlockProps> = ({
@ -25,15 +27,15 @@ export const FDTechPropertiesBlockComponent: React.FC<FDTechPropertiesBlockProps
categoryColor = 'white',
valueColor = 'yellow',
}) => {
const bg = bgMap[sectionBackground || 'navy']
const bg = bgMap[sectionBackground || 'navy']
const catColor = catColorMap[categoryColor || 'white']
const valColor = valColorMap[valueColor || 'yellow']
const count = properties?.length || 1
const count = properties?.length || 1
const gridCols =
count <= 2 ? 'grid-cols-2' : count === 3 ? 'grid-cols-3' : 'grid-cols-2 md:grid-cols-4'
return (
<section className={`w-full py-12 md:py-16 lg:py-20 ${bg}`}>
<section 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={`grid ${gridCols} gap-8 md:gap-12`}>
{properties?.map((prop, index) => (

View File

@ -2,13 +2,36 @@ import React from 'react'
import type { FDTestimonialBlock as FDTestimonialBlockProps, Media } from '@/payload-types'
import { FDImage } from '@/components/FDImage'
const bgMap: Record<string, { section: string; card: string; quote: string; meta: string; name: string; company: string }> = {
gray: { section: 'bg-fd-gray-light', card: 'bg-white', quote: 'text-fd-navy', meta: 'text-fd-navy/60', name: 'text-fd-navy', company: 'text-fd-navy/50' },
white: { section: 'bg-white', card: 'bg-fd-gray-light', quote: 'text-fd-navy', meta: 'text-fd-navy/60', name: 'text-fd-navy', company: 'text-fd-navy/50' },
navy: { section: 'bg-fd-navy', card: 'bg-white/10', quote: 'text-white', meta: 'text-white/60', name: 'text-white', company: 'text-white/50' },
const bgMap: Record<string, {
section: string; card: string
quote: string; meta: string; name: string; accent: string
}> = {
gray: {
section: 'bg-fd-gray-light dark:bg-fd-navy',
card: 'bg-white dark:bg-white/10',
quote: 'text-fd-navy dark:text-white',
meta: 'text-fd-navy/60 dark:text-white/60',
name: 'text-fd-navy dark:text-white',
accent: 'text-fd-navy dark:text-fd-yellow',
},
white: {
section: 'bg-white dark:bg-fd-navy',
card: 'bg-fd-gray-light dark:bg-white/10',
quote: 'text-fd-navy dark:text-white',
meta: 'text-fd-navy/60 dark:text-white/60',
name: 'text-fd-navy dark:text-white',
accent: 'text-fd-navy dark:text-fd-yellow',
},
navy: {
section: 'bg-fd-navy',
card: 'bg-white/10',
quote: 'text-white',
meta: 'text-white/60',
name: 'text-white',
accent: 'text-fd-yellow',
},
}
/** Avatar helper — uses FDImage with media object correctly */
const Avatar: React.FC<{ media: Media | undefined; name: string; size: number }> = ({ media, name, size }) => {
if (!media?.url) return null
return (
@ -33,26 +56,24 @@ export const FDTestimonialBlockComponent: React.FC<FDTestimonialBlockProps> = ({
layout = 'grid',
sectionBackground = 'gray',
}) => {
const theme = bgMap[sectionBackground ?? 'gray'] || bgMap.gray
const theme = bgMap[sectionBackground ?? 'gray'] || bgMap.gray
const isFeatured = layout === 'featured'
const isNavy = sectionBackground === 'navy'
return (
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${theme.section}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
{heading && (
<h2 className={`font-joey-heavy text-fd-h1 mb-10 md:mb-14 ${isNavy ? 'text-fd-yellow' : 'text-fd-navy'}`}>
<h2 className={`font-joey-heavy text-fd-h1 mb-10 md:mb-14 ${theme.accent}`}>
{heading}
</h2>
)}
{isFeatured && testimonials && testimonials.length > 0 ? (
// ── Featured layout: first testimonial large, rest below ──────
<div className="flex flex-col gap-6">
{/* First testimonial — large */}
{(() => {
const t = testimonials[0]
const t = testimonials[0]
const avatar = t.avatar as Media | undefined
return (
<div className={`${theme.card} rounded-[70px] px-8 md:px-16 py-10 md:py-16 flex flex-col gap-8`}>
@ -72,7 +93,6 @@ export const FDTestimonialBlockComponent: React.FC<FDTestimonialBlockProps> = ({
)
})()}
{/* Remaining testimonials — smaller grid */}
{testimonials.length > 1 && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{testimonials.slice(1).map((t, i) => {
@ -98,14 +118,12 @@ export const FDTestimonialBlockComponent: React.FC<FDTestimonialBlockProps> = ({
)}
</div>
) : (
// ── Grid layout ───────────────────────────────────────────────
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{testimonials?.map((t, i) => {
const avatar = t.avatar as Media | undefined
return (
<div key={i} className={`${theme.card} rounded-[70px] px-8 md:px-10 py-10 md:py-12 flex flex-col gap-6`}>
{/* Quote mark */}
<span className={`font-joey-heavy text-5xl leading-none ${isNavy ? 'text-fd-yellow' : 'text-fd-navy'} opacity-30`}>
<span className={`font-joey-heavy text-5xl leading-none ${theme.accent} opacity-30`}>
&ldquo;
</span>
<p className={`font-joey-medium text-lg leading-relaxed -mt-4 ${theme.quote}`}>

View File

@ -3,9 +3,9 @@ import type { FDTextBlock as FDTextBlockProps } from '@/payload-types'
import RichText from '@/components/RichText'
const bgMap: Record<string, string> = {
white: 'bg-white',
white: 'bg-white dark:bg-fd-navy',
navy: 'bg-fd-navy',
gray: 'bg-fd-gray-light',
gray: 'bg-fd-gray-light dark:bg-fd-navy',
yellow: 'bg-fd-yellow',
}
@ -22,10 +22,15 @@ const maxWidthMap: Record<string, string> = {
full: '',
}
// Navy text color = adapts to dark mode. White/yellow = always explicit.
const textColorMap: Record<string, { h1: string; h2: string; body: string }> = {
navy: { h1: 'text-fd-navy', h2: 'text-fd-navy', body: 'text-fd-navy' },
white: { h1: 'text-white', h2: 'text-white', body: 'text-white/90' },
yellow: { h1: 'text-fd-yellow', h2: 'text-fd-yellow', body: 'text-fd-yellow/90' },
navy: {
h1: 'text-fd-navy dark:text-fd-yellow',
h2: 'text-fd-navy dark:text-fd-yellow',
body: 'text-fd-navy dark:text-white',
},
white: { h1: 'text-white', h2: 'text-white', body: 'text-white/90' },
yellow: { h1: 'text-fd-yellow', h2: 'text-fd-yellow', body: 'text-fd-yellow/90' },
}
export const FDTextBlockComponent: React.FC<FDTextBlockProps> = ({
@ -37,9 +42,9 @@ export const FDTextBlockComponent: React.FC<FDTextBlockProps> = ({
sectionBackground = 'white',
maxWidth = 'wide',
}) => {
const bg = bgMap[sectionBackground || 'white']
const align = alignMap[alignment || 'left']
const width = maxWidthMap[maxWidth || 'wide']
const bg = bgMap[sectionBackground || 'white']
const align = alignMap[alignment || 'left']
const width = maxWidthMap[maxWidth || 'wide']
const colors = textColorMap[textColor || 'navy']
const containerAlign =
alignment === 'center' ? 'mx-auto' : alignment === 'right' ? 'ml-auto' : ''
@ -47,7 +52,7 @@ export const FDTextBlockComponent: React.FC<FDTextBlockProps> = ({
if (!heading && !subheading && !body) return null
return (
<section className={`w-full py-12 md:py-16 lg:py-20 ${bg}`}>
<section 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={`${width} ${containerAlign} ${align} flex flex-col gap-4 md:gap-6`}>
{heading && (

View File

@ -3,13 +3,18 @@ import type { FDUspChecklistBlock as FDUspChecklistBlockProps, Media } from '@/p
import { FDImage } from '@/components/FDImage'
const bgMap: Record<string, string> = {
white: 'bg-white',
gray: 'bg-fd-gray-light',
white: 'bg-white dark:bg-fd-navy',
gray: 'bg-fd-gray-light dark:bg-fd-navy',
navy: 'bg-fd-navy',
}
const textMap: Record<string, string> = {
navy: 'text-fd-navy',
const headingMap: Record<string, string> = {
navy: 'text-fd-navy dark:text-fd-yellow',
white: 'text-white',
}
const bodyMap: Record<string, string> = {
navy: 'text-fd-navy dark:text-white',
white: 'text-white',
}
@ -38,19 +43,20 @@ export const FDUspChecklistBlockComponent: React.FC<FDUspChecklistBlockProps> =
sectionBackground = 'white',
textColor = 'navy',
}) => {
const bg = bgMap[sectionBackground || 'white']
const txt = textMap[textColor || 'navy']
const media = image as Media | undefined
const bg = bgMap[sectionBackground || 'white']
const headClr = headingMap[textColor || 'navy']
const bodyClr = bodyMap[textColor || 'navy']
const media = image as Media | undefined
const hasImage = Boolean(media?.url)
const textContent = (
<div className="flex-1 flex flex-col gap-6 md:gap-8">
<h2 className={`font-joey-heavy text-fd-h1 ${txt}`}>{heading}</h2>
<h2 className={`font-joey-heavy text-fd-h1 ${headClr}`}>{heading}</h2>
<div className="flex flex-col gap-5 md:gap-6">
{items?.map((item, index) => (
<div key={index} className="flex items-start gap-4">
<CheckIcon color={checkColor || 'navy'} />
<span className={`font-joey text-fd-body-lg pt-1 ${txt}`}>{item.text}</span>
<span className={`font-joey text-fd-body-lg pt-1 ${bodyClr}`}>{item.text}</span>
</div>
))}
</div>
@ -70,7 +76,7 @@ export const FDUspChecklistBlockComponent: React.FC<FDUspChecklistBlockProps> =
) : null
return (
<section className={`w-full py-12 md:py-16 lg:py-20 ${bg}`}>
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${bg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8 flex flex-col lg:flex-row items-center gap-10 lg:gap-16">
{imagePosition === 'left' ? <>{imageContent}{textContent}</> : <>{textContent}{imageContent}</>}
</div>

View File

@ -3,18 +3,30 @@ import type { FDUspTableBlock as FDUspTableBlockProps } from '@/payload-types'
import RichText from '@/components/RichText'
const bgMap: Record<string, string> = {
white: 'bg-white',
gray: 'bg-fd-gray-light',
white: 'bg-white dark:bg-fd-navy',
gray: 'bg-fd-gray-light dark:bg-fd-navy',
navy: 'bg-fd-navy',
}
const textMap: Record<string, string> = {
navy: 'text-fd-navy',
// Heading: navy bg → yellow in dark
const headingMap: Record<string, string> = {
navy: 'text-fd-navy dark:text-fd-yellow',
white: 'text-white',
}
// Body / row titles: navy bg → white in dark
const textMap: Record<string, string> = {
navy: 'text-fd-navy dark:text-white',
white: 'text-white',
}
const proseMap: Record<string, string> = {
navy: 'text-fd-navy/80 dark:text-white/80',
white: 'text-white/80',
}
const borderMap: Record<string, string> = {
navy: 'border-fd-navy/10',
navy: 'border-fd-navy/10 dark:border-white/20',
white: 'border-white/20',
}
@ -41,16 +53,17 @@ export const FDUspTableBlockComponent: React.FC<FDUspTableBlockProps> = ({
sectionBackground = 'white',
textColor = 'navy',
}) => {
const bg = bgMap[sectionBackground || 'white']
const txt = textMap[textColor || 'navy']
const border = borderMap[textColor || 'navy']
const proseOpacity = textColor === 'white' ? 'opacity-80' : 'opacity-80'
const bg = bgMap[sectionBackground || 'white']
const headClr = headingMap[textColor || 'navy']
const txt = textMap[textColor || 'navy']
const prose = proseMap[textColor || 'navy']
const border = borderMap[textColor || 'navy']
return (
<section className={`w-full py-12 md:py-16 lg:py-20 ${bg}`}>
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${bg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
{heading && (
<h2 className={`font-joey-heavy text-fd-h1 mb-10 md:mb-14 ${txt}`}>{heading}</h2>
<h2 className={`font-joey-heavy text-fd-h1 mb-10 md:mb-14 ${headClr}`}>{heading}</h2>
)}
<div className="flex flex-col">
{rows?.map((row, index) => (
@ -64,7 +77,7 @@ export const FDUspTableBlockComponent: React.FC<FDUspTableBlockProps> = ({
<CheckIcon color={checkColor || 'navy'} />
<span className={`font-joey-bold text-fd-h3 ${txt}`}>{row.title}</span>
</div>
<div className={`font-joey text-fd-body fd-prose ${txt} ${proseOpacity} md:pl-0 pl-14`}>
<div className={`font-joey text-fd-body fd-prose ${prose} md:pl-0 pl-14`}>
<RichText data={(row.description) as any} />
</div>
</div>

View File

@ -4,22 +4,22 @@ import { FDButton } from '@/components/FDButton'
import { FDImage } from '@/components/FDImage'
const cardBgMap: Record<string, { bg: string; heading: string; body: string; isDark: boolean }> = {
navy: { bg: 'bg-fd-navy', heading: 'text-white', body: 'text-white/80', isDark: true },
yellow: { bg: 'bg-fd-yellow', heading: 'text-fd-navy', body: 'text-fd-navy/80', isDark: false },
gray: { bg: 'bg-fd-gray-light', heading: 'text-fd-navy', body: 'text-fd-navy/80', isDark: false },
white: { bg: 'bg-white shadow-xl', heading: 'text-fd-navy', body: 'text-fd-navy/80', isDark: false },
navy: { bg: 'bg-fd-navy', heading: 'text-white', body: 'text-white/80', isDark: true },
yellow: { bg: 'bg-fd-yellow', heading: 'text-fd-navy', body: 'text-fd-navy/80', isDark: false },
gray: { bg: 'bg-fd-gray-light dark:bg-white/10', heading: 'text-fd-navy dark:text-white', body: 'text-fd-navy/80 dark:text-white/80', isDark: false },
white: { bg: 'bg-white dark:bg-white/10 shadow-xl dark:shadow-none', heading: 'text-fd-navy dark:text-white', body: 'text-fd-navy/80 dark:text-white/80', isDark: false },
}
const sectionBgMap: Record<string, string> = {
white: 'bg-white',
gray: 'bg-fd-gray-light',
white: 'bg-white dark:bg-fd-navy',
gray: 'bg-fd-gray-light dark:bg-fd-navy',
navy: 'bg-fd-navy',
}
const btnVariantMap: Record<string, { variant: 'primary' | 'outline' }> = {
yellow: { variant: 'primary' },
navy: { variant: 'outline' },
white: { variant: 'primary' },
yellow: { variant: 'primary' },
navy: { variant: 'outline' },
white: { variant: 'primary' },
}
export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
@ -32,11 +32,11 @@ export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
buttonColor = 'yellow',
sectionBackground = 'white',
}) => {
const card = cardBgMap[cardBackground || 'navy']
const card = cardBgMap[cardBackground || 'navy']
const sectionBg = sectionBgMap[sectionBackground || 'white']
const { variant } = btnVariantMap[buttonColor || 'yellow']
const media = image as Media | undefined
const hasImage = media && typeof media === 'object' && media.url
const media = image as Media | undefined
const hasImage = media && typeof media === 'object' && media.url
return (
<section className={`w-full py-16 md:py-20 lg:py-[99px] ${sectionBg}`}>
@ -53,18 +53,13 @@ export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
)}
{ctaText && (
<div>
<FDButton
href={ctaLink || '#'}
variant={variant}
onDark={card.isDark}
>
<FDButton href={ctaLink || '#'} variant={variant} onDark={card.isDark}>
{ctaText}
</FDButton>
</div>
)}
</div>
{/* FIX: replaced raw <img> with FDImage */}
{hasImage && (
<div className="relative flex-1 min-h-[250px] lg:min-h-0">
<FDImage

File diff suppressed because one or more lines are too long