Initial
This commit is contained in:
2
.eslintignore
Normal file
2
.eslintignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
dist
|
||||||
|
payload-types.ts
|
||||||
23
.eslintrc.json
Normal file
23
.eslintrc.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"globals": {},
|
||||||
|
"env": {
|
||||||
|
"commonjs": true,
|
||||||
|
"es2021": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"plugins": [
|
||||||
|
"@typescript-eslint"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"@matt-fidd"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": "latest"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"max-len": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.env
|
||||||
|
src/media
|
||||||
4
nodemon.json
Normal file
4
nodemon.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"ext": "ts",
|
||||||
|
"exec": "ts-node src/server.ts"
|
||||||
|
}
|
||||||
31420
package-lock.json
generated
Normal file
31420
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
34
package.json
Normal file
34
package.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "payload-starter-typescript",
|
||||||
|
"description": "Blank template - no collections",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "dist/server.js",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts nodemon",
|
||||||
|
"build:payload": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload build",
|
||||||
|
"build:server": "tsc",
|
||||||
|
"build": "yarn build:payload && yarn build:server",
|
||||||
|
"serve": "cross-env PAYLOAD_CONFIG_PATH=dist/payload.config.js NODE_ENV=production node dist/server.js",
|
||||||
|
"generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types",
|
||||||
|
"lint": "npm run lint:check",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
|
"lint:check": "eslint ."
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"payload": "^1.0.7"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@matt-fidd/eslint-config": "^1.3.2",
|
||||||
|
"@types/express": "^4.17.9",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.30.7",
|
||||||
|
"@typescript-eslint/parser": "^5.30.7",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"eslint": "^8.20.0",
|
||||||
|
"nodemon": "^2.0.6",
|
||||||
|
"ts-node": "^9.1.1",
|
||||||
|
"typescript": "^4.7.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/blocks/Quote.ts
Normal file
29
src/blocks/Quote.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { Block } from 'payload/types';
|
||||||
|
|
||||||
|
const QuoteBlock: Block = {
|
||||||
|
slug: 'Quote',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'quoteText',
|
||||||
|
type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'quoteAttribution',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
label: 'Name',
|
||||||
|
type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'date',
|
||||||
|
label: 'Date',
|
||||||
|
type: 'text'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default QuoteBlock;
|
||||||
37
src/blocks/Spacer.ts
Normal file
37
src/blocks/Spacer.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { Block } from 'payload/types';
|
||||||
|
|
||||||
|
const SpacerBlock: Block = {
|
||||||
|
slug: 'spacer',
|
||||||
|
labels: {
|
||||||
|
singular: 'Spacer',
|
||||||
|
plural: 'Spacers'
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'size',
|
||||||
|
label: 'Size',
|
||||||
|
type: 'radio',
|
||||||
|
required: true,
|
||||||
|
defaultValue: 'medium',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'Small',
|
||||||
|
value: 'small'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Medium',
|
||||||
|
value: 'medium'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Large',
|
||||||
|
value: 'large'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
admin: {
|
||||||
|
layout: 'horizontal'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SpacerBlock;
|
||||||
33
src/collections/Media.ts
Normal file
33
src/collections/Media.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { CollectionConfig } from 'payload/types';
|
||||||
|
|
||||||
|
const Media: CollectionConfig = {
|
||||||
|
slug: 'media',
|
||||||
|
access: {
|
||||||
|
read: (): boolean => true
|
||||||
|
},
|
||||||
|
upload: {
|
||||||
|
adminThumbnail: 'card',
|
||||||
|
imageSizes: [
|
||||||
|
{
|
||||||
|
name: 'card',
|
||||||
|
width: 640,
|
||||||
|
height: 480
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'feature',
|
||||||
|
width: 1024,
|
||||||
|
height: 576
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'alt',
|
||||||
|
label: 'Alt Text',
|
||||||
|
type: 'text',
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Media;
|
||||||
27
src/collections/Pages.ts
Normal file
27
src/collections/Pages.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { CollectionConfig } from 'payload/types';
|
||||||
|
import slug from '../fields/Slug';
|
||||||
|
|
||||||
|
const Pages: CollectionConfig = {
|
||||||
|
slug: 'pages',
|
||||||
|
admin: {
|
||||||
|
useAsTitle: 'title'
|
||||||
|
},
|
||||||
|
access: {
|
||||||
|
read: (): boolean => true // Everyone can read Pages
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
label: 'Title',
|
||||||
|
type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'content',
|
||||||
|
label: 'Content',
|
||||||
|
type: 'richText'
|
||||||
|
},
|
||||||
|
slug
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Pages;
|
||||||
21
src/collections/Users.ts
Normal file
21
src/collections/Users.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { CollectionConfig } from 'payload/types';
|
||||||
|
|
||||||
|
const Users: CollectionConfig = {
|
||||||
|
slug: 'users',
|
||||||
|
auth: true,
|
||||||
|
admin: {
|
||||||
|
useAsTitle: 'email'
|
||||||
|
},
|
||||||
|
access: {
|
||||||
|
read: () => true
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
type: 'text',
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Users;
|
||||||
63
src/fields/Link.ts
Normal file
63
src/fields/Link.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { Field } from 'payload/types';
|
||||||
|
|
||||||
|
const link: Field = {
|
||||||
|
name: 'link',
|
||||||
|
type: 'group',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
type: 'radio',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'Page',
|
||||||
|
value: 'page'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Custom URL',
|
||||||
|
value: 'custom'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
defaultValue: 'page',
|
||||||
|
admin: {
|
||||||
|
layout: 'horizontal'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'row',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'label',
|
||||||
|
label: 'Label',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
admin: {
|
||||||
|
width: '50%'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'page',
|
||||||
|
label: 'Page to link to',
|
||||||
|
type: 'relationship',
|
||||||
|
relationTo: 'pages',
|
||||||
|
required: true,
|
||||||
|
admin: {
|
||||||
|
condition: (_, siblingData) => siblingData?.type === 'page',
|
||||||
|
width: '50%'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'url',
|
||||||
|
label: 'Custom URL',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
admin: {
|
||||||
|
condition: (_, siblingData) => siblingData?.type === 'custom',
|
||||||
|
width: '50%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default link;
|
||||||
18
src/fields/Slug.ts
Normal file
18
src/fields/Slug.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Field } from 'payload/types';
|
||||||
|
import formatSlug from '../utilities/formatSlug';
|
||||||
|
|
||||||
|
const slug: Field = {
|
||||||
|
name: 'slug',
|
||||||
|
label: 'Slug',
|
||||||
|
type: 'text',
|
||||||
|
admin: {
|
||||||
|
position: 'sidebar'
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
|
beforeValidate: [
|
||||||
|
formatSlug('title')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default slug;
|
||||||
24
src/globals/Nav.ts
Normal file
24
src/globals/Nav.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { GlobalConfig } from 'payload/types';
|
||||||
|
|
||||||
|
import Link from '../fields/Link';
|
||||||
|
|
||||||
|
const Nav: GlobalConfig = {
|
||||||
|
slug: 'nav',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'items',
|
||||||
|
type: 'array',
|
||||||
|
required: true,
|
||||||
|
labels: {
|
||||||
|
singular: 'Link',
|
||||||
|
plural: 'Links'
|
||||||
|
},
|
||||||
|
maxRows: 8,
|
||||||
|
fields: [
|
||||||
|
Link
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Nav;
|
||||||
87
src/payload-types.ts
Normal file
87
src/payload-types.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/**
|
||||||
|
* This file was automatically generated by Payload CMS.
|
||||||
|
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||||
|
* and re-run `payload generate:types` to regenerate this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface Config {}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "nav".
|
||||||
|
*/
|
||||||
|
export interface Nav {
|
||||||
|
id: string;
|
||||||
|
items: {
|
||||||
|
link?: {
|
||||||
|
type?: 'page' | 'custom';
|
||||||
|
label: string;
|
||||||
|
page: string | Page;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
id?: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "pages".
|
||||||
|
*/
|
||||||
|
export interface Page {
|
||||||
|
id: string;
|
||||||
|
title?: string;
|
||||||
|
content?: {
|
||||||
|
[k: string]: unknown;
|
||||||
|
}[];
|
||||||
|
slug?: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "users".
|
||||||
|
*/
|
||||||
|
export interface User {
|
||||||
|
id: string;
|
||||||
|
email?: string;
|
||||||
|
resetPasswordToken?: string;
|
||||||
|
resetPasswordExpiration?: string;
|
||||||
|
loginAttempts?: number;
|
||||||
|
lockUntil?: string;
|
||||||
|
name: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "media".
|
||||||
|
*/
|
||||||
|
export interface Media {
|
||||||
|
id: string;
|
||||||
|
url?: string;
|
||||||
|
filename?: string;
|
||||||
|
mimeType?: string;
|
||||||
|
filesize?: number;
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
sizes?: {
|
||||||
|
card?: {
|
||||||
|
url?: string;
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
mimeType?: string;
|
||||||
|
filesize?: number;
|
||||||
|
filename?: string;
|
||||||
|
};
|
||||||
|
feature?: {
|
||||||
|
url?: string;
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
mimeType?: string;
|
||||||
|
filesize?: number;
|
||||||
|
filename?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
alt: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
26
src/payload.config.ts
Normal file
26
src/payload.config.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { buildConfig } from 'payload/config';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import Users from './collections/Users';
|
||||||
|
import Media from './collections/Media';
|
||||||
|
import Pages from './collections/Pages';
|
||||||
|
|
||||||
|
import Nav from './globals/Nav';
|
||||||
|
|
||||||
|
export default buildConfig({
|
||||||
|
serverURL: 'http://localhost:3000',
|
||||||
|
admin: {
|
||||||
|
user: Users.slug
|
||||||
|
},
|
||||||
|
collections: [
|
||||||
|
Users,
|
||||||
|
Media,
|
||||||
|
Pages
|
||||||
|
],
|
||||||
|
globals: [
|
||||||
|
Nav
|
||||||
|
],
|
||||||
|
typescript: {
|
||||||
|
outputFile: path.resolve(__dirname, 'payload-types.ts')
|
||||||
|
}
|
||||||
|
});
|
||||||
26
src/server.ts
Normal file
26
src/server.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import payload from 'payload';
|
||||||
|
|
||||||
|
import * as dotenv from 'dotenv';
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
// Redirect root to Admin panel
|
||||||
|
app.get('/', (_, res) => {
|
||||||
|
res.redirect('/admin');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize Payload
|
||||||
|
payload.init({
|
||||||
|
secret: process.env.PAYLOAD_SECRET,
|
||||||
|
mongoURL: process.env.MONGODB_URI,
|
||||||
|
express: app,
|
||||||
|
onInit: () => {
|
||||||
|
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add your own express routes here
|
||||||
|
|
||||||
|
app.listen(3000);
|
||||||
18
src/utilities/formatSlug.ts
Normal file
18
src/utilities/formatSlug.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { FieldHook } from 'payload/types';
|
||||||
|
|
||||||
|
const format = (val: string): string => val.replace(/ /g, '-').replace(/[^\w-/]+/g, '').toLowerCase();
|
||||||
|
|
||||||
|
const formatSlug = (fallback: string): FieldHook => ({ value, originalDoc, data }) => {
|
||||||
|
if (typeof value === 'string')
|
||||||
|
return format(value);
|
||||||
|
|
||||||
|
const fallbackData = data && data[fallback] || originalDoc && originalDoc[fallback];
|
||||||
|
|
||||||
|
if (fallbackData && typeof fallbackData === 'string')
|
||||||
|
return format(fallbackData);
|
||||||
|
|
||||||
|
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default formatSlug;
|
||||||
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"strict": false,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"jsx": "react",
|
||||||
|
},
|
||||||
|
"ts-node": {
|
||||||
|
"transpileOnly": true
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user