feat: live preview blog

This commit is contained in:
Benno Tielen 2026-03-11 10:37:39 +01:00
parent 294a5392c0
commit d5eca3f876
11 changed files with 12547 additions and 11 deletions

20
package-lock.json generated
View file

@ -11,6 +11,7 @@
"dependencies": {
"@nyariv/sandboxjs": "0.8.28",
"@payloadcms/db-postgres": "^3.74.0",
"@payloadcms/live-preview-react": "^3.79.0",
"@payloadcms/next": "^3.74.0",
"@payloadcms/richtext-lexical": "^3.74.0",
"@payloadcms/storage-gcs": "^3.74.0",
@ -2141,6 +2142,25 @@
"payload": "3.74.0"
}
},
"node_modules/@payloadcms/live-preview": {
"version": "3.79.0",
"resolved": "https://registry.npmjs.org/@payloadcms/live-preview/-/live-preview-3.79.0.tgz",
"integrity": "sha512-Y2t6NACgeC4gZV/mwzD1L+OhJHematK0RQ8xK4P/m+8fhO+sgS4gtjpA/m6yqAkhruRTni5izZJK6SWTB9pXPw==",
"license": "MIT"
},
"node_modules/@payloadcms/live-preview-react": {
"version": "3.79.0",
"resolved": "https://registry.npmjs.org/@payloadcms/live-preview-react/-/live-preview-react-3.79.0.tgz",
"integrity": "sha512-1JY/QzfIy6iOijpbdRdnV+TuK0B0vo8nTgH+WkfCWxayXf30FlykWW8sdBc44wn4CxmLry36cEeneqAbrasiWQ==",
"license": "MIT",
"dependencies": {
"@payloadcms/live-preview": "3.79.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.1 || ^19.1.2 || ^19.2.1",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.1 || ^19.1.2 || ^19.2.1"
}
},
"node_modules/@payloadcms/next": {
"version": "3.74.0",
"license": "MIT",

View file

@ -20,6 +20,7 @@
"dependencies": {
"@nyariv/sandboxjs": "0.8.28",
"@payloadcms/db-postgres": "^3.74.0",
"@payloadcms/live-preview-react": "^3.79.0",
"@payloadcms/next": "^3.74.0",
"@payloadcms/richtext-lexical": "^3.74.0",
"@payloadcms/storage-gcs": "^3.74.0",
@ -38,6 +39,7 @@
"zod": "^4.3.6"
},
"devDependencies": {
"@storybook/nextjs-vite": "^10.2.7",
"@swc/cli": "^0.7.10",
"@swc/core": "^1.15.11",
"@types/node": "^20.19.32",
@ -46,12 +48,11 @@
"eslint": "9.26.0",
"eslint-config-next": "16.1.6",
"eslint-config-prettier": "^10.1.8",
"typescript": "5.9.3",
"vitest": "^4.0.18",
"eslint-plugin-storybook": "^10.2.7",
"storybook": "^10.2.7",
"@storybook/nextjs-vite": "^10.2.7",
"typescript": "5.9.3",
"vite": "^7.3.1",
"eslint-plugin-storybook": "^10.2.7"
"vitest": "^4.0.18"
},
"engines": {
"node": ">=22.0.0"

View file

@ -0,0 +1,42 @@
// Draft Mode API Route
//
// Enables Next.js draft mode so that pages can fetch unpublished
// Payload CMS content. This route is called by Payload's live preview
// iframe (configured in each collection's admin.livePreview.url) to
// set the draft mode cookie before redirecting to the actual page.
//
// Only authenticated Payload users can activate draft mode, ensuring
// public visitors never see draft content.
//
// See: https://nextjs.org/docs/app/guides/draft-mode
import { draftMode } from 'next/headers'
import { redirect } from 'next/navigation'
import { getPayload } from 'payload'
import config from '@/payload.config'
import { headers } from 'next/headers'
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const url = searchParams.get('url')
if (!url) {
return new Response('Missing url parameter', { status: 400 })
}
// Verify the request comes from an authenticated Payload CMS user
const payload = await getPayload({ config })
const allHeaders = await headers()
const { user } = await payload.auth({ headers: allHeaders })
if (!user) {
return new Response('Unauthorized', { status: 401 })
}
// Enable draft mode cookie — subsequent page renders will see
// draftMode().isEnabled === true and can fetch draft content
const draft = await draftMode()
draft.enable()
redirect(url)
}

View file

@ -11,17 +11,27 @@ import styles from "./styles.module.scss"
import { Blocks } from '@/compositions/Blocks/Blocks'
import { isAuthenticated } from '@/utils/auth'
import { AdminMenu } from '@/components/AdminMenu/AdminMenu'
import { RefreshRouteOnSave } from '@/components/RefreshRouteOnSave/RefreshRouteOnSave'
import { getPayload } from 'payload'
import config from '@/payload.config'
import { draftMode } from 'next/headers'
async function fetchBlog(id: string) {
const res = await fetch(`http://localhost:3000/api/blog/${id}`)
if (!res.ok) return undefined
return res.json();
async function fetchBlog(id: string, draft: boolean) {
const payload = await getPayload({ config })
const blog = await payload.findByID({
collection: 'blog',
id: id,
draft,
})
return blog
}
export default async function BlogPage({ params }: { params: Promise<{id: string}>}){
const id = (await params).id;
const data = await fetchBlog(id) as Blog;
const { isEnabled: isDraft } = await draftMode()
const data = await fetchBlog(id, isDraft) as Blog;
const url = typeof data.photo === 'object' && data.photo?.sizes?.banner?.url;
const authenticated = await isAuthenticated();
@ -35,6 +45,7 @@ export default async function BlogPage({ params }: { params: Promise<{id: string
return (
<>
{isDraft && <RefreshRouteOnSave />}
<Section paddingBottom={"small"}>
<Container>
<Title title={data.title} color={"contrast"}></Title>

View file

@ -117,6 +117,12 @@ export const Blog: CollectionConfig = {
admin: {
useAsTitle: 'title',
hidden: hide,
livePreview: {
url: ({ data }) => `/api/draft?url=/blog/${data.id}`,
}
},
versions: {
drafts: true
},
access: {
read: () => true,

View file

@ -0,0 +1,15 @@
'use client'
import { RefreshRouteOnSave as PayloadLivePreview } from '@payloadcms/live-preview-react'
import { useRouter } from 'next/navigation.js'
import React from 'react'
export const RefreshRouteOnSave: React.FC = () => {
const router = useRouter()
return (
<PayloadLivePreview
refresh={() => router.refresh()}
serverURL={process.env.PUBLIC_URL || "http://localhost:3000"}
/>
)
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,238 @@
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_blog_status" AS ENUM('draft', 'published');
CREATE TYPE "public"."enum__blog_v_blocks_text_width" AS ENUM('1/2', '3/4');
CREATE TYPE "public"."enum__blog_v_version_status" AS ENUM('draft', 'published');
CREATE TABLE "_blog_v_blocks_text" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"content" jsonb,
"width" "enum__blog_v_blocks_text_width" DEFAULT '1/2',
"_uuid" varchar,
"block_name" varchar
);
CREATE TABLE "_blog_v_blocks_document" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"file_id" uuid,
"button" varchar DEFAULT 'Download Flyer',
"_uuid" varchar,
"block_name" varchar
);
CREATE TABLE "_blog_v_blocks_donation" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"_uuid" varchar,
"block_name" varchar
);
CREATE TABLE "_blog_v_blocks_contactform" (
"_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 DEFAULT 'Ich bin dabei!',
"description" varchar DEFAULT 'Um dich anzumelden oder uns zu unterstützen, fülle bitte das Kontaktformular aus. Wir freuen uns sehr, dass du Teil unserer Gemeinschaft bist und mit deinem Engagement dazu beiträgst, unsere Ziele zu erreichen. Solltest du Fragen haben oder weitere Informationen benötigen, zögere nicht, uns zu kontaktieren wir sind gerne für dich da!',
"email" varchar DEFAULT 'kontakt@mutter-teresa-chemnitz.de',
"_uuid" varchar,
"block_name" varchar
);
CREATE TABLE "_blog_v_blocks_gallery_items" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"photo_id" uuid,
"_uuid" varchar
);
CREATE TABLE "_blog_v_blocks_gallery" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"_uuid" varchar,
"block_name" varchar
);
CREATE TABLE "_blog_v_blocks_youtube" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"youtube_id" varchar,
"_uuid" varchar,
"block_name" varchar
);
CREATE TABLE "_blog_v_blocks_button" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"text" varchar,
"url" varchar,
"_uuid" varchar,
"block_name" varchar
);
CREATE TABLE "_blog_v" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"parent_id" uuid,
"version_photo_id" uuid,
"version_title" varchar,
"version_content_excerpt" varchar,
"version_configuration_show_on_frontpage" boolean DEFAULT true,
"version_configuration_display_from_date" timestamp(3) with time zone,
"version_configuration_display_till_date" timestamp(3) with time zone,
"version_updated_at" timestamp(3) with time zone,
"version_created_at" timestamp(3) with time zone,
"version__status" "enum__blog_v_version_status" DEFAULT 'draft',
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"latest" boolean,
"autosave" boolean
);
CREATE TABLE "_blog_v_rels" (
"id" serial PRIMARY KEY NOT NULL,
"order" integer,
"parent_id" uuid NOT NULL,
"path" varchar NOT NULL,
"parish_id" uuid
);
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-03-15T14:38:00.254Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-03-15T14:38:00.534Z';
ALTER TABLE "blog_blocks_text" ALTER COLUMN "content" DROP NOT NULL;
ALTER TABLE "blog_blocks_text" ALTER COLUMN "width" DROP NOT NULL;
ALTER TABLE "blog_blocks_document" ALTER COLUMN "file_id" DROP NOT NULL;
ALTER TABLE "blog_blocks_document" ALTER COLUMN "button" DROP NOT NULL;
ALTER TABLE "blog_blocks_contactform" ALTER COLUMN "title" DROP NOT NULL;
ALTER TABLE "blog_blocks_contactform" ALTER COLUMN "description" DROP NOT NULL;
ALTER TABLE "blog_blocks_contactform" ALTER COLUMN "email" SET DEFAULT 'kontakt@mutter-teresa-chemnitz.de';
ALTER TABLE "blog_blocks_contactform" ALTER COLUMN "email" DROP NOT NULL;
ALTER TABLE "blog_blocks_gallery_items" ALTER COLUMN "photo_id" DROP NOT NULL;
ALTER TABLE "blog_blocks_youtube" ALTER COLUMN "youtube_id" DROP NOT NULL;
ALTER TABLE "blog_blocks_button" ALTER COLUMN "text" DROP NOT NULL;
ALTER TABLE "blog_blocks_button" ALTER COLUMN "url" DROP NOT NULL;
ALTER TABLE "blog" ALTER COLUMN "title" DROP NOT NULL;
ALTER TABLE "blog" ALTER COLUMN "content_excerpt" DROP NOT NULL;
ALTER TABLE "blog" ALTER COLUMN "configuration_show_on_frontpage" DROP NOT NULL;
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-04-09T13:38:00.592Z';
ALTER TABLE "group_blocks_contactform" ALTER COLUMN "email" SET DEFAULT 'kontakt@mutter-teresa-chemnitz.de';
ALTER TABLE "pages_blocks_contactform" ALTER COLUMN "email" SET DEFAULT 'kontakt@mutter-teresa-chemnitz.de';
ALTER TABLE "blog" ADD COLUMN "_status" "enum_blog_status" DEFAULT 'draft';
ALTER TABLE "_blog_v_blocks_text" ADD CONSTRAINT "_blog_v_blocks_text_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_blog_v"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_blog_v_blocks_document" ADD CONSTRAINT "_blog_v_blocks_document_file_id_documents_id_fk" FOREIGN KEY ("file_id") REFERENCES "public"."documents"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "_blog_v_blocks_document" ADD CONSTRAINT "_blog_v_blocks_document_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_blog_v"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_blog_v_blocks_donation" ADD CONSTRAINT "_blog_v_blocks_donation_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_blog_v"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_blog_v_blocks_contactform" ADD CONSTRAINT "_blog_v_blocks_contactform_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_blog_v"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_blog_v_blocks_gallery_items" ADD CONSTRAINT "_blog_v_blocks_gallery_items_photo_id_media_id_fk" FOREIGN KEY ("photo_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "_blog_v_blocks_gallery_items" ADD CONSTRAINT "_blog_v_blocks_gallery_items_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_blog_v_blocks_gallery"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_blog_v_blocks_gallery" ADD CONSTRAINT "_blog_v_blocks_gallery_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_blog_v"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_blog_v_blocks_youtube" ADD CONSTRAINT "_blog_v_blocks_youtube_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_blog_v"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_blog_v_blocks_button" ADD CONSTRAINT "_blog_v_blocks_button_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_blog_v"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_blog_v" ADD CONSTRAINT "_blog_v_parent_id_blog_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."blog"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "_blog_v" ADD CONSTRAINT "_blog_v_version_photo_id_media_id_fk" FOREIGN KEY ("version_photo_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "_blog_v_rels" ADD CONSTRAINT "_blog_v_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."_blog_v"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_blog_v_rels" ADD CONSTRAINT "_blog_v_rels_parish_fk" FOREIGN KEY ("parish_id") REFERENCES "public"."parish"("id") ON DELETE cascade ON UPDATE no action;
CREATE INDEX "_blog_v_blocks_text_order_idx" ON "_blog_v_blocks_text" USING btree ("_order");
CREATE INDEX "_blog_v_blocks_text_parent_id_idx" ON "_blog_v_blocks_text" USING btree ("_parent_id");
CREATE INDEX "_blog_v_blocks_text_path_idx" ON "_blog_v_blocks_text" USING btree ("_path");
CREATE INDEX "_blog_v_blocks_document_order_idx" ON "_blog_v_blocks_document" USING btree ("_order");
CREATE INDEX "_blog_v_blocks_document_parent_id_idx" ON "_blog_v_blocks_document" USING btree ("_parent_id");
CREATE INDEX "_blog_v_blocks_document_path_idx" ON "_blog_v_blocks_document" USING btree ("_path");
CREATE INDEX "_blog_v_blocks_document_file_idx" ON "_blog_v_blocks_document" USING btree ("file_id");
CREATE INDEX "_blog_v_blocks_donation_order_idx" ON "_blog_v_blocks_donation" USING btree ("_order");
CREATE INDEX "_blog_v_blocks_donation_parent_id_idx" ON "_blog_v_blocks_donation" USING btree ("_parent_id");
CREATE INDEX "_blog_v_blocks_donation_path_idx" ON "_blog_v_blocks_donation" USING btree ("_path");
CREATE INDEX "_blog_v_blocks_contactform_order_idx" ON "_blog_v_blocks_contactform" USING btree ("_order");
CREATE INDEX "_blog_v_blocks_contactform_parent_id_idx" ON "_blog_v_blocks_contactform" USING btree ("_parent_id");
CREATE INDEX "_blog_v_blocks_contactform_path_idx" ON "_blog_v_blocks_contactform" USING btree ("_path");
CREATE INDEX "_blog_v_blocks_gallery_items_order_idx" ON "_blog_v_blocks_gallery_items" USING btree ("_order");
CREATE INDEX "_blog_v_blocks_gallery_items_parent_id_idx" ON "_blog_v_blocks_gallery_items" USING btree ("_parent_id");
CREATE INDEX "_blog_v_blocks_gallery_items_photo_idx" ON "_blog_v_blocks_gallery_items" USING btree ("photo_id");
CREATE INDEX "_blog_v_blocks_gallery_order_idx" ON "_blog_v_blocks_gallery" USING btree ("_order");
CREATE INDEX "_blog_v_blocks_gallery_parent_id_idx" ON "_blog_v_blocks_gallery" USING btree ("_parent_id");
CREATE INDEX "_blog_v_blocks_gallery_path_idx" ON "_blog_v_blocks_gallery" USING btree ("_path");
CREATE INDEX "_blog_v_blocks_youtube_order_idx" ON "_blog_v_blocks_youtube" USING btree ("_order");
CREATE INDEX "_blog_v_blocks_youtube_parent_id_idx" ON "_blog_v_blocks_youtube" USING btree ("_parent_id");
CREATE INDEX "_blog_v_blocks_youtube_path_idx" ON "_blog_v_blocks_youtube" USING btree ("_path");
CREATE INDEX "_blog_v_blocks_button_order_idx" ON "_blog_v_blocks_button" USING btree ("_order");
CREATE INDEX "_blog_v_blocks_button_parent_id_idx" ON "_blog_v_blocks_button" USING btree ("_parent_id");
CREATE INDEX "_blog_v_blocks_button_path_idx" ON "_blog_v_blocks_button" USING btree ("_path");
CREATE INDEX "_blog_v_parent_idx" ON "_blog_v" USING btree ("parent_id");
CREATE INDEX "_blog_v_version_version_photo_idx" ON "_blog_v" USING btree ("version_photo_id");
CREATE INDEX "_blog_v_version_version_updated_at_idx" ON "_blog_v" USING btree ("version_updated_at");
CREATE INDEX "_blog_v_version_version_created_at_idx" ON "_blog_v" USING btree ("version_created_at");
CREATE INDEX "_blog_v_version_version__status_idx" ON "_blog_v" USING btree ("version__status");
CREATE INDEX "_blog_v_created_at_idx" ON "_blog_v" USING btree ("created_at");
CREATE INDEX "_blog_v_updated_at_idx" ON "_blog_v" USING btree ("updated_at");
CREATE INDEX "_blog_v_latest_idx" ON "_blog_v" USING btree ("latest");
CREATE INDEX "_blog_v_autosave_idx" ON "_blog_v" USING btree ("autosave");
CREATE INDEX "_blog_v_rels_order_idx" ON "_blog_v_rels" USING btree ("order");
CREATE INDEX "_blog_v_rels_parent_idx" ON "_blog_v_rels" USING btree ("parent_id");
CREATE INDEX "_blog_v_rels_path_idx" ON "_blog_v_rels" USING btree ("path");
CREATE INDEX "_blog_v_rels_parish_id_idx" ON "_blog_v_rels" USING btree ("parish_id");
CREATE INDEX "blog__status_idx" ON "blog" USING btree ("_status");`)
}
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
ALTER TABLE "_blog_v_blocks_text" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_blog_v_blocks_document" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_blog_v_blocks_donation" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_blog_v_blocks_contactform" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_blog_v_blocks_gallery_items" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_blog_v_blocks_gallery" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_blog_v_blocks_youtube" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_blog_v_blocks_button" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_blog_v" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_blog_v_rels" DISABLE ROW LEVEL SECURITY;
DROP TABLE "_blog_v_blocks_text" CASCADE;
DROP TABLE "_blog_v_blocks_document" CASCADE;
DROP TABLE "_blog_v_blocks_donation" CASCADE;
DROP TABLE "_blog_v_blocks_contactform" CASCADE;
DROP TABLE "_blog_v_blocks_gallery_items" CASCADE;
DROP TABLE "_blog_v_blocks_gallery" CASCADE;
DROP TABLE "_blog_v_blocks_youtube" CASCADE;
DROP TABLE "_blog_v_blocks_button" CASCADE;
DROP TABLE "_blog_v" CASCADE;
DROP TABLE "_blog_v_rels" CASCADE;
DROP INDEX "blog__status_idx";
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-03-15T10:58:14.115Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-03-15T10:58:14.432Z';
ALTER TABLE "blog_blocks_text" ALTER COLUMN "content" SET NOT NULL;
ALTER TABLE "blog_blocks_text" ALTER COLUMN "width" SET NOT NULL;
ALTER TABLE "blog_blocks_document" ALTER COLUMN "file_id" SET NOT NULL;
ALTER TABLE "blog_blocks_document" ALTER COLUMN "button" SET NOT NULL;
ALTER TABLE "blog_blocks_contactform" ALTER COLUMN "title" SET NOT NULL;
ALTER TABLE "blog_blocks_contactform" ALTER COLUMN "description" SET NOT NULL;
ALTER TABLE "blog_blocks_contactform" ALTER COLUMN "email" DROP DEFAULT;
ALTER TABLE "blog_blocks_contactform" ALTER COLUMN "email" SET NOT NULL;
ALTER TABLE "blog_blocks_gallery_items" ALTER COLUMN "photo_id" SET NOT NULL;
ALTER TABLE "blog_blocks_youtube" ALTER COLUMN "youtube_id" SET NOT NULL;
ALTER TABLE "blog_blocks_button" ALTER COLUMN "text" SET NOT NULL;
ALTER TABLE "blog_blocks_button" ALTER COLUMN "url" SET NOT NULL;
ALTER TABLE "blog" ALTER COLUMN "title" SET NOT NULL;
ALTER TABLE "blog" ALTER COLUMN "content_excerpt" SET NOT NULL;
ALTER TABLE "blog" ALTER COLUMN "configuration_show_on_frontpage" SET NOT NULL;
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-04-09T09:58:14.493Z';
ALTER TABLE "group_blocks_contactform" ALTER COLUMN "email" DROP DEFAULT;
ALTER TABLE "pages_blocks_contactform" ALTER COLUMN "email" DROP DEFAULT;
ALTER TABLE "blog" DROP COLUMN "_status";
DROP TYPE "public"."enum_blog_status";
DROP TYPE "public"."enum__blog_v_blocks_text_width";
DROP TYPE "public"."enum__blog_v_version_status";`)
}

View file

@ -18,6 +18,7 @@ import * as migration_20260106_103529_donation_appeal from './20260106_103529_do
import * as migration_20260205_155735_version_bump from './20260205_155735_version_bump';
import * as migration_20260309_111617_many_new_features from './20260309_111617_many_new_features';
import * as migration_20260310_105814 from './20260310_105814';
import * as migration_20260310_143800 from './20260310_143800';
export const migrations = [
{
@ -118,6 +119,11 @@ export const migrations = [
{
up: migration_20260310_105814.up,
down: migration_20260310_105814.down,
name: '20260310_105814'
name: '20260310_105814',
},
{
up: migration_20260310_143800.up,
down: migration_20260310_143800.down,
name: '20260310_143800'
},
];

View file

@ -468,6 +468,7 @@ export interface Blog {
};
updatedAt: string;
createdAt: string;
_status?: ('draft' | 'published') | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
@ -1298,6 +1299,7 @@ export interface BlogSelect<T extends boolean = true> {
};
updatedAt?: T;
createdAt?: T;
_status?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema

View file

@ -73,7 +73,11 @@ export default buildConfig({
}
}
}
}
},
livePreview: {
url: 'http://localhost:3000',
collections: ['blog'],
},
},
collections: [
Parish,