feat: 3 new blocks FDCtaBannerBlock, FDTestimonialBlock, FDTeamBlock

This commit is contained in:
Jeffrey 2026-02-18 13:55:07 +01:00
parent 0712c0cc9d
commit cbeae1bf85
10 changed files with 820 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

View File

@ -0,0 +1,97 @@
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 }> = {
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',
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',
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',
},
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',
},
}
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' },
}
export const FDCtaBannerBlockComponent: React.FC<FDCtaBannerBlockProps> = ({
heading,
subheading,
ctaText,
ctaLink = '/kontakt',
secondaryCtaText,
secondaryCtaLink,
sectionBackground = 'yellow',
alignment = 'center',
size = 'medium',
}) => {
const theme = bgMap[sectionBackground] || bgMap.yellow
const sizing = sizeMap[size] || sizeMap.medium
const isCenter = alignment === 'center'
return (
<section className={`w-full ${sizing.py} ${theme.section}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
<div className={`flex flex-col gap-6 md:gap-8 ${isCenter ? 'items-center text-center' : 'items-start text-left'} max-w-[800px] ${isCenter ? 'mx-auto' : ''}`}>
<div className={`flex flex-col gap-3 ${isCenter ? 'items-center' : 'items-start'}`}>
<h2 className={`font-joey-heavy leading-tight ${sizing.heading} ${theme.heading}`}>
{heading}
</h2>
{subheading && (
<p className={`font-joey leading-relaxed ${sizing.sub} ${theme.sub}`}>
{subheading}
</p>
)}
</div>
{(ctaText || secondaryCtaText) && (
<div className={`flex flex-col sm:flex-row gap-4 ${isCenter ? 'justify-center' : ''}`}>
{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}`}
>
{ctaText}
</a>
)}
{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}`}
>
{secondaryCtaText}
</a>
)}
</div>
)}
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,86 @@
import type { Block } from 'payload'
export const FDCtaBannerBlock: Block = {
slug: 'fdCtaBanner',
interfaceName: 'FDCtaBannerBlock',
labels: {
singular: 'FD CTA-banner',
plural: 'FD CTA-banners',
},
fields: [
{
name: 'heading',
type: 'text',
required: true,
localized: true,
label: 'Rubrik',
defaultValue: 'Redo att komma igång?',
},
{
name: 'subheading',
type: 'text',
localized: true,
label: 'Underrubrik (valfri)',
admin: {
description: 'Kort text under rubriken',
},
},
{
name: 'ctaText',
type: 'text',
localized: true,
label: 'CTA-knapp text',
defaultValue: 'Kontakta oss',
},
{
name: 'ctaLink',
type: 'text',
label: 'CTA-knapp länk',
defaultValue: '/kontakt',
},
{
name: 'secondaryCtaText',
type: 'text',
localized: true,
label: 'Sekundär CTA text (valfri)',
},
{
name: 'secondaryCtaLink',
type: 'text',
label: 'Sekundär CTA länk',
},
{
name: 'sectionBackground',
type: 'select',
label: 'Bakgrundsfärg',
defaultValue: 'yellow',
options: [
{ label: 'Gul', value: 'yellow' },
{ label: 'Navy', value: 'navy' },
{ label: 'Grå', value: 'gray' },
{ label: 'Vit', value: 'white' },
],
},
{
name: 'alignment',
type: 'select',
label: 'Textjustering',
defaultValue: 'center',
options: [
{ label: 'Centrerad', value: 'center' },
{ label: 'Vänster', value: 'left' },
],
},
{
name: 'size',
type: 'select',
label: 'Storlek',
defaultValue: 'medium',
options: [
{ label: 'Liten', value: 'small' },
{ label: 'Medium', value: 'medium' },
{ label: 'Stor', value: 'large' },
],
},
],
}

View File

@ -0,0 +1,136 @@
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]',
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' },
}
const colsMap: Record<string, string> = {
'2': 'sm:grid-cols-2',
'3': 'sm:grid-cols-2 lg:grid-cols-3',
'4': 'sm:grid-cols-2 lg:grid-cols-4',
}
export const FDTeamBlockComponent: React.FC<FDTeamBlockProps> = ({
heading,
subheading,
members,
columns = '3',
cardStyle = 'navy',
sectionBackground = 'white',
}) => {
const sectionBg = sectionBgMap[sectionBackground] || sectionBgMap.white
const card = cardMap[cardStyle] || cardMap.navy
const gridCols = colsMap[columns] || 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-3xl md:text-4xl lg:text-5xl leading-tight ${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'}`}>
{subheading}
</p>
)}
</div>
)}
{/* Grid */}
<div className={`grid grid-cols-1 ${gridCols} gap-6`}>
{members?.map((member, i) => {
const photo = member.photo as Media | undefined
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 ? (
<FDImage
src={photo.url}
alt={photo.alt || member.name}
width={600}
height={450}
className="w-full h-full object-cover object-top"
/>
) : (
// 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" />
<path d="M10 72c0-16.6 13.4-30 30-30s30 13.4 30 30H10z" />
</svg>
</div>
)}
</div>
{/* 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>
{member.bio && (
<p className={`font-joey text-sm leading-relaxed mt-2 ${card.bio}`}>
{member.bio}
</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}`}
>
{/* 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>
</a>
)}
{member.linkedin && (
<a
href={member.linkedin}
target="_blank"
rel="noopener noreferrer"
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>
</a>
)}
</div>
)}
</div>
</div>
)
})}
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,106 @@
import type { Block } from 'payload'
export const FDTeamBlock: Block = {
slug: 'fdTeam',
interfaceName: 'FDTeamBlock',
labels: {
singular: 'FD Team',
plural: 'FD Team',
},
fields: [
{
name: 'heading',
type: 'text',
localized: true,
label: 'Rubrik (valfri)',
admin: {
description: 'T.ex. "Möt vårt team"',
},
},
{
name: 'subheading',
type: 'text',
localized: true,
label: 'Underrubrik (valfri)',
},
{
name: 'members',
type: 'array',
label: 'Teammedlemmar',
minRows: 1,
fields: [
{
name: 'photo',
type: 'upload',
relationTo: 'media',
label: 'Profilbild',
},
{
name: 'name',
type: 'text',
required: true,
label: 'Namn',
},
{
name: 'role',
type: 'text',
required: true,
localized: true,
label: 'Titel / Roll',
},
{
name: 'bio',
type: 'textarea',
localized: true,
label: 'Bio (valfri)',
admin: {
description: 'Kort beskrivning om personen',
},
},
{
name: 'email',
type: 'email',
label: 'E-post (valfri)',
},
{
name: 'linkedin',
type: 'text',
label: 'LinkedIn URL (valfri)',
},
],
},
{
name: 'columns',
type: 'select',
label: 'Antal kolumner',
defaultValue: '3',
options: [
{ label: '2 kolumner', value: '2' },
{ label: '3 kolumner', value: '3' },
{ label: '4 kolumner', value: '4' },
],
},
{
name: 'cardStyle',
type: 'select',
label: 'Kortstil',
defaultValue: 'navy',
options: [
{ label: 'Navy', value: 'navy' },
{ label: 'Vit', value: 'white' },
{ label: 'Grå', value: 'gray' },
],
},
{
name: 'sectionBackground',
type: 'select',
label: 'Sektionsbakgrund',
defaultValue: 'white',
options: [
{ label: 'Vit', value: 'white' },
{ label: 'Grå', value: 'gray' },
{ label: 'Navy', value: 'navy' },
],
},
],
}

View File

@ -0,0 +1,142 @@
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' },
navy: { section: 'bg-fd-navy', card: 'bg-white/10', quote: 'text-white', meta: 'text-white/60', name: 'text-white', company: 'text-white/50' },
}
export const FDTestimonialBlockComponent: React.FC<FDTestimonialBlockProps> = ({
heading,
testimonials,
layout = 'grid',
sectionBackground = 'gray',
}) => {
const theme = bgMap[sectionBackground] || bgMap.gray
const isFeatured = layout === 'featured'
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'}`}>
{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 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`}>
<p className={`font-joey-medium text-xl md:text-2xl lg:text-3xl leading-relaxed ${theme.quote}`}>
&ldquo;{t.quote}&rdquo;
</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>
)}
<div>
<p className={`font-joey-bold text-lg ${theme.name}`}>{t.authorName}</p>
<p className={`font-joey text-sm ${theme.meta}`}>
{t.authorRole}{t.authorRole && t.authorCompany ? ' · ' : ''}{t.authorCompany}
</p>
</div>
</div>
</div>
)
})()}
{/* 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) => {
const avatar = t.avatar as Media | undefined
return (
<div key={i} className={`${theme.card} rounded-[70px] px-8 md:px-12 py-10 md:py-12 flex flex-col gap-6`}>
<p className={`font-joey-medium text-lg md:text-xl leading-relaxed ${theme.quote}`}>
&ldquo;{t.quote}&rdquo;
</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>
)}
<div>
<p className={`font-joey-bold text-base ${theme.name}`}>{t.authorName}</p>
<p className={`font-joey text-xs ${theme.meta}`}>
{t.authorRole}{t.authorRole && t.authorCompany ? ' · ' : ''}{t.authorCompany}
</p>
</div>
</div>
</div>
)
})}
</div>
)}
</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 ${sectionBackground === 'navy' ? 'text-fd-yellow' : 'text-fd-navy'} opacity-30`}>
&ldquo;
</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>
)}
<div>
<p className={`font-joey-bold text-base ${theme.name}`}>{t.authorName}</p>
<p className={`font-joey text-sm ${theme.meta}`}>
{t.authorRole}{t.authorRole && t.authorCompany ? ' · ' : ''}{t.authorCompany}
</p>
</div>
</div>
</div>
)
})}
</div>
)}
</div>
</section>
)
}

View File

@ -0,0 +1,87 @@
import type { Block } from 'payload'
export const FDTestimonialBlock: Block = {
slug: 'fdTestimonial',
interfaceName: 'FDTestimonialBlock',
labels: {
singular: 'FD Omdöme',
plural: 'FD Omdömen',
},
fields: [
{
name: 'heading',
type: 'text',
localized: true,
label: 'Rubrik (valfri)',
admin: {
description: 'T.ex. "Vad våra kunder säger"',
},
},
{
name: 'testimonials',
type: 'array',
label: 'Omdömen',
minRows: 1,
fields: [
{
name: 'quote',
type: 'textarea',
required: true,
localized: true,
label: 'Citat',
admin: {
description: 'Kundens citat utan citattecken',
},
},
{
name: 'authorName',
type: 'text',
required: true,
localized: true,
label: 'Namn',
},
{
name: 'authorRole',
type: 'text',
localized: true,
label: 'Titel / Roll',
admin: {
description: 'T.ex. "IT-chef"',
},
},
{
name: 'authorCompany',
type: 'text',
label: 'Företag',
},
{
name: 'avatar',
type: 'upload',
relationTo: 'media',
label: 'Profilbild (valfri)',
},
],
},
{
name: 'layout',
type: 'select',
label: 'Layout',
defaultValue: 'grid',
options: [
{ label: 'Rutnät', value: 'grid' },
{ label: 'Stor featured', value: 'featured' },
],
},
{
name: 'sectionBackground',
type: 'select',
label: 'Sektionsbakgrund',
defaultValue: 'gray',
options: [
{ label: 'Grå', value: 'gray' },
{ label: 'Vit', value: 'white' },
{ label: 'Navy', value: 'navy' },
],
},
],
}

View File

@ -35,6 +35,9 @@ import { FDDataTableBlockComponent } from '@/blocks/FDDataTableBlock/Component'
import { FDVpsCalculatorBlockComponent } from '@/blocks/FDVpsCalculatorBlock/Component'
import { FDCodeEmbedBlockComponent } from '@/blocks/FDCodeEmbedBlock/Component'
import { FDVideoBlockComponent } from '@/blocks/FDVideoBlock/Component'
import { FDCtaBannerBlockComponent } from './FDCtaBannerBlock/Component'
import { FDTestimonialBlockComponent } from './FDTestimonialBlock/Component'
import { FDTeamBlockComponent } from './FDTeamBlock/Component'
const blockComponents = {
archive: ArchiveBlock,
@ -70,6 +73,9 @@ const blockComponents = {
fdVpsCalculator: FDVpsCalculatorBlockComponent,
fdCodeEmbed: FDCodeEmbedBlockComponent,
fdVideo: FDVideoBlockComponent,
fdCtaBanner: FDCtaBannerBlockComponent,
fdTestimonial: FDTestimonialBlockComponent,
fdTeam: FDTeamBlockComponent,
}
// FD blocks handle their own full-width sections with internal padding
@ -102,6 +108,9 @@ const fullWidthBlocks = new Set([
'fdVpsCalculator',
'fdCodeEmbed',
'fdVideo',
'fdCtaBanner',
'fdTestimonial',
'fdTeam',
])
export const RenderBlocks: React.FC<{

View File

@ -34,6 +34,9 @@ import { FDDataTableBlock } from '../../blocks/FDDataTableBlock/config'
import { FDVpsCalculatorBlock } from '../../blocks/FDVpsCalculatorBlock/config'
import { FDCodeEmbedBlock } from '../../blocks/FDCodeEmbedBlock/config'
import { FDVideoBlock } from '../../blocks/FDVideoBlock/config'
import { FDCtaBannerBlock } from '../../blocks/FDCtaBannerBlock/config'
import { FDTestimonialBlock } from '../../blocks/FDTestimonialBlock/config'
import { FDTeamBlock } from '../../blocks/FDTeamBlock/config'
import {
MetaDescriptionField,
@ -126,6 +129,9 @@ export const Pages: CollectionConfig<'pages'> = {
FDTextBlock,
FDCodeEmbedBlock,
FDVideoBlock,
FDCtaBannerBlock,
FDTestimonialBlock,
FDTeamBlock
],
required: true,
admin: {

View File

@ -182,6 +182,9 @@ export interface Page {
| FDTextBlock
| FDCodeEmbedBlock
| FDVideoBlock
| FDCtaBannerBlock
| FDTestimonialBlock
| FDTeamBlock
)[];
meta?: {
title?: string | null;
@ -1236,6 +1239,89 @@ export interface FDVideoBlock {
blockName?: string | null;
blockType: 'fdVideo';
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "FDCtaBannerBlock".
*/
export interface FDCtaBannerBlock {
heading: string;
/**
* Kort text under rubriken
*/
subheading?: string | null;
ctaText?: string | null;
ctaLink?: string | null;
secondaryCtaText?: string | null;
secondaryCtaLink?: string | null;
sectionBackground?: ('yellow' | 'navy' | 'gray' | 'white') | null;
alignment?: ('center' | 'left') | null;
size?: ('small' | 'medium' | 'large') | null;
id?: string | null;
blockName?: string | null;
blockType: 'fdCtaBanner';
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "FDTestimonialBlock".
*/
export interface FDTestimonialBlock {
/**
* T.ex. "Vad våra kunder säger"
*/
heading?: string | null;
testimonials?:
| {
/**
* Kundens citat utan citattecken
*/
quote: string;
authorName: string;
/**
* T.ex. "IT-chef"
*/
authorRole?: string | null;
authorCompany?: string | null;
avatar?: (number | null) | Media;
id?: string | null;
}[]
| null;
layout?: ('grid' | 'featured') | null;
sectionBackground?: ('gray' | 'white' | 'navy') | null;
id?: string | null;
blockName?: string | null;
blockType: 'fdTestimonial';
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "FDTeamBlock".
*/
export interface FDTeamBlock {
/**
* T.ex. "Möt vårt team"
*/
heading?: string | null;
subheading?: string | null;
members?:
| {
photo?: (number | null) | Media;
name: string;
role: string;
/**
* Kort beskrivning om personen
*/
bio?: string | null;
email?: string | null;
linkedin?: string | null;
id?: string | null;
}[]
| null;
columns?: ('2' | '3' | '4') | null;
cardStyle?: ('navy' | 'white' | 'gray') | null;
sectionBackground?: ('white' | 'gray' | 'navy') | null;
id?: string | null;
blockName?: string | null;
blockType: 'fdTeam';
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts".
@ -1601,6 +1687,9 @@ export interface PagesSelect<T extends boolean = true> {
fdText?: T | FDTextBlockSelect<T>;
fdCodeEmbed?: T | FDCodeEmbedBlockSelect<T>;
fdVideo?: T | FDVideoBlockSelect<T>;
fdCtaBanner?: T | FDCtaBannerBlockSelect<T>;
fdTestimonial?: T | FDTestimonialBlockSelect<T>;
fdTeam?: T | FDTeamBlockSelect<T>;
};
meta?:
| T
@ -2180,6 +2269,68 @@ export interface FDVideoBlockSelect<T extends boolean = true> {
id?: T;
blockName?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "FDCtaBannerBlock_select".
*/
export interface FDCtaBannerBlockSelect<T extends boolean = true> {
heading?: T;
subheading?: T;
ctaText?: T;
ctaLink?: T;
secondaryCtaText?: T;
secondaryCtaLink?: T;
sectionBackground?: T;
alignment?: T;
size?: T;
id?: T;
blockName?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "FDTestimonialBlock_select".
*/
export interface FDTestimonialBlockSelect<T extends boolean = true> {
heading?: T;
testimonials?:
| T
| {
quote?: T;
authorName?: T;
authorRole?: T;
authorCompany?: T;
avatar?: T;
id?: T;
};
layout?: T;
sectionBackground?: T;
id?: T;
blockName?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "FDTeamBlock_select".
*/
export interface FDTeamBlockSelect<T extends boolean = true> {
heading?: T;
subheading?: T;
members?:
| T
| {
photo?: T;
name?: T;
role?: T;
bio?: T;
email?: T;
linkedin?: T;
id?: T;
};
columns?: T;
cardStyle?: T;
sectionBackground?: T;
id?: T;
blockName?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts_select".