chore(templates): update missing changes in vercel website template (#10827)

This PR migrates some changes that had been made to the website template
and had not been ported to the website template with vercel.

Ideally, so that this does not happen again in the future and we do not
have to do this manually, we could have a script in CI.
This commit is contained in:
Germán Jabloñski
2025-01-29 00:39:47 -03:00
committed by GitHub
parent 52f86c7780
commit c75c6ce6c9
38 changed files with 8288 additions and 3466 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -13,31 +13,17 @@ export interface Config {
collections: {
users: User;
media: Media;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
};
collectionsJoins: {};
collectionsSelect: {
users: UsersSelect<false> | UsersSelect<true>;
media: MediaSelect<false> | MediaSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
};
db: {
defaultIDType: string;
};
globals: {};
globalsSelect: {};
locale: null;
user: User & {
collection: 'users';
};
jobs: {
tasks: unknown;
workflows: unknown;
};
}
export interface UserAuthOperations {
forgotPassword: {
@@ -93,29 +79,6 @@ export interface Media {
focalX?: number | null;
focalY?: number | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents".
*/
export interface PayloadLockedDocument {
id: string;
document?:
| ({
relationTo: 'users';
value: string | User;
} | null)
| ({
relationTo: 'media';
value: string | Media;
} | null);
globalSlug?: string | null;
user: {
relationTo: 'users';
value: string | User;
};
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences".
@@ -150,71 +113,6 @@ export interface PayloadMigration {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users_select".
*/
export interface UsersSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
email?: T;
resetPasswordToken?: T;
resetPasswordExpiration?: T;
salt?: T;
hash?: T;
loginAttempts?: T;
lockUntil?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media_select".
*/
export interface MediaSelect<T extends boolean = true> {
alt?: T;
updatedAt?: T;
createdAt?: T;
url?: T;
thumbnailURL?: T;
filename?: T;
mimeType?: T;
filesize?: T;
width?: T;
height?: T;
focalX?: T;
focalY?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents_select".
*/
export interface PayloadLockedDocumentsSelect<T extends boolean = true> {
document?: T;
globalSlug?: T;
user?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences_select".
*/
export interface PayloadPreferencesSelect<T extends boolean = true> {
user?: T;
key?: T;
value?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-migrations_select".
*/
export interface PayloadMigrationsSelect<T extends boolean = true> {
name?: T;
batch?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth".

File diff suppressed because it is too large Load Diff

View File

@@ -6,17 +6,16 @@
"type": "module",
"scripts": {
"build": "cross-env NODE_OPTIONS=--no-deprecation next build",
"ci": "payload migrate && pnpm build",
"dev": "cross-env NODE_OPTIONS=--no-deprecation next dev",
"devsafe": "rm -rf .next && cross-env NODE_OPTIONS=--no-deprecation next dev",
"generate:importmap": "cross-env NODE_OPTIONS=--no-deprecation payload generate:importmap",
"generate:types": "cross-env NODE_OPTIONS=--no-deprecation payload generate:types",
"lint": "cross-env NODE_OPTIONS=--no-deprecation next lint",
"payload": "cross-env NODE_OPTIONS=--no-deprecation payload",
"start": "cross-env NODE_OPTIONS=--no-deprecation next start"
"start": "cross-env NODE_OPTIONS=--no-deprecation next start",
"ci": "payload migrate && pnpm build"
},
"dependencies": {
"@payloadcms/db-postgres": "latest",
"@payloadcms/next": "latest",
"@payloadcms/payload-cloud": "latest",
"@payloadcms/richtext-lexical": "latest",
@@ -26,7 +25,8 @@
"payload": "latest",
"react": "19.0.0",
"react-dom": "19.0.0",
"sharp": "0.32.6"
"sharp": "0.32.6",
"@payloadcms/db-postgres": "latest"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",

View File

@@ -1,5 +1,5 @@
{
"id": "2be5b1e5-29bb-4d50-9d48-d8a2f47cd65e",
"id": "9c4682b1-937a-4c35-be39-111e09bf4d0b",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",

View File

@@ -1,9 +1,9 @@
import * as migration_20250114_010521_initial from './20250114_010521_initial'
import * as migration_20250129_033106_initial from './20250129_033106_initial'
export const migrations = [
{
up: migration_20250114_010521_initial.up,
down: migration_20250114_010521_initial.down,
name: '20250114_010521_initial',
up: migration_20250129_033106_initial.up,
down: migration_20250129_033106_initial.down,
name: '20250129_033106_initial',
},
]

View File

@@ -19,13 +19,13 @@
"@payloadcms/next": "latest",
"@payloadcms/payload-cloud": "latest",
"@payloadcms/richtext-lexical": "latest",
"@payloadcms/storage-vercel-blob": "latest",
"cross-env": "^7.0.3",
"graphql": "^16.8.1",
"next": "15.1.5",
"payload": "latest",
"react": "19.0.0",
"react-dom": "19.0.0"
"react-dom": "19.0.0",
"@payloadcms/storage-vercel-blob": "latest"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",

View File

@@ -13,31 +13,17 @@ export interface Config {
collections: {
users: User;
media: Media;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
};
collectionsJoins: {};
collectionsSelect: {
users: UsersSelect<false> | UsersSelect<true>;
media: MediaSelect<false> | MediaSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
};
db: {
defaultIDType: string;
};
globals: {};
globalsSelect: {};
locale: null;
user: User & {
collection: 'users';
};
jobs: {
tasks: unknown;
workflows: unknown;
};
}
export interface UserAuthOperations {
forgotPassword: {
@@ -93,29 +79,6 @@ export interface Media {
focalX?: number | null;
focalY?: number | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents".
*/
export interface PayloadLockedDocument {
id: string;
document?:
| ({
relationTo: 'users';
value: string | User;
} | null)
| ({
relationTo: 'media';
value: string | Media;
} | null);
globalSlug?: string | null;
user: {
relationTo: 'users';
value: string | User;
};
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences".
@@ -150,71 +113,6 @@ export interface PayloadMigration {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users_select".
*/
export interface UsersSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
email?: T;
resetPasswordToken?: T;
resetPasswordExpiration?: T;
salt?: T;
hash?: T;
loginAttempts?: T;
lockUntil?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media_select".
*/
export interface MediaSelect<T extends boolean = true> {
alt?: T;
updatedAt?: T;
createdAt?: T;
url?: T;
thumbnailURL?: T;
filename?: T;
mimeType?: T;
filesize?: T;
width?: T;
height?: T;
focalX?: T;
focalY?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents_select".
*/
export interface PayloadLockedDocumentsSelect<T extends boolean = true> {
document?: T;
globalSlug?: T;
user?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences_select".
*/
export interface PayloadPreferencesSelect<T extends boolean = true> {
user?: T;
key?: T;
value?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-migrations_select".
*/
export interface PayloadMigrationsSelect<T extends boolean = true> {
name?: T;
batch?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth".

View File

@@ -6,27 +6,27 @@
"type": "module",
"scripts": {
"build": "cross-env NODE_OPTIONS=--no-deprecation next build",
"ci": "payload migrate && pnpm build",
"dev": "cross-env NODE_OPTIONS=--no-deprecation next dev",
"devsafe": "rm -rf .next && cross-env NODE_OPTIONS=--no-deprecation next dev",
"generate:importmap": "cross-env NODE_OPTIONS=--no-deprecation payload generate:importmap",
"generate:types": "cross-env NODE_OPTIONS=--no-deprecation payload generate:types",
"lint": "cross-env NODE_OPTIONS=--no-deprecation next lint",
"payload": "cross-env NODE_OPTIONS=--no-deprecation payload",
"start": "cross-env NODE_OPTIONS=--no-deprecation next start"
"start": "cross-env NODE_OPTIONS=--no-deprecation next start",
"ci": "payload migrate && pnpm build"
},
"dependencies": {
"@payloadcms/db-vercel-postgres": "latest",
"@payloadcms/next": "latest",
"@payloadcms/payload-cloud": "latest",
"@payloadcms/richtext-lexical": "latest",
"@payloadcms/storage-vercel-blob": "latest",
"cross-env": "^7.0.3",
"graphql": "^16.8.1",
"next": "15.1.5",
"payload": "latest",
"react": "19.0.0",
"react-dom": "19.0.0"
"react-dom": "19.0.0",
"@payloadcms/db-vercel-postgres": "latest",
"@payloadcms/storage-vercel-blob": "latest"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",

View File

@@ -1,5 +1,5 @@
{
"id": "8695c39d-451b-406a-b700-cfded95da90e",
"id": "a5487bec-f1c8-4892-a6cf-871d624aefeb",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",

View File

@@ -1,6 +1,6 @@
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-vercel-postgres'
export async function up({ db }: MigrateUpArgs): Promise<void> {
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
CREATE TABLE IF NOT EXISTS "users" (
"id" serial PRIMARY KEY NOT NULL,
@@ -126,7 +126,7 @@ export async function up({ db }: MigrateUpArgs): Promise<void> {
CREATE INDEX IF NOT EXISTS "payload_migrations_created_at_idx" ON "payload_migrations" USING btree ("created_at");`)
}
export async function down({ db }: MigrateDownArgs): Promise<void> {
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
DROP TABLE "users" CASCADE;
DROP TABLE "media" CASCADE;

View File

@@ -1,9 +1,9 @@
import * as migration_20250114_010454_initial from './20250114_010454_initial'
import * as migration_20250129_033058_initial from './20250129_033058_initial'
export const migrations = [
{
up: migration_20250114_010454_initial.up,
down: migration_20250114_010454_initial.down,
name: '20250114_010454_initial',
up: migration_20250129_033058_initial.up,
down: migration_20250129_033058_initial.down,
name: '20250129_033058_initial',
},
]

View File

@@ -30,6 +30,9 @@ const eslintConfig = [
],
},
},
{
ignores: ['.next/'],
},
]
export default eslintConfig

View File

@@ -7,7 +7,6 @@
"scripts": {
"build": "cross-env NODE_OPTIONS=--no-deprecation next build",
"postbuild": "next-sitemap --config next-sitemap.config.cjs",
"ci": "payload migrate && pnpm build",
"dev": "cross-env NODE_OPTIONS=--no-deprecation next dev",
"dev:prod": "cross-env NODE_OPTIONS=--no-deprecation rm -rf .next && pnpm build && pnpm start",
"generate:importmap": "cross-env NODE_OPTIONS=--no-deprecation payload generate:importmap",
@@ -17,10 +16,10 @@
"lint:fix": "cross-env NODE_OPTIONS=--no-deprecation next lint --fix",
"payload": "cross-env NODE_OPTIONS=--no-deprecation payload",
"reinstall": "cross-env NODE_OPTIONS=--no-deprecation rm -rf node_modules && rm pnpm-lock.yaml && pnpm --ignore-workspace install",
"start": "cross-env NODE_OPTIONS=--no-deprecation next start"
"start": "cross-env NODE_OPTIONS=--no-deprecation next start",
"ci": "payload migrate && pnpm build"
},
"dependencies": {
"@payloadcms/db-vercel-postgres": "latest",
"@payloadcms/live-preview-react": "latest",
"@payloadcms/next": "latest",
"@payloadcms/payload-cloud": "latest",
@@ -30,7 +29,6 @@
"@payloadcms/plugin-search": "latest",
"@payloadcms/plugin-seo": "latest",
"@payloadcms/richtext-lexical": "latest",
"@payloadcms/storage-vercel-blob": "latest",
"@payloadcms/ui": "latest",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-label": "^2.0.2",
@@ -52,7 +50,9 @@
"react-hook-form": "7.45.4",
"sharp": "0.32.6",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"@payloadcms/db-vercel-postgres": "latest",
"@payloadcms/storage-vercel-blob": "latest"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",

View File

@@ -1,6 +1,8 @@
export default {
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
export default config

View File

@@ -81,7 +81,7 @@ export default async function Page({ params: paramsPromise }: Args) {
)
}
export async function generateMetadata({ params: paramsPromise }): Promise<Metadata> {
export async function generateMetadata({ params: paramsPromise }: Args): Promise<Metadata> {
const { slug = 'home' } = await paramsPromise
const page = await queryPageBySlug({
slug,

View File

@@ -1,5 +1,5 @@
'use client'
import type { Form as FormType } from '@payloadcms/plugin-form-builder/types'
import type { FormFieldBlock, Form as FormType } from '@payloadcms/plugin-form-builder/types'
import { useRouter } from 'next/navigation'
import React, { useCallback, useState } from 'react'
@@ -8,20 +8,9 @@ import RichText from '@/components/RichText'
import { Button } from '@/components/ui/button'
import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'
import { buildInitialFormState } from './buildInitialFormState'
import { fields } from './fields'
import { getClientSideURL } from '@/utilities/getURL'
export type Value = unknown
export interface Property {
[key: string]: Value
}
export interface Data {
[key: string]: Property | Property[]
}
export type FormBlockType = {
blockName?: string
blockType?: 'formBlock'
@@ -43,7 +32,7 @@ export const FormBlock: React.FC<
} = props
const formMethods = useForm({
defaultValues: buildInitialFormState(formFromProps.fields),
defaultValues: formFromProps.fields,
})
const {
control,
@@ -58,7 +47,7 @@ export const FormBlock: React.FC<
const router = useRouter()
const onSubmit = useCallback(
(data: Data) => {
(data: FormFieldBlock[]) => {
let loadingTimerID: ReturnType<typeof setTimeout>
const submitForm = async () => {
setError(undefined)
@@ -143,7 +132,7 @@ export const FormBlock: React.FC<
formFromProps.fields &&
formFromProps.fields?.map((field, index) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Field: React.FC<any> = fields?.[field.blockType]
const Field: React.FC<any> = fields?.[field.blockType as keyof typeof fields]
if (Field) {
return (
<div className="mb-6 last:mb-0" key={index}>

View File

@@ -4,7 +4,7 @@ import React from 'react'
import { Width } from '../Width'
import { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'
export const Message: React.FC = ({ message }: { message: SerializedEditorState }) => {
export const Message: React.FC<{ message: SerializedEditorState }> = ({ message }) => {
return (
<Width className="my-12" width="100">
{message && <RichText data={message} />}

View File

@@ -1,44 +0,0 @@
import type { FormFieldBlock } from '@payloadcms/plugin-form-builder/types'
export const buildInitialFormState = (fields: FormFieldBlock[]) => {
return fields?.reduce((initialSchema, field) => {
if (field.blockType === 'checkbox') {
return {
...initialSchema,
[field.name]: field.defaultValue,
}
}
if (field.blockType === 'country') {
return {
...initialSchema,
[field.name]: '',
}
}
if (field.blockType === 'email') {
return {
...initialSchema,
[field.name]: '',
}
}
if (field.blockType === 'text') {
return {
...initialSchema,
[field.name]: '',
}
}
if (field.blockType === 'select') {
return {
...initialSchema,
[field.name]: '',
}
}
if (field.blockType === 'state') {
return {
...initialSchema,
[field.name]: '',
}
}
return initialSchema
}, {})
}

View File

@@ -125,7 +125,7 @@ export const Pages: CollectionConfig<'pages'> = {
hooks: {
afterChange: [revalidatePage],
beforeChange: [populatePublishedAt],
beforeDelete: [revalidateDelete],
afterDelete: [revalidateDelete],
},
versions: {
drafts: {

View File

@@ -1,6 +1,6 @@
'use client'
import type { PayloadAdminBarProps } from 'payload-admin-bar'
import type { PayloadAdminBarProps, PayloadMeUser } from 'payload-admin-bar'
import { cn } from '@/utilities/ui'
import { useSelectedLayoutSegments } from 'next/navigation'
@@ -37,11 +37,13 @@ export const AdminBar: React.FC<{
const { adminBarProps } = props || {}
const segments = useSelectedLayoutSegments()
const [show, setShow] = useState(false)
const collection = collectionLabels?.[segments?.[1]] ? segments?.[1] : 'pages'
const collection = (
collectionLabels[segments?.[1] as keyof typeof collectionLabels] ? segments[1] : 'pages'
) as keyof typeof collectionLabels
const router = useRouter()
const onAuthChange = React.useCallback((user) => {
setShow(user?.id)
const onAuthChange = React.useCallback((user: PayloadMeUser) => {
setShow(Boolean(user?.id))
}, [])
return (

View File

@@ -17,10 +17,10 @@ const SuccessMessage: React.FC = () => (
export const SeedButton: React.FC = () => {
const [loading, setLoading] = useState(false)
const [seeded, setSeeded] = useState(false)
const [error, setError] = useState(null)
const [error, setError] = useState<null | string>(null)
const handleClick = useCallback(
async (e) => {
async (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
if (seeded) {
@@ -65,7 +65,8 @@ export const SeedButton: React.FC = () => {
},
)
} catch (err) {
setError(err)
const error = err instanceof Error ? err.message : String(err)
setError(error)
}
},
[loading, seeded, error],

View File

@@ -14,7 +14,7 @@ const defaultCollectionLabels = {
export const PageRange: React.FC<{
className?: string
collection?: string
collection?: keyof typeof defaultCollectionLabels
collectionLabels?: {
plural?: string
singular?: string
@@ -39,7 +39,10 @@ export const PageRange: React.FC<{
if (totalDocs && indexEnd > totalDocs) indexEnd = totalDocs
const { plural, singular } =
collectionLabelsFromProps || defaultCollectionLabels[collection || ''] || defaultLabels || {}
collectionLabelsFromProps ||
(collection ? defaultCollectionLabels[collection] : undefined) ||
defaultLabels ||
{}
return (
<div className={[className, 'font-semibold'].filter(Boolean).join(' ')}>

View File

@@ -1,122 +0,0 @@
//This copy-and-pasted from lexical here: https://github.com/facebook/lexical/blob/c2ceee223f46543d12c574e62155e619f9a18a5d/packages/lexical/src/LexicalConstants.ts
import type { ElementFormatType, TextFormatType } from '@payloadcms/richtext-lexical/lexical'
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
// DOM
export const DOM_ELEMENT_TYPE = 1
export const DOM_TEXT_TYPE = 3
// Reconciling
export const NO_DIRTY_NODES = 0
export const HAS_DIRTY_NODES = 1
export const FULL_RECONCILE = 2
// Text node modes
export const IS_NORMAL = 0
export const IS_TOKEN = 1
export const IS_SEGMENTED = 2
// IS_INERT = 3
// Text node formatting
export const IS_BOLD = 1
export const IS_ITALIC = 1 << 1
export const IS_STRIKETHROUGH = 1 << 2
export const IS_UNDERLINE = 1 << 3
export const IS_CODE = 1 << 4
export const IS_SUBSCRIPT = 1 << 5
export const IS_SUPERSCRIPT = 1 << 6
export const IS_HIGHLIGHT = 1 << 7
export const IS_ALL_FORMATTING =
IS_BOLD |
IS_ITALIC |
IS_STRIKETHROUGH |
IS_UNDERLINE |
IS_CODE |
IS_SUBSCRIPT |
IS_SUPERSCRIPT |
IS_HIGHLIGHT
// Text node details
export const IS_DIRECTIONLESS = 1
export const IS_UNMERGEABLE = 1 << 1
// Element node formatting
export const IS_ALIGN_LEFT = 1
export const IS_ALIGN_CENTER = 2
export const IS_ALIGN_RIGHT = 3
export const IS_ALIGN_JUSTIFY = 4
export const IS_ALIGN_START = 5
export const IS_ALIGN_END = 6
// Reconciliation
export const NON_BREAKING_SPACE = '\u00A0'
export const DOUBLE_LINE_BREAK = '\n\n'
// For FF, we need to use a non-breaking space, or it gets composition
// in a stuck state.
const RTL = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC'
const LTR =
'A-Za-z\u00C0-\u00D6\u00D8-\u00F6' +
'\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF\u200E\u2C00-\uFB1C' +
'\uFE00-\uFE6F\uFEFD-\uFFFF'
export const RTL_REGEX = new RegExp('^[^' + LTR + ']*[' + RTL + ']')
export const LTR_REGEX = new RegExp('^[^' + RTL + ']*[' + LTR + ']')
export const TEXT_TYPE_TO_FORMAT: Record<TextFormatType | string, number> = {
bold: IS_BOLD,
code: IS_CODE,
highlight: IS_HIGHLIGHT,
italic: IS_ITALIC,
strikethrough: IS_STRIKETHROUGH,
subscript: IS_SUBSCRIPT,
superscript: IS_SUPERSCRIPT,
underline: IS_UNDERLINE,
}
export const DETAIL_TYPE_TO_DETAIL: Record<string, number> = {
directionless: IS_DIRECTIONLESS,
unmergeable: IS_UNMERGEABLE,
}
export const ELEMENT_TYPE_TO_FORMAT: Record<Exclude<ElementFormatType, ''>, number> = {
center: IS_ALIGN_CENTER,
end: IS_ALIGN_END,
justify: IS_ALIGN_JUSTIFY,
left: IS_ALIGN_LEFT,
right: IS_ALIGN_RIGHT,
start: IS_ALIGN_START,
}
export const ELEMENT_FORMAT_TO_TYPE: Record<number, ElementFormatType> = {
[IS_ALIGN_CENTER]: 'center',
[IS_ALIGN_END]: 'end',
[IS_ALIGN_JUSTIFY]: 'justify',
[IS_ALIGN_LEFT]: 'left',
[IS_ALIGN_RIGHT]: 'right',
[IS_ALIGN_START]: 'start',
}
export const TEXT_MODE_TO_TYPE: Record<string, 0 | 1 | 2> = {
normal: IS_NORMAL,
segmented: IS_SEGMENTED,
token: IS_TOKEN,
}
export const TEXT_TYPE_TO_MODE: Record<number, string> = {
[IS_NORMAL]: 'normal',
[IS_SEGMENTED]: 'segmented',
[IS_TOKEN]: 'token',
}

View File

@@ -1,209 +0,0 @@
import { BannerBlock } from '@/blocks/Banner/Component'
import { CallToActionBlock } from '@/blocks/CallToAction/Component'
import { CodeBlock, CodeBlockProps } from '@/blocks/Code/Component'
import { MediaBlock } from '@/blocks/MediaBlock/Component'
import React, { Fragment, JSX } from 'react'
import { CMSLink } from '@/components/Link'
import { DefaultNodeTypes, SerializedBlockNode } from '@payloadcms/richtext-lexical'
import type { BannerBlock as BannerBlockProps } from '@/payload-types'
import {
IS_BOLD,
IS_CODE,
IS_ITALIC,
IS_STRIKETHROUGH,
IS_SUBSCRIPT,
IS_SUPERSCRIPT,
IS_UNDERLINE,
} from './nodeFormat'
import type {
CallToActionBlock as CTABlockProps,
MediaBlock as MediaBlockProps,
} from '@/payload-types'
export type NodeTypes =
| DefaultNodeTypes
| SerializedBlockNode<CTABlockProps | MediaBlockProps | BannerBlockProps | CodeBlockProps>
type Props = {
nodes: NodeTypes[]
}
export function serializeLexical({ nodes }: Props): JSX.Element {
return (
<Fragment>
{nodes?.map((node, index): JSX.Element | null => {
if (node == null) {
return null
}
if (node.type === 'text') {
let text = <React.Fragment key={index}>{node.text}</React.Fragment>
if (node.format & IS_BOLD) {
text = <strong key={index}>{text}</strong>
}
if (node.format & IS_ITALIC) {
text = <em key={index}>{text}</em>
}
if (node.format & IS_STRIKETHROUGH) {
text = (
<span key={index} style={{ textDecoration: 'line-through' }}>
{text}
</span>
)
}
if (node.format & IS_UNDERLINE) {
text = (
<span key={index} style={{ textDecoration: 'underline' }}>
{text}
</span>
)
}
if (node.format & IS_CODE) {
text = <code key={index}>{node.text}</code>
}
if (node.format & IS_SUBSCRIPT) {
text = <sub key={index}>{text}</sub>
}
if (node.format & IS_SUPERSCRIPT) {
text = <sup key={index}>{text}</sup>
}
return text
}
// NOTE: Hacky fix for
// https://github.com/facebook/lexical/blob/d10c4e6e55261b2fdd7d1845aed46151d0f06a8c/packages/lexical-list/src/LexicalListItemNode.ts#L133
// which does not return checked: false (only true - i.e. there is no prop for false)
const serializedChildrenFn = (node: NodeTypes): JSX.Element | null => {
if (node.children == null) {
return null
} else {
if (node?.type === 'list' && node?.listType === 'check') {
for (const item of node.children) {
if ('checked' in item) {
if (!item?.checked) {
item.checked = false
}
}
}
}
return serializeLexical({ nodes: node.children as NodeTypes[] })
}
}
const serializedChildren = 'children' in node ? serializedChildrenFn(node) : ''
if (node.type === 'block') {
const block = node.fields
const blockType = block?.blockType
if (!block || !blockType) {
return null
}
switch (blockType) {
case 'cta':
return <CallToActionBlock key={index} {...block} />
case 'mediaBlock':
return (
<MediaBlock
className="col-start-1 col-span-3"
imgClassName="m-0"
key={index}
{...block}
captionClassName="mx-auto max-w-[48rem]"
enableGutter={false}
disableInnerContainer={true}
/>
)
case 'banner':
return <BannerBlock className="col-start-2 mb-4" key={index} {...block} />
case 'code':
return <CodeBlock className="col-start-2" key={index} {...block} />
default:
return null
}
} else {
switch (node.type) {
case 'linebreak': {
return <br className="col-start-2" key={index} />
}
case 'paragraph': {
return (
<p className="col-start-2" key={index}>
{serializedChildren}
</p>
)
}
case 'heading': {
const Tag = node?.tag
return (
<Tag className="col-start-2" key={index}>
{serializedChildren}
</Tag>
)
}
case 'list': {
const Tag = node?.tag
return (
<Tag className="list col-start-2" key={index}>
{serializedChildren}
</Tag>
)
}
case 'listitem': {
if (node?.checked != null) {
return (
<li
aria-checked={node.checked ? 'true' : 'false'}
className={` ${node.checked ? '' : ''}`}
key={index}
role="checkbox"
tabIndex={-1}
value={node?.value}
>
{serializedChildren}
</li>
)
} else {
return (
<li key={index} value={node?.value}>
{serializedChildren}
</li>
)
}
}
case 'quote': {
return (
<blockquote className="col-start-2" key={index}>
{serializedChildren}
</blockquote>
)
}
case 'link': {
const fields = node.fields
return (
<CMSLink
key={index}
newTab={Boolean(fields?.newTab)}
// @ts-expect-error - this should disappear when upgrading to the latest version of Payload
reference={fields.doc}
type={fields.linkType === 'internal' ? 'reference' : 'custom'}
url={fields.url}
>
{serializedChildren}
</CMSLink>
)
}
default:
return null
}
}
})}
</Fragment>
)
}

View File

@@ -10,7 +10,6 @@ export const contact: Partial<Page> = {
{
blockType: 'formBlock',
enableIntro: true,
// @ts-expect-error this should dissapear when upgrading to the latest version of Payload
form: '{{CONTACT_FORM_ID}}',
introContent: {
root: {

View File

@@ -84,7 +84,7 @@ export const homeStatic: Page = {
title: 'Payload Website Template',
},
title: 'Home',
id: 0,
id: '',
layout: [],
updatedAt: '',
createdAt: '',

View File

@@ -23,7 +23,6 @@ export const home: RequiredDataFromCollectionSlug<'pages'> = {
},
},
],
// @ts-expect-error - this should disappear when upgrading to the latest version of Payload
media: '{{IMAGE_1}}',
richText: {
root: {
@@ -502,7 +501,6 @@ export const home: RequiredDataFromCollectionSlug<'pages'> = {
{
blockName: 'Media Block',
blockType: 'mediaBlock',
// @ts-expect-error - this should disappear when upgrading to the latest version of Payload
media: '{{IMAGE_2}}',
},
{
@@ -659,7 +657,6 @@ export const home: RequiredDataFromCollectionSlug<'pages'> = {
],
meta: {
description: 'An open-source website built with Payload and Next.js.',
// @ts-expect-error - this should disappear when upgrading to the latest version of Payload
image: '{{IMAGE_1}}',
title: 'Payload Website Template',
},

View File

@@ -1,4 +1,4 @@
import type { Field } from 'payload'
import type { Field, GroupField } from 'payload'
import deepMerge from '@/utilities/deepMerge'
@@ -18,11 +18,11 @@ export const appearanceOptions: Record<LinkAppearances, { label: string; value:
type LinkType = (options?: {
appearances?: LinkAppearances[] | false
disableLabel?: boolean
overrides?: Record<string, unknown>
overrides?: Partial<GroupField>
}) => Field
export const link: LinkType = ({ appearances, disableLabel = false, overrides = {} } = {}) => {
const linkResult: Field = {
const linkResult: GroupField = {
name: 'link',
type: 'group',
admin: {

View File

@@ -53,7 +53,7 @@ export const SlugComponent: React.FC<SlugComponentProps> = ({
}, [targetFieldValue, checkboxValue, setValue, value])
const handleLock = useCallback(
(e) => {
(e: React.MouseEvent<Element>) => {
e.preventDefault()
dispatchFields({

View File

@@ -1,5 +1,5 @@
{
"id": "4744a0d7-07ca-4325-9494-f4ec014a6818",
"id": "b2ff7f1c-8dd6-4188-adb6-abfc6304df24",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",

View File

@@ -1,6 +1,6 @@
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-vercel-postgres'
export async function up({ db }: MigrateUpArgs): Promise<void> {
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
CREATE TYPE "public"."enum_pages_hero_links_link_type" AS ENUM('reference', 'custom');
CREATE TYPE "public"."enum_pages_hero_links_link_appearance" AS ENUM('default', 'outline');
@@ -1558,7 +1558,7 @@ export async function up({ db }: MigrateUpArgs): Promise<void> {
CREATE INDEX IF NOT EXISTS "footer_rels_posts_id_idx" ON "footer_rels" USING btree ("posts_id");`)
}
export async function down({ db }: MigrateDownArgs): Promise<void> {
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
DROP TABLE "pages_hero_links" CASCADE;
DROP TABLE "pages_blocks_cta_links" CASCADE;

View File

@@ -1,9 +1,9 @@
import * as migration_20250114_010510_initial from './20250114_010510_initial'
import * as migration_20250129_033102_initial from './20250129_033102_initial'
export const migrations = [
{
up: migration_20250114_010510_initial.up,
down: migration_20250114_010510_initial.down,
name: '20250114_010510_initial',
up: migration_20250129_033102_initial.up,
down: migration_20250129_033102_initial.down,
name: '20250129_033102_initial',
},
]

View File

@@ -14,15 +14,11 @@ export const formatAuthors = (
authors: NonNullable<NonNullable<Post['populatedAuthors']>[number]>[],
) => {
// Ensure we don't have any authors without a name
const filteredAuthors = authors.filter((author) => Boolean(author.name))
const authorNames = authors.map((author) => author.name).filter(Boolean)
if (filteredAuthors.length === 0) return ''
if (filteredAuthors.length === 1) return filteredAuthors[0].name
if (filteredAuthors.length === 2)
return `${filteredAuthors[0].name} and ${filteredAuthors[1].name}`
if (authorNames.length === 0) return ''
if (authorNames.length === 1) return authorNames[0]
if (authorNames.length === 2) return `${authorNames[0]} and ${authorNames[1]}`
return `${filteredAuthors
.slice(0, -1)
.map((author) => author?.name)
.join(', ')} and ${filteredAuthors[authors.length - 1].name}`
return `${authorNames.slice(0, -1).join(', ')} and ${authorNames[authorNames.length - 1]}`
}

View File

@@ -20,9 +20,9 @@ const getImageURL = (image?: Media | Config['db']['defaultIDType'] | null) => {
}
export const generateMeta = async (args: {
doc: Partial<Page> | Partial<Post>
doc: Partial<Page> | Partial<Post> | null
}): Promise<Metadata> => {
const { doc } = args || {}
const { doc } = args
const ogImage = getImageURL(doc?.meta?.image)

View File

@@ -1,5 +1,8 @@
import tailwindcssAnimate from 'tailwindcss-animate'
import typography from '@tailwindcss/typography'
/** @type {import('tailwindcss').Config} */
export default {
const config = {
content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
@@ -7,7 +10,7 @@ export default {
'./src/**/*.{ts,tsx}',
],
darkMode: ['selector', '[data-theme="dark"]'],
plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')],
plugins: [tailwindcssAnimate, typography],
prefix: '',
safelist: [
'lg:col-span-4',
@@ -104,7 +107,7 @@ export default {
to: { height: '0' },
},
},
typography: ({ theme }) => ({
typography: () => ({
DEFAULT: {
css: [
{
@@ -146,3 +149,5 @@ export default {
},
},
}
export default config

View File

@@ -1,5 +1,10 @@
{
"compilerOptions": {
/* Strictness */
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"baseUrl": ".",
"esModuleInterop": true,
"target": "ES2022",
@@ -10,7 +15,6 @@
],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"strictNullChecks": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,