Compare commits

..

73 Commits

Author SHA1 Message Date
Elliot DeNolf
6b82196f01 chore(release): v3.0.0-beta.100 [skip ci] 2024-09-06 15:25:41 -04:00
Tylan Davis
ead12c8a49 fix(ui, next): adjust modal alignment and padding (#7931)
## Description

Updates styling on modals and auth forms for more consistent spacing and
alignment.

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-09-06 14:54:39 -04:00
Jacob Fletcher
6253ec5d1a fix(ui): optimizes the relationship field by sharing a single document drawer across all values (#8094)
## Description

Currently, the relationship field's _value(s)_ each render and controls
its own document drawer. This has led to `hasMany` relationships
processing a potentially large number of drawers unnecessarily. But the
real problem is when attempting to perform side-effects as a result of a
drawer action. Currently, when you change the value of a relationship
field, all drawers within are (rightfully) unmounted because the
component representing the value was itself unmounted. This meant that
you could not update the title of a document, for example, then update
the underlying field's value, without also closing the document drawer
outright. This is needed in order to support things like creating and
duplicating documents within document drawers (#7679).

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [x] Existing test suite passes locally with my changes
2024-09-06 14:00:53 -04:00
Jacob Fletcher
f9ae56ec88 fix(ui): handles falsey relationship options on reset (#8095) 2024-09-06 12:55:09 -04:00
Sasha
0688c2b79d fix(db-postgres): sanitize tab/group path for table name (#8009)
## Description

Fixes https://github.com/payloadcms/payload/issues/7109

Example of table structures that lead to the problem with camelCased
group / tab names.
`group_field_array_localized` - `groupField` -> `array` (has a localized
field inside)
`group_field_array_nested_array` - `groupField` -> `array` ->
`nestedArray`

<!-- Please include a summary of the pull request and any related issues
it fixes. Please also include relevant motivation and context. -->

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

<!-- Please delete options that are not relevant. -->

- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
2024-09-06 11:43:47 -04:00
Sasha
c6246618ba fix(cpa): detect package manager from command execution environment (#8087)
Previously, on some machines this command:
`pnpx create-payload-app@beta app` created a project using `npm`,
instead of `pnpm`, the same with `yarn`.

Also, the way we detected the package manager was always prioritizing
`pnpm`, even if they executed the command with `yarn` / `npm`. Now we
are relying only on from which package manager user executed
`create-payload-app`.

The code for detection is grabbed from create-next-app
https://github.com/vercel/next.js/blob/canary/packages/create-next-app/helpers/get-pkg-manager.ts
2024-09-06 08:57:20 -04:00
Alexander
b69826a81e feat(cpa): add support for bun package manager in v3 installer (#7709)
Adds support for bun package manger in v3, enabled with `--use-bun`
flag.

Related: #6932 (for v2)
2024-09-05 23:50:03 -04:00
Paul
e80da7cb75 chore: add jsdocs for authentication types and add missing config to docs (#8082) 2024-09-06 00:04:13 +00:00
Francisco Lourenço
6f512b6ca8 docs: fix TextFieldProps in client field component example (#8080)
## Description

Without using `React.FC<>`, the type needs to be placed on the right
side of the props object.

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

<!-- Please delete options that are not relevant. -->

- [x] Chore (non-breaking change which does not add functionality)

## Checklist:

- [ ] ~I have added tests that prove my fix is effective or that my
feature works~
- [ ] ~Existing test suite passes locally with my changes~
- [x] I have made corresponding changes to the documentation
2024-09-05 15:41:48 -06:00
Elliot DeNolf
22ee8bf383 chore(release): v3.0.0-beta.99 [skip ci] 2024-09-05 12:38:08 -04:00
Jacob Fletcher
308fad8a7a fix(ui): significantly optimizes relationship field (#8063)
## Description

Reduces the number of client-side requests made by the relationship
field component, and fixes the visual "blink" of the field's value on
initial load. Does so through a new `useIgnoredEffect` hook that allows
this component's effects to be precisely triggered based on whether a
only _subset_ of its dependencies have changed, which looks something
like this:

```tsx
// ...
useIgnoredEffect(() => {
  // Do something
}, [deps], [ignoredDeps])
```

"Ignored deps" are still treated as normal dependencies of the
underlying `useEffect` hook, but they do not cause the provided function
to execute. This is useful if you have a list of dependencies that
change often, but need to scope your effect's logic to explicit
dependencies within that list. This is a typical pattern in React using
refs, just standardized within a reusable hook.

This significantly reduces the overall number of re-renders and
duplicative API requests within the relationship field because the
`useEffect` hooks that control the fetching of these related documents
were running unnecessarily often. In the future, we really ought to
leverage the `RelationshipProvider` used in the List View so that we can
also reduce the number of duplicative requests across _unrelated fields_
within the same document.

Before:


https://github.com/user-attachments/assets/ece7c85e-20fb-49f6-b393-c5e9d5176192

After:


https://github.com/user-attachments/assets/9f0a871e-f10f-4fd6-a58b-8146ece288c4

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
2024-09-04 21:37:00 -04:00
Jessica Chowdhury
6427b7eb29 fix: only show restore as draft option when drafts enabled (#8066)
## Description

In version comparison view, the `Restore as draft` button should only be
visible when `versions.drafts: true`.

Before:
<img width="1414" alt="Screenshot 2024-09-04 at 3 33 21 PM"
src="https://github.com/user-attachments/assets/1f96d804-46d7-443a-99ea-7b6481839b47">

After:
<img width="1307" alt="Screenshot 2024-09-04 at 3 38 42 PM"
src="https://github.com/user-attachments/assets/d2621ddd-2b14-4dab-936c-29a5521444de">


- [X] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [X] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [X] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-09-04 19:54:34 +00:00
Sasha
3a657847f2 fix(db-postgres): query hasMany text/number in array/blocks (#8003)
## Description

Fixes https://github.com/payloadcms/payload/issues/7671

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)
## Checklist:

- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
2024-09-04 11:53:43 -04:00
Elliot DeNolf
8212c0d65f chore(eslint): silence some warnings that always get auto-fixed 2024-09-04 11:26:36 -04:00
Elliot DeNolf
772f869cc6 chore(release): v3.0.0-beta.98 [skip ci] 2024-09-03 12:59:23 -04:00
Alessio Gravili
b6a8d1c461 perf(richtext-lexical)!: greatly simplify lexical loading and improve performance (#8041)
We noticed that we can bring functions down to the client directly
without having to wrap them in a component first. This greatly
simplifies the loading of all lexical client components

**BREAKING:**
- `createClientComponent` is no longer exported as it's not needed
anymore
- The exported `ClientComponentProps` type has been renamed to
`BaseClientFeatureProps`.
- The order of arguments in `sanitizeClientEditorConfig` has changed
2024-09-03 12:48:41 -04:00
Elliot DeNolf
11576eda13 ci: adjust label pr on open [skip ci] (#8043) 2024-09-03 11:38:21 -04:00
Elliot DeNolf
3c62e6c772 chore(eslint): lint entire codebase including db packages (#8042) 2024-09-03 11:22:41 -04:00
Alessio Gravili
5b74879c5e chore: add lint commit to .git-blame-ignore-revs 2024-09-03 11:20:26 -04:00
Alessio Gravili
7fd736ea5b chore: lint entire codebase including db packages 2024-09-03 11:19:19 -04:00
Germán Jabloñski
7a3507d597 fix(richtext-lexical): toolbar styles (#7936)
fix https://github.com/payloadcms/payload/issues/7925.

The `active` style was not effective due to a typo in the CSS (`them`
instead of `theme`).

I took the opportunity to improve a few things:
- Now the colors on hover, active, and hover+active are slightly
different.
- Added a missing gap to the fixed toolbar buttons.

Gap changes: Before:
![CleanShot 2024-09-03 at 00 02
52@2x](https://github.com/user-attachments/assets/2381468c-7bdd-43f6-93b6-5baa587dd0a6)

After:
![CleanShot 2024-09-03 at 00 01
22@2x](https://github.com/user-attachments/assets/53d0cac9-9718-4b97-a478-f249b10d416e)


Thanks @tylandavis for the help!
2024-09-03 00:04:12 -04:00
Paul
9bcdf0dc81 fix(plugin-seo): meta image selection not working (#8024)
Fixes https://github.com/payloadcms/payload/issues/8016
2024-09-02 05:11:27 +00:00
Paul
8203fe86cd fix: padding on the right of the default padding when scrollbars are enabled in the browser (#8023) 2024-09-02 04:22:02 +00:00
Elliot DeNolf
39cd8283c8 chore(scripts): release notes emoji 2024-09-01 19:39:52 -04:00
Giuseppe Chiruzzi
1130a581c0 feat(plugin-seo): add Italian translations (#8020)
Added italian translation and updated index.ts
2024-09-01 23:03:12 +00:00
Riley Pearce
d9cccc7081 fix(richtext-lexical): incorrect error check in TableActionMenu (#7964)
Fixes #7961 and #8021
2024-09-01 18:29:02 -04:00
Elliot DeNolf
751803d4f4 chore(cpa): get templates using tar (#8006)
Remove `degit` in favor of tar files from codeload.

Degit is rather dated and has unfixed bugs such as #5402  and #7463 .
2024-08-30 22:51:32 -04:00
Paul
ee3d5856e3 fix: collection pagination limits being merged with defaults instead of overidden (#8004) 2024-08-30 23:29:20 +00:00
Paul
cf9e13aebb fix(ui): radio fields are now selectable as options in filtering in query builder (#8002) 2024-08-30 23:04:31 +00:00
Elliot DeNolf
9816787fbf chore: remove all unused imports (#7999)
Removes all unused imports.

Temporarily swapped in
https://github.com/sweepline/eslint-plugin-unused-imports to
differentiate between unused imports and unused vars. The default rule
does not differentiate.
2024-08-30 16:52:08 -04:00
Alessio Gravili
b5fb92530c chore(eslint): change no-empty-object-type to warn instead of error (#7998) 2024-08-30 20:29:06 +00:00
Elliot DeNolf
2c1c0dae70 chore(release): eslint/3.0.0-beta.97 2024-08-30 16:11:29 -04:00
Paul
9295a6130e chore(templates): bump versions to just beta instead of pinned (#7997) 2024-08-30 19:30:06 +00:00
Paul
91fc5fb31b chore(templates): update folder structure for seed script in website template (#7995) 2024-08-30 19:14:03 +00:00
Paul
e25730f95c fix(ui): list view crash when using a code field type (#7994) 2024-08-30 12:47:33 -06:00
Elliot DeNolf
7f6b0f087f chore(release): v3.0.0-beta.97 [skip ci] 2024-08-30 14:21:21 -04:00
Paul
c1533bfd3e fix(templates): add button to exit preview mode (#7991) 2024-08-30 17:44:11 +00:00
Elliot DeNolf
442d105841 fix: migrations exit code (#7989)
Migration command were not returning proper error codes on failure. This
caused issues with CI in particular.

Fixes #7031 for 3.0
2024-08-30 16:37:39 +00:00
Elliot DeNolf
c45ee0d26b ci: add drizzle as valid pr title scope [skip ci] 2024-08-30 12:25:24 -04:00
Jarrod Flesch
b97dcc33c7 chore: hoist selection provider (#7985) 2024-08-30 11:02:58 -04:00
Elliot DeNolf
8202c3dee8 feat: move logger configuration to Payload config (#7973)
Removes `loggerOptions` and `loggerDestination` from `initOptions`
(these were not able to be used anyway).

Creates new `logger` property on the Payload config.

```ts
// Logger options only
logger: {
   level: 'info',
}

// Logger options with destination stream
logger: {
   options: {
   level: 'info',
   },
   destination: process.stdout
},

// Logger instance
logger: pino({ name: 'my-logger' })
```
2024-08-30 09:37:51 -04:00
Paul
b6ae6890aa fix(ui): upload field not showing admin.description (#7978) 2024-08-30 04:22:43 +00:00
Elliot DeNolf
c14dbfba40 build: bump nodejs (#7935)
Bumped to 22.6.0
2024-08-29 23:46:06 -04:00
Elliot DeNolf
0a36529dc5 build(deps): bump node.js to 22.7.0 2024-08-29 23:29:40 -04:00
Paul
e033488db7 fix(nested-docs-plugin): throw an error to the UI if children are not passing validation (#7977) 2024-08-30 02:48:38 +00:00
Paul
90b3e83fc2 feat(templates): update website src directory structure (#7971) 2024-08-30 02:41:02 +00:00
Elliot DeNolf
76dda13ca1 chore: significantly improve test suite eslint performance, lint and prettier everything (#7975)
Linting test/admin beta: > 3 minutes (stopped counting after 3 min)
Linting test/admin after my PR: 8s

Linting ui beta: 18s
Linting ui after my PR:  18s
2024-08-29 22:13:05 -04:00
Paul
e071382a79 fix(ui): upload with has many bulk select not working with postgres (#7976)
Fixes https://github.com/payloadcms/payload/issues/7921
2024-08-30 02:01:38 +00:00
Alessio Gravili
131f2def3c chore: undo lint changes to db-* and drizzle 2024-08-29 22:01:37 -04:00
Alessio Gravili
d97cd2fd5d chore: add lint commit to .git-blame-ignore-revs 2024-08-29 21:36:33 -04:00
Alessio Gravili
86fdad0bb8 chore: significantly improve eslint performance, lint and prettier everything 2024-08-29 21:25:50 -04:00
Alessio Gravili
bc367ab73c chore(eslint): upgrade to typescript-eslint v8, upgrade all eslint packages (#7082) 2024-08-29 16:27:58 -04:00
Jacob Fletcher
c0728220ff fix(ui): propagates sort change events through list query provider (#7968) 2024-08-29 13:18:05 -04:00
Jacob Fletcher
6893f404ac chore: removes duplicative loop over column state to determine linked cells (#7958) 2024-08-29 12:35:51 -04:00
Elliot DeNolf
2a8bd4c775 chore(release): v3.0.0-beta.96 [skip ci] 2024-08-29 11:25:10 -04:00
James Mikrut
ac10bad723 fix(db-postgres): nested localized arrays (#7962)
## Description

Fixes a bug with nested arrays within either localized blocks or arrays.
2024-08-29 15:01:53 +00:00
Elliot DeNolf
142616e6ad chore(eslint): curly [skip-lint] (#7959)
Now enforcing curly brackets on all if statements. Includes auto-fixer.


```ts
//  Bad
if (foo) foo++;

//  Good
if (foo) {
  foo++;
}
```




Note: this did not lint the `drizzle` package or any `db-*` packages.
This will be done in the future.
2024-08-29 10:15:36 -04:00
Jarrod Flesch
dd3d985091 chore: upload field style fix (#7942) 2024-08-29 00:11:56 -04:00
Jarrod Flesch
de3d7c95e7 fix: prevents duplicate active nav indicators (#7943) 2024-08-29 00:11:42 -04:00
Elliot DeNolf
570422ff9a chore(db-mongodb): adjust default exports (#7945) 2024-08-29 04:09:44 +00:00
Elliot DeNolf
53c41bdfd8 chore(cpa): unused vars (#7944) 2024-08-29 03:59:44 +00:00
Elliot DeNolf
e5c34ead16 chore: plugin lint fixes (#7947) 2024-08-29 03:59:16 +00:00
Elliot DeNolf
6e561b11ca chore(graphql): adjust default exports (#7946) 2024-08-29 03:51:03 +00:00
Jarrod Flesch
f7146362df chore: brings back tests from has many PR (#7917) 2024-08-28 22:44:58 -04:00
Elliot DeNolf
ec9d1cda2d chore(eslint): lint:fix on all packages (#7941)
- Run `lint:fix` on all packages to fix anything that may have slipped
through without being autofixed
- A few manual fixes as well.
2024-08-29 02:35:17 +00:00
Elliot DeNolf
657326b528 chore(eslint): remove unused .eslintignore files [skip ci] 2024-08-28 22:12:19 -04:00
James Mikrut
538b7ee616 feat!: auto-removes localized property from localized fields within other localized fields (#7933)
## Description

Payload localization works on a field-by-field basis. As you can nest
fields within other fields, you could potentially nest a localized field
within a localized field—but this would be redundant and unnecessary.
There would be no reason to define a localized field within a localized
parent field, given that the entire data structure from the parent field
onward would be localized.

Up until this point, Payload would _allow_ you to nest a localized field
within another localized field, and this might have worked in MongoDB
but it will throw errors in Postgres.

Now, Payload will automatically remove the `localized: true` property
from sub-fields within `sanitizeFields` if a parent field is localized.

This could potentially be a breaking change if you have a configuration
with MongoDB that nests localized fields within localized fields.

## Migrating

You probably only need to migrate if you are using MongoDB, as there,
you may not have noticed any problems. But in Postgres or SQLite, this
would have caused issues so it's unlikely that you've made it too far
without experiencing issues due to a nested localized fields config.

In the event you would like to keep existing data in this fashion, we
have added a `compatibility.allowLocalizedWithinLocalized` flag to the
Payload config, which you can set to `true`, and Payload will then
disable this new sanitization step.

Set this compatibility flag to `true` only if you have an existing
Payload MongoDB database from pre-3.0, and you have nested localized
fields that you would like to maintain without migrating.
2024-08-29 01:56:17 +00:00
Elliot DeNolf
828f5d866d build(scripts): add lint scripts to all, turbo lint tasks [skip ci] 2024-08-28 21:55:51 -04:00
Alessio Gravili
e375f6e727 feat: significantly reduce payload install size by removing unnecessary monaco-editor dependency (#7939)
This reduces the total install size of `payload` from 115 MB to 34 MB. 

We never used monaco-editor within payload - we were only using
`@monaco-editor/react` which is a lot smaller.

Since we expose its types to the end user, we have to add it to our
`dependencies`, not `devDependencies`.

Before:
https://npmgraph.js.org/?q=payload@3.0.0-canary.1a675ae#select=exact%3Apayload%403.0.0-canary.1a675ae&zoom=w

After:
https://npmgraph.js.org/?q=payload%403.0.0-canary.cdb9474#zoom=h&select=exact%3Apayload%403.0.0-canary.cdb9474
2024-08-28 23:24:42 +00:00
Paul
cc9b877e88 fix: improve validation errors for unique fields (#7937) 2024-08-28 16:10:54 -06:00
Alessio Gravili
dc12047723 feat: reduce package size and amount of dependencies by upgrading json-schema-to-typescript (#7938)
Closes https://github.com/payloadcms/payload/issues/7934
2024-08-28 21:59:32 +00:00
Jarrod Flesch
12fb691e4f chore: upload dropzone style changes (#7932) 2024-08-28 15:49:14 -04:00
Alessio Gravili
0962850086 fix: incorrect config.upload types (#7874)
Fixes https://github.com/payloadcms/payload/issues/7698

Now exporting `FetchAPIFileUploadOptions` from payload, as that type is
now used in `config.upload`.
2024-08-28 15:39:51 -04:00
1254 changed files with 43649 additions and 18560 deletions

View File

@@ -22,3 +22,9 @@ fb7d1be2f3325d076b7c967b1730afcef37922c2
# 3.0 prettier & lint everywhere again
83fd4c66222d7846eeb5cc332dfa99bf1e830831
# Upgrade to typescript-eslint v8, then prettier & lint everywhere
86fdad0bb8ab27810599c8a32f3d8cba1341e1df
# Prettier and lint remaining db packages
7fd736ea5b2e9fc4ef936e9dc9e5e3d722f6d8bf

View File

@@ -17,7 +17,7 @@ concurrency:
cancel-in-progress: true
env:
NODE_VERSION: 18.20.2
NODE_VERSION: 22.6.0
PNPM_VERSION: 9.7.1
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry

View File

@@ -39,6 +39,7 @@ jobs:
db-mongodb
db-postgres
db-sqlite
drizzle
email-nodemailer
eslint
graphql
@@ -106,14 +107,15 @@ jobs:
label-pr-on-open:
name: label-pr-on-open
runs-on: ubuntu-latest
if: github.event.action == 'opened'
steps:
- name: Tag with main branch with v2
if: github.event.action == 'opened' && github.event.pull_request.base.ref == 'main'
if: github.event.pull_request.base.ref == 'main'
uses: actions-ecosystem/action-add-labels@v1
with:
labels: v2
- name: Tag with beta branch with v3
if: github.event.action == 'opened' && github.event.pull_request.base.ref == 'beta'
if: github.event.pull_request.base.ref == 'beta'
uses: actions-ecosystem/action-add-labels@v1
with:
labels: v3

View File

@@ -6,7 +6,7 @@ on:
- beta
env:
NODE_VERSION: 18.20.2
NODE_VERSION: 22.6.0
PNPM_VERSION: 9.7.1
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry

View File

@@ -1 +1 @@
v18.20.2
v22.6.0

2
.nvmrc
View File

@@ -1 +1 @@
v18.20.2
v22.6.0

2
.tool-versions Normal file
View File

@@ -0,0 +1,2 @@
pnpm 9.7.1
nodejs 22.6.0

11
.vscode/settings.json vendored
View File

@@ -31,8 +31,15 @@
"editor.formatOnSave": true
},
"editor.formatOnSaveMode": "file",
// All ESLint rules to 'warn' to differentate from TypeScript's 'error' level
"eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
"eslint.rules.customizations": [
// Defaultt all ESLint errors to 'warn' to differentate from TypeScript's 'error' level
{ "rule": "*", "severity": "warn" },
// Silence some warnings that will get auto-fixed
{ "rule": "perfectionist/*", "severity": "off", "fixable": true },
{ "rule": "curly", "severity": "off", "fixable": true },
{ "rule": "object-shorthand", "severity": "off", "fixable": true }
],
"typescript.tsdk": "node_modules/typescript/lib",
// Load .git-blame-ignore-revs file
"gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"],

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
<a href="https://payloadcms.com"><img width="100%" src="https://github.com/payloadcms/payload/blob/main/packages/payload/src/admin/assets/images/github-banner-alt.jpg?raw=true" alt="Payload headless CMS Admin panel built with React" /></a>
<br />
<br />
<p align="left">
<a href="https://github.com/payloadcms/payload/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/payloadcms/payload/main.yml?style=flat-square"></a>
&nbsp;

View File

@@ -438,7 +438,7 @@ All [Field Components](./fields) automatically receive their respective Client F
import React from 'react'
import type { TextFieldProps } from 'payload'
export const MyClientFieldComponent: TextFieldProps = ({ field: { name } }) => {
export const MyClientFieldComponent = ({ field: { name } }: TextFieldProps) => {
return (
<p>
{`This field's name is ${name}`}

View File

@@ -85,6 +85,7 @@ The following options are available:
| **`lockTime`** | Set the time (in milliseconds) that a user should be locked out if they fail authentication more times than `maxLoginAttempts` allows for. |
| **`loginWithUsername`** | Ability to allow users to login with username/password. [More](/docs/authentication/overview#login-with-username) |
| **`maxLoginAttempts`** | Only allow a user to attempt logging in X amount of times. Automatically locks out a user from authenticating if this limit is passed. Set to `0` to disable. |
| **`removeTokenFromResponses`** | Set to true if you want to remove the token from the returned authentication API responses such as login or refresh. |
| **`strategies`** | Advanced - an array of custom authentification strategies to extend this collection's authentication with. [More details](./custom-strategies). |
| **`tokenExpiration`** | How long (in seconds) to keep the user logged in. JWTs and HTTP-only cookies will both expire at the same time. |
| **`useAPIKey`** | Payload Authentication provides for API keys to be set on each user within an Authentication-enabled Collection. [More details](./api-keys). |

View File

@@ -71,9 +71,11 @@ The following options are available:
| **`db`** \* | The Database Adapter which will be used by Payload. [More details](../database/overview). |
| **`serverURL`** | A string used to define the absolute URL of your app. This includes the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port. |
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
| **`compatibility`** | Compatibility flags for earlier versions of Payload. [More details](#compatibility-flags). |
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cors). |
| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). |
| **`logger`** | Logger options, logger options with a destination stream, or an instantiated logger instance. [More details](https://getpino.io/#/docs/api?id=options). |
| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). |
| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. |
| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/overview#csrf-protection). |
@@ -253,3 +255,13 @@ import type { Config, SanitizedConfig } from 'payload'
The Payload Config only lives on the server and is not allowed to contain any client-side code. That way, you can load up the Payload Config in any server environment or standalone script, without having to use Bundlers or Node.js loaders to handle importing client-only modules (e.g. scss files or React Components) without any errors.
Behind the curtains, the Next.js-based Admin Panel generates a ClientConfig, which strips away any server-only code and enriches the config with React Components.
## Compatibility flags
The Payload Config can accept compatibility flags for running the newest versions but with older databases. You should only use these flags if you need to, and should confirm that you need to prior to enabling these flags.
`allowLocalizedWithinLocalized`
Payload localization works on a field-by-field basis. As you can nest fields within other fields, you could potentially nest a localized field within a localized field—but this would be redundant and unnecessary. There would be no reason to define a localized field within a localized parent field, given that the entire data structure from the parent field onward would be localized.
By default, Payload will remove the `localized: true` property from sub-fields if a parent field is localized. Set this compatibility flag to `true` only if you have an existing Payload MongoDB database from pre-3.0, and you have nested localized fields that you would like to maintain without migrating.

View File

@@ -57,7 +57,6 @@ export default buildConfig({
| `pool` \* | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres` or to `@vercel/postgres` |
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
| `migrationDir` | Customize the directory that migrations are stored. |
| `logger` | The instance of the logger to be passed to drizzle. By default Payload's will be used. |
| `schemaName` (experimental) | A string for the postgres schema to use, defaults to 'public'. |
| `idType` | A string of 'serial', or 'uuid' that is used for the data type given to id columns. |
| `transactionOptions` | A PgTransactionConfig object for transactions, or set to `false` to disable using transactions. [More details](https://orm.drizzle.team/docs/transactions) |

View File

@@ -25,13 +25,12 @@ export const defaultESLintIgnores = [
let FlatConfig
export const rootParserOptions = {
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
EXPERIMENTAL_useProjectService: {
allowDefaultProjectForFiles: ['./src/*.ts', './src/*.tsx'],
maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING: 100,
},
sourceType: 'module',
ecmaVersion: 'latest',
projectService: {
maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING: 40,
allowDefaultProject: ['scripts/*.ts', '*.js', '*.mjs', '*.spec.ts', '*.d.ts'],
},
}
/** @type {FlatConfig[]} */
@@ -40,20 +39,12 @@ export const rootEslintConfig = [
{
ignores: [
...defaultESLintIgnores,
'packages/eslint-*/**',
'test/live-preview/next-app',
'packages/**/*.spec.ts',
'templates/**',
],
},
{
languageOptions: {
parserOptions: {
project: './tsconfig.json',
tsconfigDirName: import.meta.dirname,
...rootParserOptions,
},
},
},
{
plugins: {
payload: payloadPlugin,
@@ -78,6 +69,15 @@ export const rootEslintConfig = [
export default [
...rootEslintConfig,
{
languageOptions: {
parserOptions: {
...rootParserOptions,
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
files: ['packages/eslint-config/**/*.ts'],
rules: {

View File

@@ -15,7 +15,7 @@
width: 150px;
}
:global([data-theme="light"]) {
:global([data-theme='light']) {
.logo {
filter: invert(1);
}

View File

@@ -10,12 +10,12 @@ export const RenderParams: React.FC<{
className?: string
}> = ({ params = ['error', 'message', 'success'], message, className }) => {
const searchParams = useSearchParams()
const paramValues = params.map(param => searchParams.get(param)).filter(Boolean)
const paramValues = params.map((param) => searchParams.get(param)).filter(Boolean)
if (paramValues.length) {
return (
<div className={className}>
{paramValues.map(paramValue => (
{paramValues.map((paramValue) => (
<Message
key={paramValue}
message={(message || 'PARAM')?.replace('PARAM', paramValue || '')}

View File

@@ -1,7 +1,7 @@
@use './queries.scss' as *;
@use './colors.scss' as *;
@use './type.scss' as *;
@import "./theme.scss";
@import './theme.scss';
:root {
--base: 24px;
@@ -88,7 +88,7 @@ p {
margin: var(--base) 0;
@include mid-break {
margin: calc(var(--base) * .75) 0;
margin: calc(var(--base) * 0.75) 0;
}
}
@@ -102,12 +102,12 @@ a {
color: currentColor;
&:focus {
opacity: .8;
opacity: 0.8;
outline: none;
}
&:active {
opacity: .7;
opacity: 0.7;
outline: none;
}
}

View File

@@ -16,7 +16,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const [user, setUser] = useState<User | null>()
const create = useCallback<Create>(
async args => {
async (args) => {
if (api === 'rest') {
const user = await rest(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users`, args)
setUser(user)
@@ -38,7 +38,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
)
const login = useCallback<Login>(
async args => {
async (args) => {
if (api === 'rest') {
const user = await rest(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/login`, args)
setUser(user)
@@ -110,7 +110,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
}, [api])
const forgotPassword = useCallback<ForgotPassword>(
async args => {
async (args) => {
if (api === 'rest') {
const user = await rest(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/forgot-password`,
@@ -132,7 +132,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
)
const resetPassword = useCallback<ResetPassword>(
async args => {
async (args) => {
if (api === 'rest') {
const user = await rest(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/reset-password`,

View File

@@ -1,4 +1,4 @@
@import "../../_css/common";
@import '../../_css/common';
.form {
margin-bottom: var(--base);

View File

@@ -139,7 +139,7 @@ export const AccountForm: React.FC = () => {
label="Confirm Password"
required
register={register}
validate={value => value === password.current || 'The passwords do not match'}
validate={(value) => value === password.current || 'The passwords do not match'}
error={errors.passwordConfirm}
/>
</Fragment>

View File

@@ -1,4 +1,4 @@
@import "../../_css/common";
@import '../../_css/common';
.form {
margin-bottom: var(--base);

View File

@@ -103,7 +103,7 @@ export const CreateAccountForm: React.FC = () => {
label="Confirm Password"
required
register={register}
validate={value => value === password.current || 'The passwords do not match'}
validate={(value) => value === password.current || 'The passwords do not match'}
error={errors.passwordConfirm}
/>
<Button

View File

@@ -1,4 +1,4 @@
@import "../_css/common";
@import '../_css/common';
.createAccount {
margin-bottom: var(--block-padding);

View File

@@ -1,4 +1,4 @@
@import "../../_css/common";
@import '../../_css/common';
.form {
margin-bottom: var(--base);

View File

@@ -1,4 +1,4 @@
@import "../_css/common";
@import '../_css/common';
.login {
margin-bottom: var(--block-padding);

View File

@@ -5,7 +5,7 @@ import Link from 'next/link'
import { useAuth } from '../../_providers/Auth'
export const LogoutPage: React.FC = props => {
export const LogoutPage: React.FC = (props) => {
const { logout } = useAuth()
const [success, setSuccess] = useState('')
const [error, setError] = useState('')

View File

@@ -1,4 +1,4 @@
@import "../../_css/common";
@import '../../_css/common';
.error {
color: red;
@@ -20,4 +20,3 @@
.message {
margin-bottom: var(--base);
}

View File

@@ -1,4 +1,4 @@
@import "../_css/common";
@import '../_css/common';
.recoverPassword {
margin-bottom: var(--block-padding);

View File

@@ -1,4 +1,4 @@
@import "../../_css/common";
@import '../../_css/common';
.form {
width: 66.66%;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,7 @@
width: 150px;
}
:global([data-theme="light"]) {
:global([data-theme='light']) {
.logo {
filter: invert(1);
}

View File

@@ -9,12 +9,12 @@ export const RenderParams: React.FC<{
}> = ({ params = ['error', 'message', 'success'], message, className }) => {
const router = useRouter()
const searchParams = new URLSearchParams(router.query as any)
const paramValues = params.map(param => searchParams.get(param)).filter(Boolean)
const paramValues = params.map((param) => searchParams.get(param)).filter(Boolean)
if (paramValues.length) {
return (
<div className={className}>
{paramValues.map(paramValue => (
{paramValues.map((paramValue) => (
<Message key={paramValue} message={(message || 'PARAM')?.replace('PARAM', paramValue)} />
))}
</div>

View File

@@ -1,7 +1,7 @@
@use './queries.scss' as *;
@use './colors.scss' as *;
@use './type.scss' as *;
@import "./theme.scss";
@import './theme.scss';
:root {
--base: 24px;
@@ -88,7 +88,7 @@ p {
margin: var(--base) 0;
@include mid-break {
margin: calc(var(--base) * .75) 0;
margin: calc(var(--base) * 0.75) 0;
}
}
@@ -102,12 +102,12 @@ a {
color: currentColor;
&:focus {
opacity: .8;
opacity: 0.8;
outline: none;
}
&:active {
opacity: .7;
opacity: 0.7;
outline: none;
}
}

View File

@@ -1,4 +1,4 @@
@import "../../css/common";
@import '../../css/common';
.account {
margin-bottom: var(--block-padding);

View File

@@ -150,7 +150,7 @@ const Account: React.FC = () => {
label="Confirm Password"
required
register={register}
validate={value => value === password.current || 'The passwords do not match'}
validate={(value) => value === password.current || 'The passwords do not match'}
error={errors.passwordConfirm}
/>
</Fragment>

View File

@@ -1,4 +1,4 @@
@import "../../css/common";
@import '../../css/common';
.createAccount {
margin-bottom: var(--block-padding);

View File

@@ -106,7 +106,7 @@ const CreateAccount: React.FC = () => {
label="Confirm Password"
required
register={register}
validate={value => value === password.current || 'The passwords do not match'}
validate={(value) => value === password.current || 'The passwords do not match'}
error={errors.passwordConfirm}
/>
<Button

View File

@@ -1,4 +1,4 @@
@import "../../css/common";
@import '../../css/common';
.login {
margin-bottom: var(--block-padding);

View File

@@ -1,4 +1,4 @@
@import "../../css/common";
@import '../../css/common';
.recoverPassword {
margin-bottom: var(--block-padding);
@@ -24,4 +24,3 @@
.message {
margin-bottom: var(--base);
}

View File

@@ -1,4 +1,4 @@
@import "../../css/common";
@import '../../css/common';
.resetPassword {
margin-bottom: var(--block-padding);

View File

@@ -14,7 +14,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const [user, setUser] = useState<User | null>()
const create = useCallback<Create>(
async args => {
async (args) => {
if (api === 'rest') {
const user = await rest(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users`, args)
setUser(user)
@@ -36,7 +36,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
)
const login = useCallback<Login>(
async args => {
async (args) => {
if (api === 'rest') {
const user = await rest(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/login`, args)
setUser(user)
@@ -108,7 +108,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
}, [api])
const forgotPassword = useCallback<ForgotPassword>(
async args => {
async (args) => {
if (api === 'rest') {
const user = await rest(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/forgot-password`,
@@ -130,7 +130,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
)
const resetPassword = useCallback<ResetPassword>(
async args => {
async (args) => {
if (api === 'rest') {
const user = await rest(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/reset-password`,

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
'use client'
import type { ElementType } from 'react';
import type { ElementType } from 'react'
import Link from 'next/link'
import React from 'react'

View File

@@ -1,4 +1,4 @@
import type { Ref } from 'react';
import type { Ref } from 'react'
import React, { forwardRef } from 'react'

View File

@@ -15,7 +15,7 @@
width: 150px;
}
:global([data-theme="light"]) {
:global([data-theme='light']) {
.logo {
filter: invert(1);
}

View File

@@ -10,12 +10,12 @@ export const RenderParams: React.FC<{
params?: string[]
}> = ({ className, message, params = ['error', 'message', 'success'] }) => {
const searchParams = useSearchParams()
const paramValues = params.map(param => searchParams.get(param)).filter(Boolean)
const paramValues = params.map((param) => searchParams.get(param)).filter(Boolean)
if (paramValues.length) {
return (
<div className={className}>
{paramValues.map(paramValue => (
{paramValues.map((paramValue) => (
<Message
key={paramValue}
message={(message || 'PARAM')?.replace('PARAM', paramValue || '')}

View File

@@ -1,4 +1,4 @@
@import "../../_css/common";
@import '../../_css/common';
.form {
margin-bottom: var(--base);

View File

@@ -136,7 +136,7 @@ export const AccountForm: React.FC = () => {
register={register}
required
type="password"
validate={value => value === password.current || 'The passwords do not match'}
validate={(value) => value === password.current || 'The passwords do not match'}
/>
</Fragment>
)}

View File

@@ -1,4 +1,4 @@
@import "../../_css/common";
@import '../../_css/common';
.form {
margin-bottom: var(--base);

View File

@@ -103,7 +103,7 @@ export const CreateAccountForm: React.FC = () => {
register={register}
required
type="password"
validate={value => value === password.current || 'The passwords do not match'}
validate={(value) => value === password.current || 'The passwords do not match'}
/>
<Button
appearance="primary"

View File

@@ -1,4 +1,4 @@
@import "../_css/common";
@import '../_css/common';
.createAccount {
margin-bottom: var(--block-padding);

View File

@@ -1,4 +1,4 @@
@import "../../_css/common";
@import '../../_css/common';
.form {
margin-bottom: var(--base);

View File

@@ -1,4 +1,4 @@
@import "../_css/common";
@import '../_css/common';
.login {
margin-bottom: var(--block-padding);

View File

@@ -1,4 +1,4 @@
@import "../../_css/common";
@import '../../_css/common';
.error {
color: red;
@@ -20,4 +20,3 @@
.message {
margin-bottom: var(--base);
}

View File

@@ -1,4 +1,4 @@
@import "../_css/common";
@import '../_css/common';
.recoverPassword {
margin-bottom: var(--block-padding);

View File

@@ -1,4 +1,4 @@
@import "../../_css/common";
@import '../../_css/common';
.form {
width: 66.66%;

View File

@@ -3,8 +3,8 @@ import type { User } from '../../payload-types'
export const checkRole = (allRoles: User['roles'] = [], user: User = undefined): boolean => {
if (user) {
if (
allRoles.some(role => {
return user?.roles?.some(individualRole => {
allRoles.some((role) => {
return user?.roles?.some((individualRole) => {
return individualRole === role
})
})

View File

@@ -100,10 +100,10 @@ On boot, a seed script is included to scaffold a basic database for you to use a
### Conflicting routes
>In a monorepo when routes are bootstrapped to the same host, they can conflict with Payload's own routes if they have the same name. In our template we've named the Nextjs API routes to `next` to avoid this conflict.
> In a monorepo when routes are bootstrapped to the same host, they can conflict with Payload's own routes if they have the same name. In our template we've named the Nextjs API routes to `next` to avoid this conflict.
>
>This can happen with any other routes conflicting with Payload such as `admin` and we recommend using different names for custom routes.
>Alternatively you can also rename Payload's own routes via the [configuration](https://payloadcms.com/docs/configuration/overview).
> This can happen with any other routes conflicting with Payload such as `admin` and we recommend using different names for custom routes.
> Alternatively you can also rename Payload's own routes via the [configuration](https://payloadcms.com/docs/configuration/overview).
## Production

View File

@@ -10,12 +10,12 @@ const files = ['./next.config.js', './next-env.d.ts']
const directories = ['./src/app']
const eject = async (): Promise<void> => {
files.forEach(file => {
files.forEach((file) => {
fs.unlinkSync(path.join(__dirname, file))
})
directories.forEach(directory => {
fs.rm(path.join(__dirname, directory), { recursive: true }, err => {
directories.forEach((directory) => {
fs.rm(path.join(__dirname, directory), { recursive: true }, (err) => {
if (err) throw err
})
})

View File

@@ -29,7 +29,18 @@ $breakpoint: 1000px;
html {
font-size: 20px;
line-height: 1.5;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-family:
system-ui,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Open Sans',
'Helvetica Neue',
sans-serif;
@media (max-width: $breakpoint) {
font-size: 16px;

View File

@@ -20,7 +20,7 @@ const start = async (): Promise<void> => {
const payload = await getPayloadClient({
initOptions: {
express: app,
onInit: async newPayload => {
onInit: async (newPayload) => {
newPayload.logger.info(`Payload Admin URL: ${newPayload.getAdminURL()}`)
},
},

View File

@@ -18,7 +18,7 @@ const start = async (): Promise<void> => {
const payload = await getPayloadClient({
initOptions: {
express: app,
onInit: async newPayload => {
onInit: async (newPayload) => {
newPayload.logger.info(`Payload Admin URL: ${newPayload.getAdminURL()}`)
},
},

View File

@@ -4,10 +4,7 @@
"module": "commonjs",
"outDir": "dist",
"noEmit": false,
"jsx": "react",
"jsx": "react"
},
"include": [
"src/server.ts",
"src/payload.config.ts",
]
"include": ["src/server.ts", "src/payload.config.ts"]
}

View File

@@ -33,7 +33,7 @@ export const fetchPage = async (
}
: {}),
},
).then(res => res.json())
).then((res) => res.json())
return pageRes?.docs?.[0] ?? null
}

View File

@@ -3,8 +3,8 @@ import type { Page } from '../../payload-types'
export const fetchPages = async (): Promise<Page[]> => {
const pageRes: {
docs: Page[]
} = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/pages?depth=0&limit=100`).then(res =>
res.json(),
} = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/pages?depth=0&limit=100`).then(
(res) => res.json(),
) // eslint-disable-line function-paren-newline
return pageRes?.docs ?? []

View File

@@ -9,7 +9,7 @@ import classes from './index.module.scss'
const Title: React.FC = () => <span>Dashboard</span>
export const AdminBarClient: React.FC<PayloadAdminBarProps> = props => {
export const AdminBarClient: React.FC<PayloadAdminBarProps> = (props) => {
const [user, setUser] = useState<PayloadMeUser>()
return (

View File

@@ -11,7 +11,7 @@ import classes from './index.module.scss'
export async function Header() {
const mainMenu: MainMenu = await fetch(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/globals/main-menu`,
).then(res => res.json())
).then((res) => res.json())
const { navItems } = mainMenu

View File

@@ -29,7 +29,18 @@ $breakpoint: 1000px;
html {
font-size: 20px;
line-height: 1.5;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-family:
system-ui,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Open Sans',
'Helvetica Neue',
sans-serif;
@media (max-width: $breakpoint) {
font-size: 16px;

View File

@@ -11,7 +11,7 @@ export const AdminBar: React.FC<{
adminBarProps?: PayloadAdminBarProps
user?: PayloadMeUser
setUser?: (user: PayloadMeUser) => void // eslint-disable-line no-unused-vars
}> = props => {
}> = (props) => {
const { adminBarProps, user, setUser } = props
return (

View File

@@ -43,7 +43,7 @@ export const Header: React.FC<{
mainMenu: MainMenu
}
adminBarProps: PayloadAdminBarProps
}> = props => {
}> = (props) => {
const { globals, adminBarProps } = props
const [user, setUser] = useState<PayloadMeUser>()

View File

@@ -14,7 +14,7 @@ const Page: React.FC<
mainMenu: MainMenu
preview?: boolean
}
> = props => {
> = (props) => {
const { title, richText } = props
return (
@@ -119,7 +119,7 @@ export const getStaticPaths: GetStaticPaths = async () => {
const { docs: pages } = pagesData
if (pages && Array.isArray(pages) && pages.length > 0) {
paths = pages.map(page => ({ params: { slug: page.slug } }))
paths = pages.map((page) => ({ params: { slug: page.slug } }))
}
}

View File

@@ -29,7 +29,18 @@ $breakpoint: 1000px;
html {
font-size: 20px;
line-height: 1.5;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-family:
system-ui,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Open Sans',
'Helvetica Neue',
sans-serif;
@media (max-width: $breakpoint) {
font-size: 16px;
@@ -136,7 +147,18 @@ $breakpoint: 1000px;
html {
font-size: 20px;
line-height: 1.5;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-family:
system-ui,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Open Sans',
'Helvetica Neue',
sans-serif;
@media (max-width: $breakpoint) {
font-size: 16px;

View File

@@ -4,7 +4,7 @@ import Page, { getStaticProps as sharedGetStaticProps } from './[slug]'
export default Page
export const getStaticProps: GetStaticProps = async ctx => {
export const getStaticProps: GetStaticProps = async (ctx) => {
const func = sharedGetStaticProps.bind(this)
return func(ctx)
}

View File

@@ -12,10 +12,10 @@
"preLaunchTask": "npm: build:server",
"env": {
"PAYLOAD_CONFIG_PATH": "${workspaceFolder}/src/payload.config.ts"
},
}
// "outFiles": [
// "${workspaceFolder}/dist/**/*.js"
// ]
},
}
]
}

View File

@@ -11,7 +11,7 @@ export const Pages: CollectionConfig = {
admin: {
useAsTitle: 'title',
defaultColumns: ['title', 'slug', 'updatedAt'],
preview: doc => {
preview: (doc) => {
return `${process.env.PAYLOAD_PUBLIC_SITE_URL}/api/preview?url=${encodeURIComponent(
formatAppURL({
doc,

View File

@@ -125,7 +125,7 @@ const link: LinkType = ({ appearances, disableLabel = false, overrides = {} } =
]
if (appearances) {
appearanceOptionsToUse = appearances.map(appearance => appearanceOptions[appearance])
appearanceOptionsToUse = appearances.map((appearance) => appearanceOptions[appearance])
}
linkResult.fields.push({

View File

@@ -17,7 +17,7 @@ export function isObject(item: unknown): boolean {
export default function deepMerge<T, R>(target: T, source: R): T {
const output = { ...target }
if (isObject(target) && isObject(source)) {
Object.keys(source).forEach(key => {
Object.keys(source).forEach((key) => {
if (isObject(source[key])) {
if (!(key in target)) {
Object.assign(output, { [key]: source[key] })

View File

@@ -32,7 +32,7 @@ const Newsletter: CollectionConfig = {
name: 'email',
type: 'text',
required: true,
}
},
],
}

View File

@@ -3,8 +3,7 @@ import generateEmailHTML from './generateEmailHTML'
const generateForgotPasswordEmail = async ({ token }): Promise<string> =>
generateEmailHTML({
headline: 'Locked out?',
content:
'<p>Let&apos;s get you back in.</p>',
content: '<p>Let&apos;s get you back in.</p>',
cta: {
buttonLabel: 'Reset your password',
url: `${process.env.PAYLOAD_PUBLIC_SERVER_URL}/reset-password?token=${token}`,

View File

@@ -1,317 +1,345 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style type="text/css">
body,
html {
margin: 0;
padding: 0;
}
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style type="text/css">
body,
html {
margin: 0;
padding: 0;
}
body,
html,
.bg {
height: 100%;
}
body,
html,
.bg {
height: 100%;
}
body,
h1,
h2,
h3,
h4,
p,
em,
strong {
font-family: sans-serif;
}
body,
h1,
h2,
h3,
h4,
p,
em,
strong {
font-family: sans-serif;
}
body {
font-size: 15px;
color: #333333;
}
body {
font-size: 15px;
color: #333333;
}
a {
color: #333333;
outline: 0;
text-decoration: underline;
}
a {
color: #333333;
outline: 0;
text-decoration: underline;
}
a img {
border: 0;
outline: 0;
}
a img {
border: 0;
outline: 0;
}
img {
max-width: 100%;
height: auto;
vertical-align: top;
}
img {
max-width: 100%;
height: auto;
vertical-align: top;
}
h1,
h2,
h3,
h4,
h5 {
font-weight: 900;
line-height: 1.25;
}
h1 {
font-size: 40px;
color: #333333;
margin: 0 0 25px 0;
}
h2 {
color: #333333;
margin: 0 0 25px 0;
font-size: 30px;
line-height: 30px;
}
h3 {
font-size: 25px;
color: #333333;
margin: 0 0 25px 0;
}
h4 {
font-size: 20px;
color: #333333;
margin: 0 0 15px 0;
line-height: 30px;
}
h5 {
color: #333333;
font-size: 17px;
font-weight: 900;
margin: 0 0 15px;
}
table {
border-collapse: collapse;
}
p,
td {
font-size: 14px;
line-height: 25px;
color: #333333;
}
p {
margin: 0 0 25px;
}
ul {
padding-left: 15px;
margin-left: 15px;
font-size: 14px;
line-height: 25px;
margin-bottom: 25px;
}
li {
font-size: 14px;
line-height: 25px;
color: #333333;
}
table.hr td {
font-size: 0;
line-height: 2px;
}
.white {
color: white;
}
/********************************
MAIN
********************************/
.main {
background: white;
}
/********************************
MAX WIDTHS
********************************/
.max-width {
max-width: 800px;
width: 94%;
margin: 0 3%;
}
/********************************
REUSABLES
********************************/
.padding {
padding: 60px;
}
.center {
text-align: center;
}
.no-border {
border: 0;
outline: none;
text-decoration: none;
}
.no-margin {
margin: 0;
}
.spacer {
line-height: 45px;
height: 45px;
}
/********************************
PANELS
********************************/
.panel {
width: 100%;
}
@media screen and (max-width : 800px) {
h1,
h2,
h3,
h4,
h5 {
font-weight: 900;
line-height: 1.25;
}
h1 {
font-size: 24px !important;
margin: 0 0 20px 0 !important;
font-size: 40px;
color: #333333;
margin: 0 0 25px 0;
}
h2 {
font-size: 20px !important;
margin: 0 0 20px 0 !important;
color: #333333;
margin: 0 0 25px 0;
font-size: 30px;
line-height: 30px;
}
h3 {
font-size: 20px !important;
margin: 0 0 20px 0 !important;
font-size: 25px;
color: #333333;
margin: 0 0 25px 0;
}
h4 {
font-size: 18px !important;
margin: 0 0 15px 0 !important;
font-size: 20px;
color: #333333;
margin: 0 0 15px 0;
line-height: 30px;
}
h5 {
font-size: 15px !important;
margin: 0 0 10px !important;
color: #333333;
font-size: 17px;
font-weight: 900;
margin: 0 0 15px;
}
table {
border-collapse: collapse;
}
p,
td {
font-size: 14px;
line-height: 25px;
color: #333333;
}
p {
margin: 0 0 25px;
}
ul {
padding-left: 15px;
margin-left: 15px;
font-size: 14px;
line-height: 25px;
margin-bottom: 25px;
}
li {
font-size: 14px;
line-height: 25px;
color: #333333;
}
table.hr td {
font-size: 0;
line-height: 2px;
}
.white {
color: white;
}
/********************************
MAIN
********************************/
.main {
background: white;
}
/********************************
MAX WIDTHS
********************************/
.max-width {
width: 90% !important;
margin: 0 5% !important;
max-width: 800px;
width: 94%;
margin: 0 3%;
}
td.padding {
padding: 30px !important;
/********************************
REUSABLES
********************************/
.padding {
padding: 60px;
}
td.padding-vert {
padding-top: 20px !important;
padding-bottom: 20px !important;
.center {
text-align: center;
}
td.padding-horiz {
padding-left: 20px !important;
padding-right: 20px !important;
.no-border {
border: 0;
outline: none;
text-decoration: none;
}
.no-margin {
margin: 0;
}
.spacer {
line-height: 20px !important;
height: 20px !important;
line-height: 45px;
height: 45px;
}
}
</style>
</head>
<body>
<div style="background-color:#F3F3F3; height: 100%;">
<table height="100%" width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#f3f3f3"
style="background-color: #f3f3f3;">
<tr>
<td valign="top" align="left">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td align="center" valign="top">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td align="center">
<table class="max-width" cellpadding="0" cellspacing="0" border="0" width="100%"
style="width: 100%;">
<tbody>
<tr>
<td class="spacer">&nbsp;</td>
</tr>
<tr>
<td class="padding main">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td>
<!-- LOGO -->
<a href="https://payloadcms.com/" target="_blank">
<img src="https://payloadcms.com/images/logo-dark.png" width="150"
height="auto" />
</a>
</td>
</tr>
<tr>
<td class="spacer">&nbsp;</td>
</tr>
<tr>
<td>
<!-- HEADLINE -->
<h1 style="margin: 0 0 30px;">{{headline}}</h1>
</td>
</tr>
<tr>
<td>
<!-- CONTENT -->
{{{content}}}
/********************************
PANELS
********************************/
<!-- CTA -->
{{#if cta}}
<div>
<a href="{{cta.url}}"
style="background-color:#222222;border-radius:4px;color:#ffffff;display:inline-block;font-family:sans-serif;font-size:13px;font-weight:bold;line-height:60px;text-align:center;text-decoration:none;width:200px;-webkit-text-size-adjust:none;">
{{cta.buttonLabel}}
.panel {
width: 100%;
}
@media screen and (max-width: 800px) {
h1 {
font-size: 24px !important;
margin: 0 0 20px 0 !important;
}
h2 {
font-size: 20px !important;
margin: 0 0 20px 0 !important;
}
h3 {
font-size: 20px !important;
margin: 0 0 20px 0 !important;
}
h4 {
font-size: 18px !important;
margin: 0 0 15px 0 !important;
}
h5 {
font-size: 15px !important;
margin: 0 0 10px !important;
}
.max-width {
width: 90% !important;
margin: 0 5% !important;
}
td.padding {
padding: 30px !important;
}
td.padding-vert {
padding-top: 20px !important;
padding-bottom: 20px !important;
}
td.padding-horiz {
padding-left: 20px !important;
padding-right: 20px !important;
}
.spacer {
line-height: 20px !important;
height: 20px !important;
}
}
</style>
</head>
<body>
<div style="background-color: #f3f3f3; height: 100%">
<table
height="100%"
width="100%"
cellpadding="0"
cellspacing="0"
border="0"
bgcolor="#f3f3f3"
style="background-color: #f3f3f3"
>
<tr>
<td valign="top" align="left">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td align="center" valign="top">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td align="center">
<table
class="max-width"
cellpadding="0"
cellspacing="0"
border="0"
width="100%"
style="width: 100%"
>
<tbody>
<tr>
<td class="spacer">&nbsp;</td>
</tr>
<tr>
<td class="padding main">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td>
<!-- LOGO -->
<a href="https://payloadcms.com/" target="_blank">
<img
src="https://payloadcms.com/images/logo-dark.png"
width="150"
height="auto"
/>
</a>
</div>
{{/if}}
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</div>
</body>
</td>
</tr>
<tr>
<td class="spacer">&nbsp;</td>
</tr>
<tr>
<td>
<!-- HEADLINE -->
<h1 style="margin: 0 0 30px">{{headline}}</h1>
</td>
</tr>
<tr>
<td>
<!-- CONTENT -->
{{{content}}}
<!-- CTA -->
{{#if cta}}
<div>
<a
href="{{cta.url}}"
style="
background-color: #222222;
border-radius: 4px;
color: #ffffff;
display: inline-block;
font-family: sans-serif;
font-size: 13px;
font-weight: bold;
line-height: 60px;
text-align: center;
text-decoration: none;
width: 200px;
-webkit-text-size-adjust: none;
"
>
{{cta.buttonLabel}}
</a>
</div>
{{/if}}
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</div>
</body>
</html>

View File

@@ -8,7 +8,6 @@ if (process.env.NODE_ENV === 'production') {
// Configure a custom transport here
},
}
} else {
email = {
fromName: 'Ethereal Email',

View File

@@ -1 +1 @@
export default {};
export default {}

View File

@@ -1,4 +1,3 @@
import dotenv from 'dotenv'
import path from 'path'
import { buildConfig } from 'payload/config'
@@ -14,7 +13,7 @@ const mockModulePath = path.resolve(__dirname, './emptyModule.js')
export default buildConfig({
admin: {
webpack: config => ({
webpack: (config) => ({
...config,
resolve: {
...config?.resolve,
@@ -36,10 +35,7 @@ export default buildConfig({
},
}),
},
collections: [
Newsletter,
Users,
],
collections: [Newsletter, Users],
typescript: {
outputFile: path.resolve(__dirname, 'payload-types.ts'),
},

View File

@@ -1,4 +1,4 @@
@use "../shared.scss";
@use '../shared.scss';
.checkbox {
position: relative;

View File

@@ -1,4 +1,4 @@
@use "../shared.scss";
@use '../shared.scss';
.select {
position: relative;

View File

@@ -1,4 +1,4 @@
@use "../shared.scss";
@use '../shared.scss';
.wrap {
position: relative;

View File

@@ -1,4 +1,4 @@
@use "../shared.scss";
@use '../shared.scss';
.wrap {
position: relative;

View File

@@ -1,4 +1,4 @@
@use "../shared.scss";
@use '../shared.scss';
.select {
position: relative;

View File

@@ -1,4 +1,4 @@
@use "../shared.scss";
@use '../shared.scss';
.select {
position: relative;

View File

@@ -1,4 +1,4 @@
@use "../shared.scss";
@use '../shared.scss';
.wrap {
position: relative;

View File

@@ -1,4 +1,4 @@
@use "../shared.scss";
@use '../shared.scss';
.wrap {
position: relative;

View File

@@ -41,7 +41,7 @@
margin-right: calc(var(--base) * -0.5);
width: calc(100% + #{var(--base)});
>* {
> * {
width: 100%;
}
}

View File

@@ -1,4 +1,4 @@
@use "../../../css/common.scss" as *;
@use '../../../css/common.scss' as *;
@mixin formInput() {
all: unset;

View File

@@ -35,7 +35,8 @@
background-color: var(--color-black);
color: var(--color-white);
&:hover, &:focus {
&:hover,
&:focus {
background-color: var(--color-white);
color: var(--color-black);
box-shadow: inset 0 0 0 1px var(--color-black);
@@ -46,7 +47,8 @@
background-color: var(--color-white);
box-shadow: inset 0 0 0 1px var(--color-black);
&:hover, &:focus {
&:hover,
&:focus {
background-color: var(--color-black);
color: var(--color-white);
box-shadow: inset 0 0 0 1px var(--color-black);

View File

@@ -26,11 +26,11 @@
cursor: pointer;
display: none;
&[aria-expanded="true"] {
&[aria-expanded='true'] {
transform: rotate(-25deg);
}
@include mid-break {
display: block;
}
}
}

View File

@@ -28,4 +28,4 @@
.menuItem {
@extend %h4;
margin-top: 0;
}
}

View File

@@ -3,10 +3,10 @@
@use './type.scss' as *;
:root {
--breakpoint-xs-width : #{$breakpoint-xs-width};
--breakpoint-s-width : #{$breakpoint-s-width};
--breakpoint-m-width : #{$breakpoint-m-width};
--breakpoint-l-width : #{$breakpoint-l-width};
--breakpoint-xs-width: #{$breakpoint-xs-width};
--breakpoint-s-width: #{$breakpoint-s-width};
--breakpoint-m-width: #{$breakpoint-m-width};
--breakpoint-l-width: #{$breakpoint-l-width};
--scrollbar-width: 17px;
--base: 24px;
@@ -100,7 +100,7 @@ p {
margin: var(--base) 0;
@include mid-break {
margin: calc(var(--base) * .75) 0;
margin: calc(var(--base) * 0.75) 0;
}
}
@@ -114,12 +114,12 @@ a {
color: currentColor;
&:focus {
opacity: .8;
opacity: 0.8;
outline: none;
}
&:active {
opacity: .7;
opacity: 0.7;
outline: none;
}
}

View File

@@ -1,10 +1,10 @@
:root {
--color-red: rgb(255,0,0);
--color-red: rgb(255, 0, 0);
--color-green: rgb(178, 255, 214);
--color-white: rgb(255, 255, 255);
--color-dark-gray: rgb(51,52,52);
--color-mid-gray: rgb(196,196,196);
--color-gray: rgb(212,212,212);
--color-light-gray: rgb(244,244,244);
--color-dark-gray: rgb(51, 52, 52);
--color-mid-gray: rgb(196, 196, 196);
--color-gray: rgb(212, 212, 212);
--color-light-gray: rgb(244, 244, 244);
--color-black: rgb(0, 0, 0);
}

Some files were not shown because too many files have changed in this diff Show More