Skip to content

Commit

Permalink
Merge pull request #2289 from payloadcms/feat/form-builder-example
Browse files Browse the repository at this point in the history
Feat/form builder example
  • Loading branch information
PatrikKozak authored Apr 12, 2023
2 parents ec2933c + 1387ba9 commit b9a5bb3
Show file tree
Hide file tree
Showing 108 changed files with 13,936 additions and 0 deletions.
4 changes: 4 additions & 0 deletions examples/form-builder/cms/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
PAYLOAD_PUBLIC_SITE_URL=http://localhost:3000
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:8000
MONGODB_URI=mongodb://localhost/form-builder-example
PAYLOAD_SECRET=ENTER-STRING-HERE
4 changes: 4 additions & 0 deletions examples/form-builder/cms/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['@payloadcms'],
}
5 changes: 5 additions & 0 deletions examples/form-builder/cms/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build
dist
node_modules
package-lock.json
.env
1 change: 1 addition & 0 deletions examples/form-builder/cms/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
legacy-peer-deps=true
8 changes: 8 additions & 0 deletions examples/form-builder/cms/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
printWidth: 100,
parser: "typescript",
semi: false,
singleQuote: true,
trailingComma: "all",
arrowParens: "avoid",
};
21 changes: 21 additions & 0 deletions examples/form-builder/cms/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Form Builder Example CMS",
"program": "${workspaceFolder}/src/server.ts",
"preLaunchTask": "npm: build:server",
"env": {
"PAYLOAD_CONFIG_PATH": "${workspaceFolder}/src/payload.config.ts"
},
// "outFiles": [
// "${workspaceFolder}/dist/**/*.js"
// ]
},
]
}
26 changes: 26 additions & 0 deletions examples/form-builder/cms/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Form Builder Example CMS

This is an example repo for a CMS built with [Payload](https://payloadcms.com). This repo showcases how to utilize Payload's [Form Builder Plugin](https://github.com/payloadcms/plugin-form-builder).

## Getting Started

1. Clone this repo
2. `cd` into the directory and run `yarn` or `npm install`
3. Copy (`cp`) the `.env.example` file to an `.env` file
4. Run `yarn dev` or `npm run dev` to start the development server
5. Visit `http://localhost:8000/admin` to access the admin panel
6. Login with the following credentials:
- Email: `dev@payloadcms.com`
- Password: `test`

## Frontend Development

There is a fully working Next.js app tailored specifically for this example which can be found [here](../nextjs). Follow the instructions there to get started. You can use this repo as a backend for the frontend and see for yourself how it all works together.

## Usage

Once booted up, a `Basic Form` will be immediately available to view on the home page along with a few other forms on their corresponding pages.

- These forms are seeded into the `forms` collection.
- A few pages have also been seeded in on start up and utilize a layout building block called `Form Block` that is wired up to use the different forms from the `forms` collection.
- This is done by adding a `relationship` field in the form-block config and setting its `relationTo` field to the `forms` collection.
4 changes: 4 additions & 0 deletions examples/form-builder/cms/nodemon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"ext": "ts",
"exec": "ts-node src/server.ts"
}
33 changes: 33 additions & 0 deletions examples/form-builder/cms/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "form-builder-example-cms",
"description": "The CMS that utilizes Payload's form builder plugin.",
"version": "1.0.0",
"main": "dist/server.js",
"license": "MIT",
"scripts": {
"dev": "cross-env PAYLOAD_SEED=true PAYLOAD_DROP_DATABASE=true 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 copyfiles && yarn build:payload && yarn build:server",
"serve": "cross-env PAYLOAD_CONFIG_PATH=dist/payload.config.js NODE_ENV=production node dist/server.js",
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png}\" dist/",
"generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types",
"generate:graphQLSchema": "PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:graphQLSchema"
},
"dependencies": {
"@faceless-ui/modal": "^2.0.1",
"@payloadcms/plugin-form-builder": "^1.0.12",
"@payloadcms/plugin-seo": "^1.0.8",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"payload": "^1.6.19"
},
"devDependencies": {
"@types/express": "^4.17.9",
"copyfiles": "^2.4.1",
"cross-env": "^7.0.3",
"nodemon": "^2.0.6",
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
}
}
11 changes: 11 additions & 0 deletions examples/form-builder/cms/src/access/publishedOnly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Access } from 'payload/config';

export const publishedOnly: Access = ({ req: { user } }) => {
if (user) return true;

return {
_status: {
equals: 'published',
},
};
};
33 changes: 33 additions & 0 deletions examples/form-builder/cms/src/blocks/Form/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Block } from 'payload/types';
import richText from '../../fields/richText';

