feat: add imageOverlay field to AlternateHero, WideCard, UspChecklist blocks
This commit is contained in:
parent
fb8b75ecaa
commit
e7df2e3cba
@ -3,6 +3,17 @@ import type { FDAlternateHeroBlock as Props, Media } from '@/payload-types'
|
|||||||
import { FDImage } from '@/components/FDImage'
|
import { FDImage } from '@/components/FDImage'
|
||||||
import { FDButton } from '@/components/FDButton'
|
import { FDButton } from '@/components/FDButton'
|
||||||
|
|
||||||
|
const overlayMap: Record<string, string> = {
|
||||||
|
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',
|
||||||
|
blackMedium: 'bg-black/40',
|
||||||
|
}
|
||||||
|
|
||||||
export const FDAlternateHeroBlockComponent: React.FC<Props> = ({
|
export const FDAlternateHeroBlockComponent: React.FC<Props> = ({
|
||||||
heading,
|
heading,
|
||||||
description,
|
description,
|
||||||
@ -12,9 +23,11 @@ export const FDAlternateHeroBlockComponent: React.FC<Props> = ({
|
|||||||
secondaryCtaLink = '#',
|
secondaryCtaLink = '#',
|
||||||
image,
|
image,
|
||||||
imageCaption,
|
imageCaption,
|
||||||
|
imageOverlay = 'none',
|
||||||
sectionBackground = 'white',
|
sectionBackground = 'white',
|
||||||
anchorId,
|
anchorId,
|
||||||
}) => {
|
}) => {
|
||||||
|
const overlay = overlayMap[imageOverlay || 'none']
|
||||||
const media = image as Media | undefined
|
const media = image as Media | undefined
|
||||||
const hasImage = media && typeof media === 'object' && media.url
|
const hasImage = media && typeof media === 'object' && media.url
|
||||||
const isDark = sectionBackground === 'navy'
|
const isDark = sectionBackground === 'navy'
|
||||||
@ -65,7 +78,7 @@ export const FDAlternateHeroBlockComponent: React.FC<Props> = ({
|
|||||||
{/* Full-width image — no border radius, bleeds edge to edge */}
|
{/* Full-width image — no border radius, bleeds edge to edge */}
|
||||||
{hasImage && (
|
{hasImage && (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="relative w-full" style={{ maxHeight: '620px', height: '45vw', minHeight: '220px' }}>
|
<div className="relative w-full overflow-hidden" style={{ maxHeight: '620px', height: '45vw', minHeight: '220px' }}>
|
||||||
<FDImage
|
<FDImage
|
||||||
media={media}
|
media={media}
|
||||||
size="hero"
|
size="hero"
|
||||||
@ -75,6 +88,7 @@ export const FDAlternateHeroBlockComponent: React.FC<Props> = ({
|
|||||||
sizes="100vw"
|
sizes="100vw"
|
||||||
fallbackAlt={heading || ''}
|
fallbackAlt={heading || ''}
|
||||||
/>
|
/>
|
||||||
|
{overlay && <div className={`absolute inset-0 ${overlay}`} />}
|
||||||
</div>
|
</div>
|
||||||
{imageCaption && (
|
{imageCaption && (
|
||||||
<div className={`text-center py-3 font-joey text-fd-small opacity-60 ${bodyClass} ${bgClass}`}>
|
<div className={`text-center py-3 font-joey text-fd-small opacity-60 ${bodyClass} ${bgClass}`}>
|
||||||
|
|||||||
@ -68,6 +68,25 @@ export const FDAlternateHeroBlock: Block = {
|
|||||||
condition: (_, siblingData) => Boolean(siblingData?.image),
|
condition: (_, siblingData) => Boolean(siblingData?.image),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'imageOverlay',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Bildöverlagring',
|
||||||
|
defaultValue: 'none',
|
||||||
|
options: [
|
||||||
|
{ label: 'Ingen', value: 'none' },
|
||||||
|
{ label: 'Navy (lätt)', value: 'navyLight' },
|
||||||
|
{ label: 'Navy (medium)', value: 'navyMedium' },
|
||||||
|
{ label: 'Gul (lätt)', value: 'yellowLight' },
|
||||||
|
{ label: 'Gul (medium)', value: 'yellowMedium' },
|
||||||
|
{ label: 'Sepia', value: 'sepia' },
|
||||||
|
{ label: 'Svart (lätt)', value: 'blackLight' },
|
||||||
|
{ label: 'Svart (medium)', value: 'blackMedium' },
|
||||||
|
],
|
||||||
|
admin: {
|
||||||
|
condition: (_, siblingData) => Boolean(siblingData?.image),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'sectionBackground',
|
name: 'sectionBackground',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
|
|||||||
@ -18,6 +18,17 @@ const bodyMap: Record<string, string> = {
|
|||||||
white: 'text-white',
|
white: 'text-white',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const overlayMap: Record<string, string> = {
|
||||||
|
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',
|
||||||
|
blackMedium: 'bg-black/40',
|
||||||
|
}
|
||||||
|
|
||||||
const checkColors: Record<string, { circle: string; check: string }> = {
|
const checkColors: Record<string, { circle: string; check: string }> = {
|
||||||
navy: { circle: 'fill-fd-navy dark:fill-white/20', check: 'fill-white dark:fill-fd-yellow' },
|
navy: { circle: 'fill-fd-navy dark:fill-white/20', check: 'fill-white dark:fill-fd-yellow' },
|
||||||
yellow: { circle: 'fill-fd-yellow', check: 'fill-fd-navy' },
|
yellow: { circle: 'fill-fd-yellow', check: 'fill-fd-navy' },
|
||||||
@ -38,6 +49,7 @@ export const FDUspChecklistBlockComponent: React.FC<FDUspChecklistBlockProps> =
|
|||||||
heading,
|
heading,
|
||||||
items,
|
items,
|
||||||
image,
|
image,
|
||||||
|
imageOverlay = 'none',
|
||||||
imagePosition = 'right',
|
imagePosition = 'right',
|
||||||
checkColor = 'navy',
|
checkColor = 'navy',
|
||||||
sectionBackground = 'white',
|
sectionBackground = 'white',
|
||||||
@ -49,6 +61,7 @@ export const FDUspChecklistBlockComponent: React.FC<FDUspChecklistBlockProps> =
|
|||||||
const bodyClr = bodyMap[textColor || 'navy']
|
const bodyClr = bodyMap[textColor || 'navy']
|
||||||
const media = image as Media | undefined
|
const media = image as Media | undefined
|
||||||
const hasImage = Boolean(media?.url)
|
const hasImage = Boolean(media?.url)
|
||||||
|
const overlay = overlayMap[imageOverlay || 'none']
|
||||||
|
|
||||||
const textContent = (
|
const textContent = (
|
||||||
<div className="flex-1 flex flex-col gap-6 md:gap-8">
|
<div className="flex-1 flex flex-col gap-6 md:gap-8">
|
||||||
@ -65,14 +78,15 @@ export const FDUspChecklistBlockComponent: React.FC<FDUspChecklistBlockProps> =
|
|||||||
)
|
)
|
||||||
|
|
||||||
const imageContent = hasImage ? (
|
const imageContent = hasImage ? (
|
||||||
<div className="flex-1">
|
<div className="flex-1 relative overflow-hidden rounded-[40px]">
|
||||||
<FDImage
|
<FDImage
|
||||||
media={media!}
|
media={media!}
|
||||||
size="large"
|
size="large"
|
||||||
className="w-full h-auto rounded-[40px] object-cover"
|
className="w-full h-auto object-cover"
|
||||||
sizes="(max-width: 1024px) 100vw, 550px"
|
sizes="(max-width: 1024px) 100vw, 550px"
|
||||||
fallbackAlt={heading || ''}
|
fallbackAlt={heading || ''}
|
||||||
/>
|
/>
|
||||||
|
{overlay && <div className={`absolute inset-0 ${overlay}`} />}
|
||||||
</div>
|
</div>
|
||||||
) : null
|
) : null
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,25 @@ export const FDUspChecklistBlock: Block = {
|
|||||||
relationTo: 'media',
|
relationTo: 'media',
|
||||||
label: 'Bild (valfri)',
|
label: 'Bild (valfri)',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'imageOverlay',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Bildöverlagring',
|
||||||
|
defaultValue: 'none',
|
||||||
|
options: [
|
||||||
|
{ label: 'Ingen', value: 'none' },
|
||||||
|
{ label: 'Navy (lätt)', value: 'navyLight' },
|
||||||
|
{ label: 'Navy (medium)', value: 'navyMedium' },
|
||||||
|
{ label: 'Gul (lätt)', value: 'yellowLight' },
|
||||||
|
{ label: 'Gul (medium)', value: 'yellowMedium' },
|
||||||
|
{ label: 'Sepia', value: 'sepia' },
|
||||||
|
{ label: 'Svart (lätt)', value: 'blackLight' },
|
||||||
|
{ label: 'Svart (medium)', value: 'blackMedium' },
|
||||||
|
],
|
||||||
|
admin: {
|
||||||
|
condition: (_, siblingData) => Boolean(siblingData?.image),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'imagePosition',
|
name: 'imagePosition',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
|
|||||||
@ -24,12 +24,24 @@ const btnVariantMap: Record<string, { variant: 'primary' | 'outline' }> = {
|
|||||||
|
|
||||||
const cardRadius = 'rounded-[32px] md:rounded-[50px] lg:rounded-[70px]'
|
const cardRadius = 'rounded-[32px] md:rounded-[50px] lg:rounded-[70px]'
|
||||||
|
|
||||||
|
const overlayMap: Record<string, string> = {
|
||||||
|
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',
|
||||||
|
blackMedium: 'bg-black/40',
|
||||||
|
}
|
||||||
|
|
||||||
export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
|
export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
|
||||||
heading,
|
heading,
|
||||||
body,
|
body,
|
||||||
ctaText,
|
ctaText,
|
||||||
ctaLink,
|
ctaLink,
|
||||||
image,
|
image,
|
||||||
|
imageOverlay = 'none',
|
||||||
cardBackground = 'navy',
|
cardBackground = 'navy',
|
||||||
buttonColor = 'yellow',
|
buttonColor = 'yellow',
|
||||||
sectionBackground = 'white',
|
sectionBackground = 'white',
|
||||||
@ -40,6 +52,7 @@ export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
|
|||||||
const { variant } = btnVariantMap[buttonColor || 'yellow']
|
const { variant } = btnVariantMap[buttonColor || 'yellow']
|
||||||
const media = image as Media | undefined
|
const media = image as Media | undefined
|
||||||
const hasImage = media && typeof media === 'object' && media.url
|
const hasImage = media && typeof media === 'object' && media.url
|
||||||
|
const overlay = overlayMap[imageOverlay || 'none']
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section id={anchorId || undefined} className={`w-full py-16 md:py-20 lg:py-[99px] ${sectionBg}`}>
|
<section id={anchorId || undefined} className={`w-full py-16 md:py-20 lg:py-[99px] ${sectionBg}`}>
|
||||||
@ -65,13 +78,16 @@ export const FDWideCardBlockComponent: React.FC<FDWideCardBlockProps> = ({
|
|||||||
|
|
||||||
{hasImage && (
|
{hasImage && (
|
||||||
<div className="flex items-center justify-center w-full min-[820px]:w-[45%] lg:w-[480px] flex-shrink-0 p-6 md:p-10 lg:p-12">
|
<div className="flex items-center justify-center w-full min-[820px]:w-[45%] lg:w-[480px] flex-shrink-0 p-6 md:p-10 lg:p-12">
|
||||||
<FDImage
|
<div className="relative w-full">
|
||||||
media={media}
|
<FDImage
|
||||||
size="large"
|
media={media}
|
||||||
className="w-full h-auto max-h-[320px] object-contain drop-shadow-xl"
|
size="large"
|
||||||
sizes="(max-width: 820px) 80vw, 400px"
|
className="w-full h-auto max-h-[320px] object-contain drop-shadow-xl"
|
||||||
fallbackAlt={heading || ''}
|
sizes="(max-width: 820px) 80vw, 400px"
|
||||||
/>
|
fallbackAlt={heading || ''}
|
||||||
|
/>
|
||||||
|
{overlay && <div className={`absolute inset-0 ${overlay}`} />}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -42,6 +42,25 @@ export const FDWideCardBlock: Block = {
|
|||||||
relationTo: 'media',
|
relationTo: 'media',
|
||||||
label: 'Bild (valfri)',
|
label: 'Bild (valfri)',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'imageOverlay',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Bildöverlagring',
|
||||||
|
defaultValue: 'none',
|
||||||
|
options: [
|
||||||
|
{ label: 'Ingen', value: 'none' },
|
||||||
|
{ label: 'Navy (lätt)', value: 'navyLight' },
|
||||||
|
{ label: 'Navy (medium)', value: 'navyMedium' },
|
||||||
|
{ label: 'Gul (lätt)', value: 'yellowLight' },
|
||||||
|
{ label: 'Gul (medium)', value: 'yellowMedium' },
|
||||||
|
{ label: 'Sepia', value: 'sepia' },
|
||||||
|
{ label: 'Svart (lätt)', value: 'blackLight' },
|
||||||
|
{ label: 'Svart (medium)', value: 'blackMedium' },
|
||||||
|
],
|
||||||
|
admin: {
|
||||||
|
condition: (_, siblingData) => Boolean(siblingData?.image),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'cardBackground',
|
name: 'cardBackground',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
|
|||||||
38641
src/migrations/20260313_081702.json
Normal file
38641
src/migrations/20260313_081702.json
Normal file
File diff suppressed because it is too large
Load Diff
33
src/migrations/20260313_081702.ts
Normal file
33
src/migrations/20260313_081702.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
|
||||||
|
|
||||||
|
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TYPE "public"."enum_pages_blocks_fd_usp_checklist_image_overlay" AS ENUM('none', 'navyLight', 'navyMedium', 'yellowLight', 'yellowMedium', 'sepia', 'blackLight', 'blackMedium');
|
||||||
|
CREATE TYPE "public"."enum_pages_blocks_fd_wide_card_image_overlay" AS ENUM('none', 'navyLight', 'navyMedium', 'yellowLight', 'yellowMedium', 'sepia', 'blackLight', 'blackMedium');
|
||||||
|
CREATE TYPE "public"."enum_pages_blocks_fd_alternate_hero_image_overlay" AS ENUM('none', 'navyLight', 'navyMedium', 'yellowLight', 'yellowMedium', 'sepia', 'blackLight', 'blackMedium');
|
||||||
|
CREATE TYPE "public"."enum__pages_v_blocks_fd_usp_checklist_image_overlay" AS ENUM('none', 'navyLight', 'navyMedium', 'yellowLight', 'yellowMedium', 'sepia', 'blackLight', 'blackMedium');
|
||||||
|
CREATE TYPE "public"."enum__pages_v_blocks_fd_wide_card_image_overlay" AS ENUM('none', 'navyLight', 'navyMedium', 'yellowLight', 'yellowMedium', 'sepia', 'blackLight', 'blackMedium');
|
||||||
|
CREATE TYPE "public"."enum__pages_v_blocks_fd_alternate_hero_image_overlay" AS ENUM('none', 'navyLight', 'navyMedium', 'yellowLight', 'yellowMedium', 'sepia', 'blackLight', 'blackMedium');
|
||||||
|
ALTER TABLE "pages_blocks_fd_usp_checklist" ADD COLUMN "image_overlay" "enum_pages_blocks_fd_usp_checklist_image_overlay" DEFAULT 'none';
|
||||||
|
ALTER TABLE "pages_blocks_fd_wide_card" ADD COLUMN "image_overlay" "enum_pages_blocks_fd_wide_card_image_overlay" DEFAULT 'none';
|
||||||
|
ALTER TABLE "pages_blocks_fd_alternate_hero" ADD COLUMN "image_overlay" "enum_pages_blocks_fd_alternate_hero_image_overlay" DEFAULT 'none';
|
||||||
|
ALTER TABLE "_pages_v_blocks_fd_usp_checklist" ADD COLUMN "image_overlay" "enum__pages_v_blocks_fd_usp_checklist_image_overlay" DEFAULT 'none';
|
||||||
|
ALTER TABLE "_pages_v_blocks_fd_wide_card" ADD COLUMN "image_overlay" "enum__pages_v_blocks_fd_wide_card_image_overlay" DEFAULT 'none';
|
||||||
|
ALTER TABLE "_pages_v_blocks_fd_alternate_hero" ADD COLUMN "image_overlay" "enum__pages_v_blocks_fd_alternate_hero_image_overlay" DEFAULT 'none';`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "pages_blocks_fd_usp_checklist" DROP COLUMN "image_overlay";
|
||||||
|
ALTER TABLE "pages_blocks_fd_wide_card" DROP COLUMN "image_overlay";
|
||||||
|
ALTER TABLE "pages_blocks_fd_alternate_hero" DROP COLUMN "image_overlay";
|
||||||
|
ALTER TABLE "_pages_v_blocks_fd_usp_checklist" DROP COLUMN "image_overlay";
|
||||||
|
ALTER TABLE "_pages_v_blocks_fd_wide_card" DROP COLUMN "image_overlay";
|
||||||
|
ALTER TABLE "_pages_v_blocks_fd_alternate_hero" DROP COLUMN "image_overlay";
|
||||||
|
DROP TYPE "public"."enum_pages_blocks_fd_usp_checklist_image_overlay";
|
||||||
|
DROP TYPE "public"."enum_pages_blocks_fd_wide_card_image_overlay";
|
||||||
|
DROP TYPE "public"."enum_pages_blocks_fd_alternate_hero_image_overlay";
|
||||||
|
DROP TYPE "public"."enum__pages_v_blocks_fd_usp_checklist_image_overlay";
|
||||||
|
DROP TYPE "public"."enum__pages_v_blocks_fd_wide_card_image_overlay";
|
||||||
|
DROP TYPE "public"."enum__pages_v_blocks_fd_alternate_hero_image_overlay";`)
|
||||||
|
}
|
||||||
@ -27,8 +27,8 @@ export const generateMeta = async (args: {
|
|||||||
const ogImage = getImageURL(doc?.meta?.image)
|
const ogImage = getImageURL(doc?.meta?.image)
|
||||||
|
|
||||||
const title = doc?.meta?.title
|
const title = doc?.meta?.title
|
||||||
? doc?.meta?.title + ' | Payload Website Template'
|
? doc?.meta?.title + ' | Fiber Direkt'
|
||||||
: 'Payload Website Template'
|
: 'Fiber Direkt'
|
||||||
|
|
||||||
return {
|
return {
|
||||||
description: doc?.meta?.description,
|
description: doc?.meta?.description,
|
||||||
|
|||||||
@ -3,14 +3,14 @@ import { getServerSideURL } from './getURL'
|
|||||||
|
|
||||||
const defaultOpenGraph: Metadata['openGraph'] = {
|
const defaultOpenGraph: Metadata['openGraph'] = {
|
||||||
type: 'website',
|
type: 'website',
|
||||||
description: 'An open-source website built with Payload and Next.js.',
|
description: 'Fiber Direkt – snabb och pålitlig fiber till ditt företag.',
|
||||||
images: [
|
images: [
|
||||||
{
|
{
|
||||||
url: `${getServerSideURL()}/website-template-OG.webp`,
|
url: `${getServerSideURL()}/website-template-OG.webp`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
siteName: 'Payload Website Template',
|
siteName: 'Fiber Direkt',
|
||||||
title: 'Payload Website Template',
|
title: 'Fiber Direkt',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mergeOpenGraph = (og?: Metadata['openGraph']): Metadata['openGraph'] => {
|
export const mergeOpenGraph = (og?: Metadata['openGraph']): Metadata['openGraph'] => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user