feat: add FDButton component, fix button hover on navy, make CTA image optional

This commit is contained in:
Jeffrey 2026-02-19 20:30:43 +01:00
parent 1ab4e41c00
commit 80be2c4098
8 changed files with 179 additions and 199 deletions

View File

@ -2,19 +2,7 @@ import React from 'react'
import type { FDCtaSideImageBlock as FDCtaSideImageBlockProps } from '@/payload-types'
import type { Media } from '@/payload-types'
import { FDImage } from '@/components/FDImage'
const overlayColorMap: Record<string, string> = {
navy: 'bg-fd-navy',
yellow: 'bg-fd-yellow',
black: 'bg-black',
}
const overlayOpacityMap: Record<string, string> = {
'20': 'opacity-20',
'30': 'opacity-30',
'50': 'opacity-50',
'70': 'opacity-70',
}
import { FDButton } from '@/components/FDButton'
export const FDCtaSideImageBlockComponent: React.FC<FDCtaSideImageBlockProps> = ({
heading,
@ -24,69 +12,61 @@ export const FDCtaSideImageBlockComponent: React.FC<FDCtaSideImageBlockProps> =
image,
imagePosition = 'right',
theme = 'dark',
customBackgroundColor,
customTextLight = true,
imageOverlay = 'none',
imageOverlayOpacity = '30',
}) => {
const isCustom = theme === 'custom'
const isDark = isCustom ? customTextLight : theme === 'dark'
const media = image as Media
let sectionBg: string
let sectionStyle: React.CSSProperties = {}
if (isCustom && customBackgroundColor) {
sectionStyle = { backgroundColor: customBackgroundColor }
sectionBg = ''
} else {
sectionBg = isDark ? 'bg-fd-navy' : 'bg-white'
}
const hasOverlay = imageOverlay && imageOverlay !== 'none'
const overlayColor = overlayColorMap[imageOverlay || ''] || ''
const overlayOpacity = overlayOpacityMap[imageOverlayOpacity || '30'] || 'opacity-30'
const isDark = theme === 'dark'
const hasImage = !!image
const textContent = (
<div className="flex flex-col flex-1 items-start gap-8 lg:gap-[41px]">
<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 ${isDark ? 'text-fd-yellow' : 'text-fd-navy'}`}>
<h2
className={`w-full font-joey-heavy text-3xl md:text-4xl lg:text-5xl leading-tight lg:leading-[57.6px] ${
isDark ? 'text-fd-yellow' : 'text-fd-navy'
}`}
>
{heading}
</h2>
<p className={`w-full font-joey text-fd-body-lg ${isDark ? 'text-white' : 'text-fd-navy'}`}>
<p
className={`w-full font-joey text-lg md:text-xl lg:text-2xl leading-relaxed lg:leading-[38px] ${
isDark ? 'text-white' : 'text-fd-navy'
}`}
>
{body}
</p>
</div>
{ctaText && (
<a
href={ctaLink || '#'}
className={isDark ? 'fd-btn-primary' : 'fd-btn-secondary'}
>
<FDButton href={ctaLink || '#'} variant="primary" onDark={isDark}>
{ctaText}
</a>
</FDButton>
)}
</div>
)
const imageContent = media?.url ? (
<div className="relative w-full lg:w-[575px] h-[350px] lg:h-[479px] overflow-hidden rounded-[70px]">
const imageContent = hasImage ? (
<div className="w-full lg:w-[575px] lg:h-[479px] flex-shrink-0">
<FDImage
media={media}
size="large"
fill
className="object-cover"
sizes="(max-width: 1024px) 100vw, 575px"
fallbackAlt={heading || ''}
media={image as Media}
fallbackAlt={heading}
className="w-full h-full object-cover rounded-[70px]"
/>
{hasOverlay && (
<div className={`absolute inset-0 ${overlayColor} ${overlayOpacity}`} aria-hidden="true" />
)}
</div>
) : null
return (
<section className={`w-full py-16 lg:py-[79px] ${sectionBg}`} style={sectionStyle}>
<section className={`w-full py-16 lg:py-[79px] ${isDark ? 'bg-fd-navy' : 'bg-white'}`}>
<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}</>}
{imagePosition === 'left' ? (
<>
{imageContent}
{textContent}
</>
) : (
<>
{textContent}
{imageContent}
</>
)}
</div>
</section>
)

View File

@ -1,5 +1,6 @@
import React from 'react'
import type { FDFeatureAnnouncementBlock as FDFeatureAnnouncementBlockProps } from '@/payload-types'
import { FDButton } from '@/components/FDButton'
export const FDFeatureAnnouncementBlockComponent: React.FC<FDFeatureAnnouncementBlockProps> = ({
heading,
@ -8,31 +9,31 @@ export const FDFeatureAnnouncementBlockComponent: React.FC<FDFeatureAnnouncement
ctaLink = '#',
theme = 'gray',
}) => {
const bgClass =
theme === 'dark'
? 'bg-fd-navy'
: theme === 'gray'
? 'bg-fd-gray'
: 'bg-white'
const isDark = theme === 'dark'
const headingColor = theme === 'dark' ? 'text-fd-yellow' : 'text-fd-navy'
const bodyColor = theme === 'dark' ? 'text-white' : 'text-fd-navy'
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'
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-fd-h1 text-center ${headingColor}`}>
<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}`}
>
{heading}
</h2>
<p className={`w-full max-w-[1112px] font-joey text-fd-h2 text-center ${bodyColor}`}>
<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}`}
>
{body}
</p>
{ctaText && (
<a href={ctaLink || '#'} className="fd-btn-primary">
<FDButton href={ctaLink || '#'} variant="primary" onDark={isDark}>
{ctaText}
</a>
</FDButton>
)}
</div>
</section>

