Merge branch 'beta' of https://github.com/payloadcms/payload into fix-row-field-width

This commit is contained in:
Bruno Crosier
2024-09-09 23:32:25 +01:00
1300 changed files with 44820 additions and 18875 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

@@ -431,14 +431,14 @@ export const MyClientComponent: React.FC = () => {
See [Using Hooks](#using-hooks) for more details.
</Banner>
All [Field Components](./fields) automatically receive their respective Client Field Config through a common [`field`](./fields#the-field-prop) prop:
All [Field Components](./fields) automatically receive their respective Field Config through a common [`field`](./fields#the-field-prop) prop:
```tsx
'use client'
import React from 'react'
import type { TextFieldProps } from 'payload'
import type { TextFieldClientComponent } from 'payload'
export const MyClientFieldComponent: TextFieldProps = ({ field: { name } }) => {
export const MyClientFieldComponent: TextFieldClientComponent = ({ field: { name } }) => {
return (
<p>
{`This field's name is ${name}`}

View File

@@ -136,7 +136,7 @@ All Field Components receive the following props:
| Property | Description |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`docPreferences`** | An object that contains the [Preferences](./preferences) for the document.
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
| **`field`** | The field's config. [More details](#the-field-prop) |
| **`locale`** | The locale of the field. [More details](../configuration/localization). |
| **`readOnly`** | A boolean value that represents if the field is read-only or not. |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
@@ -175,46 +175,46 @@ export const CustomTextField: React.FC = () => {
#### TypeScript
When building Custom Field Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview). The convention is to append `Props` to the type of field, i.e. `TextFieldProps`.
When building Custom Field Components, you can import the component type to ensure type safety. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview) and for every client/server environment. The convention is to prepend the field type onto the target type, i.e. `TextFieldClientComponent`:
```tsx
import type {
ArrayFieldProps,
BlocksFieldProps,
CheckboxFieldProps,
CodeFieldProps,
CollapsibleFieldProps,
DateFieldProps,
EmailFieldProps,
GroupFieldProps,
HiddenFieldProps,
JSONFieldProps,
NumberFieldProps,
PointFieldProps,
RadioFieldProps,
RelationshipFieldProps,
RichTextFieldProps,
RowFieldProps,
SelectFieldProps,
TabsFieldProps,
TextFieldProps,
TextareaFieldProps,
UploadFieldProps
TextFieldClientComponent,
TextFieldServerComponent,
TextFieldClientProps,
TextFieldServerProps,
// ...and so on for each Field Type
} from 'payload'
```
### The `field` Prop
All Field Components are passed a client-friendly version of their Field Config through a common `field` prop. Since the raw Field Config is [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types), Payload sanitized it into a [Client Config](./components#accessing-the-payload-config) that is safe to pass into Client Components.
All Field Components are passed their own Field Config through a common `field` prop. Within a Server Component, this is the raw Field Config. Within Client Components, however, the raw Field Config is [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types). Instead, Client Components receives a [Client Config](./components#accessing-the-payload-config), which is a sanitizes version of the Field Config that is safe to pass into Client Components.
The exact shape of this prop is unique to the specific [Field Type](../fields/overview) being rendered, minus all non-serializable properties. Any [Custom Components](../components) are also resolved into a "mapped component" that is safe to pass.
```tsx
import React from 'react'
import type { TextFieldServerComponent } from 'payload'
export const MyServerTextField: TextFieldServerComponent = ({ payload, field: { name } }) => {
const result = await payload.find({
collection: 'myCollection',
depth: 1,
})
// ...
}
```
Client Component:
```tsx
'use client'
import React from 'react'
import type { TextFieldProps } from 'payload'
import type { TextFieldClientComponent } from 'payload'
export const MyClientFieldComponent: React.FC<TextFieldProps> = ({ field: { name } }) => {
export const MyClientTextField: TextFieldClientComponent = ({ field: { name } }) => {
return (
<p>
{`This field's name is ${name}`}
@@ -238,40 +238,18 @@ The following additional properties are also provided to the `field` prop:
#### TypeScript
When building Custom Field Components, you can import the client field props to ensure type safety in your component. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview). The convention is to append `Client` to the type of field, i.e. `TextFieldClient`.
When building Custom Field Components, you can import the client field props to ensure type safety in your component. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to prepend the field type onto the target type, i.e. `TextFieldClientComponent`:
```tsx
import type {
ArrayFieldClient,
BlocksFieldClient,
CheckboxFieldClient,
CodeFieldClient,
CollapsibleFieldClient,
DateFieldClient,
EmailFieldClient,
GroupFieldClient,
HiddenFieldClient,
JSONFieldClient,
NumberFieldClient,
PointFieldClient,
RadioFieldClient,
RelationshipFieldClient,
RichTextFieldClient,
RowFieldClient,
SelectFieldClient,
TabsFieldClient,
TextFieldClient,
TextareaFieldClient,
UploadFieldClient
TextFieldClientComponent,
TextFieldServerComponent,
TextFieldClientProps,
TextFieldServerProps,
// ...and so on for each Field Type
} from 'payload'
```
When working on the client, you will never have access to objects of type `Field`. This is reserved for the server-side. Instead, you can use `ClientField` which is a union type of all the client fields:
```tsx
import type { ClientField } from 'payload'
```
### The Cell Component
The Cell Component is rendered in the table of the List View. It represents the value of the field when displayed in a table cell.
@@ -353,7 +331,7 @@ When building Custom Label Components, you can import the component props to ens
import type {
TextFieldLabelServerComponent,
TextFieldLabelClientComponent,
// And so on for each Field Type
// ...and so on for each Field Type
} from 'payload'
```

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

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