feature: image with text
Some checks failed
Deploy / deploy (push) Has been cancelled

This commit is contained in:
Benno Tielen 2026-06-11 10:57:13 +02:00
parent 30a8565531
commit f752a48e5a
13 changed files with 28168 additions and 16 deletions

View file

@ -13,6 +13,7 @@ import { CollapsiblesBlock } from '@/collections/blocks/Collapsibles'
import { TitleBlock } from '@/collections/blocks/Title'
import { NextPrevButtonsBlock } from '@/collections/blocks/NextPrevButtons'
import { ContactPersonBlock } from '@/collections/blocks/ContactPersonBlock'
import { ImageWithTextBlock } from '@/collections/blocks/ImageWithText'
export const Groups: CollectionConfig = {
slug: 'group',
@ -94,7 +95,8 @@ export const Groups: CollectionConfig = {
ButtonBlock,
ImageCardsBlock,
CollapsiblesBlock,
NextPrevButtonsBlock
NextPrevButtonsBlock,
ImageWithTextBlock
]
}
],

View file

@ -17,6 +17,7 @@ import { HorizontalRuleBlock } from '@/collections/blocks/HorizontalRule'
import { BlogSliderBlock } from '@/collections/blocks/BlogSlider'
import { MassTimesBlock } from '@/collections/blocks/MassTimes'
import { CollapsibleImageWithTextBlock } from '@/collections/blocks/CollapsibleImageWithText'
import { ImageWithTextBlock } from '@/collections/blocks/ImageWithText'
import { CollapsibleMapWithTextBlock } from '@/collections/blocks/CollapsibleMapWithText'
import { CollapsiblesBlock } from '@/collections/blocks/Collapsibles'
import { EventsBlock } from '@/collections/blocks/Events'
@ -103,6 +104,7 @@ export const Pages: CollectionConfig = {
HorizontalRuleBlock,
BlogSliderBlock,
CollapsibleImageWithTextBlock,
ImageWithTextBlock,
CollapsibleMapWithTextBlock,
CollapsiblesBlock,
MassTimesBlock,

View file

@ -10,6 +10,7 @@ import { TitleBlock } from '@/collections/blocks/Title'
import { CollapsiblesBlock } from '@/collections/blocks/Collapsibles'
import { isPublishedPublic } from '@/collections/access/public'
import { NextPrevButtonsBlock } from '@/collections/blocks/NextPrevButtons'
import { ImageWithTextBlock } from '@/collections/blocks/ImageWithText'
export const Parish: CollectionConfig = {
slug: 'parish',
@ -126,7 +127,8 @@ export const Parish: CollectionConfig = {
ImageCardsBlock,
TitleBlock,
CollapsiblesBlock,
NextPrevButtonsBlock
NextPrevButtonsBlock,
ImageWithTextBlock
]
},
{

View file

@ -0,0 +1,80 @@
import { Block } from 'payload'
export const ImageWithTextBlock: Block = {
slug: 'imageWithText',
labels: {
singular: {
de: 'Bild mit Text',
},
plural: {
de: 'Bilder mit Text',
},
},
fields: [
{
name: 'title',
type: 'text',
required: false,
label: {
de: 'Titel',
},
},
{
name: 'titleColor',
type: 'select',
label: {
de: 'Titelfarbe',
},
options: [
{ label: { de: 'Basis' }, value: 'base' },
{ label: { de: 'Kontrast' }, value: 'contrast' },
],
defaultValue: 'base',
required: true,
},
{
name: 'backgroundColor',
type: 'select',
label: {
de: 'Hintergrundfarbe',
},
options: [
{ label: { de: 'Keine' }, value: 'none' },
{ label: { de: 'Soft' }, value: 'soft' },
{ label: { de: 'Off-White' }, value: 'off-white' },
],
defaultValue: 'none',
required: true,
},
{
name: 'image',
type: 'upload',
relationTo: 'media',
required: true,
label: {
de: 'Bild',
},
},
{
name: 'imagePosition',
type: 'select',
label: {
de: 'Bildposition',
},
options: [
{ label: { de: 'Links' }, value: 'left' },
{ label: { de: 'Rechts' }, value: 'right' },
],
defaultValue: 'left',
required: true,
},
{
name: 'text',
type: 'richText',
required: true,
label: {
de: 'Text',
},
},
],
}

View file

@ -14,6 +14,7 @@ import { Banner } from '@/components/Banner/Banner'
import { MainText } from '@/components/MainText/MainText'
import { HR } from '@/components/HorizontalRule/HorizontalRule'
import { CollapsibleImageWithText } from '@/compositions/CollapsibleImageWithText/CollapsibleImageWithText'
import { ImageWithText } from '@/compositions/ImageWithText/ImageWithText'
import { CollapsibleMapWithText } from '@/compositions/CollapsibleMapWithText/CollapsibleMapWithText'
import { Collapsible } from '@/components/Collapsible/Collapsible'
import { PublicationAndNewsletter } from '@/compositions/PublicationAndNewsletter/PublicationAndNewsletter'
@ -235,6 +236,25 @@ export function Blocks({ content }: BlocksProps) {
)
}
if (item.blockType === 'imageWithText') {
const imageUrl = getPhoto("tablet", item.image) || ''
return (
<ImageWithText
key={item.id}
title={item.title || undefined}
titleSize={'md'}
text={item.text}
image={imageUrl}
imagePosition={item.imagePosition}
ratio={'1/3'}
padding={'medium'}
backgroundColor={item.backgroundColor}
alternativeText={typeof item.image === 'object' ? item.image.alt : ''}
schema={item.titleColor}
/>
)
}
if (item.blockType === 'collapsibleMapWithText') {
const bg = item.backgroundColor === 'soft' || item.backgroundColor === 'off-white'
? item.backgroundColor as 'soft' | 'off-white'

View file

@ -10,6 +10,8 @@ import { ImageCardsBlock } from '@/compositions/Blocks/ImageCardsBlock'
import { Title } from '@/components/Title/Title'
import { Collapsible } from '@/components/Collapsible/Collapsible'
import { NextPrevButtons } from '@/components/NextPrevButtons/NextPrevButtons'
import { ImageWithText } from '@/compositions/ImageWithText/ImageWithText'
import { getPhoto } from '@/utils/dto/gallery'
type BlocksProps = {
content: Parish['content']
@ -106,6 +108,25 @@ export function ParishBlocks({ content }: BlocksProps) {
</Section>
}
if (item.blockType === "imageWithText") {
const imageUrl = getPhoto("tablet", item.image) || ''
return (
<ImageWithText
key={item.id}
title={item.title || undefined}
titleSize={"md"}
text={item.text}
image={imageUrl}
imagePosition={item.imagePosition === "right" ? "right" : "left"}
ratio={"1/3"}
padding={"medium"}
backgroundColor={item.backgroundColor}
alternativeText={typeof item.image === 'object' ? item.image.alt : ''}
schema={item.titleColor}
/>
)
}
if (item.blockType === 'nextPrevButtons') {
const prev = item.prev?.href && item.prev?.text
? { href: item.prev.href, text: item.prev.text }

View file

@ -1,6 +1,8 @@
import { Meta, StoryObj } from '@storybook/nextjs-vite'
import { SerializedEditorState } from 'lexical'
import forest from "../../assets/forest.jpeg"
import chris from "../../assets/christophorus.jpeg"
import { Button } from '@/components/Button/Button'
import { ImageWithText } from './ImageWithText'
const meta: Meta<typeof ImageWithText> = {
@ -10,6 +12,48 @@ const meta: Meta<typeof ImageWithText> = {
type Story = StoryObj<typeof ImageWithText>;
export default meta
// Minimal Lexical editor state, mirroring the helpers in RichText.stories.tsx,
// so we can exercise the richtext branch of `text`.
const richText: SerializedEditorState = {
root: {
type: 'root',
format: '',
indent: 0,
version: 1,
direction: 'ltr',
children: [
{
type: 'paragraph',
format: '',
indent: 0,
version: 1,
direction: 'ltr',
textFormat: 0,
textStyle: '',
children: [
{ type: 'text', format: 0, mode: 'normal', style: '', text: 'Dies ist ein ', detail: 0, version: 1 },
{ type: 'text', format: 1, mode: 'normal', style: '', text: 'formatierter', detail: 0, version: 1 },
{ type: 'text', format: 0, mode: 'normal', style: '', text: ' Absatz mit ', detail: 0, version: 1 },
{ type: 'text', format: 2, mode: 'normal', style: '', text: 'kursivem', detail: 0, version: 1 },
{ type: 'text', format: 0, mode: 'normal', style: '', text: ' Text.', detail: 0, version: 1 },
],
},
{
type: 'paragraph',
format: '',
indent: 0,
version: 1,
direction: 'ltr',
textFormat: 0,
textStyle: '',
children: [
{ type: 'text', format: 0, mode: 'normal', style: '', text: 'Ein zweiter Absatz beweist, dass mehrzeiliger Richtext gerendert wird.', detail: 0, version: 1 },
],
},
],
},
} as unknown as SerializedEditorState
export const AboutUs: Story = {
args: {
image: forest,
@ -30,3 +74,109 @@ export const Christophorus: Story = {
text: 'Die St. Christophorus Kirche in Berlin-Neukölln ist ein bedeutendes Beispiel für modernen Kirchenbau in der Hauptstadt. Erbaut in den 1960er Jahren, spiegelt das Gebäude die Architektur und künstlerische Gestaltung dieser Zeit wider und zeichnet sich durch schlichte, klare Linien und einen funktionalen Stil aus. Die Kirche ist nach dem heiligen Christophorus benannt, dem Schutzpatron der Reisenden, und bietet den Gemeindemitgliedern und Besuchern einen Ort der Ruhe und Besinnung im lebhaften Stadtteil Neukölln. Neben Gottesdiensten finden hier regelmäßig kulturelle Veranstaltungen und soziale Projekte statt, die die Kirche zu einem wichtigen Treffpunkt im Kiez machen.',
},
}
// Image on the right instead of the default left.
export const ImageRight: Story = {
args: {
image: chris,
backgroundColor: 'soft',
schema: 'contrast',
imagePosition: 'right',
title: 'St. Christophorus',
text: 'Mit der neuen Eigenschaft "imagePosition" lässt sich das Bild auf die rechte Seite legen, während der Text links steht.',
},
}
// No title — the heading is omitted entirely.
export const WithoutTitle: Story = {
args: {
image: forest,
backgroundColor: 'soft',
text: 'Der Titel ist jetzt optional. Ohne "title" wird nur das Bild und der Text gerendert, ohne Überschrift.',
},
}
// `text` as Lexical richtext instead of a plain string.
export const RichTextContent: Story = {
args: {
image: forest,
title: 'Richtext-Inhalt',
text: richText,
},
}
// Reduced section padding via the new `padding` prop.
export const SmallPadding: Story = {
args: {
image: chris,
backgroundColor: 'off-white',
padding: 'small',
title: 'Kompakter Abstand',
text: 'Mit "padding" wird der vertikale Abstand der Section gesteuert (small | medium | large).',
},
}
// Several stacked ImageWithText sections whose image alternates left / right.
export const Alternating: Story = {
render: () => {
const sections = [
{ image: forest, title: 'Über uns', text: 'Wir begrüßen Sie herzlich in unserer Pfarrei Hl. Drei Könige und im bunten Neukölln mit einer Vielfalt von Kulturen und Nationalitäten.' },
{ image: chris, title: 'St. Christophorus', text: 'Die St. Christophorus Kirche in Berlin-Neukölln ist ein bedeutendes Beispiel für modernen Kirchenbau in der Hauptstadt.' },
{ image: forest, title: 'Gemeindeleben', text: 'Neben Gottesdiensten finden regelmäßig kulturelle Veranstaltungen und soziale Projekte statt.' },
{ image: chris, title: 'Mitmachen', text: 'Herzlich willkommen sind alle, die mitfeiern und mitbeten möchten.' },
]
return (
<>
{sections.map((section, index) => (
<ImageWithText
key={index}
image={section.image}
title={section.title}
text={section.text}
titleSize={"md"}
ratio={"1/3"}
padding={"medium"}
imagePosition={index % 2 === 0 ? 'left' : 'right'}
backgroundColor={index % 2 === 0 ? undefined : 'soft'}
/>
))}
</>
)
},
}
// 1/3 ratio: image column takes one third, text column two thirds (default is 1/2).
export const ImageThirdRatio: Story = {
args: {
image: chris,
backgroundColor: 'soft',
schema: 'contrast',
ratio: '1/3',
title: 'Schmaleres Bild',
text: 'Mit "ratio: 1/3" nimmt die Bildspalte ein Drittel der Breite ein und die Textspalte zwei Drittel. Standard ist "1/2" beide Spalten gleich breit.',
},
}
// Smaller title via the `titleSize` prop (default is "lg").
export const SmallTitle: Story = {
args: {
image: forest,
backgroundColor: 'soft',
titleSize: 'md',
title: 'Kleinerer Titel',
text: 'Mit "titleSize" lässt sich die Größe der Überschrift steuern (xl | lg | md | sm). Standard ist "lg".',
},
}
// Optional call-to-action link rendered below the text.
export const WithLink: Story = {
args: {
image: forest,
schema: 'contrast',
backgroundColor: 'soft',
title: 'Mit Aktion',
text: 'Über die "link"-Eigenschaft kann ein beliebiges Element etwa ein Button unter dem Text angezeigt werden.',
link: <Button size={'md'} schema={'contrast'} href={'#'}>Mehr erfahren</Button>,
},
}

View file

@ -1,4 +1,4 @@
import { BackgroundColor, Section } from '@/components/Section/Section'
import { Section } from '@/components/Section/Section'
import { Title } from '@/components/Title/Title'
import { Container } from '@/components/Container/Container'
import Image, { StaticImageData } from 'next/image'
@ -6,33 +6,51 @@ import styles from './styles.module.scss'
import classNames from 'classnames'
import { Row } from '@/components/Flex/Row'
import { TextDiv } from '@/components/Text/TextDiv'
import { RichText } from '@/components/Text/RichText'
import { SerializedEditorState } from 'lexical'
type ImageWithTextProps = {
backgroundColor?: BackgroundColor,
title: string,
backgroundColor?: 'soft' | "off-white" | 'none',
padding?: 'small' | 'medium' | 'large',
title?: string,
titleSize?: 'xl' | 'lg' | 'md' | 'sm',
image: StaticImageData | string,
text: string
text: string | SerializedEditorState,
imagePosition?: 'left' | 'right',
ratio?: '1/2' | '1/3',
link?: React.ReactNode
schema?: 'base' | 'contrast',
unoptimized?: boolean,
opaque?: boolean
alternativeText?: string
}
export const ImageWithText = (
{
backgroundColor,
padding,
title,
image,
titleSize = 'lg',
text, link,
imagePosition = 'left',
ratio = '1/2',
schema = 'base',
unoptimized = true,
opaque = false,
alternativeText = ''
}: ImageWithTextProps) => {
const bg = backgroundColor === "none" ? undefined : backgroundColor;
return (
<Section backgroundColor={backgroundColor}>
<Section backgroundColor={bg} padding={padding}>
<Container>
<Row alignItems={'center'}>
<div className={classNames(styles.col, styles.imageCol)}>
<div
className={classNames(styles.col, styles.imageCol, { [styles.imageThird]: ratio === '1/3' })}
style={{ order: imagePosition === 'right' ? 1 : 0 }}
>
<Image
className={classNames({[styles.image]: true, [styles.imageOpaque]: opaque})}
width={800}
@ -40,10 +58,10 @@ export const ImageWithText = (
src={image}
objectFit={'cover'}
unoptimized={unoptimized}
alt={''} />
alt={alternativeText} />
</div>
<div className={styles.col}>
<Title title={title} size={'lg'} color={schema} />
<div className={classNames(styles.col, { [styles.textTwoThirds]: ratio === '1/3' })}>
{title && <Title title={title} size={titleSize} color={schema} />}
<Image
className={styles.imageMobile}
@ -52,9 +70,11 @@ export const ImageWithText = (
src={image}
objectFit={'cover'}
unoptimized={unoptimized}
alt={''} />
alt={alternativeText} />
<TextDiv text={text} />
{typeof text === 'string'
? <TextDiv text={text} />
: <RichText data={text} />}
{link &&
<div className={styles.right}>

View file

@ -30,6 +30,14 @@
width: calc(50% - 40px);
}
.imageThird {
width: calc(33.333% - 40px);
}
.textTwoThirds {
width: calc(66.666% - 40px);
}
@media screen and (max-width: 750px) {
.imageMobile {
display: block;
@ -39,7 +47,8 @@
display: none;
}
.col {
.col,
.textTwoThirds {
width: 100%;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,186 @@
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_parish_blocks_image_with_text_title_color" AS ENUM('base', 'contrast');
CREATE TYPE "public"."enum_parish_blocks_image_with_text_background_color" AS ENUM('none', 'soft', 'off-white');
CREATE TYPE "public"."enum_parish_blocks_image_with_text_image_position" AS ENUM('left', 'right');
CREATE TYPE "public"."enum__parish_v_blocks_image_with_text_title_color" AS ENUM('base', 'contrast');
CREATE TYPE "public"."enum__parish_v_blocks_image_with_text_background_color" AS ENUM('none', 'soft', 'off-white');
CREATE TYPE "public"."enum__parish_v_blocks_image_with_text_image_position" AS ENUM('left', 'right');
CREATE TYPE "public"."enum_group_blocks_image_with_text_title_color" AS ENUM('base', 'contrast');
CREATE TYPE "public"."enum_group_blocks_image_with_text_background_color" AS ENUM('none', 'soft', 'off-white');
CREATE TYPE "public"."enum_group_blocks_image_with_text_image_position" AS ENUM('left', 'right');
CREATE TYPE "public"."enum__group_v_blocks_image_with_text_title_color" AS ENUM('base', 'contrast');
CREATE TYPE "public"."enum__group_v_blocks_image_with_text_background_color" AS ENUM('none', 'soft', 'off-white');
CREATE TYPE "public"."enum__group_v_blocks_image_with_text_image_position" AS ENUM('left', 'right');
CREATE TYPE "public"."enum_pages_blocks_image_with_text_title_color" AS ENUM('base', 'contrast');
CREATE TYPE "public"."enum_pages_blocks_image_with_text_background_color" AS ENUM('none', 'soft', 'off-white');
CREATE TYPE "public"."enum_pages_blocks_image_with_text_image_position" AS ENUM('left', 'right');
CREATE TYPE "public"."enum__pages_v_blocks_image_with_text_title_color" AS ENUM('base', 'contrast');
CREATE TYPE "public"."enum__pages_v_blocks_image_with_text_background_color" AS ENUM('none', 'soft', 'off-white');
CREATE TYPE "public"."enum__pages_v_blocks_image_with_text_image_position" AS ENUM('left', 'right');
CREATE TABLE "parish_blocks_image_with_text" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"title" varchar,
"title_color" "enum_parish_blocks_image_with_text_title_color" DEFAULT 'base',
"background_color" "enum_parish_blocks_image_with_text_background_color" DEFAULT 'none',
"image_id" uuid,
"image_position" "enum_parish_blocks_image_with_text_image_position" DEFAULT 'left',
"text" jsonb,
"block_name" varchar
);
CREATE TABLE "_parish_v_blocks_image_with_text" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"title" varchar,
"title_color" "enum__parish_v_blocks_image_with_text_title_color" DEFAULT 'base',
"background_color" "enum__parish_v_blocks_image_with_text_background_color" DEFAULT 'none',
"image_id" uuid,
"image_position" "enum__parish_v_blocks_image_with_text_image_position" DEFAULT 'left',
"text" jsonb,
"_uuid" varchar,
"block_name" varchar
);
CREATE TABLE "group_blocks_image_with_text" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"title" varchar,
"title_color" "enum_group_blocks_image_with_text_title_color" DEFAULT 'base',
"background_color" "enum_group_blocks_image_with_text_background_color" DEFAULT 'none',
"image_id" uuid,
"image_position" "enum_group_blocks_image_with_text_image_position" DEFAULT 'left',
"text" jsonb,
"block_name" varchar
);
CREATE TABLE "_group_v_blocks_image_with_text" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"title" varchar,
"title_color" "enum__group_v_blocks_image_with_text_title_color" DEFAULT 'base',
"background_color" "enum__group_v_blocks_image_with_text_background_color" DEFAULT 'none',
"image_id" uuid,
"image_position" "enum__group_v_blocks_image_with_text_image_position" DEFAULT 'left',
"text" jsonb,
"_uuid" varchar,
"block_name" varchar
);
CREATE TABLE "pages_blocks_image_with_text" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"title" varchar,
"title_color" "enum_pages_blocks_image_with_text_title_color" DEFAULT 'base',
"background_color" "enum_pages_blocks_image_with_text_background_color" DEFAULT 'none',
"image_id" uuid,
"image_position" "enum_pages_blocks_image_with_text_image_position" DEFAULT 'left',
"text" jsonb,
"block_name" varchar
);
CREATE TABLE "_pages_v_blocks_image_with_text" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"title" varchar,
"title_color" "enum__pages_v_blocks_image_with_text_title_color" DEFAULT 'base',
"background_color" "enum__pages_v_blocks_image_with_text_background_color" DEFAULT 'none',
"image_id" uuid,
"image_position" "enum__pages_v_blocks_image_with_text_image_position" DEFAULT 'left',
"text" jsonb,
"_uuid" varchar,
"block_name" varchar
);
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-06-14T08:49:19.434Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-06-14T08:49:19.726Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-07-11T08:49:19.782Z';
ALTER TABLE "parish_blocks_image_with_text" ADD CONSTRAINT "parish_blocks_image_with_text_image_id_media_id_fk" FOREIGN KEY ("image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "parish_blocks_image_with_text" ADD CONSTRAINT "parish_blocks_image_with_text_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."parish"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_parish_v_blocks_image_with_text" ADD CONSTRAINT "_parish_v_blocks_image_with_text_image_id_media_id_fk" FOREIGN KEY ("image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "_parish_v_blocks_image_with_text" ADD CONSTRAINT "_parish_v_blocks_image_with_text_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_parish_v"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "group_blocks_image_with_text" ADD CONSTRAINT "group_blocks_image_with_text_image_id_media_id_fk" FOREIGN KEY ("image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "group_blocks_image_with_text" ADD CONSTRAINT "group_blocks_image_with_text_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."group"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_group_v_blocks_image_with_text" ADD CONSTRAINT "_group_v_blocks_image_with_text_image_id_media_id_fk" FOREIGN KEY ("image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "_group_v_blocks_image_with_text" ADD CONSTRAINT "_group_v_blocks_image_with_text_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_group_v"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "pages_blocks_image_with_text" ADD CONSTRAINT "pages_blocks_image_with_text_image_id_media_id_fk" FOREIGN KEY ("image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "pages_blocks_image_with_text" ADD CONSTRAINT "pages_blocks_image_with_text_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_pages_v_blocks_image_with_text" ADD CONSTRAINT "_pages_v_blocks_image_with_text_image_id_media_id_fk" FOREIGN KEY ("image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "_pages_v_blocks_image_with_text" ADD CONSTRAINT "_pages_v_blocks_image_with_text_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_pages_v"("id") ON DELETE cascade ON UPDATE no action;
CREATE INDEX "parish_blocks_image_with_text_order_idx" ON "parish_blocks_image_with_text" USING btree ("_order");
CREATE INDEX "parish_blocks_image_with_text_parent_id_idx" ON "parish_blocks_image_with_text" USING btree ("_parent_id");
CREATE INDEX "parish_blocks_image_with_text_path_idx" ON "parish_blocks_image_with_text" USING btree ("_path");
CREATE INDEX "parish_blocks_image_with_text_image_idx" ON "parish_blocks_image_with_text" USING btree ("image_id");
CREATE INDEX "_parish_v_blocks_image_with_text_order_idx" ON "_parish_v_blocks_image_with_text" USING btree ("_order");
CREATE INDEX "_parish_v_blocks_image_with_text_parent_id_idx" ON "_parish_v_blocks_image_with_text" USING btree ("_parent_id");
CREATE INDEX "_parish_v_blocks_image_with_text_path_idx" ON "_parish_v_blocks_image_with_text" USING btree ("_path");
CREATE INDEX "_parish_v_blocks_image_with_text_image_idx" ON "_parish_v_blocks_image_with_text" USING btree ("image_id");
CREATE INDEX "group_blocks_image_with_text_order_idx" ON "group_blocks_image_with_text" USING btree ("_order");
CREATE INDEX "group_blocks_image_with_text_parent_id_idx" ON "group_blocks_image_with_text" USING btree ("_parent_id");
CREATE INDEX "group_blocks_image_with_text_path_idx" ON "group_blocks_image_with_text" USING btree ("_path");
CREATE INDEX "group_blocks_image_with_text_image_idx" ON "group_blocks_image_with_text" USING btree ("image_id");
CREATE INDEX "_group_v_blocks_image_with_text_order_idx" ON "_group_v_blocks_image_with_text" USING btree ("_order");
CREATE INDEX "_group_v_blocks_image_with_text_parent_id_idx" ON "_group_v_blocks_image_with_text" USING btree ("_parent_id");
CREATE INDEX "_group_v_blocks_image_with_text_path_idx" ON "_group_v_blocks_image_with_text" USING btree ("_path");
CREATE INDEX "_group_v_blocks_image_with_text_image_idx" ON "_group_v_blocks_image_with_text" USING btree ("image_id");
CREATE INDEX "pages_blocks_image_with_text_order_idx" ON "pages_blocks_image_with_text" USING btree ("_order");
CREATE INDEX "pages_blocks_image_with_text_parent_id_idx" ON "pages_blocks_image_with_text" USING btree ("_parent_id");
CREATE INDEX "pages_blocks_image_with_text_path_idx" ON "pages_blocks_image_with_text" USING btree ("_path");
CREATE INDEX "pages_blocks_image_with_text_image_idx" ON "pages_blocks_image_with_text" USING btree ("image_id");
CREATE INDEX "_pages_v_blocks_image_with_text_order_idx" ON "_pages_v_blocks_image_with_text" USING btree ("_order");
CREATE INDEX "_pages_v_blocks_image_with_text_parent_id_idx" ON "_pages_v_blocks_image_with_text" USING btree ("_parent_id");
CREATE INDEX "_pages_v_blocks_image_with_text_path_idx" ON "_pages_v_blocks_image_with_text" USING btree ("_path");
CREATE INDEX "_pages_v_blocks_image_with_text_image_idx" ON "_pages_v_blocks_image_with_text" USING btree ("image_id");`)
}
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
ALTER TABLE "parish_blocks_image_with_text" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_parish_v_blocks_image_with_text" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "group_blocks_image_with_text" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_group_v_blocks_image_with_text" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "pages_blocks_image_with_text" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_pages_v_blocks_image_with_text" DISABLE ROW LEVEL SECURITY;
DROP TABLE "parish_blocks_image_with_text" CASCADE;
DROP TABLE "_parish_v_blocks_image_with_text" CASCADE;
DROP TABLE "group_blocks_image_with_text" CASCADE;
DROP TABLE "_group_v_blocks_image_with_text" CASCADE;
DROP TABLE "pages_blocks_image_with_text" CASCADE;
DROP TABLE "_pages_v_blocks_image_with_text" CASCADE;
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-06-14T07:26:50.172Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-06-14T07:26:50.530Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-07-11T07:26:50.607Z';
DROP TYPE "public"."enum_parish_blocks_image_with_text_title_color";
DROP TYPE "public"."enum_parish_blocks_image_with_text_background_color";
DROP TYPE "public"."enum_parish_blocks_image_with_text_image_position";
DROP TYPE "public"."enum__parish_v_blocks_image_with_text_title_color";
DROP TYPE "public"."enum__parish_v_blocks_image_with_text_background_color";
DROP TYPE "public"."enum__parish_v_blocks_image_with_text_image_position";
DROP TYPE "public"."enum_group_blocks_image_with_text_title_color";
DROP TYPE "public"."enum_group_blocks_image_with_text_background_color";
DROP TYPE "public"."enum_group_blocks_image_with_text_image_position";
DROP TYPE "public"."enum__group_v_blocks_image_with_text_title_color";
DROP TYPE "public"."enum__group_v_blocks_image_with_text_background_color";
DROP TYPE "public"."enum__group_v_blocks_image_with_text_image_position";
DROP TYPE "public"."enum_pages_blocks_image_with_text_title_color";
DROP TYPE "public"."enum_pages_blocks_image_with_text_background_color";
DROP TYPE "public"."enum_pages_blocks_image_with_text_image_position";
DROP TYPE "public"."enum__pages_v_blocks_image_with_text_title_color";
DROP TYPE "public"."enum__pages_v_blocks_image_with_text_background_color";
DROP TYPE "public"."enum__pages_v_blocks_image_with_text_image_position";`)
}

View file

@ -50,6 +50,7 @@ import * as migration_20260605_124103_gallery_caption from './20260605_124103_ga
import * as migration_20260605_130843_add_worship_language_other from './20260605_130843_add_worship_language_other';
import * as migration_20260609_113259_parish_gallery_caption from './20260609_113259_parish_gallery_caption';
import * as migration_20260611_072650_add_contact_person_to_group from './20260611_072650_add_contact_person_to_group';
import * as migration_20260611_084920_add_image_with_text_block from './20260611_084920_add_image_with_text_block';
export const migrations = [
{
@ -310,6 +311,11 @@ export const migrations = [
{
up: migration_20260611_072650_add_contact_person_to_group.up,
down: migration_20260611_072650_add_contact_person_to_group.down,
name: '20260611_072650_add_contact_person_to_group'
name: '20260611_072650_add_contact_person_to_group',
},
{
up: migration_20260611_084920_add_image_with_text_block.up,
down: migration_20260611_084920_add_image_with_text_block.down,
name: '20260611_084920_add_image_with_text_block'
},
];

View file

@ -310,6 +310,31 @@ export interface Parish {
blockName?: string | null;
blockType: 'nextPrevButtons';
}
| {
title?: string | null;
titleColor: 'base' | 'contrast';
backgroundColor: 'none' | 'soft' | 'off-white';
image: string | Media;
imagePosition: 'left' | 'right';
text: {
root: {
type: string;
children: {
type: any;
version: number;
[k: string]: unknown;
}[];
direction: ('ltr' | 'rtl') | null;
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
indent: number;
version: number;
};
[k: string]: unknown;
};
id?: string | null;
blockName?: string | null;
blockType: 'imageWithText';
}
)[]
| null;
contact: string;
@ -612,6 +637,31 @@ export interface Page {
blockName?: string | null;
blockType: 'collapsibleImageWithText';
}
| {
title?: string | null;
titleColor: 'base' | 'contrast';
backgroundColor: 'none' | 'soft' | 'off-white';
image: string | Media;
imagePosition: 'left' | 'right';
text: {
root: {
type: string;
children: {
type: any;
version: number;
[k: string]: unknown;
}[];
direction: ('ltr' | 'rtl') | null;
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
indent: number;
version: number;
};
[k: string]: unknown;
};
id?: string | null;
blockName?: string | null;
blockType: 'imageWithText';
}
| {
title: string;
text: string;
@ -906,6 +956,31 @@ export interface Group {
blockName?: string | null;
blockType: 'nextPrevButtons';
}
| {
title?: string | null;
titleColor: 'base' | 'contrast';
backgroundColor: 'none' | 'soft' | 'off-white';
image: string | Media;
imagePosition: 'left' | 'right';
text: {
root: {
type: string;
children: {
type: any;
version: number;
[k: string]: unknown;
}[];
direction: ('ltr' | 'rtl') | null;
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
indent: number;
version: number;
};
[k: string]: unknown;
};
id?: string | null;
blockName?: string | null;
blockType: 'imageWithText';
}
)[]
| null;
updatedAt: string;
@ -1700,6 +1775,18 @@ export interface ParishSelect<T extends boolean = true> {
id?: T;
blockName?: T;
};
imageWithText?:
| T
| {
title?: T;
titleColor?: T;
backgroundColor?: T;
image?: T;
imagePosition?: T;
text?: T;
id?: T;
blockName?: T;
};
};
contact?: T;
photo?: T;
@ -2124,6 +2211,18 @@ export interface GroupSelect<T extends boolean = true> {
id?: T;
blockName?: T;
};
imageWithText?:
| T
| {
title?: T;
titleColor?: T;
backgroundColor?: T;
image?: T;
imagePosition?: T;
text?: T;
id?: T;
blockName?: T;
};
};
updatedAt?: T;
createdAt?: T;
@ -2283,6 +2382,18 @@ export interface PagesSelect<T extends boolean = true> {
id?: T;
blockName?: T;
};
imageWithText?:
| T
| {
title?: T;
titleColor?: T;
backgroundColor?: T;
image?: T;
imagePosition?: T;
text?: T;
id?: T;
blockName?: T;
};
collapsibleMapWithText?:
| T
| {