feat: FDVideoHeroBlock
This commit is contained in:
parent
f9327f8d98
commit
d7f3a52838
158
src/blocks/FDVideoHeroBlock/Component.tsx
Normal file
158
src/blocks/FDVideoHeroBlock/Component.tsx
Normal file
@ -0,0 +1,158 @@
|
||||
'use client'
|
||||
|
||||
import React, { useRef, useEffect, useState } from 'react'
|
||||
import type { FDVideoHeroBlock as FDVideoHeroBlockProps, Media } from '@/payload-types'
|
||||
import { FDButton } from '@/components/FDButton'
|
||||
|
||||
export const FDVideoHeroBlockComponent: React.FC<FDVideoHeroBlockProps> = (props) => {
|
||||
const {
|
||||
videoMp4,
|
||||
videoWebm,
|
||||
posterImage,
|
||||
heading,
|
||||
body,
|
||||
ctaText,
|
||||
ctaLink,
|
||||
secondaryCtaText,
|
||||
secondaryCtaLink,
|
||||
overlayColor = 'none',
|
||||
overlayStrength = 'medium',
|
||||
textAlign = 'left',
|
||||
minHeight = 'screen',
|
||||
disableVideoOnMobile = false,
|
||||
anchorId,
|
||||
} = props
|
||||
|
||||
const videoRef = useRef<HTMLVideoElement>(null)
|
||||
const [isMobile, setIsMobile] = useState(false)
|
||||
|
||||
// Detect mobile for conditional video loading
|
||||
useEffect(() => {
|
||||
const checkMobile = () => setIsMobile(window.innerWidth < 768)
|
||||
checkMobile()
|
||||
window.addEventListener('resize', checkMobile)
|
||||
return () => window.removeEventListener('resize', checkMobile)
|
||||
}, [])
|
||||
|
||||
// Resolve media objects
|
||||
const mp4Media = videoMp4 as Media | undefined
|
||||
const webmMedia = videoWebm as Media | undefined
|
||||
const poster = posterImage as Media | undefined
|
||||
|
||||
const mp4Url = mp4Media?.url || ''
|
||||
const webmUrl = webmMedia?.url || ''
|
||||
const posterUrl = poster?.url || ''
|
||||
|
||||
const showVideo = mp4Url && !(disableVideoOnMobile && isMobile)
|
||||
|
||||
// Overlay classes
|
||||
const hasOverlay = overlayColor !== 'none'
|
||||
const overlayOpacityMap: Record<string, string> = {
|
||||
light: 'opacity-30',
|
||||
medium: 'opacity-50',
|
||||
heavy: 'opacity-70',
|
||||
}
|
||||
const overlayBgMap: Record<string, string> = {
|
||||
black: 'bg-black',
|
||||
navy: 'bg-fd-navy',
|
||||
}
|
||||
const overlayClass = hasOverlay
|
||||
? `${overlayBgMap[overlayColor] || ''} ${overlayOpacityMap[overlayStrength] || 'opacity-50'}`
|
||||
: ''
|
||||
|
||||
// Text colors — white when overlay is present, navy otherwise
|
||||
const hasText = heading || body
|
||||
const textColorHeading = hasOverlay ? 'text-white' : 'text-fd-navy'
|
||||
const textColorBody = hasOverlay ? 'text-white/90' : 'text-fd-navy/80'
|
||||
|
||||
// Min height
|
||||
const heightMap: Record<string, string> = {
|
||||
screen: 'min-h-screen',
|
||||
large: 'min-h-[80vh]',
|
||||
medium: 'min-h-[60vh]',
|
||||
}
|
||||
const heightClass = heightMap[minHeight] || 'min-h-screen'
|
||||
|
||||
// Text alignment
|
||||
const alignClass = textAlign === 'center' ? 'text-center items-center' : 'text-left items-start'
|
||||
|
||||
return (
|
||||
<section
|
||||
id={anchorId || undefined}
|
||||
className={`relative w-full ${heightClass} flex items-end overflow-hidden`}
|
||||
>
|
||||
{/* Video / Poster background */}
|
||||
{showVideo ? (
|
||||
<video
|
||||
ref={videoRef}
|
||||
autoPlay
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
poster={posterUrl || undefined}
|
||||
className="absolute inset-0 w-full h-full object-cover"
|
||||
aria-hidden="true"
|
||||
>
|
||||
{webmUrl && <source src={webmUrl} type="video/webm" />}
|
||||
<source src={mp4Url} type="video/mp4" />
|
||||
</video>
|
||||
) : posterUrl ? (
|
||||
<img
|
||||
src={posterUrl}
|
||||
alt=""
|
||||
className="absolute inset-0 w-full h-full object-cover"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{/* Overlay */}
|
||||
{hasOverlay && (
|
||||
<div
|
||||
className={`absolute inset-0 ${overlayClass}`}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Content */}
|
||||
{(hasText || ctaText || secondaryCtaText) && (
|
||||
<div className="relative z-10 w-full pb-16 md:pb-20 lg:pb-[99px] pt-32 md:pt-40">
|
||||
<div className={`max-w-[1200px] mx-auto px-6 md:px-8 flex flex-col ${alignClass}`}>
|
||||
{/* Text container — constrain width */}
|
||||
<div className={`max-w-[640px] ${textAlign === 'center' ? 'mx-auto' : ''}`}>
|
||||
{heading && (
|
||||
<h1
|
||||
className={`fd-h1 font-joey-heavy ${textColorHeading} mb-4 md:mb-6`}
|
||||
>
|
||||
{heading}
|
||||
</h1>
|
||||
)}
|
||||
{body && (
|
||||
<p
|
||||
className={`fd-body-lg font-joey ${textColorBody} mb-8 md:mb-10 whitespace-pre-line`}
|
||||
>
|
||||
{body}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* CTAs */}
|
||||
{(ctaText || secondaryCtaText) && (
|
||||
<div className={`flex flex-wrap gap-4 ${textAlign === 'center' ? 'justify-center' : ''}`}>
|
||||
{ctaText && ctaLink && (
|
||||
<FDButton href={ctaLink} onDark={hasOverlay}>
|
||||
{ctaText}
|
||||
</FDButton>
|
||||
)}
|
||||
{secondaryCtaText && secondaryCtaLink && (
|
||||
<FDButton href={secondaryCtaLink} variant="outline" onDark={hasOverlay}>
|
||||
{secondaryCtaText}
|
||||
</FDButton>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
157
src/blocks/FDVideoHeroBlock/config.ts
Normal file
157
src/blocks/FDVideoHeroBlock/config.ts
Normal file
@ -0,0 +1,157 @@
|
||||
import type { Block } from 'payload'
|
||||
import { anchorField } from '@/fields/anchorField'
|
||||
|
||||
export const FDVideoHeroBlock: Block = {
|
||||
slug: 'fdVideoHero',
|
||||
interfaceName: 'FDVideoHeroBlock',
|
||||
imageURL: '/block-thumbnails/fd-video-hero.svg',
|
||||
imageAltText: 'FD Video Hero',
|
||||
labels: {
|
||||
singular: 'FD Video Hero',
|
||||
plural: 'FD Video Heroes',
|
||||
},
|
||||
fields: [
|
||||
// --- Video sources ---
|
||||
{
|
||||
name: 'videoMp4',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
required: true,
|
||||
label: 'Video (MP4)',
|
||||
admin: {
|
||||
description: 'Huvudvideo — MP4 (H.264). Fungerar i alla webbläsare. Håll filstorleken under 5 MB för bästa prestanda.',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'videoWebm',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
label: 'Video (WebM) — valfri',
|
||||
admin: {
|
||||
description: 'Progressiv förbättring — WebM är mindre och bättre kvalitet. Webbläsare som stödjer WebM väljer denna automatiskt.',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'posterImage',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
label: 'Poster / fallback-bild',
|
||||
admin: {
|
||||
description: 'Visas medan videon laddas och som fallback på mobil om video hoppas över.',
|
||||
},
|
||||
},
|
||||
|
||||
// --- Text content (all optional) ---
|
||||
{
|
||||
name: 'heading',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
label: 'Rubrik (valfri)',
|
||||
admin: {
|
||||
description: 'H1-rubrik som visas ovanpå videon.',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'body',
|
||||
type: 'textarea',
|
||||
localized: true,
|
||||
label: 'Brödtext (valfri)',
|
||||
admin: {
|
||||
description: 'Kort text under rubriken.',
|
||||
},
|
||||
},
|
||||
|
||||
// --- CTA buttons (optional) ---
|
||||
{
|
||||
name: 'ctaText',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
label: 'Primär CTA-text',
|
||||
admin: {
|
||||
description: 'T.ex. "Kom igång"',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ctaLink',
|
||||
type: 'text',
|
||||
label: 'Primär CTA-länk',
|
||||
},
|
||||
{
|
||||
name: 'secondaryCtaText',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
label: 'Sekundär CTA-text',
|
||||
},
|
||||
{
|
||||
name: 'secondaryCtaLink',
|
||||
type: 'text',
|
||||
label: 'Sekundär CTA-länk',
|
||||
},
|
||||
|
||||
// --- Overlay ---
|
||||
{
|
||||
name: 'overlayColor',
|
||||
type: 'select',
|
||||
label: 'Overlay-färg',
|
||||
defaultValue: 'none',
|
||||
options: [
|
||||
{ label: 'Ingen', value: 'none' },
|
||||
{ label: 'Svart', value: 'black' },
|
||||
{ label: 'Navy', value: 'navy' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'overlayStrength',
|
||||
type: 'select',
|
||||
label: 'Overlay-styrka',
|
||||
defaultValue: 'medium',
|
||||
admin: {
|
||||
condition: (_, siblingData) => siblingData?.overlayColor !== 'none',
|
||||
description: 'Hur stark overlay ovanpå videon (för läsbarhet).',
|
||||
},
|
||||
options: [
|
||||
{ label: 'Lätt (30%)', value: 'light' },
|
||||
{ label: 'Medium (50%)', value: 'medium' },
|
||||
{ label: 'Stark (70%)', value: 'heavy' },
|
||||
],
|
||||
},
|
||||
|
||||
// --- Layout options ---
|
||||
{
|
||||
name: 'textAlign',
|
||||
type: 'select',
|
||||
label: 'Textposition',
|
||||
defaultValue: 'left',
|
||||
options: [
|
||||
{ label: 'Vänster', value: 'left' },
|
||||
{ label: 'Center', value: 'center' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'minHeight',
|
||||
type: 'select',
|
||||
label: 'Minimihöjd',
|
||||
defaultValue: 'screen',
|
||||
admin: {
|
||||
description: 'Hur hög video-sektionen ska vara.',
|
||||
},
|
||||
options: [
|
||||
{ label: 'Helskärm (100vh)', value: 'screen' },
|
||||
{ label: 'Stor (80vh)', value: 'large' },
|
||||
{ label: 'Medium (60vh)', value: 'medium' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'disableVideoOnMobile',
|
||||
type: 'checkbox',
|
||||
label: 'Visa bara poster-bild på mobil',
|
||||
defaultValue: false,
|
||||
admin: {
|
||||
description: 'Hoppa över video på små skärmar för att spara bandbredd. Poster-bilden visas istället.',
|
||||
},
|
||||
},
|
||||
|
||||
// --- Always last ---
|
||||
anchorField,
|
||||
],
|
||||
}
|
||||
@ -38,6 +38,8 @@ import { FDServiceCalculatorBlockComponent } from '@/blocks/FDServiceCalculatorB
|
||||
import { FDLinkCardsBlockComponent } from '@/blocks/FDLinkCardsBlock/Component'
|
||||
import { FDSpecCardsBlockComponent } from '@/blocks/FDSpecCardsBlock/Component'
|
||||
import { FDQuizBlockComponent } from '@/blocks/FDQuizBlock/Component'
|
||||
import { FDVideoHeroBlockComponent } from '@/blocks/FDVideoHeroBlock/Component'
|
||||
|
||||
|
||||
const blockComponents: Record<string, React.FC<any>> = {
|
||||
formBlock: FormBlock,
|
||||
@ -76,6 +78,7 @@ const blockComponents: Record<string, React.FC<any>> = {
|
||||
fdLinkCards: FDLinkCardsBlockComponent,
|
||||
fdSpecCards: FDSpecCardsBlockComponent,
|
||||
fdQuiz: FDQuizBlockComponent,
|
||||
fdVideoHero: FDVideoHeroBlockComponent,
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -41,6 +41,8 @@ import { FDServiceCalculatorBlock } from '../../blocks/FDServiceCalculatorBlock/
|
||||
import { FDLinkCardsBlock } from '../../blocks/FDLinkCardsBlock/config'
|
||||
import { FDSpecCardsBlock } from '../../blocks/FDSpecCardsBlock/config'
|
||||
import { FDQuizBlock } from '../../blocks/FDQuizBlock/config'
|
||||
import { FDVideoHeroBlock } from '../../blocks/FDVideoHeroBlock/config'
|
||||
|
||||
|
||||
import {
|
||||
MetaDescriptionField,
|
||||
@ -140,6 +142,7 @@ export const Pages: CollectionConfig<'pages'> = {
|
||||
FDLinkCardsBlock,
|
||||
FDSpecCardsBlock,
|
||||
FDQuizBlock,
|
||||
FDVideoHeroBlock,
|
||||
],
|
||||
required: true,
|
||||
admin: {
|
||||
|
||||
38509
src/migrations/20260304_203759.json
Normal file
38509
src/migrations/20260304_203759.json
Normal file
File diff suppressed because it is too large
Load Diff
112
src/migrations/20260304_203759.ts
Normal file
112
src/migrations/20260304_203759.ts
Normal file
@ -0,0 +1,112 @@
|
||||
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_video_hero_overlay_color" AS ENUM('none', 'black', 'navy');
|
||||
CREATE TYPE "public"."enum_pages_blocks_fd_video_hero_overlay_strength" AS ENUM('light', 'medium', 'heavy');
|
||||
CREATE TYPE "public"."enum_pages_blocks_fd_video_hero_text_align" AS ENUM('left', 'center');
|
||||
CREATE TYPE "public"."enum_pages_blocks_fd_video_hero_min_height" AS ENUM('screen', 'large', 'medium');
|
||||
CREATE TYPE "public"."enum__pages_v_blocks_fd_video_hero_overlay_color" AS ENUM('none', 'black', 'navy');
|
||||
CREATE TYPE "public"."enum__pages_v_blocks_fd_video_hero_overlay_strength" AS ENUM('light', 'medium', 'heavy');
|
||||
CREATE TYPE "public"."enum__pages_v_blocks_fd_video_hero_text_align" AS ENUM('left', 'center');
|
||||
CREATE TYPE "public"."enum__pages_v_blocks_fd_video_hero_min_height" AS ENUM('screen', 'large', 'medium');
|
||||
CREATE TABLE "pages_blocks_fd_video_hero" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"_path" text NOT NULL,
|
||||
"id" varchar PRIMARY KEY NOT NULL,
|
||||
"video_mp4_id" integer,
|
||||
"video_webm_id" integer,
|
||||
"poster_image_id" integer,
|
||||
"cta_link" varchar,
|
||||
"secondary_cta_link" varchar,
|
||||
"overlay_color" "enum_pages_blocks_fd_video_hero_overlay_color" DEFAULT 'none',
|
||||
"overlay_strength" "enum_pages_blocks_fd_video_hero_overlay_strength" DEFAULT 'medium',
|
||||
"text_align" "enum_pages_blocks_fd_video_hero_text_align" DEFAULT 'left',
|
||||
"min_height" "enum_pages_blocks_fd_video_hero_min_height" DEFAULT 'screen',
|
||||
"disable_video_on_mobile" boolean DEFAULT false,
|
||||
"anchor_id" varchar,
|
||||
"block_name" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE "pages_blocks_fd_video_hero_locales" (
|
||||
"heading" varchar,
|
||||
"body" varchar,
|
||||
"cta_text" varchar,
|
||||
"secondary_cta_text" varchar,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "_locales" NOT NULL,
|
||||
"_parent_id" varchar NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "_pages_v_blocks_fd_video_hero" (
|
||||
"_order" integer NOT NULL,
|
||||
"_parent_id" integer NOT NULL,
|
||||
"_path" text NOT NULL,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"video_mp4_id" integer,
|
||||
"video_webm_id" integer,
|
||||
"poster_image_id" integer,
|
||||
"cta_link" varchar,
|
||||
"secondary_cta_link" varchar,
|
||||
"overlay_color" "enum__pages_v_blocks_fd_video_hero_overlay_color" DEFAULT 'none',
|
||||
"overlay_strength" "enum__pages_v_blocks_fd_video_hero_overlay_strength" DEFAULT 'medium',
|
||||
"text_align" "enum__pages_v_blocks_fd_video_hero_text_align" DEFAULT 'left',
|
||||
"min_height" "enum__pages_v_blocks_fd_video_hero_min_height" DEFAULT 'screen',
|
||||
"disable_video_on_mobile" boolean DEFAULT false,
|
||||
"anchor_id" varchar,
|
||||
"_uuid" varchar,
|
||||
"block_name" varchar
|
||||
);
|
||||
|
||||
CREATE TABLE "_pages_v_blocks_fd_video_hero_locales" (
|
||||
"heading" varchar,
|
||||
"body" varchar,
|
||||
"cta_text" varchar,
|
||||
"secondary_cta_text" varchar,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "_locales" NOT NULL,
|
||||
"_parent_id" integer NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "pages_blocks_fd_video_hero" ADD CONSTRAINT "pages_blocks_fd_video_hero_video_mp4_id_media_id_fk" FOREIGN KEY ("video_mp4_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "pages_blocks_fd_video_hero" ADD CONSTRAINT "pages_blocks_fd_video_hero_video_webm_id_media_id_fk" FOREIGN KEY ("video_webm_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "pages_blocks_fd_video_hero" ADD CONSTRAINT "pages_blocks_fd_video_hero_poster_image_id_media_id_fk" FOREIGN KEY ("poster_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "pages_blocks_fd_video_hero" ADD CONSTRAINT "pages_blocks_fd_video_hero_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "pages_blocks_fd_video_hero_locales" ADD CONSTRAINT "pages_blocks_fd_video_hero_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_fd_video_hero"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "_pages_v_blocks_fd_video_hero" ADD CONSTRAINT "_pages_v_blocks_fd_video_hero_video_mp4_id_media_id_fk" FOREIGN KEY ("video_mp4_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "_pages_v_blocks_fd_video_hero" ADD CONSTRAINT "_pages_v_blocks_fd_video_hero_video_webm_id_media_id_fk" FOREIGN KEY ("video_webm_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "_pages_v_blocks_fd_video_hero" ADD CONSTRAINT "_pages_v_blocks_fd_video_hero_poster_image_id_media_id_fk" FOREIGN KEY ("poster_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||
ALTER TABLE "_pages_v_blocks_fd_video_hero" ADD CONSTRAINT "_pages_v_blocks_fd_video_hero_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_pages_v"("id") ON DELETE cascade ON UPDATE no action;
|
||||
ALTER TABLE "_pages_v_blocks_fd_video_hero_locales" ADD CONSTRAINT "_pages_v_blocks_fd_video_hero_locales_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_pages_v_blocks_fd_video_hero"("id") ON DELETE cascade ON UPDATE no action;
|
||||
CREATE INDEX "pages_blocks_fd_video_hero_order_idx" ON "pages_blocks_fd_video_hero" USING btree ("_order");
|
||||
CREATE INDEX "pages_blocks_fd_video_hero_parent_id_idx" ON "pages_blocks_fd_video_hero" USING btree ("_parent_id");
|
||||
CREATE INDEX "pages_blocks_fd_video_hero_path_idx" ON "pages_blocks_fd_video_hero" USING btree ("_path");
|
||||
CREATE INDEX "pages_blocks_fd_video_hero_video_mp4_idx" ON "pages_blocks_fd_video_hero" USING btree ("video_mp4_id");
|
||||
CREATE INDEX "pages_blocks_fd_video_hero_video_webm_idx" ON "pages_blocks_fd_video_hero" USING btree ("video_webm_id");
|
||||
CREATE INDEX "pages_blocks_fd_video_hero_poster_image_idx" ON "pages_blocks_fd_video_hero" USING btree ("poster_image_id");
|
||||
CREATE UNIQUE INDEX "pages_blocks_fd_video_hero_locales_locale_parent_id_unique" ON "pages_blocks_fd_video_hero_locales" USING btree ("_locale","_parent_id");
|
||||
CREATE INDEX "_pages_v_blocks_fd_video_hero_order_idx" ON "_pages_v_blocks_fd_video_hero" USING btree ("_order");
|
||||
CREATE INDEX "_pages_v_blocks_fd_video_hero_parent_id_idx" ON "_pages_v_blocks_fd_video_hero" USING btree ("_parent_id");
|
||||
CREATE INDEX "_pages_v_blocks_fd_video_hero_path_idx" ON "_pages_v_blocks_fd_video_hero" USING btree ("_path");
|
||||
CREATE INDEX "_pages_v_blocks_fd_video_hero_video_mp4_idx" ON "_pages_v_blocks_fd_video_hero" USING btree ("video_mp4_id");
|
||||
CREATE INDEX "_pages_v_blocks_fd_video_hero_video_webm_idx" ON "_pages_v_blocks_fd_video_hero" USING btree ("video_webm_id");
|
||||
CREATE INDEX "_pages_v_blocks_fd_video_hero_poster_image_idx" ON "_pages_v_blocks_fd_video_hero" USING btree ("poster_image_id");
|
||||
CREATE UNIQUE INDEX "_pages_v_blocks_fd_video_hero_locales_locale_parent_id_uniqu" ON "_pages_v_blocks_fd_video_hero_locales" USING btree ("_locale","_parent_id");`)
|
||||
}
|
||||
|
||||
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
|
||||
await db.execute(sql`
|
||||
DROP TABLE "pages_blocks_fd_video_hero" CASCADE;
|
||||
DROP TABLE "pages_blocks_fd_video_hero_locales" CASCADE;
|
||||
DROP TABLE "_pages_v_blocks_fd_video_hero" CASCADE;
|
||||
DROP TABLE "_pages_v_blocks_fd_video_hero_locales" CASCADE;
|
||||
DROP TYPE "public"."enum_pages_blocks_fd_video_hero_overlay_color";
|
||||
DROP TYPE "public"."enum_pages_blocks_fd_video_hero_overlay_strength";
|
||||
DROP TYPE "public"."enum_pages_blocks_fd_video_hero_text_align";
|
||||
DROP TYPE "public"."enum_pages_blocks_fd_video_hero_min_height";
|
||||
DROP TYPE "public"."enum__pages_v_blocks_fd_video_hero_overlay_color";
|
||||
DROP TYPE "public"."enum__pages_v_blocks_fd_video_hero_overlay_strength";
|
||||
DROP TYPE "public"."enum__pages_v_blocks_fd_video_hero_text_align";
|
||||
DROP TYPE "public"."enum__pages_v_blocks_fd_video_hero_min_height";`)
|
||||
}
|
||||
@ -3,6 +3,7 @@ import * as migration_20260224_133833 from './20260224_133833';
|
||||
import * as migration_20260226_095439 from './20260226_095439';
|
||||
import * as migration_20260302_145030 from './20260302_145030';
|
||||
import * as migration_20260304_194657 from './20260304_194657';
|
||||
import * as migration_20260304_203759 from './20260304_203759';
|
||||
|
||||
export const migrations = [
|
||||
{
|
||||
@ -28,6 +29,11 @@ export const migrations = [
|
||||
{
|
||||
up: migration_20260304_194657.up,
|
||||
down: migration_20260304_194657.down,
|
||||
name: '20260304_194657'
|
||||
name: '20260304_194657',
|
||||
},
|
||||
{
|
||||
up: migration_20260304_203759.up,
|
||||
down: migration_20260304_203759.down,
|
||||
name: '20260304_203759'
|
||||
},
|
||||
];
|
||||
|
||||
@ -191,6 +191,7 @@ export interface Page {
|
||||
| FDLinkCardsBlock
|
||||
| FDSpecCardsBlock
|
||||
| FDQuizBlock
|
||||
| FDVideoHeroBlock
|
||||
)[];
|
||||
meta?: {
|
||||
title?: string | null;
|
||||
@ -1619,6 +1620,60 @@ export interface FDQuizBlock {
|
||||
blockName?: string | null;
|
||||
blockType: 'fdQuiz';
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "FDVideoHeroBlock".
|
||||
*/
|
||||
export interface FDVideoHeroBlock {
|
||||
/**
|
||||
* Huvudvideo — MP4 (H.264). Fungerar i alla webbläsare. Håll filstorleken under 5 MB för bästa prestanda.
|
||||
*/
|
||||
videoMp4: number | Media;
|
||||
/**
|
||||
* Progressiv förbättring — WebM är mindre och bättre kvalitet. Webbläsare som stödjer WebM väljer denna automatiskt.
|
||||
*/
|
||||
videoWebm?: (number | null) | Media;
|
||||
/**
|
||||
* Visas medan videon laddas och som fallback på mobil om video hoppas över.
|
||||
*/
|
||||
posterImage?: (number | null) | Media;
|
||||
/**
|
||||
* H1-rubrik som visas ovanpå videon.
|
||||
*/
|
||||
heading?: string | null;
|
||||
/**
|
||||
* Kort text under rubriken.
|
||||
*/
|
||||
body?: string | null;
|
||||
/**
|
||||
* T.ex. "Kom igång"
|
||||
*/
|
||||
ctaText?: string | null;
|
||||
ctaLink?: string | null;
|
||||
secondaryCtaText?: string | null;
|
||||
secondaryCtaLink?: string | null;
|
||||
overlayColor?: ('none' | 'black' | 'navy') | null;
|
||||
/**
|
||||
* Hur stark overlay ovanpå videon (för läsbarhet).
|
||||
*/
|
||||
overlayStrength?: ('light' | 'medium' | 'heavy') | null;
|
||||
textAlign?: ('left' | 'center') | null;
|
||||
/**
|
||||
* Hur hög video-sektionen ska vara.
|
||||
*/
|
||||
minHeight?: ('screen' | 'large' | 'medium') | null;
|
||||
/**
|
||||
* Hoppa över video på små skärmar för att spara bandbredd. Poster-bilden visas istället.
|
||||
*/
|
||||
disableVideoOnMobile?: boolean | null;
|
||||
/**
|
||||
* Valfritt. Används för att länka direkt till denna sektion, t.ex. "priser" ger /sida#priser. Använd bara små bokstäver, siffror och bindestreck.
|
||||
*/
|
||||
anchorId?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'fdVideoHero';
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "posts".
|
||||
@ -2002,6 +2057,7 @@ export interface PagesSelect<T extends boolean = true> {
|
||||
fdLinkCards?: T | FDLinkCardsBlockSelect<T>;
|
||||
fdSpecCards?: T | FDSpecCardsBlockSelect<T>;
|
||||
fdQuiz?: T | FDQuizBlockSelect<T>;
|
||||
fdVideoHero?: T | FDVideoHeroBlockSelect<T>;
|
||||
};
|
||||
meta?:
|
||||
| T
|
||||
@ -2820,6 +2876,29 @@ export interface FDQuizBlockSelect<T extends boolean = true> {
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "FDVideoHeroBlock_select".
|
||||
*/
|
||||
export interface FDVideoHeroBlockSelect<T extends boolean = true> {
|
||||
videoMp4?: T;
|
||||
videoWebm?: T;
|
||||
posterImage?: T;
|
||||
heading?: T;
|
||||
body?: T;
|
||||
ctaText?: T;
|
||||
ctaLink?: T;
|
||||
secondaryCtaText?: T;
|
||||
secondaryCtaLink?: T;
|
||||
overlayColor?: T;
|
||||
overlayStrength?: T;
|
||||
textAlign?: T;
|
||||
minHeight?: T;
|
||||
disableVideoOnMobile?: T;
|
||||
anchorId?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "posts_select".
|
||||
|
||||
Loading…
Reference in New Issue
Block a user