View File

@ -1,5 +1,6 @@
import React from 'react'
import type { FDHeroBlock as FDHeroBlockProps, Media } from '@/payload-types'
import { FDButton } from '@/components/FDButton'
export const FDHeroBlockComponent: React.FC<FDHeroBlockProps> = ({
heading,
@ -35,8 +36,7 @@ export const FDHeroBlockComponent: React.FC<FDHeroBlockProps> = ({
const overlayClass =
overlayOpacity === '30' ? 'bg-black/30' : overlayOpacity === '70' ? 'bg-black/70' : 'bg-black/50'
const secondaryBtnClass =
isDark && textColor !== 'navy' ? 'fd-btn-secondary-dark' : 'fd-btn-secondary'
const secondaryOnDark = textColor === 'navy' ? false : isDark
return (
<section
@ -44,39 +44,34 @@ export const FDHeroBlockComponent: React.FC<FDHeroBlockProps> = ({
>
{hasBgImage && (
<>
<img
src={bgImageUrl}
alt=""
className="absolute inset-0 w-full h-full object-cover"
aria-hidden="true"
/>
<img src={bgImageUrl} alt="" className="absolute inset-0 w-full h-full object-cover" aria-hidden="true" />
<div className={`absolute inset-0 ${overlayClass}`} aria-hidden="true" />
</>
)}
<div className="relative max-w-[1200px] mx-auto px-6 md:px-8 flex flex-col items-start gap-6 md:gap-8">
<h1 className={`w-full max-w-[884px] font-joey-heavy text-fd-display ${headingColor}`}>
<h1 className={`w-full max-w-[884px] font-joey-heavy text-3xl md:text-5xl lg:text-[78px] leading-tight lg:leading-none ${headingColor}`}>
{heading}
</h1>
{subheading && (
<h2 className={`w-full max-w-[884px] font-joey-medium text-fd-h1 ${textBodyColor}`}>
<h2 className={`w-full max-w-[884px] font-joey-medium text-2xl md:text-4xl lg:text-[50px] leading-tight ${textBodyColor}`}>
{subheading}
</h2>
)}
{body && (
<p className={`w-full max-w-[597px] font-joey text-fd-body-lg ${textBodyColor}`}>
<p className={`w-full max-w-[597px] font-joey text-lg md:text-xl lg:text-2xl lg:leading-snug ${textBodyColor}`}>
{body}
</p>
)}
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4">
{ctaText && (
<a href={ctaLink || '#'} className="fd-btn-primary">
<FDButton href={ctaLink || '#'} variant="primary" onDark={isDark}>
{ctaText}
</a>
</FDButton>
)}
{secondaryCtaText && (
<a href={secondaryCtaLink || '#'} className={secondaryBtnClass}>
<FDButton href={secondaryCtaLink || '#'} variant="outline" onDark={secondaryOnDark}>
{secondaryCtaText}
</a>
</FDButton>
)}
</div>
</div>

View File

@ -1,64 +0,0 @@
import React from 'react'
import type { FDHeroBlock as FDHeroBlockProps, Media } from '@/payload-types'
import { FDImage } from '@/components/FDImage'
export const FDHeroBlockComponent: React.FC<FDHeroBlockProps> = ({
heading,
subheading,
body,
ctaText,
ctaLink = '#',
secondaryCtaText,
secondaryCtaLink = '#',
backgroundImage,
overlayOpacity = '50',
textColor = 'auto',
theme = 'light',
}) => {
const media = backgroundImage as Media | undefined
const hasBgImage = Boolean(media?.url)
const isDark = hasBgImage || theme === 'dark'
let headingColor: string
let textBodyColor: string
if (textColor === 'white') {
headingColor = 'text-white'
textBodyColor = 'text-white'
} else if (textColor === 'navy') {
headingColor = 'text-fd-navy'
textBodyColor = 'text-fd-navy'
} else {
headingColor = isDark ? 'text-fd-yellow' : 'text-fd-navy'
textBodyColor = isDark ? 'text-white' : 'text-fd-navy'
}
const overlayClass = overlayOpacity === '30' ? 'bg-black/30' : overlayOpacity === '70' ? 'bg-black/70' : 'bg-black/50'
return (
<section className={`relative w-full py-16 md:py-20 lg:py-[99px] ${hasBgImage ? '' : isDark ? 'bg-fd-navy' : 'bg-white'} overflow-hidden`}>
{hasBgImage && (
<>
<FDImage
media={backgroundImage as Media}
size="hero"
fill
priority
className="absolute inset-0 w-full h-full object-cover"
sizes="100vw"
fallbackAlt=""
/>
<div className={`absolute inset-0 ${overlayClass}`} aria-hidden="true" />
</>
)}
<div className="relative max-w-[1200px] mx-auto px-6 md:px-8 flex flex-col items-start gap-6 md:gap-8">
<h1 className={`w-full max-w-[884px] font-joey-heavy text-3xl md:text-5xl lg:text-[78px] leading-tight lg:leading-none ${headingColor}`}>{heading}</h1>
{subheading && <h2 className={`w-full max-w-[884px] font-joey-medium text-2xl md:text-4xl lg:text-[50px] leading-tight ${textBodyColor}`}>{subheading}</h2>}
{body && <p className={`w-full max-w-[597px] font-joey text-lg md:text-xl lg:text-2xl lg:leading-snug ${textBodyColor}`}>{body}</p>}
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4">
{ctaText && <a href={ctaLink || '#'} className="inline-flex items-center justify-center px-8 py-2.5 bg-fd-yellow hover:bg-fd-yellow/90 rounded-full font-joey-bold text-fd-navy text-lg md:text-2xl leading-[38px] transition-colors">{ctaText}</a>}
{secondaryCtaText && <a href={secondaryCtaLink || '#'} className={`inline-flex items-center justify-center px-8 py-2.5 rounded-full font-joey-bold text-lg md:text-2xl leading-[38px] border-2 transition-colors ${textColor === 'navy' ? 'border-fd-navy text-fd-navy hover:bg-fd-navy/5' : isDark ? 'border-white text-white hover:bg-white/10' : 'border-fd-navy text-fd-navy hover:bg-fd-navy/5'}`}>{secondaryCtaText}</a>}
</div>
</div>
</section>
)
}

View File

@ -1,33 +1,37 @@
import React from 'react'
import type { FDPricingCardBlock as FDPricingCardBlockProps } from '@/payload-types'
import { FDButton } from '@/components/FDButton'
const sectionBgMap: Record<string, string> = {
white: 'bg-white',
navy: 'bg-fd-navy',
gray: 'bg-fd-gray-light',
white: 'bg-white',
navy: 'bg-fd-navy',
gray: 'bg-fd-gray-light',
yellow: 'bg-fd-yellow',
}
const titleColorMap: Record<string, string> = {
navy: 'text-fd-navy',
white: 'text-white',
navy: 'text-fd-navy',
white: 'text-white',
yellow: 'text-fd-yellow',
}
const cardStyleMap: Record<string, { bg: string; border: string; title: string; subtitle: string; body: string; bullet: string }> = {
outlined: { bg: 'bg-white', border: 'border-[6px] border-[#d1d5db]', title: 'text-fd-navy', subtitle: 'text-fd-navy', body: 'text-fd-navy/80', bullet: 'text-fd-navy' },
navy: { bg: 'bg-fd-navy', border: '', title: 'text-fd-yellow', subtitle: 'text-white', body: 'text-white/80', bullet: 'text-white' },
gray: { bg: 'bg-[#e5e5e5]', border: '', title: 'text-fd-navy', subtitle: 'text-fd-navy', body: 'text-fd-navy/80', bullet: 'text-fd-navy' },
yellow: { bg: 'bg-fd-yellow', border: '', title: 'text-fd-navy', subtitle: 'text-fd-navy', body: 'text-fd-navy/80', bullet: 'text-fd-navy' },
white: { bg: 'bg-white shadow-lg', border: '', title: 'text-fd-navy', subtitle: 'text-fd-navy', body: 'text-fd-navy/80', bullet: 'text-fd-navy' },
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-[#e5e5e5]', 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 },
}
// Map to fd-btn classes; the 'a' tag just uses the class directly
const buttonStyleMap: Record<string, string> = {
yellow: 'fd-btn-primary',
navy: 'fd-btn-navy',
outlinedNavy: 'fd-btn-secondary',
outlinedWhite: 'fd-btn-secondary-dark',
// Maps CMS buttonColor to FDButton variant — outline used where primary yellow wouldn't be visible
const buttonVariantMap: Record<string, { variant: 'primary' | 'outline' }> = {
yellow: { variant: 'primary' },
navy: { variant: 'primary' },
outlinedNavy: { variant: 'outline' },
outlinedWhite: { variant: 'outline' },
}
const gridColsMap: Record<number, string> = {
@ -47,15 +51,18 @@ export const FDPricingCardBlockComponent: React.FC<FDPricingCardBlockProps> = ({
const sectionBg = sectionBgMap[sectionBackground || 'white']
const sectionTitleColor = titleColorMap[titleColor || 'navy']
const style = cardStyleMap[cardStyle || 'outlined']
const btnClass = buttonStyleMap[buttonColor || 'yellow'] || 'fd-btn-primary'
const { variant } = buttonVariantMap[buttonColor || 'yellow']
const cardCount = cards?.length || 1
const gridCols = gridColsMap[cardCount] || gridColsMap[3]
// outline-dark vs outline-light is determined by the card background
const outlineOnDark = style.isDark
return (
<section className={`w-full py-12 md:py-16 lg:py-20 ${sectionBg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
{sectionTitle && (
<h2 className={`font-joey-heavy text-fd-h1 text-center mb-10 md:mb-14 ${sectionTitleColor}`}>
<h2 className={`font-joey-heavy text-3xl md:text-4xl lg:text-[54px] leading-tight text-center mb-10 md:mb-14 ${sectionTitleColor}`}>
{sectionTitle}
</h2>
)}
@ -63,28 +70,41 @@ export const FDPricingCardBlockComponent: React.FC<FDPricingCardBlockProps> = ({
{cards?.map((card, index) => (
<div
key={index}
className={`${style.bg} ${style.border} rounded-[32px] md:rounded-[50px] lg:rounded-[70px] px-8 md:px-10 py-10 md:py-12 flex flex-col gap-5`}
className={`${style.bg} ${style.border} rounded-[32px] px-8 md:px-10 py-10 md:py-12 flex flex-col gap-5`}
>
<h3 className={`font-joey-heavy text-fd-h2 ${style.title}`}>{card.title}</h3>
<h3 className={`font-joey-heavy text-2xl md:text-3xl lg:text-4xl leading-tight ${style.title}`}>
{card.title}
</h3>
{card.subtitle && (
<p className={`font-joey-bold text-fd-h3 ${style.subtitle}`}>{card.subtitle}</p>
<p className={`font-joey-bold text-xl md:text-2xl leading-tight ${style.subtitle}`}>
{card.subtitle}
</p>
)}
{card.description && (
<p className={`font-joey text-fd-body ${style.body}`}>{card.description}</p>
<p className={`font-joey text-base md:text-lg leading-relaxed ${style.body}`}>
{card.description}
</p>
)}
{card.bulletPoints && card.bulletPoints.length > 0 && (
<ul className={`flex flex-col gap-1 ${style.bullet}`}>
<ul className={`flex flex-col gap-2 ${style.bullet}`}>
{card.bulletPoints.map((point, i) => (
<li key={i} className="flex items-start gap-3">
<span className="mt-2 w-2 h-2 rounded-full bg-current flex-shrink-0" />
<span className="font-joey text-fd-body">{point.text}</span>
<span className="font-joey text-base md:text-lg">{point.text}</span>
</li>
))}
</ul>
)}
{card.ctaText && (
<div className="mt-auto pt-4">
<a href={card.ctaLink || '#'} className={btnClass}>{card.ctaText}</a>
<FDButton
href={card.ctaLink || '#'}
variant={variant}
onDark={variant === 'outline' ? outlineOnDark : style.isDark}
className="text-lg md:text-xl"
>
{card.ctaText}
</FDButton>
</div>
)}
</div>

View File

@ -1,19 +1,12 @@
import React from 'react'
import type { FDWideCardBlock as FDWideCardBlockProps, Media } from '@/payload-types'
import { FDImage } from '@/components/FDImage'
import { FDButton } from '@/components/FDButton'
const cardBgMap: Record<string, { bg: string; heading: string; body: string }> = {
navy: { bg: 'bg-fd-navy', heading: 'text-white', body: 'text-white/80' },
yellow: { bg: 'bg-fd-yellow', heading: 'text-fd-navy', body: 'text-fd-navy/80' },
gray: { bg: 'bg-[#e5e5e5]', heading: 'text-fd-navy', body: 'text-fd-navy/80' },
white: { bg: 'bg-white shadow-xl', heading: 'text-fd-navy', body: 'text-fd-navy/80' },
}
// Map to fd-btn classes
const btnMap: Record<string, string> = {
yellow: 'fd-btn-primary',
navy: 'fd-btn-navy',
white: 'fd-btn-white',
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-[#e5e5e5]', 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 },
}
const sectionBgMap: Record<string, string> = {
@ -22,6 +15,13 @@ const sectionBgMap: Record<string, string> = {
navy: 'bg-fd-navy',
}
// Button variant per CMS color choice — outline used for navy cards with navy button (would be invisible)
const btnVariantMap: Record<string, { variant: 'primary' | 'outline' }> = {
yellow: { variant: 'primary' },
navy: { variant: 'outline' },
white: { variant: 'primary' },
}
export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
heading,
body,
@ -33,36 +33,41 @@ export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
sectionBackground = 'white',
}) => {
const card = cardBgMap[cardBackground || 'navy']
const btnClass = btnMap[buttonColor || 'yellow'] || 'fd-btn-primary'
const sectionBg = sectionBgMap[sectionBackground || 'white']
const { variant } = btnVariantMap[buttonColor || 'yellow']
const media = image as Media | undefined
const hasImage = Boolean(media?.url)
const imageUrl = media?.url || ''
const hasImage = Boolean(imageUrl)
return (
<section className={`w-full py-12 md:py-16 lg:py-20 ${sectionBg}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
<div className={`${card.bg} rounded-[70px] overflow-hidden flex flex-col lg:flex-row`}>
<div className="flex-1 flex flex-col justify-center gap-5 md:gap-6 px-10 md:px-14 lg:px-16 py-12 md:py-16">
<h2 className={`font-joey-heavy text-fd-h2 ${card.heading}`}>{heading}</h2>
<h2 className={`font-joey-heavy text-2xl md:text-3xl lg:text-[42px] leading-tight ${card.heading}`}>
{heading}
</h2>
{body && (
<p className={`font-joey text-fd-body ${card.body}`}>{body}</p>
<p className={`font-joey text-base md:text-lg lg:text-xl leading-relaxed ${card.body}`}>
{body}
</p>
)}
{ctaText && (
<div>
<a href={ctaLink || '#'} className={btnClass}>{ctaText}</a>
<FDButton
href={ctaLink || '#'}
variant={variant}
onDark={card.isDark}
className="text-lg md:text-xl"
>
{ctaText}
</FDButton>
</div>
)}
</div>
{hasImage && (
<div className="relative flex-1 min-h-[250px] lg:min-h-0">
<FDImage
media={media!}
size="large"
fill
className="object-cover"
sizes="(max-width: 1024px) 100vw, 600px"
fallbackAlt={heading || ''}
/>
<div className="flex-1 min-h-[250px] lg:min-h-0">
<img src={imageUrl} alt={media?.alt || ''} className="w-full h-full object-cover" />
</div>
)}
</div>

View File

@ -0,0 +1,43 @@
import React from 'react'
type FDButtonProps = {
href: string
children: React.ReactNode
variant?: 'primary' | 'outline'
onDark?: boolean
className?: string
}
/**
* FDButton shared button component for all FD blocks.
*
* variant="primary" onDark={true} yellow bg, hover white (use on navy backgrounds)
* variant="primary" onDark={false} yellow bg, hover yellow/80 (use on light backgrounds)
* variant="outline" onDark={true} white border + text, hover white/10
* variant="outline" onDark={false} navy border + text, hover navy/5
*/
export const FDButton: React.FC<FDButtonProps> = ({
href,
children,
variant = 'primary',
onDark = false,
className = '',
}) => {
const base =
'inline-flex items-center justify-center px-8 py-2.5 rounded-full font-joey-bold text-lg md:text-2xl leading-[38px] transition-colors'
const styles = {
'primary-dark': 'bg-fd-yellow text-fd-navy hover:bg-white hover:text-fd-navy',
'primary-light': 'bg-fd-yellow text-fd-navy hover:bg-fd-yellow/80',
'outline-dark': 'border-2 border-white text-white hover:bg-white/10',
'outline-light': 'border-2 border-fd-navy text-fd-navy hover:bg-fd-navy/5',
}
const key = `${variant}-${onDark ? 'dark' : 'light'}` as keyof typeof styles
return (
<a href={href} className={`${base} ${styles[key]} ${className}`}>
{children}
</a>
)
}

File diff suppressed because one or more lines are too long