chore(examples/redirects): migrates to 2.0 (#3514)
This commit is contained in:
@@ -1,4 +0,0 @@
|
|||||||
MONGODB_URI=mongodb://127.0.0.1/payload-example-redirects
|
|
||||||
PAYLOAD_SECRET=ENTER-STRING-HERE
|
|
||||||
PAYLOAD_PUBLIC_SITE_URL=http://localhost:3000
|
|
||||||
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:8000
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
printWidth: 100,
|
|
||||||
parser: "typescript",
|
|
||||||
semi: false,
|
|
||||||
singleQuote: true,
|
|
||||||
trailingComma: "all",
|
|
||||||
arrowParens: "avoid",
|
|
||||||
};
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import type { RichTextElement } from 'payload/dist/fields/config/types'
|
|
||||||
|
|
||||||
const elements: RichTextElement[] = ['blockquote', 'h2', 'h3', 'h4', 'h5', 'h6', 'link']
|
|
||||||
|
|
||||||
export default elements
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
import type { RichTextElement, RichTextField, RichTextLeaf } from 'payload/dist/fields/config/types'
|
|
||||||
|
|
||||||
import deepMerge from '../../utilities/deepMerge'
|
|
||||||
import link from '../link'
|
|
||||||
import elements from './elements'
|
|
||||||
import leaves from './leaves'
|
|
||||||
|
|
||||||
type RichText = (
|
|
||||||
overrides?: Partial<RichTextField>,
|
|
||||||
additions?: {
|
|
||||||
elements?: RichTextElement[]
|
|
||||||
leaves?: RichTextLeaf[]
|
|
||||||
},
|
|
||||||
) => RichTextField
|
|
||||||
|
|
||||||
const richText: RichText = (
|
|
||||||
overrides,
|
|
||||||
additions = {
|
|
||||||
elements: [],
|
|
||||||
leaves: [],
|
|
||||||
},
|
|
||||||
) =>
|
|
||||||
deepMerge<RichTextField, Partial<RichTextField>>(
|
|
||||||
{
|
|
||||||
name: 'richText',
|
|
||||||
type: 'richText',
|
|
||||||
required: true,
|
|
||||||
admin: {
|
|
||||||
upload: {
|
|
||||||
collections: {
|
|
||||||
media: {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
type: 'richText',
|
|
||||||
name: 'caption',
|
|
||||||
label: 'Caption',
|
|
||||||
admin: {
|
|
||||||
elements: [...elements],
|
|
||||||
leaves: [...leaves],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'radio',
|
|
||||||
name: 'alignment',
|
|
||||||
label: 'Alignment',
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: 'Left',
|
|
||||||
value: 'left',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Center',
|
|
||||||
value: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Right',
|
|
||||||
value: 'right',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'enableLink',
|
|
||||||
type: 'checkbox',
|
|
||||||
label: 'Enable Link',
|
|
||||||
},
|
|
||||||
link({
|
|
||||||
appearances: false,
|
|
||||||
disableLabel: true,
|
|
||||||
overrides: {
|
|
||||||
admin: {
|
|
||||||
condition: (_, data) => Boolean(data?.enableLink),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
elements: [...elements, ...(additions.elements || [])],
|
|
||||||
leaves: [...leaves, ...(additions.leaves || [])],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
overrides,
|
|
||||||
)
|
|
||||||
|
|
||||||
export default richText
|
|
||||||
2
examples/redirects/next-pages/.env.example
Normal file
2
examples/redirects/next-pages/.env.example
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
NEXT_PUBLIC_APP_URL=http://localhost:3001
|
||||||
|
NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3000
|
||||||
8
examples/redirects/next-pages/.prettierrc.js
Normal file
8
examples/redirects/next-pages/.prettierrc.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module.exports = {
|
||||||
|
printWidth: 100,
|
||||||
|
parser: 'typescript',
|
||||||
|
semi: false,
|
||||||
|
singleQuote: true,
|
||||||
|
trailingComma: 'all',
|
||||||
|
arrowParens: 'avoid',
|
||||||
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
# Redirects Example Front-End
|
# Redirects Example Front-End
|
||||||
|
|
||||||
This is a [Next.js](https://nextjs.org/) app made explicitly for Payload's [Redirects Example](https://github.com/payloadcms/payload/tree/main/examples/redirects/cms).
|
This is a [Next.js](https://nextjs.org) app using the [Pages Router](https://nextjs.org/docs/pages). It was made explicitly for Payload's [Redirects Example](https://github.com/payloadcms/payload/tree/master/examples/redireects/payload).
|
||||||
|
|
||||||
|
> This example uses the Pages Router, the legacy API of Next.js. If your app is using the latest [App Router](https://nextjs.org/docs/app), we will soon add a new example for you to use soon.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
### Payload
|
### Payload
|
||||||
|
|
||||||
First you'll need a running CMS. If you have not done so already, open up the `cms` folder alongside this example and follow the setup instructions. Take note of your server URL, you'll need this in the next step.
|
First you'll need a running Payload app. There is one made explicitly for this example and [can be found here](https://github.com/payloadcms/payload/tree/master/examples/redirects/payload). If you have not done so already, clone it down and follow the setup instructions there.
|
||||||
|
|
||||||
### Next.js App
|
### Next.js App
|
||||||
|
|
||||||
@@ -14,13 +16,13 @@ First you'll need a running CMS. If you have not done so already, open up the `c
|
|||||||
2. `cd` into this directory and run `yarn` or `npm install`
|
2. `cd` into this directory and run `yarn` or `npm install`
|
||||||
3. `cp .env.example .env` to copy the example environment variables
|
3. `cp .env.example .env` to copy the example environment variables
|
||||||
4. `yarn dev` or `npm run dev` to start the server
|
4. `yarn dev` or `npm run dev` to start the server
|
||||||
5. `open http://localhost:3000` to see the result
|
5. `open http://localhost:3001` to see the result
|
||||||
|
|
||||||
Once running you will find a couple seeded pages on your local environment with some basic instructions. You can also start editing the pages by modifying the documents within your CMS. See the [Redirects Example CMS](https://github.com/payloadcms/payload/tree/main/examples/redirects/cms) for full details.
|
Once running you will find a couple seeded pages on your local environment with some basic instructions. You can also start editing the pages by modifying the documents within Payload. See the [Redirects Example](https://github.com/payloadcms/payload/tree/main/examples/redirects/payload) for full details.
|
||||||
|
|
||||||
## Learn More
|
## Learn More
|
||||||
|
|
||||||
To learn more about PayloadCMS and Next.js, take a look at the following resources:
|
To learn more about Payload and Next.js, take a look at the following resources:
|
||||||
|
|
||||||
- [Payload Documentation](https://payloadcms.com/docs) - learn about Payload features and API.
|
- [Payload Documentation](https://payloadcms.com/docs) - learn about Payload features and API.
|
||||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react'
|
||||||
import escapeHTML from 'escape-html'
|
import escapeHTML from 'escape-html'
|
||||||
import Link from 'next/link'
|
|
||||||
import { Text } from 'slate'
|
import { Text } from 'slate'
|
||||||
|
|
||||||
// eslint-disable-next-line no-use-before-define
|
// eslint-disable-next-line no-use-before-define
|
||||||
@@ -8,7 +7,10 @@ type Children = Leaf[]
|
|||||||
|
|
||||||
type Leaf = {
|
type Leaf = {
|
||||||
type: string
|
type: string
|
||||||
doc?: any
|
value?: {
|
||||||
|
url: string
|
||||||
|
alt: string
|
||||||
|
}
|
||||||
children?: Children
|
children?: Children
|
||||||
url?: string
|
url?: string
|
||||||
[key: string]: unknown
|
[key: string]: unknown
|
||||||
@@ -76,15 +78,11 @@ const serialize = (children: Children): React.ReactElement[] =>
|
|||||||
case 'li':
|
case 'li':
|
||||||
return <li key={i}>{serialize(node.children)}</li>
|
return <li key={i}>{serialize(node.children)}</li>
|
||||||
case 'link':
|
case 'link':
|
||||||
if (node?.linkType === 'internal') {
|
return (
|
||||||
return <Link href={`/${node?.doc?.value?.slug}`}>{serialize(node.children)}</Link>
|
<a href={escapeHTML(node.url)} key={i}>
|
||||||
} else {
|
{serialize(node.children)}
|
||||||
return (
|
</a>
|
||||||
<a href={escapeHTML(node.url)} key={i}>
|
)
|
||||||
{serialize(node.children)}
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return <p key={i}>{serialize(node.children)}</p>
|
return <p key={i}>{serialize(node.children)}</p>
|
||||||
@@ -5,7 +5,7 @@ const nextConfig = {
|
|||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
swcMinify: true,
|
swcMinify: true,
|
||||||
images: {
|
images: {
|
||||||
domains: ['localhost', process.env.NEXT_PUBLIC_CMS_URL],
|
domains: ['localhost', process.env.NEXT_PUBLIC_PAYLOAD_URL],
|
||||||
},
|
},
|
||||||
redirects,
|
redirects,
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev -p 3001",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
@@ -42,7 +42,7 @@ export const getStaticProps: GetStaticProps = async (context: GetStaticPropsCont
|
|||||||
let doc
|
let doc
|
||||||
|
|
||||||
const pageReq = await fetch(
|
const pageReq = await fetch(
|
||||||
`${process.env.NEXT_PUBLIC_CMS_URL}/api/pages?where[slug][equals]=${slug}&depth=2&draft=true`,
|
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/pages?where[slug][equals]=${slug}&depth=2&draft=true`,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (pageReq.ok) {
|
if (pageReq.ok) {
|
||||||
@@ -73,7 +73,7 @@ export const getStaticPaths: GetStaticPaths = async () => {
|
|||||||
let pagesData
|
let pagesData
|
||||||
|
|
||||||
pagesReq = await fetch(
|
pagesReq = await fetch(
|
||||||
`${process.env.NEXT_PUBLIC_CMS_URL}/api/pages?where[_status][equals]=published&depth=0&limit=300`,
|
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/pages?where[_status][equals]=published&depth=0&limit=300`,
|
||||||
)
|
)
|
||||||
pagesData = await pagesReq.json()
|
pagesData = await pagesReq.json()
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ export interface IGlobals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getAllGlobals = async (): Promise<IGlobals> => {
|
export const getAllGlobals = async (): Promise<IGlobals> => {
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/globals/main-menu?depth=1`)
|
const res = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/globals/main-menu?depth=1`)
|
||||||
const mainMenu = await res.json()
|
const mainMenu = await res.json()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
/**
|
/**
|
||||||
* This file was automatically generated by Payload.
|
* This file was automatically generated by Payload.
|
||||||
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||||
@@ -10,6 +11,8 @@ export interface Config {
|
|||||||
pages: Page
|
pages: Page
|
||||||
users: User
|
users: User
|
||||||
redirects: Redirect
|
redirects: Redirect
|
||||||
|
'payload-preferences': PayloadPreference
|
||||||
|
'payload-migrations': PayloadMigration
|
||||||
}
|
}
|
||||||
globals: {
|
globals: {
|
||||||
'main-menu': MainMenu
|
'main-menu': MainMenu
|
||||||
@@ -18,24 +21,25 @@ export interface Config {
|
|||||||
export interface Page {
|
export interface Page {
|
||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
richText: Array<{
|
richText: {
|
||||||
[k: string]: unknown
|
[k: string]: unknown
|
||||||
}>
|
}[]
|
||||||
slug?: string
|
slug?: string
|
||||||
_status?: 'draft' | 'published'
|
|
||||||
createdAt: string
|
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
password?: string
|
createdAt: string
|
||||||
|
_status?: 'draft' | 'published'
|
||||||
}
|
}
|
||||||
export interface User {
|
export interface User {
|
||||||
id: string
|
id: string
|
||||||
email?: string
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
|
email: string
|
||||||
resetPasswordToken?: string
|
resetPasswordToken?: string
|
||||||
resetPasswordExpiration?: string
|
resetPasswordExpiration?: string
|
||||||
|
salt?: string
|
||||||
|
hash?: string
|
||||||
loginAttempts?: number
|
loginAttempts?: number
|
||||||
lockUntil?: string
|
lockUntil?: string
|
||||||
createdAt: string
|
|
||||||
updatedAt: string
|
|
||||||
password?: string
|
password?: string
|
||||||
}
|
}
|
||||||
export interface Redirect {
|
export interface Redirect {
|
||||||
@@ -44,28 +48,70 @@ export interface Redirect {
|
|||||||
to: {
|
to: {
|
||||||
type?: 'reference' | 'custom'
|
type?: 'reference' | 'custom'
|
||||||
reference: {
|
reference: {
|
||||||
value: string | Page
|
|
||||||
relationTo: 'pages'
|
relationTo: 'pages'
|
||||||
|
value: string | Page
|
||||||
}
|
}
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
createdAt: string
|
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
password?: string
|
createdAt: string
|
||||||
|
}
|
||||||
|
export interface PayloadPreference {
|
||||||
|
id: string
|
||||||
|
user: {
|
||||||
|
relationTo: 'users'
|
||||||
|
value: string | User
|
||||||
|
}
|
||||||
|
key?: string
|
||||||
|
value?:
|
||||||
|
| {
|
||||||
|
[k: string]: unknown
|
||||||
|
}
|
||||||
|
| unknown[]
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null
|
||||||
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
export interface PayloadMigration {
|
||||||
|
id: string
|
||||||
|
name?: string
|
||||||
|
batch?: number
|
||||||
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
}
|
}
|
||||||
export interface MainMenu {
|
export interface MainMenu {
|
||||||
id: string
|
id: string
|
||||||
navItems: Array<{
|
navItems?: {
|
||||||
link: {
|
link: {
|
||||||
type?: 'reference' | 'custom'
|
type?: 'reference' | 'custom'
|
||||||
newTab?: boolean
|
newTab?: boolean
|
||||||
reference: {
|
reference: {
|
||||||
value: string | Page
|
|
||||||
relationTo: 'pages'
|
relationTo: 'pages'
|
||||||
|
value: string | Page
|
||||||
}
|
}
|
||||||
url: string
|
url: string
|
||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
id?: string
|
id?: string
|
||||||
}>
|
}[]
|
||||||
|
updatedAt?: string
|
||||||
|
createdAt?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'payload' {
|
||||||
|
export interface GeneratedTypes {
|
||||||
|
collections: {
|
||||||
|
pages: Page
|
||||||
|
users: User
|
||||||
|
redirects: Redirect
|
||||||
|
'payload-preferences': PayloadPreference
|
||||||
|
'payload-migrations': PayloadMigration
|
||||||
|
}
|
||||||
|
globals: {
|
||||||
|
'main-menu': MainMenu
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,21 @@
|
|||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext } from 'react'
|
||||||
import { MainMenu } from '../../payload-types';
|
import { MainMenu } from '../../payload-types'
|
||||||
|
|
||||||
export type MainMenuType = MainMenu
|
export type MainMenuType = MainMenu
|
||||||
|
|
||||||
export interface IGlobals {
|
export interface IGlobals {
|
||||||
mainMenu: MainMenuType,
|
mainMenu: MainMenuType
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GlobalsContext = createContext<IGlobals>({} as IGlobals);
|
export const GlobalsContext = createContext<IGlobals>({} as IGlobals)
|
||||||
export const useGlobals = (): IGlobals => useContext(GlobalsContext);
|
export const useGlobals = (): IGlobals => useContext(GlobalsContext)
|
||||||
|
|
||||||
export const GlobalsProvider: React.FC<IGlobals & {
|
export const GlobalsProvider: React.FC<
|
||||||
children: React.ReactNode
|
IGlobals & {
|
||||||
}> = (props) => {
|
children: React.ReactNode
|
||||||
const {
|
}
|
||||||
mainMenu,
|
> = props => {
|
||||||
children,
|
const { mainMenu, children } = props
|
||||||
} = props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GlobalsContext.Provider
|
<GlobalsContext.Provider
|
||||||
@@ -26,5 +25,5 @@ export const GlobalsProvider: React.FC<IGlobals & {
|
|||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</GlobalsContext.Provider>
|
</GlobalsContext.Provider>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@@ -16,8 +16,9 @@ module.exports = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const redirectsRes = await fetch(
|
const redirectsRes = await fetch(
|
||||||
`${process.env.NEXT_PUBLIC_CMS_URL}/api/redirects?limit=1000&depth=1`,
|
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/redirects?limit=1000&depth=1`,
|
||||||
)
|
)
|
||||||
|
|
||||||
const redirectsData = await redirectsRes.json()
|
const redirectsData = await redirectsRes.json()
|
||||||
|
|
||||||
const { docs } = redirectsData
|
const { docs } = redirectsData
|
||||||
1
examples/redirects/next-pages/utilities/canUseDOM.ts
Normal file
1
examples/redirects/next-pages/utilities/canUseDOM.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export default !!(typeof window !== 'undefined' && window.document && window.document.createElement)
|
||||||
5
examples/redirects/next-pages/utilities/toKebabCase.ts
Normal file
5
examples/redirects/next-pages/utilities/toKebabCase.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const toKebabCase = string =>
|
||||||
|
string
|
||||||
|
?.replace(/([a-z])([A-Z])/g, '$1-$2')
|
||||||
|
.replace(/\s+/g, '-')
|
||||||
|
.toLowerCase()
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
||||||
NEXT_PUBLIC_CMS_URL=http://localhost:8000
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
printWidth: 100,
|
|
||||||
parser: "typescript",
|
|
||||||
semi: false,
|
|
||||||
singleQuote: true,
|
|
||||||
trailingComma: "all",
|
|
||||||
arrowParens: "avoid",
|
|
||||||
};
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/* tslint:disable */
|
|
||||||
/**
|
|
||||||
* This file was automatically generated by Payload.
|
|
||||||
* 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 {
|
|
||||||
collections: {
|
|
||||||
pages: Page;
|
|
||||||
users: User;
|
|
||||||
redirects: Redirect;
|
|
||||||
};
|
|
||||||
globals: {
|
|
||||||
'main-menu': MainMenu;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export interface Page {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
richText: {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}[];
|
|
||||||
slug?: string;
|
|
||||||
_status?: 'draft' | 'published';
|
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
password?: string;
|
|
||||||
}
|
|
||||||
export interface User {
|
|
||||||
id: string;
|
|
||||||
email?: string;
|
|
||||||
resetPasswordToken?: string;
|
|
||||||
resetPasswordExpiration?: string;
|
|
||||||
loginAttempts?: number;
|
|
||||||
lockUntil?: string;
|
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
password?: string;
|
|
||||||
}
|
|
||||||
export interface Redirect {
|
|
||||||
id: string;
|
|
||||||
from: string;
|
|
||||||
to: {
|
|
||||||
type?: 'reference' | 'custom';
|
|
||||||
reference: {
|
|
||||||
value: string | Page;
|
|
||||||
relationTo: 'pages';
|
|
||||||
};
|
|
||||||
url: string;
|
|
||||||
};
|
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
password?: string;
|
|
||||||
}
|
|
||||||
export interface MainMenu {
|
|
||||||
id: string;
|
|
||||||
navItems: {
|
|
||||||
link: {
|
|
||||||
type?: 'reference' | 'custom';
|
|
||||||
newTab?: boolean;
|
|
||||||
reference: {
|
|
||||||
value: string | Page;
|
|
||||||
relationTo: 'pages';
|
|
||||||
};
|
|
||||||
url: string;
|
|
||||||
label: string;
|
|
||||||
};
|
|
||||||
id?: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export default !!(
|
|
||||||
(typeof window !== 'undefined'
|
|
||||||
&& window.document && window.document.createElement)
|
|
||||||
);
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export const toKebabCase = (string) => string?.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase();
|
|
||||||
|
|
||||||
4
examples/redirects/payload/.env.example
Normal file
4
examples/redirects/payload/.env.example
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
DATABASE_URI=mongodb://127.0.0.1/payload-example-redirects
|
||||||
|
PAYLOAD_SECRET=ENTER-STRING-HERE
|
||||||
|
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000
|
||||||
|
PAYLOAD_PUBLIC_SITE_URL=http://localhost:3001
|
||||||
8
examples/redirects/payload/.prettierrc.js
Normal file
8
examples/redirects/payload/.prettierrc.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module.exports = {
|
||||||
|
printWidth: 100,
|
||||||
|
parser: 'typescript',
|
||||||
|
semi: false,
|
||||||
|
singleQuote: true,
|
||||||
|
trailingComma: 'all',
|
||||||
|
arrowParens: 'avoid',
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
{
|
{
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Redirects Example CMS",
|
"name": "Payload Redirects Example",
|
||||||
"program": "${workspaceFolder}/src/server.ts",
|
"program": "${workspaceFolder}/src/server.ts",
|
||||||
"preLaunchTask": "npm: build:server",
|
"preLaunchTask": "npm: build:server",
|
||||||
"env": {
|
"env": {
|
||||||
@@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
This example demonstrates how to implement http redirects into Payload using the official [Redirects Plugin](https://github.com/payloadcms/plugin-redirects).
|
This example demonstrates how to implement http redirects into Payload using the official [Redirects Plugin](https://github.com/payloadcms/plugin-redirects).
|
||||||
|
|
||||||
There is a fully working Next.js app made explicitly for this example which can be found [here](../nextjs). Follow the instructions there to get started. If you are setting up redirects for another front-end, please consider contributing to this repo with your own example!
|
There are various fully working front-ends made explicitly for this example, including:
|
||||||
|
|
||||||
|
- [Next.js Pages Router](../next-pages)
|
||||||
|
|
||||||
|
Follow the instructions in each respective README to get started. If you are setting up redirects for another front-end, please consider contributing to this repo with your own example!
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -12,8 +16,8 @@ To spin up this example locally, follow these steps:
|
|||||||
2. `cd` into this directory and run `yarn` or `npm install`
|
2. `cd` into this directory and run `yarn` or `npm install`
|
||||||
3. `cp .env.example .env` to copy the example environment variables
|
3. `cp .env.example .env` to copy the example environment variables
|
||||||
4. `yarn dev` or `npm run dev` to start the server and seed the database
|
4. `yarn dev` or `npm run dev` to start the server and seed the database
|
||||||
5. `open http://localhost:8000/admin` to access the admin panel
|
5. `open http://localhost:3000/admin` to access the admin panel
|
||||||
6. Login with email `dev@payloadcms.com` and password `test`
|
6. Login with email `demo@payloadcms.com` and password `demo`
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "payload-example-redirects-cms",
|
"name": "payload-example-redirects-example",
|
||||||
"description": "The CMS is used to demonstrate the redirects feature.",
|
"description": "Payload redirects example.",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "dist/server.js",
|
"main": "dist/server.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
"lint:fix": "eslint --fix --ext .ts,.tsx src"
|
"lint:fix": "eslint --fix --ext .ts,.tsx src"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@payloadcms/bundler-webpack": "^1.0.0-beta.5",
|
||||||
|
"@payloadcms/db-mongodb": "^1.0.0-beta.8",
|
||||||
|
"@payloadcms/richtext-slate": "^1.0.0-beta.4",
|
||||||
"@payloadcms/plugin-redirects": "^1.0.0",
|
"@payloadcms/plugin-redirects": "^1.0.0",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
17
examples/redirects/payload/src/BeforeLogin/index.tsx
Normal file
17
examples/redirects/payload/src/BeforeLogin/index.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const BeforeLogin: React.FC = () => {
|
||||||
|
if (process.env.PAYLOAD_PUBLIC_SEED === 'true') {
|
||||||
|
return (
|
||||||
|
<p>
|
||||||
|
{'Log in with the email '}
|
||||||
|
<strong>demo@payloadcms.com</strong>
|
||||||
|
{' and the password '}
|
||||||
|
<strong>demo</strong>.
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BeforeLogin
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import type { RichTextElement } from '@payloadcms/richtext-slate'
|
||||||
|
|
||||||
|
const elements: RichTextElement[] = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'link']
|
||||||
|
|
||||||
|
export default elements
|
||||||
92
examples/redirects/payload/src/fields/richText/index.ts
Normal file
92
examples/redirects/payload/src/fields/richText/index.ts
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import { slateEditor } from '@payloadcms/richtext-slate'
|
||||||
|
import type { RichTextElement, RichTextLeaf } from '@payloadcms/richtext-slate/dist/types'
|
||||||
|
import type { RichTextField } from 'payload/types'
|
||||||
|
|
||||||
|
import deepMerge from '../../utilities/deepMerge'
|
||||||
|
import link from '../link'
|
||||||
|
import elements from './elements'
|
||||||
|
import leaves from './leaves'
|
||||||
|
|
||||||
|
type RichText = (
|
||||||
|
overrides?: Partial<RichTextField>,
|
||||||
|
additions?: {
|
||||||
|
elements?: RichTextElement[]
|
||||||
|
leaves?: RichTextLeaf[]
|
||||||
|
},
|
||||||
|
) => RichTextField
|
||||||
|
|
||||||
|
const richText: RichText = (
|
||||||
|
overrides,
|
||||||
|
additions = {
|
||||||
|
elements: [],
|
||||||
|
leaves: [],
|
||||||
|
},
|
||||||
|
) =>
|
||||||
|
deepMerge<RichTextField, Partial<RichTextField>>(
|
||||||
|
{
|
||||||
|
name: 'richText',
|
||||||
|
type: 'richText',
|
||||||
|
required: true,
|
||||||
|
editor: slateEditor({
|
||||||
|
admin: {
|
||||||
|
upload: {
|
||||||
|
collections: {
|
||||||
|
media: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'richText',
|
||||||
|
name: 'caption',
|
||||||
|
label: 'Caption',
|
||||||
|
editor: slateEditor({
|
||||||
|
admin: {
|
||||||
|
elements: [...elements],
|
||||||
|
leaves: [...leaves],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'radio',
|
||||||
|
name: 'alignment',
|
||||||
|
label: 'Alignment',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'Left',
|
||||||
|
value: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Center',
|
||||||
|
value: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Right',
|
||||||
|
value: 'right',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'enableLink',
|
||||||
|
type: 'checkbox',
|
||||||
|
label: 'Enable Link',
|
||||||
|
},
|
||||||
|
link({
|
||||||
|
appearances: false,
|
||||||
|
disableLabel: true,
|
||||||
|
overrides: {
|
||||||
|
admin: {
|
||||||
|
condition: (_, data) => Boolean(data?.enableLink),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
elements: [...elements, ...(additions.elements || [])],
|
||||||
|
leaves: [...leaves, ...(additions.leaves || [])],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
overrides,
|
||||||
|
)
|
||||||
|
|
||||||
|
export default richText
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { RichTextLeaf } from 'payload/dist/fields/config/types'
|
import { RichTextLeaf } from '@payloadcms/richtext-slate'
|
||||||
|
|
||||||
const defaultLeaves: RichTextLeaf[] = ['bold', 'italic', 'underline']
|
const defaultLeaves: RichTextLeaf[] = ['bold', 'italic', 'underline']
|
||||||
|
|
||||||
117
examples/redirects/payload/src/payload-types.ts
Normal file
117
examples/redirects/payload/src/payload-types.ts
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* This file was automatically generated by Payload.
|
||||||
|
* 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 {
|
||||||
|
collections: {
|
||||||
|
pages: Page
|
||||||
|
users: User
|
||||||
|
redirects: Redirect
|
||||||
|
'payload-preferences': PayloadPreference
|
||||||
|
'payload-migrations': PayloadMigration
|
||||||
|
}
|
||||||
|
globals: {
|
||||||
|
'main-menu': MainMenu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export interface Page {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
richText: {
|
||||||
|
[k: string]: unknown
|
||||||
|
}[]
|
||||||
|
slug?: string
|
||||||
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
|
_status?: 'draft' | 'published'
|
||||||
|
}
|
||||||
|
export interface User {
|
||||||
|
id: string
|
||||||
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
|
email: string
|
||||||
|
resetPasswordToken?: string
|
||||||
|
resetPasswordExpiration?: string
|
||||||
|
salt?: string
|
||||||
|
hash?: string
|
||||||
|
loginAttempts?: number
|
||||||
|
lockUntil?: string
|
||||||
|
password?: string
|
||||||
|
}
|
||||||
|
export interface Redirect {
|
||||||
|
id: string
|
||||||
|
from: string
|
||||||
|
to: {
|
||||||
|
type?: 'reference' | 'custom'
|
||||||
|
reference: {
|
||||||
|
relationTo: 'pages'
|
||||||
|
value: string | Page
|
||||||
|
}
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
export interface PayloadPreference {
|
||||||
|
id: string
|
||||||
|
user: {
|
||||||
|
relationTo: 'users'
|
||||||
|
value: string | User
|
||||||
|
}
|
||||||
|
key?: string
|
||||||
|
value?:
|
||||||
|
| {
|
||||||
|
[k: string]: unknown
|
||||||
|
}
|
||||||
|
| unknown[]
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null
|
||||||
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
export interface PayloadMigration {
|
||||||
|
id: string
|
||||||
|
name?: string
|
||||||
|
batch?: number
|
||||||
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
export interface MainMenu {
|
||||||
|
id: string
|
||||||
|
navItems?: {
|
||||||
|
link: {
|
||||||
|
type?: 'reference' | 'custom'
|
||||||
|
newTab?: boolean
|
||||||
|
reference: {
|
||||||
|
relationTo: 'pages'
|
||||||
|
value: string | Page
|
||||||
|
}
|
||||||
|
url: string
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
id?: string
|
||||||
|
}[]
|
||||||
|
updatedAt?: string
|
||||||
|
createdAt?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'payload' {
|
||||||
|
export interface GeneratedTypes {
|
||||||
|
collections: {
|
||||||
|
pages: Page
|
||||||
|
users: User
|
||||||
|
redirects: Redirect
|
||||||
|
'payload-preferences': PayloadPreference
|
||||||
|
'payload-migrations': PayloadMigration
|
||||||
|
}
|
||||||
|
globals: {
|
||||||
|
'main-menu': MainMenu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import { webpackBundler } from '@payloadcms/bundler-webpack'
|
||||||
|
import { mongooseAdapter } from '@payloadcms/db-mongodb'
|
||||||
|
import { slateEditor } from '@payloadcms/richtext-slate'
|
||||||
import redirects from '@payloadcms/plugin-redirects'
|
import redirects from '@payloadcms/plugin-redirects'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { buildConfig } from 'payload/config'
|
import { buildConfig } from 'payload/config'
|
||||||
@@ -5,14 +8,25 @@ import { buildConfig } from 'payload/config'
|
|||||||
import { Pages } from './collections/Pages'
|
import { Pages } from './collections/Pages'
|
||||||
import { Users } from './collections/Users'
|
import { Users } from './collections/Users'
|
||||||
import { MainMenu } from './globals/MainMenu'
|
import { MainMenu } from './globals/MainMenu'
|
||||||
|
import BeforeLogin from './BeforeLogin'
|
||||||
|
|
||||||
export default buildConfig({
|
export default buildConfig({
|
||||||
collections: [Pages, Users],
|
collections: [Pages, Users],
|
||||||
|
admin: {
|
||||||
|
bundler: webpackBundler(),
|
||||||
|
components: {
|
||||||
|
beforeLogin: [BeforeLogin],
|
||||||
|
},
|
||||||
|
},
|
||||||
cors: ['http://localhost:3000', process.env.PAYLOAD_PUBLIC_SITE_URL],
|
cors: ['http://localhost:3000', process.env.PAYLOAD_PUBLIC_SITE_URL],
|
||||||
globals: [MainMenu],
|
globals: [MainMenu],
|
||||||
typescript: {
|
typescript: {
|
||||||
outputFile: path.resolve(__dirname, 'payload-types.ts'),
|
outputFile: path.resolve(__dirname, 'payload-types.ts'),
|
||||||
},
|
},
|
||||||
|
editor: slateEditor({}),
|
||||||
|
db: mongooseAdapter({
|
||||||
|
url: process.env.DATABASE_URI,
|
||||||
|
}),
|
||||||
plugins: [
|
plugins: [
|
||||||
redirects({
|
redirects({
|
||||||
collections: ['pages'],
|
collections: ['pages'],
|
||||||
@@ -1,7 +1,13 @@
|
|||||||
|
import path from 'path'
|
||||||
import type { Redirect } from '../payload-types'
|
import type { Redirect } from '../payload-types'
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
require('dotenv').config({
|
||||||
|
path: path.resolve(__dirname, '../../.env'),
|
||||||
|
})
|
||||||
|
|
||||||
export const externalRedirect: Partial<Redirect> = {
|
export const externalRedirect: Partial<Redirect> = {
|
||||||
from: 'http://localhost:3000/redirect-to-external',
|
from: `${process.env.PAYLOAD_PUBLIC_SITE_URL}/redirect-to-external`,
|
||||||
to: {
|
to: {
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
url: 'https://www.payloadcms.com',
|
url: 'https://www.payloadcms.com',
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
|
import path from 'path'
|
||||||
import type { Page } from '../payload-types'
|
import type { Page } from '../payload-types'
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
require('dotenv').config({
|
||||||
|
path: path.resolve(__dirname, '../../.env'),
|
||||||
|
})
|
||||||
|
|
||||||
export const home: Partial<Page> = {
|
export const home: Partial<Page> = {
|
||||||
title: 'Home Page',
|
title: 'Home Page',
|
||||||
slug: 'home',
|
slug: 'home',
|
||||||
@@ -56,7 +62,7 @@ export const home: Partial<Page> = {
|
|||||||
text: 'Paste ',
|
text: 'Paste ',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'http://localhost:3000/redirect-to-internal',
|
text: `${process.env.PAYLOAD_PUBLIC_SITE_URL}/redirect-to-internal`,
|
||||||
bold: true,
|
bold: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -79,7 +85,7 @@ export const home: Partial<Page> = {
|
|||||||
text: ', or paste ',
|
text: ', or paste ',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'http://localhost:3000/redirect-to-external',
|
text: `${process.env.PAYLOAD_PUBLIC_SITE_URL}/redirect-to-external`,
|
||||||
bold: true,
|
bold: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -9,8 +9,8 @@ export const seed = async (payload: Payload): Promise<void> => {
|
|||||||
await payload.create({
|
await payload.create({
|
||||||
collection: 'users',
|
collection: 'users',
|
||||||
data: {
|
data: {
|
||||||
email: 'dev@payloadcms.com',
|
email: 'demo@payloadcms.com',
|
||||||
password: 'test',
|
password: 'demo',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1,7 +1,13 @@
|
|||||||
|
import path from 'path'
|
||||||
import type { Redirect } from '../payload-types'
|
import type { Redirect } from '../payload-types'
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
require('dotenv').config({
|
||||||
|
path: path.resolve(__dirname, '../../.env'),
|
||||||
|
})
|
||||||
|
|
||||||
export const internalRedirect: Partial<Redirect> = {
|
export const internalRedirect: Partial<Redirect> = {
|
||||||
from: 'http://localhost:3000/redirect-to-internal',
|
from: `${process.env.PAYLOAD_PUBLIC_SITE_URL}/redirect-to-internal`,
|
||||||
to: {
|
to: {
|
||||||
type: 'reference',
|
type: 'reference',
|
||||||
reference: {
|
reference: {
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
|
import path from 'path'
|
||||||
import type { Page } from '../payload-types'
|
import type { Page } from '../payload-types'
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
require('dotenv').config({
|
||||||
|
path: path.resolve(__dirname, '../../.env'),
|
||||||
|
})
|
||||||
|
|
||||||
export const redirectPage: Partial<Page> = {
|
export const redirectPage: Partial<Page> = {
|
||||||
title: 'Redirect Page',
|
title: 'Redirect Page',
|
||||||
slug: 'redirected',
|
slug: 'redirected',
|
||||||
@@ -10,7 +16,7 @@ export const redirectPage: Partial<Page> = {
|
|||||||
text: 'You have been successfully redirected to this page if you navigated from ',
|
text: 'You have been successfully redirected to this page if you navigated from ',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'http://localhost:3000/redirect-to-internal',
|
text: `${process.env.PAYLOAD_PUBLIC_SITE_URL}/redirect-to-internal`,
|
||||||
bold: true,
|
bold: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -19,7 +19,6 @@ app.get('/', (_, res) => {
|
|||||||
const start = async (): Promise<void> => {
|
const start = async (): Promise<void> => {
|
||||||
await payload.init({
|
await payload.init({
|
||||||
secret: process.env.PAYLOAD_SECRET,
|
secret: process.env.PAYLOAD_SECRET,
|
||||||
mongoURL: process.env.MONGODB_URI,
|
|
||||||
express: app,
|
express: app,
|
||||||
onInit: () => {
|
onInit: () => {
|
||||||
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`)
|
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`)
|
||||||
@@ -31,7 +30,7 @@ const start = async (): Promise<void> => {
|
|||||||
await seed(payload)
|
await seed(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.listen(8000)
|
app.listen(3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
start()
|
start()
|
||||||
@@ -15,9 +15,6 @@
|
|||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"paths": {
|
|
||||||
"payload/generated-types": ["./src/payload-types.ts"]
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src"
|
"src"
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user