fix: mobile audit — gray token, FDImage props, border radius, padding
This commit is contained in:
parent
5b64cbf24c
commit
097615569b
@ -340,6 +340,7 @@ html:not([data-theme]) {
|
||||
--color-fd-gray-warm: #F8F8F6;
|
||||
--color-fd-gray-cool: #F5F7F9;
|
||||
--color-fd-gray-200: #C8CCD0;
|
||||
--color-fd-gray-light: #F0F0F0;
|
||||
--color-fd-gray-300: #A9AEB5;
|
||||
--color-fd-gray-400: #8A919A;
|
||||
--color-fd-gray-500: #6B737E;
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import React from 'react'
|
||||
import type { FDAlternateHeroBlock as Props, Media } from '@/payload-types'
|
||||
import { FDImage } from '@/components/FDImage'
|
||||
import { FDButton } from '@/components/FDButton'
|
||||
|
||||
export const FDAlternateHeroBlockComponent: React.FC<Props> = ({
|
||||
heading,
|
||||
@ -13,8 +15,9 @@ export const FDAlternateHeroBlockComponent: React.FC<Props> = ({
|
||||
sectionBackground = 'white',
|
||||
}) => {
|
||||
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-surface-alt' : 'bg-white'
|
||||
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'
|
||||
|
||||
@ -33,31 +36,33 @@ export const FDAlternateHeroBlockComponent: React.FC<Props> = ({
|
||||
{(primaryCtaText || secondaryCtaText) && (
|
||||
<div className="flex flex-col sm:flex-row items-center justify-center gap-4 mt-2">
|
||||
{primaryCtaText && (
|
||||
<a href={primaryCtaLink || '#'} className="fd-btn-primary">
|
||||
<FDButton href={primaryCtaLink || '#'} variant="primary" onDark={isDark}>
|
||||
{primaryCtaText} →
|
||||
</a>
|
||||
</FDButton>
|
||||
)}
|
||||
{secondaryCtaText && (
|
||||
<a
|
||||
href={secondaryCtaLink || '#'}
|
||||
className={isDark ? 'fd-btn-secondary-dark' : 'fd-btn-secondary'}
|
||||
>
|
||||
<FDButton href={secondaryCtaLink || '#'} variant="outline" onDark={isDark}>
|
||||
{secondaryCtaText}
|
||||
</a>
|
||||
</FDButton>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Full-width image — no container, no border radius */}
|
||||
{media?.url && (
|
||||
{/* FIX: Full-width image using FDImage with fill, replacing raw <img> */}
|
||||
{hasImage && (
|
||||
<div className="w-full">
|
||||
<img
|
||||
src={media.url}
|
||||
alt={(media as any).alt || heading}
|
||||
className="w-full object-cover block"
|
||||
style={{ maxHeight: '620px', objectPosition: 'center top' }}
|
||||
<div className="relative w-full" style={{ maxHeight: '620px', height: '45vw', minHeight: '220px' }}>
|
||||
<FDImage
|
||||
media={media}
|
||||
size="hero"
|
||||
fill
|
||||
priority
|
||||
className="object-cover object-center"
|
||||
sizes="100vw"
|
||||
fallbackAlt={heading || ''}
|
||||
/>
|
||||
</div>
|
||||
{imageCaption && (
|
||||
<div className={`text-center py-3 font-joey text-fd-small opacity-60 ${bodyClass} ${bgClass}`}>
|
||||
{imageCaption}
|
||||
|
||||
@ -13,7 +13,7 @@ const cardStyleMap: Record<
|
||||
border: '',
|
||||
},
|
||||
gray: {
|
||||
bg: 'bg-[#e5e5e5] dark:bg-white/10',
|
||||
bg: 'bg-fd-gray-light dark:bg-white/10',
|
||||
headingText: 'text-fd-navy dark:text-fd-yellow',
|
||||
bodyText: 'text-fd-navy dark:text-white',
|
||||
linkText: 'text-fd-navy hover:text-fd-navy/70 dark:text-fd-yellow dark:hover:text-fd-yellow/80',
|
||||
@ -73,7 +73,7 @@ export const FDCardGridBlockComponent: React.FC<FDCardGridBlockProps> = ({
|
||||
const gridCols = layoutGridMap[layout] || layoutGridMap['1-1-1']
|
||||
|
||||
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">
|
||||
<div className={`grid grid-cols-1 md:grid-cols-2 ${gridCols} gap-4 md:gap-6`}>
|
||||
{cards?.map((card, index) => {
|
||||
@ -84,7 +84,7 @@ export const FDCardGridBlockComponent: React.FC<FDCardGridBlockProps> = ({
|
||||
if (mode === 'centeredHeading') {
|
||||
cardContent = (
|
||||
<div
|
||||
className={`${style.bg} ${style.border} rounded-[70px] px-10 md:px-14 py-14 md:py-20 flex items-center justify-center min-h-[280px] md:min-h-[360px]`}
|
||||
className={`${style.bg} ${style.border} rounded-[70px] px-8 md:px-14 py-14 md:py-20 flex items-center justify-center min-h-[280px] md:min-h-[360px]`}
|
||||
>
|
||||
<span
|
||||
className={`font-joey-heavy text-fd-display leading-tight text-center ${style.headingText}`}
|
||||
@ -96,7 +96,7 @@ export const FDCardGridBlockComponent: React.FC<FDCardGridBlockProps> = ({
|
||||
} else if (mode === 'centeredBody') {
|
||||
cardContent = (
|
||||
<div
|
||||
className={`${style.bg} ${style.border} rounded-[70px] px-10 md:px-14 py-14 md:py-20 flex items-center justify-center min-h-[280px] md:min-h-[360px]`}
|
||||
className={`${style.bg} ${style.border} rounded-[70px] px-8 md:px-14 py-14 md:py-20 flex items-center justify-center min-h-[280px] md:min-h-[360px]`}
|
||||
>
|
||||
<p
|
||||
className={`font-joey text-fd-body-lg text-center ${style.bodyText}`}
|
||||
@ -106,9 +106,10 @@ export const FDCardGridBlockComponent: React.FC<FDCardGridBlockProps> = ({
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
// FIX: px-6 on mobile → px-10 on md+ to prevent 40px padding squashing 375px cards
|
||||
cardContent = (
|
||||
<div
|
||||
className={`${style.bg} ${style.border} rounded-[70px] px-10 md:px-14 py-10 md:py-14 flex flex-col gap-1 h-full`}
|
||||
className={`${style.bg} ${style.border} rounded-[70px] px-6 md:px-10 lg:px-14 py-8 md:py-12 lg:py-14 flex flex-col gap-1 h-full`}
|
||||
>
|
||||
{card.heading && (
|
||||
<h3
|
||||
|
||||
@ -9,22 +9,25 @@ export const FDContactBlockComponent: React.FC<FDContactBlockProps> = ({
|
||||
return (
|
||||
<section className="relative w-full bg-fd-navy py-16 md:py-20 lg:pt-[100px] lg:pb-[120px]">
|
||||
<div className="max-w-[1200px] mx-auto px-6 md:px-8 flex flex-col items-center gap-8 lg:gap-10">
|
||||
<h2 className="w-full font-joey-heavy text-fd-navy text-fd-h1 text-fd-yellow text-center">
|
||||
{/* FIX: removed conflicting text-fd-navy class, kept text-fd-yellow */}
|
||||
<h2 className="w-full font-joey-heavy text-fd-h1 text-fd-yellow text-center">
|
||||
{heading}
|
||||
</h2>
|
||||
<div className="flex flex-row items-stretch gap-4 md:gap-7 w-full max-w-[656px]">
|
||||
|
||||
{/* FIX: flex-col on mobile → sm:flex-row so cards don't squash at 375px */}
|
||||
<div className="flex flex-col sm:flex-row items-stretch gap-4 md:gap-7 w-full max-w-[656px]">
|
||||
{contactMethods?.map((method, index) => {
|
||||
const media = method.icon as Media
|
||||
const card = (
|
||||
<div className="flex-1 flex flex-col items-center gap-3 md:gap-5 cursor-pointer transition-transform hover:scale-105">
|
||||
{media?.url && (
|
||||
<div className="relative w-full h-[120px] md:h-[160px] lg:h-[200px] overflow-hidden rounded-[70px]">
|
||||
<div className="relative w-full h-[140px] sm:h-[120px] md:h-[160px] lg:h-[200px] overflow-hidden rounded-[70px]">
|
||||
<FDImage
|
||||
media={media}
|
||||
size="medium"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="(max-width: 768px) 50vw, 300px"
|
||||
sizes="(max-width: 640px) 90vw, (max-width: 768px) 50vw, 300px"
|
||||
fallbackAlt={method.label}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -20,14 +20,14 @@ export const FDCtaSideImageBlockComponent: React.FC<FDCtaSideImageBlockProps> =
|
||||
<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-3xl md:text-4xl lg:text-5xl leading-tight lg:leading-[57.6px] ${
|
||||
className={`w-full font-joey-heavy text-fd-h1 leading-tight ${
|
||||
isDark ? 'text-fd-yellow' : 'text-fd-navy'
|
||||
}`}
|
||||
>
|
||||
{heading}
|
||||
</h2>
|
||||
<p
|
||||
className={`w-full font-joey text-lg md:text-xl lg:text-2xl leading-relaxed lg:leading-[38px] ${
|
||||
className={`w-full font-joey text-fd-body-lg leading-relaxed ${
|
||||
isDark ? 'text-white' : 'text-fd-navy'
|
||||
}`}
|
||||
>
|
||||
@ -47,14 +47,17 @@ export const FDCtaSideImageBlockComponent: React.FC<FDCtaSideImageBlockProps> =
|
||||
<div className="w-full lg:w-[575px] lg:h-[479px] flex-shrink-0">
|
||||
<FDImage
|
||||
media={image as Media}
|
||||
size="large"
|
||||
fallbackAlt={heading}
|
||||
className="w-full h-full object-cover rounded-[70px]"
|
||||
sizes="(max-width: 1024px) 100vw, 575px"
|
||||
/>
|
||||
</div>
|
||||
) : null
|
||||
|
||||
return (
|
||||
<section className={`w-full py-16 lg:py-[79px] ${isDark ? 'bg-fd-navy' : 'bg-white'}`}>
|
||||
// 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'}`}>
|
||||
<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' ? (
|
||||
<>
|
||||
|
||||
@ -21,12 +21,11 @@ const cardStyleMap: Record<string, {
|
||||
}> = {
|
||||
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 },
|
||||
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 },
|
||||
}
|
||||
|
||||
// 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' },
|
||||
@ -54,34 +53,33 @@ export const FDPricingCardBlockComponent: React.FC<FDPricingCardBlockProps> = ({
|
||||
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}`}>
|
||||
<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">
|
||||
{sectionTitle && (
|
||||
<h2 className={`font-joey-heavy text-3xl md:text-4xl lg:text-[54px] leading-tight text-center mb-10 md:mb-14 ${sectionTitleColor}`}>
|
||||
<h2 className={`font-joey-heavy text-fd-h1 text-center mb-10 md:mb-14 ${sectionTitleColor}`}>
|
||||
{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
|
||||
key={index}
|
||||
className={`${style.bg} ${style.border} rounded-[32px] px-8 md:px-10 py-10 md:py-12 flex flex-col gap-5`}
|
||||
className={`${style.bg} ${style.border} rounded-[70px] px-8 md:px-10 py-10 md:py-12 flex flex-col gap-5`}
|
||||
>
|
||||
<h3 className={`font-joey-heavy text-2xl md:text-3xl lg:text-4xl leading-tight ${style.title}`}>
|
||||
<h3 className={`font-joey-heavy text-fd-h2 leading-tight ${style.title}`}>
|
||||
{card.title}
|
||||
</h3>
|
||||
{card.subtitle && (
|
||||
<p className={`font-joey-bold text-xl md:text-2xl leading-tight ${style.subtitle}`}>
|
||||
<p className={`font-joey-bold text-fd-h3 leading-tight ${style.subtitle}`}>
|
||||
{card.subtitle}
|
||||
</p>
|
||||
)}
|
||||
{card.description && (
|
||||
<p className={`font-joey text-base md:text-lg leading-relaxed ${style.body}`}>
|
||||
<p className={`font-joey text-fd-body-lg leading-relaxed ${style.body}`}>
|
||||
{card.description}
|
||||
</p>
|
||||
)}
|
||||
@ -90,7 +88,7 @@ export const FDPricingCardBlockComponent: React.FC<FDPricingCardBlockProps> = ({
|
||||
{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-base md:text-lg">{point.text}</span>
|
||||
<span className="font-joey text-fd-body-lg">{point.text}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
@ -101,7 +99,6 @@ export const FDPricingCardBlockComponent: React.FC<FDPricingCardBlockProps> = ({
|
||||
href={card.ctaLink || '#'}
|
||||
variant={variant}
|
||||
onDark={variant === 'outline' ? outlineOnDark : style.isDark}
|
||||
className="text-lg md:text-xl"
|
||||
>
|
||||
{card.ctaText}
|
||||
</FDButton>
|
||||
|
||||
@ -14,7 +14,8 @@ export const FDServicesGridBlockComponent: React.FC<FDServicesGridBlockProps> =
|
||||
columns = '4',
|
||||
}) => {
|
||||
return (
|
||||
<section className="relative w-full bg-white py-16 md:py-20 lg:py-24">
|
||||
// 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]">
|
||||
<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">
|
||||
{heading}
|
||||
|
||||
@ -1,18 +1,17 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react'
|
||||
import type { FDTeamBlock as FDTeamBlockProps, Media } from '@/payload-types'
|
||||
import { FDImage } from '@/components/FDImage'
|
||||
|
||||
const sectionBgMap: Record<string, string> = {
|
||||
white: 'bg-white',
|
||||
gray: 'bg-[#e5e5e5]',
|
||||
gray: 'bg-fd-gray-light',
|
||||
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-[#e5e5e5]', 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' },
|
||||
}
|
||||
|
||||
const colsMap: Record<string, string> = {
|
||||
@ -29,9 +28,9 @@ export const FDTeamBlockComponent: React.FC<FDTeamBlockProps> = ({
|
||||
cardStyle = 'navy',
|
||||
sectionBackground = 'white',
|
||||
}) => {
|
||||
const sectionBg = sectionBgMap[sectionBackground] || sectionBgMap.white
|
||||
const card = cardMap[cardStyle] || cardMap.navy
|
||||
const gridCols = colsMap[columns] || 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 (
|
||||
@ -42,12 +41,12 @@ export const FDTeamBlockComponent: React.FC<FDTeamBlockProps> = ({
|
||||
{(heading || subheading) && (
|
||||
<div className="flex flex-col gap-3 mb-10 md:mb-14">
|
||||
{heading && (
|
||||
<h2 className={`font-joey-heavy text-3xl md:text-4xl lg:text-5xl leading-tight ${isNavySection ? 'text-fd-yellow' : 'text-fd-navy'}`}>
|
||||
<h2 className={`font-joey-heavy text-fd-h1 ${isNavySection ? 'text-fd-yellow' : 'text-fd-navy'}`}>
|
||||
{heading}
|
||||
</h2>
|
||||
)}
|
||||
{subheading && (
|
||||
<p className={`font-joey text-lg md:text-xl ${isNavySection ? 'text-white/70' : 'text-fd-navy/60'}`}>
|
||||
<p className={`font-joey text-fd-body-lg ${isNavySection ? 'text-white/70' : 'text-fd-navy/60'}`}>
|
||||
{subheading}
|
||||
</p>
|
||||
)}
|
||||
@ -57,22 +56,24 @@ export const FDTeamBlockComponent: React.FC<FDTeamBlockProps> = ({
|
||||
{/* 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 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">
|
||||
{photo?.url ? (
|
||||
{hasPhoto ? (
|
||||
<FDImage
|
||||
src={photo.url}
|
||||
alt={photo.alt || member.name}
|
||||
width={600}
|
||||
height={450}
|
||||
media={photo}
|
||||
size="medium"
|
||||
className="w-full h-full object-cover object-top"
|
||||
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
|
||||
fallbackAlt={member.name}
|
||||
/>
|
||||
) : (
|
||||
// Placeholder when no photo
|
||||
<div className={`w-full h-full flex items-center justify-center ${cardStyle === 'navy' ? 'bg-fd-navy/50' : 'bg-fd-navy/10'}`}>
|
||||
<svg viewBox="0 0 80 80" className="w-20 h-20 opacity-30" fill="currentColor">
|
||||
<circle cx="40" cy="30" r="18" />
|
||||
@ -84,11 +85,11 @@ export const FDTeamBlockComponent: React.FC<FDTeamBlockProps> = ({
|
||||
|
||||
{/* Info */}
|
||||
<div className="flex flex-col gap-2 px-8 py-8 flex-1">
|
||||
<p className={`font-joey-bold text-xl ${card.name}`}>{member.name}</p>
|
||||
<p className={`font-joey text-sm ${card.role}`}>{member.role}</p>
|
||||
<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>
|
||||
|
||||
{member.bio && (
|
||||
<p className={`font-joey text-sm leading-relaxed mt-2 ${card.bio}`}>
|
||||
<p className={`font-joey text-fd-small leading-relaxed mt-2 ${card.bio}`}>
|
||||
{member.bio}
|
||||
</p>
|
||||
)}
|
||||
@ -102,7 +103,6 @@ export const FDTeamBlockComponent: React.FC<FDTeamBlockProps> = ({
|
||||
aria-label={`E-post till ${member.name}`}
|
||||
className={`transition-colors ${card.icon}`}
|
||||
>
|
||||
{/* Email 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>
|
||||
@ -116,7 +116,6 @@ export const FDTeamBlockComponent: React.FC<FDTeamBlockProps> = ({
|
||||
aria-label={`LinkedIn för ${member.name}`}
|
||||
className={`transition-colors ${card.icon}`}
|
||||
>
|
||||
{/* LinkedIn 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>
|
||||
|
||||
@ -1,29 +1,48 @@
|
||||
// @ts-nocheck
|
||||
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-[#e5e5e5]', 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-[#e5e5e5]', quote: 'text-fd-navy', meta: 'text-fd-navy/60', name: 'text-fd-navy', company: 'text-fd-navy/50' },
|
||||
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' },
|
||||
}
|
||||
|
||||
/** 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 (
|
||||
<div
|
||||
className="rounded-full overflow-hidden flex-shrink-0"
|
||||
style={{ width: size, height: size }}
|
||||
>
|
||||
<FDImage
|
||||
media={media}
|
||||
size="thumbnail"
|
||||
className="w-full h-full object-cover"
|
||||
sizes={`${size}px`}
|
||||
fallbackAlt={name}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const FDTestimonialBlockComponent: React.FC<FDTestimonialBlockProps> = ({
|
||||
heading,
|
||||
testimonials,
|
||||
layout = 'grid',
|
||||
sectionBackground = 'gray',
|
||||
}) => {
|
||||
const theme = bgMap[sectionBackground] || 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-3xl md:text-4xl lg:text-5xl leading-tight mb-10 md:mb-14 ${sectionBackground === 'navy' ? 'text-fd-yellow' : 'text-fd-navy'}`}>
|
||||
<h2 className={`font-joey-heavy text-fd-h1 mb-10 md:mb-14 ${isNavy ? 'text-fd-yellow' : 'text-fd-navy'}`}>
|
||||
{heading}
|
||||
</h2>
|
||||
)}
|
||||
@ -36,22 +55,12 @@ export const FDTestimonialBlockComponent: React.FC<FDTestimonialBlockProps> = ({
|
||||
const t = testimonials[0]
|
||||
const avatar = t.avatar as Media | undefined
|
||||
return (
|
||||
<div className={`${theme.card} rounded-[70px] px-10 md:px-16 py-12 md:py-16 flex flex-col gap-8`}>
|
||||
<div className={`${theme.card} rounded-[70px] px-8 md:px-16 py-10 md:py-16 flex flex-col gap-8`}>
|
||||
<p className={`font-joey-medium text-xl md:text-2xl lg:text-3xl leading-relaxed ${theme.quote}`}>
|
||||
“{t.quote}”
|
||||
</p>
|
||||
<div className="flex items-center gap-4">
|
||||
{avatar?.url && (
|
||||
<div className="w-14 h-14 rounded-full overflow-hidden flex-shrink-0">
|
||||
<FDImage
|
||||
src={avatar.url}
|
||||
alt={avatar.alt || t.authorName}
|
||||
width={56}
|
||||
height={56}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Avatar media={avatar} name={t.authorName} size={56} />
|
||||
<div>
|
||||
<p className={`font-joey-bold text-lg ${theme.name}`}>{t.authorName}</p>
|
||||
<p className={`font-joey text-sm ${theme.meta}`}>
|
||||
@ -74,17 +83,7 @@ export const FDTestimonialBlockComponent: React.FC<FDTestimonialBlockProps> = ({
|
||||
“{t.quote}”
|
||||
</p>
|
||||
<div className="flex items-center gap-3">
|
||||
{avatar?.url && (
|
||||
<div className="w-10 h-10 rounded-full overflow-hidden flex-shrink-0">
|
||||
<FDImage
|
||||
src={avatar.url}
|
||||
alt={avatar.alt || t.authorName}
|
||||
width={40}
|
||||
height={40}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Avatar media={avatar} name={t.authorName} size={40} />
|
||||
<div>
|
||||
<p className={`font-joey-bold text-base ${theme.name}`}>{t.authorName}</p>
|
||||
<p className={`font-joey text-xs ${theme.meta}`}>
|
||||
@ -106,24 +105,14 @@ export const FDTestimonialBlockComponent: React.FC<FDTestimonialBlockProps> = ({
|
||||
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 ${sectionBackground === 'navy' ? 'text-fd-yellow' : 'text-fd-navy'} opacity-30`}>
|
||||
<span className={`font-joey-heavy text-5xl leading-none ${isNavy ? 'text-fd-yellow' : 'text-fd-navy'} opacity-30`}>
|
||||
“
|
||||
</span>
|
||||
<p className={`font-joey-medium text-lg leading-relaxed -mt-4 ${theme.quote}`}>
|
||||
{t.quote}
|
||||
</p>
|
||||
<div className="flex items-center gap-3 mt-auto">
|
||||
{avatar?.url && (
|
||||
<div className="w-10 h-10 rounded-full overflow-hidden flex-shrink-0">
|
||||
<FDImage
|
||||
src={avatar.url}
|
||||
alt={avatar.alt || t.authorName}
|
||||
width={40}
|
||||
height={40}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Avatar media={avatar} name={t.authorName} size={40} />
|
||||
<div>
|
||||
<p className={`font-joey-bold text-base ${theme.name}`}>{t.authorName}</p>
|
||||
<p className={`font-joey text-sm ${theme.meta}`}>
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import React from 'react'
|
||||
import type { FDWideCardBlock as FDWideCardBlockProps, Media } from '@/payload-types'
|
||||
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-[#e5e5e5]', 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 },
|
||||
}
|
||||
|
||||
@ -15,7 +16,6 @@ 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' },
|
||||
@ -36,19 +36,18 @@ export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
|
||||
const sectionBg = sectionBgMap[sectionBackground || 'white']
|
||||
const { variant } = btnVariantMap[buttonColor || 'yellow']
|
||||
const media = image as Media | undefined
|
||||
const imageUrl = media?.url || ''
|
||||
const hasImage = Boolean(imageUrl)
|
||||
const hasImage = media && typeof media === 'object' && media.url
|
||||
|
||||
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">
|
||||
<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-2xl md:text-3xl lg:text-[42px] leading-tight ${card.heading}`}>
|
||||
<div className="flex-1 flex flex-col justify-center gap-5 md:gap-6 px-8 md:px-14 lg:px-16 py-12 md:py-16">
|
||||
<h2 className={`font-joey-heavy text-fd-h1 leading-tight ${card.heading}`}>
|
||||
{heading}
|
||||
</h2>
|
||||
{body && (
|
||||
<p className={`font-joey text-base md:text-lg lg:text-xl leading-relaxed ${card.body}`}>
|
||||
<p className={`font-joey text-fd-body-lg leading-relaxed ${card.body}`}>
|
||||
{body}
|
||||
</p>
|
||||
)}
|
||||
@ -58,16 +57,24 @@ export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
|
||||
href={ctaLink || '#'}
|
||||
variant={variant}
|
||||
onDark={card.isDark}
|
||||
className="text-lg md:text-xl"
|
||||
>
|
||||
{ctaText}
|
||||
</FDButton>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* FIX: replaced raw <img> with FDImage */}
|
||||
{hasImage && (
|
||||
<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 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, 50vw"
|
||||
fallbackAlt={heading || ''}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user