export const FormBlock: Block = {
slug: 'formBlock',
labels: {
singular: 'Form Block',
plural: 'Form Blocks',
},
graphQL: {
singularName: 'FormBlock',
},
fields: [
{
name: 'form',
type: 'relationship',
relationTo: 'forms',
required: true,
},
{
name: 'enableIntro',
label: 'Enable Intro Content',
type: 'checkbox',
},
richText({
name: 'introContent',
label: 'Intro Content',
admin: {
condition: (_, { enableIntro }) => Boolean(enableIntro),
},
}),
],
};
44 changes: 44 additions & 0 deletions examples/form-builder/cms/src/collections/Pages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { CollectionConfig } from 'payload/types';
import { publishedOnly } from '../access/publishedOnly';
import { FormBlock } from '../blocks/Form';
import { slugField } from '../fields/slug';

export const Pages: CollectionConfig = {
slug: 'pages',
admin: {
useAsTitle: 'title',
defaultColumns: ['title', 'slug', 'updatedAt'],
},
versions: {
drafts: true,
},
access: {
read: publishedOnly,
},
fields: [
{
name: 'title',
type: 'text',
required: true,
},
{
type: 'tabs',
tabs: [
{
label: 'Content',
fields: [
{
name: 'layout',
type: 'blocks',
required: true,
blocks: [
FormBlock,
],
},
],
},
],
},
slugField(),
],
};
12 changes: 12 additions & 0 deletions examples/form-builder/cms/src/collections/Users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { CollectionConfig } from 'payload/types';

export const Users: CollectionConfig = {
slug: 'users',
auth: true,
admin: {
useAsTitle: 'email',
},
fields: [
// Don't need any user fields here
],
};
151 changes: 151 additions & 0 deletions examples/form-builder/cms/src/fields/link.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { Field } from 'payload/types';
import deepMerge from '../utilities/deepMerge';

export const appearanceOptions = {
primary: {
label: 'Primary Button',
value: 'primary',
},
secondary: {
label: 'Secondary Button',
value: 'secondary',
},
default: {
label: 'Default',
value: 'default',
},
};

export type LinkAppearances = 'primary' | 'secondary' | 'default'

type LinkType = (
options?: {
appearances?: LinkAppearances[] | false
disableLabel?: boolean
overrides?: Record<string, unknown>
}
) => Field;

const link: LinkType = ({
appearances,
disableLabel = false,
overrides = {},
} = {}) => {
const linkResult: Field = {
name: 'link',
type: 'group',
admin: {
hideGutter: true,
},
fields: [
{
type: 'row',
fields: [
{
name: 'type',
type: 'radio',
options: [
{
label: 'Internal link',
value: 'reference',
},
{
label: 'Custom URL',
value: 'custom',
},
],
defaultValue: 'reference',
admin: {
layout: 'horizontal',
width: '50%',
},
},
{
name: 'newTab',
label: 'Open in new tab',
type: 'checkbox',
admin: {
width: '50%',
style: {
alignSelf: 'flex-end',
},
},
},
],
},
],
};

const linkTypes: Field[] = [
{
name: 'reference',
label: 'Document to link to',
type: 'relationship',
relationTo: ['pages'],
required: true,
maxDepth: 1,
admin: {
condition: (_, siblingData) => siblingData?.type === 'reference',
},
},
{
name: 'url',
label: 'Custom URL',
type: 'text',
required: true,
admin: {
condition: (_, siblingData) => siblingData?.type === 'custom',
},
},
];

if (!disableLabel) {
linkTypes[0].admin.width = '50%';
linkTypes[1].admin.width = '50%';

linkResult.fields.push({
type: 'row',
fields: [
...linkTypes,
{
name: 'label',
label: 'Label',
type: 'text',
required: true,
admin: {
width: '50%',
},
},
],
});
} else {
linkResult.fields = [...linkResult.fields, ...linkTypes];
}


if (appearances !== false) {
let appearanceOptionsToUse = [
appearanceOptions.default,
appearanceOptions.primary,
appearanceOptions.secondary,
];

if (appearances) {
appearanceOptionsToUse = appearances.map((appearance) => appearanceOptions[appearance]);
}

linkResult.fields.push({
name: 'appearance',
type: 'select',
defaultValue: 'default',
options: appearanceOptionsToUse,
admin: {
description: 'Choose how the link should be rendered.',
},
});
}

return deepMerge(linkResult, overrides);
};

export default link;
13 changes: 13 additions & 0 deletions examples/form-builder/cms/src/fields/richText/elements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { RichTextElement } from 'payload/dist/fields/config/types';

const elements: RichTextElement[] = [
'blockquote',
'h2',
'h3',
'h4',
'h5',
'h6',
'link',
];

export default elements;
Loading

0 comments on commit b9a5bb3

Please sign in to comment.