feat(cms): Home/About/Services/Contact/Common Globals + JSON migration (MITHOME-87)
Payload Global configs mirroring proto/src/content/types.ts:
- src/globals/{Home,About,Services,Contact,Common}.ts
- src/globals/fields/stringArray.ts — shared helper: Payload has no
native string[] field, so every plain string array from the old
content types (trustBullets, paragraphs, features, spec items, …)
becomes an array of one-field { value } objects.
- home.partners is intentionally NOT included — that becomes its own
Partners collection (logo -> Media upload) in MITHOME-89, to avoid
two disagreeing sources for the same data.
- contact.form.fields.gdpr.label stays a plain textarea (not lexical
richText): the JSON source is a hand-written HTML string with an
<a> tag; richText's node-tree serialization would need its own
migration/render logic, out of scope for this bootstrap pass.
scripts/migrate-content-to-payload.ts: one-shot, idempotent Local API
migration reading the existing JSON files and calling updateGlobal —
does not touch or delete the JSON files. Run via the new
`npm run migrate:content` script.
Registered the five Globals in payload.config.ts.
Also included here (belongs with the previous "resolve double-root-
layout conflict" commit but didn't actually get staged there —
verified only now by diffing HEAD against the working tree):
(frontend)/layout.tsx's relative imports corrected to ../../ instead
of ../ (one directory deeper than the original src/app/layout.tsx).
Verified:
- npm run build / lint, tsc --noEmit, npm test (58 passed) all clean
- npm run migrate:content against the real dev MongoDB container,
then read back via payload.findGlobal() — hero.title, trustBullets,
services.items[0].features, footer.address, faq.items.length all
match the JSON source
- Real browser: logged into /admin, opened the Home global editor —
Hero/Trust bullets group renders and shows the migrated Hungarian
content correctly (see screenshot shared in chat)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
3183098926
commit
3132fcb8eb
@@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
* MITHOME-87: egyszeri migrációs script — a proto/src/content/pages/*.json
|
||||||
|
* + common.json tartalmát átemeli a Payload Globals-ekbe (Home, About,
|
||||||
|
* Services, Contact, Common) a Local API-n keresztül.
|
||||||
|
*
|
||||||
|
* Futtatás (proto/ mappából, futó MongoDB-vel és beállított env-ekkel):
|
||||||
|
* node --env-file=.env.local --import tsx scripts/migrate-content-to-payload.ts
|
||||||
|
*
|
||||||
|
* Idempotens: updateGlobal-t hív, tetszőlegesen többször futtatható —
|
||||||
|
* mindig a JSON az aktuális "forrás igazság", felülírja a Payload-ban
|
||||||
|
* lévő korábbi állapotot. NEM törli/nem érinti a JSON fájlokat.
|
||||||
|
*/
|
||||||
|
import { getPayload } from 'payload'
|
||||||
|
import config from '../src/payload.config'
|
||||||
|
|
||||||
|
import homeJson from '../src/content/pages/home.json'
|
||||||
|
import aboutJson from '../src/content/pages/about.json'
|
||||||
|
import servicesJson from '../src/content/pages/services.json'
|
||||||
|
import contactJson from '../src/content/pages/contact.json'
|
||||||
|
import commonJson from '../src/content/common.json'
|
||||||
|
|
||||||
|
/** string[] -> [{ value: string }] — lásd src/globals/fields/stringArray.ts */
|
||||||
|
function toStringArray(items: readonly string[]): { value: string }[] {
|
||||||
|
return items.map((value) => ({ value }))
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildHomeData(json: typeof homeJson) {
|
||||||
|
const { hero, about, services, cta, serviceFeatures } = json
|
||||||
|
return {
|
||||||
|
hero: {
|
||||||
|
...hero,
|
||||||
|
trustBullets: toStringArray(hero.trustBullets),
|
||||||
|
},
|
||||||
|
about,
|
||||||
|
services: {
|
||||||
|
...services,
|
||||||
|
items: services.items.map((item) => ({
|
||||||
|
...item,
|
||||||
|
features: toStringArray(item.features),
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
cta,
|
||||||
|
serviceFeatures,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAboutData(json: typeof aboutJson) {
|
||||||
|
const { meta, hero, story, mission, team, cta } = json
|
||||||
|
return {
|
||||||
|
meta,
|
||||||
|
hero,
|
||||||
|
story: { ...story, paragraphs: toStringArray(story.paragraphs) },
|
||||||
|
mission,
|
||||||
|
team: { ...team, paragraphs: toStringArray(team.paragraphs) },
|
||||||
|
cta,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildServicesData(json: typeof servicesJson) {
|
||||||
|
const { meta, hero, details, support, cta } = json
|
||||||
|
return {
|
||||||
|
meta,
|
||||||
|
hero,
|
||||||
|
details: {
|
||||||
|
...details,
|
||||||
|
services: details.services.map((service) => ({
|
||||||
|
...service,
|
||||||
|
specs: {
|
||||||
|
...service.specs,
|
||||||
|
items: toStringArray(service.specs.items),
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
support,
|
||||||
|
cta,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
const payload = await getPayload({ config })
|
||||||
|
|
||||||
|
await payload.updateGlobal({ slug: 'home', data: buildHomeData(homeJson) })
|
||||||
|
payload.logger.info('Home global migrálva')
|
||||||
|
|
||||||
|
await payload.updateGlobal({ slug: 'about', data: buildAboutData(aboutJson) })
|
||||||
|
payload.logger.info('About global migrálva')
|
||||||
|
|
||||||
|
await payload.updateGlobal({ slug: 'services', data: buildServicesData(servicesJson) })
|
||||||
|
payload.logger.info('Services global migrálva')
|
||||||
|
|
||||||
|
await payload.updateGlobal({ slug: 'contact', data: contactJson })
|
||||||
|
payload.logger.info('Contact global migrálva')
|
||||||
|
|
||||||
|
await payload.updateGlobal({ slug: 'common', data: commonJson })
|
||||||
|
payload.logger.info('Common global migrálva')
|
||||||
|
|
||||||
|
payload.logger.info('MITHOME-87 migráció kész.')
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
run().catch((error) => {
|
||||||
|
console.error('Migráció sikertelen:', error)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
@@ -2,11 +2,11 @@ import type { Metadata, Viewport } from "next";
|
|||||||
import { Geist, Geist_Mono } from "next/font/google";
|
import { Geist, Geist_Mono } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
import Header from "../components/Header";
|
import Header from "../../components/Header";
|
||||||
import Footer from "../components/Footer";
|
import Footer from "../../components/Footer";
|
||||||
import { ThemeProvider } from "../components/ThemeProvider";
|
import { ThemeProvider } from "../../components/ThemeProvider";
|
||||||
import { siteConfig } from "../config/site";
|
import { siteConfig } from "../../config/site";
|
||||||
import { common } from "../content";
|
import { common } from "../../content";
|
||||||
|
|
||||||
const geistSans = Geist({
|
const geistSans = Geist({
|
||||||
variable: "--font-geist-sans",
|
variable: "--font-geist-sans",
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// Auto-generated by Payload (`npx payload generate:importmap`).
|
import { CollectionCards as CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 } from '@payloadcms/next/rsc'
|
||||||
// Kept empty until a collection/global config references a custom admin
|
|
||||||
// component — regenerate with the CLI command whenever one does.
|
/** @type import('payload').ImportMap */
|
||||||
export const importMap = {}
|
export const importMap = {
|
||||||
|
"@payloadcms/next/rsc#CollectionCards": CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import type { GlobalConfig } from 'payload'
|
||||||
|
|
||||||
|
import { stringArrayField } from './fields/stringArray'
|
||||||
|
|
||||||
|
/** Mirrors AboutPageContent (proto/src/content/types.ts) — MITHOME-87. */
|
||||||
|
export const About: GlobalConfig = {
|
||||||
|
slug: 'about',
|
||||||
|
admin: {
|
||||||
|
group: 'Oldalak',
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'meta',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'description', type: 'textarea', required: true },
|
||||||
|
{ name: 'ogDescription', type: 'textarea', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'hero',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'story',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
stringArrayField('paragraphs', 'Paragraphs'),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mission',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'text', required: true },
|
||||||
|
{
|
||||||
|
name: 'values',
|
||||||
|
type: 'array',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'description', type: 'textarea', required: true },
|
||||||
|
{ name: 'icon', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'team',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'text', required: true },
|
||||||
|
stringArrayField('paragraphs', 'Paragraphs'),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cta',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'textarea', required: true },
|
||||||
|
{ name: 'button', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import type { GlobalConfig } from 'payload'
|
||||||
|
|
||||||
|
/** Mirrors CommonContent (proto/src/content/types.ts) — MITHOME-87. */
|
||||||
|
export const Common: GlobalConfig = {
|
||||||
|
slug: 'common',
|
||||||
|
admin: {
|
||||||
|
group: 'Oldalak',
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'buttons',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'contact', type: 'text', required: true },
|
||||||
|
{ name: 'learnMore', type: 'text', required: true },
|
||||||
|
{ name: 'webmail', type: 'text', required: true },
|
||||||
|
{ name: 'sendMessage', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'labels',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'required', type: 'text', required: true },
|
||||||
|
{ name: 'features', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'validation',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'required', type: 'text', required: true },
|
||||||
|
{ name: 'invalidEmail', type: 'text', required: true },
|
||||||
|
{
|
||||||
|
name: 'minLength',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
admin: {
|
||||||
|
description: 'A {min} placeholder futásidőben cserélődik ki.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'staging',
|
||||||
|
type: 'group',
|
||||||
|
fields: [{ name: 'banner', type: 'text', required: true }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'footer',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'copyright',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
admin: {
|
||||||
|
description: 'A {year} placeholder futásidőben cserélődik ki.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ name: 'address', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'a11y',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'openMenu', type: 'text', required: true },
|
||||||
|
{ name: 'closeMenu', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
import type { GlobalConfig } from 'payload'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mirrors ContactPageContent (proto/src/content/types.ts) — MITHOME-87.
|
||||||
|
*
|
||||||
|
* WHY `gdpr.label` textarea és nem richText: a JSON forrás egy kézzel
|
||||||
|
* beírt <a> taget tartalmazó HTML string (lásd contact.json). A lexical
|
||||||
|
* richText mező más (JSON node-fa) szerializációt használna, ami extra
|
||||||
|
* migrációs/render logikát igényelne — ezt itt, bootstrap szinten nem
|
||||||
|
* bontjuk ki, marad egyszerű (HTML-t tartalmazó) szöveg mező.
|
||||||
|
*/
|
||||||
|
export const Contact: GlobalConfig = {
|
||||||
|
slug: 'contact',
|
||||||
|
admin: {
|
||||||
|
group: 'Oldalak',
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'meta',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'description', type: 'textarea', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'hero',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'form',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'successMessage', type: 'text', required: true },
|
||||||
|
{ name: 'errorMessage', type: 'text', required: true },
|
||||||
|
{
|
||||||
|
name: 'fields',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'label', type: 'text', required: true },
|
||||||
|
{ name: 'placeholder', type: 'text', required: true },
|
||||||
|
{ name: 'error', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'email',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'label', type: 'text', required: true },
|
||||||
|
{ name: 'placeholder', type: 'text', required: true },
|
||||||
|
{ name: 'errorRequired', type: 'text', required: true },
|
||||||
|
{ name: 'errorInvalid', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'subject',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'label', type: 'text', required: true },
|
||||||
|
{ name: 'placeholder', type: 'text', required: true },
|
||||||
|
{ name: 'error', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'message',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'label', type: 'text', required: true },
|
||||||
|
{ name: 'placeholder', type: 'text', required: true },
|
||||||
|
{ name: 'errorRequired', type: 'text', required: true },
|
||||||
|
{ name: 'errorMinLength', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'gdpr',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'label', type: 'textarea', required: true },
|
||||||
|
{ name: 'error', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ name: 'submitButton', type: 'text', required: true },
|
||||||
|
{ name: 'submittingButton', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'info',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{
|
||||||
|
name: 'email',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'responseTime', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'company',
|
||||||
|
type: 'group',
|
||||||
|
fields: [{ name: 'title', type: 'text', required: true }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'webmail',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'linkText', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'faq',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{
|
||||||
|
name: 'items',
|
||||||
|
type: 'array',
|
||||||
|
fields: [
|
||||||
|
{ name: 'question', type: 'text', required: true },
|
||||||
|
{ name: 'answer', type: 'textarea', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
import type { GlobalConfig } from 'payload'
|
||||||
|
|
||||||
|
import { stringArrayField } from './fields/stringArray'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mirrors HomePageContent (proto/src/content/types.ts) — MITHOME-87.
|
||||||
|
*
|
||||||
|
* WHY nincs `partners` mező: a home.partners.items a JSON-ban ma egy
|
||||||
|
* beágyazott lista, de a Payload oldalon önálló `Partners` collection lesz
|
||||||
|
* (logó = Media upload reference) — lásd MITHOME-89. Itt szándékosan
|
||||||
|
* kihagyjuk, nehogy két, egymásnak ellentmondó forrás legyen.
|
||||||
|
*/
|
||||||
|
export const Home: GlobalConfig = {
|
||||||
|
slug: 'home',
|
||||||
|
admin: {
|
||||||
|
group: 'Oldalak',
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'hero',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'text', required: true },
|
||||||
|
{ name: 'description', type: 'textarea', required: true },
|
||||||
|
stringArrayField('trustBullets', 'Trust bullets'),
|
||||||
|
{
|
||||||
|
name: 'cta',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'primary',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'text', type: 'text', required: true },
|
||||||
|
{ name: 'href', type: 'text', required: true },
|
||||||
|
{ name: 'external', type: 'checkbox', defaultValue: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'secondary',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'text', type: 'text', required: true },
|
||||||
|
{ name: 'href', type: 'text', required: true },
|
||||||
|
{ name: 'external', type: 'checkbox', defaultValue: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'about',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{
|
||||||
|
name: 'usps',
|
||||||
|
type: 'array',
|
||||||
|
fields: [
|
||||||
|
{ name: 'id', type: 'text', required: true },
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'description', type: 'textarea', required: true },
|
||||||
|
{ name: 'icon', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'services',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'text', required: true },
|
||||||
|
{
|
||||||
|
name: 'items',
|
||||||
|
type: 'array',
|
||||||
|
fields: [
|
||||||
|
{ name: 'id', type: 'text', required: true },
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'description', type: 'textarea', required: true },
|
||||||
|
{ name: 'icon', type: 'text', required: true },
|
||||||
|
stringArrayField('features', 'Features'),
|
||||||
|
{ name: 'ctaText', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cta',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'textarea', required: true },
|
||||||
|
{ name: 'button', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'serviceFeatures',
|
||||||
|
type: 'group',
|
||||||
|
fields: [{ name: 'title', type: 'text', required: true }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import type { GlobalConfig } from 'payload'
|
||||||
|
|
||||||
|
import { stringArrayField } from './fields/stringArray'
|
||||||
|
|
||||||
|
/** Mirrors ServicesPageContent (proto/src/content/types.ts) — MITHOME-87. */
|
||||||
|
export const Services: GlobalConfig = {
|
||||||
|
slug: 'services',
|
||||||
|
admin: {
|
||||||
|
group: 'Oldalak',
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'meta',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'description', type: 'textarea', required: true },
|
||||||
|
{ name: 'ogDescription', type: 'textarea', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'hero',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'details',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'text', required: true },
|
||||||
|
{
|
||||||
|
name: 'services',
|
||||||
|
type: 'array',
|
||||||
|
fields: [
|
||||||
|
{ name: 'icon', type: 'text', required: true },
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'description', type: 'textarea', required: true },
|
||||||
|
{
|
||||||
|
name: 'specs',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
stringArrayField('items', 'Items'),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'support',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'text', required: true },
|
||||||
|
{
|
||||||
|
name: 'channels',
|
||||||
|
type: 'array',
|
||||||
|
fields: [
|
||||||
|
{ name: 'icon', type: 'text', required: true },
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'description', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cta',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{ name: 'title', type: 'text', required: true },
|
||||||
|
{ name: 'subtitle', type: 'textarea', required: true },
|
||||||
|
{ name: 'primaryButton', type: 'text', required: true },
|
||||||
|
{ name: 'secondaryButton', type: 'text', required: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import type { ArrayField } from 'payload'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payload has no native "array of plain strings" field — the closest
|
||||||
|
* built-in shape is an array of one-field objects. Used for every
|
||||||
|
* string[] in the old content/types.ts (trustBullets, paragraphs,
|
||||||
|
* features, spec items, …) so the JSON -> Payload migration script has a
|
||||||
|
* single, consistent shape to transform into.
|
||||||
|
*/
|
||||||
|
export function stringArrayField(name: string, label?: string, required = false): ArrayField {
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
type: 'array',
|
||||||
|
label,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'value',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
required,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,11 +5,9 @@
|
|||||||
* (proto/src/lib/mongodb.ts) — Payload a `mongooseAdapter`-en keresztül
|
* (proto/src/lib/mongodb.ts) — Payload a `mongooseAdapter`-en keresztül
|
||||||
* ugyanabba az adatbázisba ír, nincs szükség külön DB-re/szerverre.
|
* ugyanabba az adatbázisba ír, nincs szükség külön DB-re/szerverre.
|
||||||
*
|
*
|
||||||
* Ez a fájl jelenleg csak a bootstrap-hez szükséges minimumot tartalmazza
|
* MITHOME-87: Home/About/Services/Contact/Common Globals hozzáadva — ezek
|
||||||
* (Users collection az admin bejelentkezéshez — Payload nem tud admin
|
* tükrözik a proto/src/content/pages/*.json + common.json struktúráját.
|
||||||
* felületet renderelni auth collection nélkül). A tényleges tartalom-
|
* A LegalPages/Partners/Media collectionök a MITHOME-88..89-ben kerülnek be.
|
||||||
* collectionök/globalok (Home, About, Services, Contact, Common, LegalPages,
|
|
||||||
* Partners, Media) a MITHOME-87..90 ticketekben kerülnek be.
|
|
||||||
*/
|
*/
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from 'url'
|
||||||
@@ -19,6 +17,11 @@ import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
|||||||
import sharp from 'sharp'
|
import sharp from 'sharp'
|
||||||
|
|
||||||
import { Users } from './collections/Users'
|
import { Users } from './collections/Users'
|
||||||
|
import { Home } from './globals/Home'
|
||||||
|
import { About } from './globals/About'
|
||||||
|
import { Services } from './globals/Services'
|
||||||
|
import { Contact } from './globals/Contact'
|
||||||
|
import { Common } from './globals/Common'
|
||||||
|
|
||||||
const filename = fileURLToPath(import.meta.url)
|
const filename = fileURLToPath(import.meta.url)
|
||||||
const dirname = path.dirname(filename)
|
const dirname = path.dirname(filename)
|
||||||
@@ -34,6 +37,8 @@ export default buildConfig({
|
|||||||
|
|
||||||
collections: [Users],
|
collections: [Users],
|
||||||
|
|
||||||
|
globals: [Home, About, Services, Contact, Common],
|
||||||
|
|
||||||
secret: process.env.PAYLOAD_SECRET || '',
|
secret: process.env.PAYLOAD_SECRET || '',
|
||||||
|
|
||||||
typescript: {
|
typescript: {
|
||||||
|
|||||||
Reference in New Issue
Block a user