This commit is contained in:
2022-07-20 19:24:59 +01:00
commit b709b69364
19 changed files with 31916 additions and 0 deletions

2
.eslintignore Normal file
View File

@@ -0,0 +1,2 @@
dist
payload-types.ts

23
.eslintrc.json Normal file
View 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
View File

@@ -0,0 +1,5 @@
node_modules/
dist/
build/
.env
src/media

4
nodemon.json Normal file
View File

@@ -0,0 +1,4 @@
{
"ext": "ts",
"exec": "ts-node src/server.ts"
}

31420
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

34
package.json Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);

View 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
View 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
}
}