Compare commits

..

No commits in common. "c605420dcbeb08cdffdb734c416ee39ffdaacb81" and "1bd95548fa9a41e25f56beda85a675d468939fed" have entirely different histories.

28 changed files with 6 additions and 65297 deletions

16
package-lock.json generated
View file

@ -13,7 +13,6 @@
"@payloadcms/db-postgres": "^3.74.0", "@payloadcms/db-postgres": "^3.74.0",
"@payloadcms/live-preview-react": "^3.74.0", "@payloadcms/live-preview-react": "^3.74.0",
"@payloadcms/next": "^3.74.0", "@payloadcms/next": "^3.74.0",
"@payloadcms/plugin-search": "^3.74.0",
"@payloadcms/richtext-lexical": "^3.74.0", "@payloadcms/richtext-lexical": "^3.74.0",
"@payloadcms/storage-gcs": "^3.74.0", "@payloadcms/storage-gcs": "^3.74.0",
"classnames": "^2.5.1", "classnames": "^2.5.1",
@ -2012,21 +2011,6 @@
"react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1" "react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1"
} }
}, },
"node_modules/@payloadcms/plugin-search": {
"version": "3.74.0",
"resolved": "https://registry.npmjs.org/@payloadcms/plugin-search/-/plugin-search-3.74.0.tgz",
"integrity": "sha512-LFExPKtv3bQPsRQ6LZ4IRUYFPs2bsvcT6ctjqwU1hp3o6+Ily9ltZcA19+Bu6gBw4DvWKHlczVgotmAewGAiPw==",
"license": "MIT",
"dependencies": {
"@payloadcms/next": "3.74.0",
"@payloadcms/ui": "3.74.0"
},
"peerDependencies": {
"payload": "3.74.0",
"react": "^19.0.1 || ^19.1.2 || ^19.2.1",
"react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1"
}
},
"node_modules/@payloadcms/richtext-lexical": { "node_modules/@payloadcms/richtext-lexical": {
"version": "3.74.0", "version": "3.74.0",
"license": "MIT", "license": "MIT",

View file

@ -24,7 +24,6 @@
"@payloadcms/db-postgres": "^3.74.0", "@payloadcms/db-postgres": "^3.74.0",
"@payloadcms/live-preview-react": "^3.74.0", "@payloadcms/live-preview-react": "^3.74.0",
"@payloadcms/next": "^3.74.0", "@payloadcms/next": "^3.74.0",
"@payloadcms/plugin-search": "^3.74.0",
"@payloadcms/richtext-lexical": "^3.74.0", "@payloadcms/richtext-lexical": "^3.74.0",
"@payloadcms/storage-gcs": "^3.74.0", "@payloadcms/storage-gcs": "^3.74.0",
"classnames": "^2.5.1", "classnames": "^2.5.1",

View file

@ -1,15 +0,0 @@
import { fetchSearchResults } from '@/fetch/search'
import { SearchPage } from '@/pageComponents/Search/SearchPage'
export const dynamic = 'force-dynamic'
export default async function Page({
searchParams,
}: {
searchParams: Promise<{ q?: string }>
}) {
const { q = '' } = await searchParams
const results = await fetchSearchResults(q)
return <SearchPage query={q} results={results} />
}

View file

@ -12,8 +12,6 @@ import { HeadingFeatureClient as HeadingFeatureClient_e70f5e05f09f93e00b997edb1e
import { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' import { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
import { LinkToDoc as LinkToDoc_aead06e4cbf6b2620c5c51c9ab283634 } from '@payloadcms/plugin-search/client'
import { ReindexButton as ReindexButton_aead06e4cbf6b2620c5c51c9ab283634 } from '@payloadcms/plugin-search/client'
import { default as default_9bcae99938dc292be0063ce32055e14c } from '../../../components/Logo/Logo' import { default as default_9bcae99938dc292be0063ce32055e14c } from '../../../components/Logo/Logo'
import { GcsClientUploadHandler as GcsClientUploadHandler_06e62ca02c7c441053a9b643e5545934 } from '@payloadcms/storage-gcs/client' import { GcsClientUploadHandler as GcsClientUploadHandler_06e62ca02c7c441053a9b643e5545934 } from '@payloadcms/storage-gcs/client'
import { CollectionCards as CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 } from '@payloadcms/next/rsc' import { CollectionCards as CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 } from '@payloadcms/next/rsc'
@ -33,8 +31,6 @@ export const importMap = {
"@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
"@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
"@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
"@payloadcms/plugin-search/client#LinkToDoc": LinkToDoc_aead06e4cbf6b2620c5c51c9ab283634,
"@payloadcms/plugin-search/client#ReindexButton": ReindexButton_aead06e4cbf6b2620c5c51c9ab283634,
"/components/Logo/Logo#default": default_9bcae99938dc292be0063ce32055e14c, "/components/Logo/Logo#default": default_9bcae99938dc292be0063ce32055e14c,
"@payloadcms/storage-gcs/client#GcsClientUploadHandler": GcsClientUploadHandler_06e62ca02c7c441053a9b643e5545934, "@payloadcms/storage-gcs/client#GcsClientUploadHandler": GcsClientUploadHandler_06e62ca02c7c441053a9b643e5545934,
"@payloadcms/next/rsc#CollectionCards": CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 "@payloadcms/next/rsc#CollectionCards": CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1

View file

@ -21,7 +21,6 @@ import { EventsBlock } from '@/collections/blocks/Events'
import { PublicationAndNewsletterBlock } from '@/collections/blocks/PublicationAndNewsletter' import { PublicationAndNewsletterBlock } from '@/collections/blocks/PublicationAndNewsletter'
import { ContactPersonBlock } from '@/collections/blocks/ContactPersonBlock' import { ContactPersonBlock } from '@/collections/blocks/ContactPersonBlock'
import { ImageCardsBlock } from '@/collections/blocks/ImageCards' import { ImageCardsBlock } from '@/collections/blocks/ImageCards'
import { ClassifiedsBlock } from '@/collections/blocks/Classifieds'
import { isPublishedPublic } from '@/collections/access/public' import { isPublishedPublic } from '@/collections/access/public'
export const Pages: CollectionConfig = { export const Pages: CollectionConfig = {
@ -103,7 +102,6 @@ export const Pages: CollectionConfig = {
EventsBlock, EventsBlock,
ContactPersonBlock, ContactPersonBlock,
ImageCardsBlock, ImageCardsBlock,
ClassifiedsBlock,
], ],
}, },
], ],

View file

@ -65,7 +65,7 @@ export const Parish: CollectionConfig = {
{ {
name: 'contactPersons', name: 'contactPersons',
label: { label: {
de: "Kontakt" de: "Ansprechpartner"
}, },
type: 'array', type: 'array',
fields: [ fields: [

View file

@ -1,14 +0,0 @@
import { Block } from 'payload'
export const ClassifiedsBlock: Block = {
slug: 'classifieds',
labels: {
singular: {
de: 'Kleinanzeigen',
},
plural: {
de: 'Kleinanzeigen',
},
},
fields: [],
}

View file

@ -27,7 +27,7 @@
.shade { .shade {
background-color: $shade2; background-color: $shade2;
color: $base-color !important; color: $base-color;
} }
.shade:hover { .shade:hover {

View file

@ -71,7 +71,7 @@
line-height: 95%; line-height: 95%;
} }
@media screen and (max-width: 1400px) { @media screen and (max-width: 1100px) {
.menu { .menu {
flex-direction: column; flex-direction: column;
gap: 30px; gap: 30px;

View file

@ -11,7 +11,6 @@ import { MegaMenu } from '@/components/MegaMenu/MegaMenu'
import { CollapsibleArrow } from '@/components/CollapsibleArrow/CollapsibleArrow' import { CollapsibleArrow } from '@/components/CollapsibleArrow/CollapsibleArrow'
import Link from 'next/link' import Link from 'next/link'
import { siteConfig } from '@/config/site' import { siteConfig } from '@/config/site'
import { MenuSearch } from './MenuSearch'
/** /**
* Represents a simple item component. * Represents a simple item component.
@ -181,7 +180,6 @@ export const Menu = ({menu}: MenuProps) => {
items={menu.rightItems} items={menu.rightItems}
onItemClick={() => setDisplayMenuMobile(false)} onItemClick={() => setDisplayMenuMobile(false)}
/> />
<MenuSearch onSubmitted={() => setDisplayMenuMobile(false)} />
</div> </div>
</nav> </nav>

View file

@ -1,41 +0,0 @@
'use client'
import { FormEvent, useState } from 'react'
import { useRouter } from 'next/navigation'
import Image from 'next/image'
import SearchIcon from './search.svg'
import styles from './styles.module.scss'
type MenuSearchProps = {
onSubmitted?: () => void
}
export const MenuSearch = ({ onSubmitted }: MenuSearchProps) => {
const router = useRouter()
const [value, setValue] = useState('')
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
const q = value.trim()
if (!q) return
router.push(`/suche?q=${encodeURIComponent(q)}`)
onSubmitted?.()
}
return (
<form className={styles.search} onSubmit={handleSubmit} role="search">
<input
type="search"
name="q"
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Suchen..."
aria-label="Suche"
className={styles.searchInput}
/>
<button type="submit" className={styles.searchButton} aria-label="Suchen">
<Image src={SearchIcon} width={20} height={20} alt="" />
</button>
</form>
)
}

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="11" cy="11" r="7" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20 20L16.65 16.65" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 367 B

View file

@ -80,46 +80,7 @@
max-height: 1000px; max-height: 1000px;
} }
.search { @media screen and (max-width: 1100px) {
display: flex;
align-items: center;
}
.searchInput {
width: 0;
padding: 0;
border: none;
border-bottom: 1px solid transparent;
background: transparent;
color: inherit;
font: inherit;
outline: none;
box-sizing: border-box;
transition: width 0.3s ease-in-out, padding 0.3s ease-in-out, border-color 0.3s ease-in-out;
&::-webkit-search-cancel-button {
-webkit-appearance: none;
}
}
.search:hover .searchInput,
.search:focus-within .searchInput {
width: 180px;
padding: 4px 8px;
border-bottom-color: $shade1;
}
.searchButton {
background: none;
border: none;
cursor: pointer;
padding: 4px;
display: flex;
align-items: center;
color: inherit;
}
@media screen and (max-width: 1400px) {
.nav { .nav {
flex-direction: column; flex-direction: column;
padding: 15px 15px; padding: 15px 15px;
@ -155,16 +116,4 @@
height: 100vh; height: 100vh;
overflow: scroll; overflow: scroll;
} }
.search {
width: 100%;
}
.searchInput,
.search:hover .searchInput,
.search:focus-within .searchInput {
width: 100%;
padding: 8px;
border-bottom-color: $border-color-light;
}
} }

View file

@ -21,7 +21,6 @@ import { BlogSliderBlock } from '@/compositions/Blocks/BlogSliderBlock'
import { MassTimesBlock } from '@/compositions/Blocks/MassTimesBlock' import { MassTimesBlock } from '@/compositions/Blocks/MassTimesBlock'
import { EventsBlock } from '@/compositions/Blocks/EventsBlock' import { EventsBlock } from '@/compositions/Blocks/EventsBlock'
import { ImageCardsBlock } from '@/compositions/Blocks/ImageCardsBlock' import { ImageCardsBlock } from '@/compositions/Blocks/ImageCardsBlock'
import { ClassifiedsFromApi } from '@/components/Classifieds/ClassifiedsFromApi'
type BlocksProps = { type BlocksProps = {
content: Blog['content']['content'] | NonNullable<Page['content']> content: Blog['content']['content'] | NonNullable<Page['content']>
@ -240,16 +239,6 @@ export function Blocks({ content }: BlocksProps) {
return <ImageCardsBlock key={item.id} items={item.items} /> return <ImageCardsBlock key={item.id} items={item.items} />
} }
if (item.blockType === 'classifieds') {
return (
<Section key={item.id} padding={'small'}>
<Container>
<ClassifiedsFromApi />
</Container>
</Section>
)
}
if (item.blockType === 'contactPersonBlock') { if (item.blockType === 'contactPersonBlock') {
const contact = typeof item.contact === 'object' const contact = typeof item.contact === 'object'
? item.contact ? item.contact

View file

@ -1,23 +0,0 @@
import { getPayload } from 'payload'
import config from '@/payload.config'
import { Search } from '@/payload-types'
export async function fetchSearchResults(query: string): Promise<Search[]> {
const trimmed = query.trim()
if (!trimmed) return []
const payload = await getPayload({ config })
const result = await payload.find({
collection: 'search',
where: {
title: {
contains: trimmed,
},
},
depth: 1,
limit: 50,
sort: 'priority',
})
return result.docs
}

File diff suppressed because it is too large Load diff

View file

@ -1,59 +0,0 @@
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
CREATE TABLE "search" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"title" varchar,
"priority" numeric,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);
CREATE TABLE "search_rels" (
"id" serial PRIMARY KEY NOT NULL,
"order" integer,
"parent_id" uuid NOT NULL,
"path" varchar NOT NULL,
"parish_id" uuid,
"blog_id" uuid,
"event_id" uuid,
"group_id" uuid
);
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-04-19T09:34:10.248Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-04-19T09:34:10.532Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-05-13T09:34:10.591Z';
ALTER TABLE "payload_locked_documents_rels" ADD COLUMN "search_id" uuid;
ALTER TABLE "search_rels" ADD CONSTRAINT "search_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."search"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "search_rels" ADD CONSTRAINT "search_rels_parish_fk" FOREIGN KEY ("parish_id") REFERENCES "public"."parish"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "search_rels" ADD CONSTRAINT "search_rels_blog_fk" FOREIGN KEY ("blog_id") REFERENCES "public"."blog"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "search_rels" ADD CONSTRAINT "search_rels_event_fk" FOREIGN KEY ("event_id") REFERENCES "public"."event"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "search_rels" ADD CONSTRAINT "search_rels_group_fk" FOREIGN KEY ("group_id") REFERENCES "public"."group"("id") ON DELETE cascade ON UPDATE no action;
CREATE INDEX "search_updated_at_idx" ON "search" USING btree ("updated_at");
CREATE INDEX "search_created_at_idx" ON "search" USING btree ("created_at");
CREATE INDEX "search_rels_order_idx" ON "search_rels" USING btree ("order");
CREATE INDEX "search_rels_parent_idx" ON "search_rels" USING btree ("parent_id");
CREATE INDEX "search_rels_path_idx" ON "search_rels" USING btree ("path");
CREATE INDEX "search_rels_parish_id_idx" ON "search_rels" USING btree ("parish_id");
CREATE INDEX "search_rels_blog_id_idx" ON "search_rels" USING btree ("blog_id");
CREATE INDEX "search_rels_event_id_idx" ON "search_rels" USING btree ("event_id");
CREATE INDEX "search_rels_group_id_idx" ON "search_rels" USING btree ("group_id");
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_search_fk" FOREIGN KEY ("search_id") REFERENCES "public"."search"("id") ON DELETE cascade ON UPDATE no action;
CREATE INDEX "payload_locked_documents_rels_search_id_idx" ON "payload_locked_documents_rels" USING btree ("search_id");`)
}
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
ALTER TABLE "search" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "search_rels" DISABLE ROW LEVEL SECURITY;
DROP TABLE "search" CASCADE;
DROP TABLE "search_rels" CASCADE;
ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT "payload_locked_documents_rels_search_fk";
DROP INDEX "payload_locked_documents_rels_search_id_idx";
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-04-12T12:46:39.042Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-04-12T12:46:39.348Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-05-10T12:46:39.403Z';
ALTER TABLE "payload_locked_documents_rels" DROP COLUMN "search_id";`)
}

File diff suppressed because it is too large Load diff

View file

@ -1,22 +0,0 @@
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-04-19T09:46:18.288Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-04-19T09:46:18.569Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-05-13T09:46:18.627Z';
ALTER TABLE "search_rels" ADD COLUMN "pages_id" uuid;
ALTER TABLE "search_rels" ADD CONSTRAINT "search_rels_pages_fk" FOREIGN KEY ("pages_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
CREATE INDEX "search_rels_pages_id_idx" ON "search_rels" USING btree ("pages_id");`)
}
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
ALTER TABLE "search_rels" DROP CONSTRAINT "search_rels_pages_fk";
DROP INDEX "search_rels_pages_id_idx";
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-04-19T09:34:10.248Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-04-19T09:34:10.532Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-05-13T09:34:10.591Z';
ALTER TABLE "search_rels" DROP COLUMN "pages_id";`)
}

File diff suppressed because it is too large Load diff

View file

@ -1,44 +0,0 @@
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
CREATE TABLE "pages_blocks_classifieds" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"block_name" varchar
);
CREATE TABLE "_pages_v_blocks_classifieds" (
"_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
);
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-04-19T12:20:19.986Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-04-19T12:20:20.277Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-05-13T12:20:20.339Z';
ALTER TABLE "pages_blocks_classifieds" ADD CONSTRAINT "pages_blocks_classifieds_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_pages_v_blocks_classifieds" ADD CONSTRAINT "_pages_v_blocks_classifieds_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_pages_v"("id") ON DELETE cascade ON UPDATE no action;
CREATE INDEX "pages_blocks_classifieds_order_idx" ON "pages_blocks_classifieds" USING btree ("_order");
CREATE INDEX "pages_blocks_classifieds_parent_id_idx" ON "pages_blocks_classifieds" USING btree ("_parent_id");
CREATE INDEX "pages_blocks_classifieds_path_idx" ON "pages_blocks_classifieds" USING btree ("_path");
CREATE INDEX "_pages_v_blocks_classifieds_order_idx" ON "_pages_v_blocks_classifieds" USING btree ("_order");
CREATE INDEX "_pages_v_blocks_classifieds_parent_id_idx" ON "_pages_v_blocks_classifieds" USING btree ("_parent_id");
CREATE INDEX "_pages_v_blocks_classifieds_path_idx" ON "_pages_v_blocks_classifieds" USING btree ("_path");`)
}
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
ALTER TABLE "pages_blocks_classifieds" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_pages_v_blocks_classifieds" DISABLE ROW LEVEL SECURITY;
DROP TABLE "pages_blocks_classifieds" CASCADE;
DROP TABLE "_pages_v_blocks_classifieds" CASCADE;
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-04-19T09:46:18.288Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-04-19T09:46:18.569Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-05-13T09:46:18.627Z';`)
}

View file

@ -30,9 +30,6 @@ import * as migration_20260409_083638 from './20260409_083638';
import * as migration_20260410_114057_imagecards_block from './20260410_114057_imagecards_block'; import * as migration_20260410_114057_imagecards_block from './20260410_114057_imagecards_block';
import * as migration_20260410_115248_parish_title_block from './20260410_115248_parish_title_block'; import * as migration_20260410_115248_parish_title_block from './20260410_115248_parish_title_block';
import * as migration_20260410_124639 from './20260410_124639'; import * as migration_20260410_124639 from './20260410_124639';
import * as migration_20260413_093410_search from './20260413_093410_search';
import * as migration_20260413_094618_search_pages from './20260413_094618_search_pages';
import * as migration_20260413_122020 from './20260413_122020';
export const migrations = [ export const migrations = [
{ {
@ -193,21 +190,6 @@ export const migrations = [
{ {
up: migration_20260410_124639.up, up: migration_20260410_124639.up,
down: migration_20260410_124639.down, down: migration_20260410_124639.down,
name: '20260410_124639', name: '20260410_124639'
},
{
up: migration_20260413_093410_search.up,
down: migration_20260413_093410_search.down,
name: '20260413_093410_search',
},
{
up: migration_20260413_094618_search_pages.up,
down: migration_20260413_094618_search_pages.down,
name: '20260413_094618_search_pages',
},
{
up: migration_20260413_122020.up,
down: migration_20260413_122020.down,
name: '20260413_122020'
}, },
]; ];

View file

@ -80,7 +80,7 @@ export const Parish = (
<Events events={tranformWorship(worship)} n={4}/> <Events events={tranformWorship(worship)} n={4}/>
</Col> </Col>
<Col> <Col>
<Title title={"Kontakt"} size={"md"} color={"contrast"} /> <Title title={"Ansprechpersonen"} size={"md"} color={"contrast"} />
<ContactPersonList persons={contactPersons} /> <ContactPersonList persons={contactPersons} />
</Col> </Col>

View file

@ -1,59 +0,0 @@
import Link from 'next/link'
import { Search } from '@/payload-types'
import { Section } from '@/components/Section/Section'
import { Container } from '@/components/Container/Container'
import { PageHeader } from '@/compositions/PageHeader/PageHeader'
import { getSearchResultUrl } from '@/utils/getSearchResultUrl'
import styles from './styles.module.scss'
const RELATION_LABELS: Record<Search['doc']['relationTo'], string> = {
pages: 'Seite',
blog: 'Nachricht',
parish: 'Gemeinde',
event: 'Veranstaltung',
group: 'Gruppe',
}
type SearchPageProps = {
query: string
results: Search[]
}
export const SearchPage = ({ query, results }: SearchPageProps) => {
const linkedResults = results
.map((result) => ({ result, href: getSearchResultUrl(result.doc) }))
.filter((r): r is { result: Search; href: string } => r.href !== null)
const description = query
? `Suchergebnisse für „${query}"`
: 'Bitte geben Sie einen Suchbegriff ein.'
return (
<>
<PageHeader title="Suche" description={description} />
<Section padding="small">
<Container>
{query && linkedResults.length === 0 && (
<p className={styles.empty}>Keine Ergebnisse für {query}.</p>
)}
{linkedResults.length > 0 && (
<ul className={styles.results}>
{linkedResults.map(({ result, href }) => (
<li key={result.id} className={styles.result}>
<Link href={href} className={styles.resultLink}>
<span className={styles.resultTitle}>{result.title}</span>
<span className={styles.resultType}>
{RELATION_LABELS[result.doc.relationTo]}
</span>
</Link>
</li>
))}
</ul>
)}
</Container>
</Section>
</>
)
}

View file

@ -1,49 +0,0 @@
@import "template.scss";
.results {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 1px;
}
.result {
border-bottom: 1px solid $border-color-light;
}
.resultLink {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: 20px;
padding: 16px 0;
color: inherit;
text-decoration: none;
transition: opacity 100ms ease-in;
&:hover {
opacity: 0.7;
}
}
.resultTitle {
font-size: 18px;
font-weight: 500;
}
.resultType {
font-size: 14px;
color: $base-color;
opacity: 0.6;
text-transform: uppercase;
letter-spacing: 0.05em;
flex-shrink: 0;
}
.empty {
font-size: 18px;
color: $base-color;
opacity: 0.7;
}

View file

@ -87,7 +87,6 @@ export interface Config {
documents: Document; documents: Document;
media: Media; media: Media;
users: User; users: User;
search: Search;
'payload-kv': PayloadKv; 'payload-kv': PayloadKv;
'payload-jobs': PayloadJob; 'payload-jobs': PayloadJob;
'payload-locked-documents': PayloadLockedDocument; 'payload-locked-documents': PayloadLockedDocument;
@ -116,7 +115,6 @@ export interface Config {
documents: DocumentsSelect<false> | DocumentsSelect<true>; documents: DocumentsSelect<false> | DocumentsSelect<true>;
media: MediaSelect<false> | MediaSelect<true>; media: MediaSelect<false> | MediaSelect<true>;
users: UsersSelect<false> | UsersSelect<true>; users: UsersSelect<false> | UsersSelect<true>;
search: SearchSelect<false> | SearchSelect<true>;
'payload-kv': PayloadKvSelect<false> | PayloadKvSelect<true>; 'payload-kv': PayloadKvSelect<false> | PayloadKvSelect<true>;
'payload-jobs': PayloadJobsSelect<false> | PayloadJobsSelect<true>; 'payload-jobs': PayloadJobsSelect<false> | PayloadJobsSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>; 'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
@ -613,11 +611,6 @@ export interface Page {
blockName?: string | null; blockName?: string | null;
blockType: 'imageCards'; blockType: 'imageCards';
} }
| {
id?: string | null;
blockName?: string | null;
blockType: 'classifieds';
}
)[] )[]
| null; | null;
updatedAt: string; updatedAt: string;
@ -1075,40 +1068,6 @@ export interface User {
| null; | null;
password?: string | null; password?: string | null;
} }
/**
* This is a collection of automatically created search results. These results are used by the global site search and will be updated automatically as documents in the CMS are created or updated.
*
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "search".
*/
export interface Search {
id: string;
title?: string | null;
priority?: number | null;
doc:
| {
relationTo: 'parish';
value: string | Parish;
}
| {
relationTo: 'pages';
value: string | Page;
}
| {
relationTo: 'blog';
value: string | Blog;
}
| {
relationTo: 'event';
value: string | Event;
}
| {
relationTo: 'group';
value: string | Group;
};
updatedAt: string;
createdAt: string;
}
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-kv". * via the `definition` "payload-kv".
@ -1313,10 +1272,6 @@ export interface PayloadLockedDocument {
| ({ | ({
relationTo: 'users'; relationTo: 'users';
value: string | User; value: string | User;
} | null)
| ({
relationTo: 'search';
value: string | Search;
} | null); } | null);
globalSlug?: string | null; globalSlug?: string | null;
user: { user: {
@ -1970,12 +1925,6 @@ export interface PagesSelect<T extends boolean = true> {
id?: T; id?: T;
blockName?: T; blockName?: T;
}; };
classifieds?:
| T
| {
id?: T;
blockName?: T;
};
}; };
updatedAt?: T; updatedAt?: T;
createdAt?: T; createdAt?: T;
@ -2113,17 +2062,6 @@ export interface UsersSelect<T extends boolean = true> {
expiresAt?: T; expiresAt?: T;
}; };
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "search_select".
*/
export interface SearchSelect<T extends boolean = true> {
title?: T;
priority?: T;
doc?: T;
updatedAt?: T;
createdAt?: T;
}
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-kv_select". * via the `definition` "payload-kv_select".

View file

@ -44,7 +44,6 @@ import { Pages } from '@/collections/Pages'
import { Prayers } from '@/collections/Prayers' import { Prayers } from '@/collections/Prayers'
import { siteConfig } from '@/config/site' import { siteConfig } from '@/config/site'
import { generateRecurringMassesTask } from '@/jobs/generateRecurringMasses' import { generateRecurringMassesTask } from '@/jobs/generateRecurringMasses'
import { searchPlugin } from '@payloadcms/plugin-search'
const filename = fileURLToPath(import.meta.url) const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename) const dirname = path.dirname(filename)
@ -197,35 +196,5 @@ export default buildConfig({
options: {}, options: {},
acl: undefined, acl: undefined,
}), }),
searchPlugin({
collections: ['parish', 'pages', 'blog', 'event', 'group'],
defaultPriorities: {
parish: 10,
pages: 15,
group: 20,
event: 30,
blog: 40,
},
// The plugin only reads `title` from the source doc, but Parish and
// Group use `name` instead. Map `name` → `title` so those collections
// get an indexed, searchable title.
beforeSync: ({ originalDoc, searchDoc }) => ({
...searchDoc,
title: originalDoc.title || originalDoc.name || searchDoc.title || '',
}),
// The plugin hardcodes `maxDepth: 0` on the polymorphic `doc` field,
// so `doc.value` is always returned as a string ID — even with depth>0
// at query time. We need it populated so the search results page can
// read each referenced document's `slug` to build URLs like
// /gemeinde/[slug] and /gruppe/[slug].
searchOverrides: {
fields: ({ defaultFields }) =>
defaultFields.map((field) =>
'name' in field && field.name === 'doc' && field.type === 'relationship'
? { ...field, maxDepth: 1 }
: field,
),
},
})
], ],
}) })

View file

@ -1,20 +0,0 @@
import { Search } from '@/payload-types'
export function getSearchResultUrl(doc: Search['doc']): string | null {
if (!doc || typeof doc.value === 'string') return null
switch (doc.relationTo) {
case 'pages':
return doc.value.slug ? `/${doc.value.slug}` : null
case 'blog':
return `/blog/${doc.value.id}`
case 'parish':
return doc.value.slug ? `/gemeinde/${doc.value.slug}` : null
case 'event':
return `/veranstaltungen/${doc.value.id}`
case 'group':
return doc.value.slug ? `/gruppe/${doc.value.slug}` : null
default:
return null
}
}