chore: migrate to payload / nextjs

This commit is contained in:
syntaxbullet
2026-06-16 13:02:47 +02:00
parent aff090b693
commit 6b395e5735
257 changed files with 33616 additions and 1451 deletions

View File

@@ -0,0 +1,47 @@
import type { TextFieldSingleValidation } from 'payload'
import {
BoldFeature,
ItalicFeature,
LinkFeature,
ParagraphFeature,
lexicalEditor,
UnderlineFeature,
type LinkFields,
} from '@payloadcms/richtext-lexical'
export const defaultLexical = lexicalEditor({
features: [
ParagraphFeature(),
UnderlineFeature(),
BoldFeature(),
ItalicFeature(),
LinkFeature({
enabledCollections: ['pages', 'posts'],
fields: ({ defaultFields }) => {
const defaultFieldsWithoutUrl = defaultFields.filter((field) => {
if ('name' in field && field.name === 'url') return false
return true
})
return [
...defaultFieldsWithoutUrl,
{
name: 'url',
type: 'text',
admin: {
condition: (_data, siblingData) => siblingData?.linkType !== 'internal',
},
label: ({ t }) => t('fields:enterURL'),
required: true,
validate: ((value, options) => {
if ((options?.siblingData as LinkFields)?.linkType === 'internal') {
return true // no validation needed, as no url should exist for internal links
}
return value ? true : 'URL is required'
}) as TextFieldSingleValidation,
},
]
},
}),
],
})

139
src/fields/link.ts Normal file
View File

@@ -0,0 +1,139 @@
import type { Field, GroupField } from 'payload'
import deepMerge from '@/utilities/deepMerge'
export type LinkAppearances = 'default' | 'outline'
export const appearanceOptions: Record<LinkAppearances, { label: string; value: string }> = {
default: {
label: 'Default',
value: 'default',
},
outline: {
label: 'Outline',
value: 'outline',
},
}
type LinkType = (options?: {
appearances?: LinkAppearances[] | false
disableLabel?: boolean
overrides?: Partial<GroupField>
}) => Field
export const link: LinkType = ({ appearances, disableLabel = false, overrides = {} } = {}) => {
const linkResult: GroupField = {
name: 'link',
type: 'group',
admin: {
hideGutter: true,
},
fields: [
{
type: 'row',
fields: [
{
name: 'type',
type: 'radio',
admin: {
layout: 'horizontal',
width: '50%',
},
defaultValue: 'reference',
options: [
{
label: 'Internal link',
value: 'reference',
},
{
label: 'Custom URL',
value: 'custom',
},
],
},
{
name: 'newTab',
type: 'checkbox',
admin: {
style: {
alignSelf: 'flex-end',
},
width: '50%',
},
label: 'Open in new tab',
},
],
},
],
}
const linkTypes: Field[] = [
{
name: 'reference',
type: 'relationship',
admin: {
condition: (_, siblingData) => siblingData?.type === 'reference',
},
label: 'Document to link to',
relationTo: ['pages', 'posts'],
required: true,
},
{
name: 'url',
type: 'text',
admin: {
condition: (_, siblingData) => siblingData?.type === 'custom',
},
label: 'Custom URL',
required: true,
},
]
if (!disableLabel) {
linkTypes.map((linkType) => ({
...linkType,
admin: {
...linkType.admin,
width: '50%',
},
}))
linkResult.fields.push({
type: 'row',
fields: [
...linkTypes,
{
name: 'label',
type: 'text',
admin: {
width: '50%',
},
label: 'Label',
required: true,
},
],
})
} else {
linkResult.fields = [...linkResult.fields, ...linkTypes]
}
if (appearances !== false) {
let appearanceOptionsToUse = [appearanceOptions.default, appearanceOptions.outline]
if (appearances) {
appearanceOptionsToUse = appearances.map((appearance) => appearanceOptions[appearance])
}
linkResult.fields.push({
name: 'appearance',
type: 'select',
admin: {
description: 'Choose how the link should be rendered.',
},
defaultValue: 'default',
options: appearanceOptionsToUse,
})
}
return deepMerge(linkResult, overrides)
}

28
src/fields/linkGroup.ts Normal file
View File

@@ -0,0 +1,28 @@
import type { ArrayField, Field } from 'payload'
import type { LinkAppearances } from './link'
import deepMerge from '@/utilities/deepMerge'
import { link } from './link'
type LinkGroupType = (options?: {
appearances?: LinkAppearances[] | false
overrides?: Partial<ArrayField>
}) => Field
export const linkGroup: LinkGroupType = ({ appearances, overrides = {} } = {}) => {
const generatedLinkGroup: Field = {
name: 'links',
type: 'array',
fields: [
link({
appearances,
}),
],
admin: {
initCollapsed: true,
},
}
return deepMerge(generatedLinkGroup, overrides)
}