Compare commits
96 Commits
local-dock
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
2e372d1aae | ||
|
1496eefc14 | ||
|
e93b5e653a | ||
|
8fa28a31ce | ||
|
64da6f4553 | ||
|
5e74f45855 | ||
|
ab8b409725 | ||
|
35ac1ece0e | ||
|
b8a92095d8 | ||
|
9ce6eb5bcc | ||
|
ee243f7d20 | ||
|
9edb207991 | ||
|
e060d942f0 | ||
|
c09862c702 | ||
|
fdfbce506e | ||
|
f16e874f31 | ||
|
8d05864c15 | ||
|
90f1750945 | ||
|
abe4a3c883 | ||
|
519df326ce | ||
|
3d4499fb80 | ||
|
a27c335113 | ||
|
199234a7e2 | ||
|
95a00c63ea | ||
8a85724baf | |||
|
b25a83b164 | ||
23357f0934 | |||
|
83ea63dde4 | ||
efd4be35f7 | |||
|
b6e56b0f83 | ||
|
b6357c5676 | ||
|
7a198ec4c3 | ||
|
1ba93cfb6d | ||
|
116bdcecdb | ||
|
1b5f02637c | ||
|
75827c3bc7 | ||
|
f1ac6429c7 | ||
|
efec10e6d6 | ||
|
cb0a2f77a8 | ||
|
043470fe0c | ||
|
689c21b69a | ||
|
7943ffbd55 | ||
|
5d652dc606 | ||
|
4dfe80213e | ||
|
f3596d4258 | ||
|
bb426df41a | ||
|
f558be2bcd | ||
|
d6fe6446a5 | ||
|
5eb7b7037b | ||
|
0a14bb39de | ||
|
fa48a192e3 | ||
|
9fa279b962 | ||
|
5d191e1e28 | ||
|
60f7a4e4f2 | ||
|
f9ee909e01 | ||
|
b69d3ca9bc | ||
|
d77c33f548 | ||
|
e63dd42b6c | ||
|
2cfca5e7cf | ||
|
f928366b27 | ||
|
b448fcc8bb | ||
|
26363eb249 | ||
|
ec284177ee | ||
|
bc6c4ddde7 | ||
|
ace6e50b73 | ||
|
e002125805 | ||
|
cab583964b | ||
|
de5e8ab560 | ||
|
02556b6d62 | ||
|
a81703d75a | ||
|
22298a82e3 | ||
|
c23501d5a5 | ||
|
12621849e2 | ||
|
3a8e66dcec | ||
|
63b8c3f5ae | ||
|
6b49eebeb8 | ||
|
82d5beaa90 | ||
|
18995ef44f | ||
|
d1a0449d67 | ||
|
ed5a2ccc05 | ||
|
57601b133a | ||
8ceaf85ce0 | |||
|
4fb8c8362d | ||
|
09d8134d04 | ||
|
b437f7993d | ||
|
a169c111c2 | ||
|
f6c1f4fe78 | ||
|
97173fce29 | ||
|
69ead39b39 | ||
|
6a151fdd6f | ||
|
40e1ab22ad | ||
|
e215f882b7 | ||
|
95e03404c5 | ||
|
e9d28c472d | ||
|
80fdf4332f | ||
|
0a9255122a |
@ -2,9 +2,10 @@
|
||||
kind: pipeline
|
||||
name: publish pipeline
|
||||
steps:
|
||||
- name: publish nextload container
|
||||
- name: publish nextjs container
|
||||
image: plugins/docker
|
||||
settings:
|
||||
target: prod
|
||||
username: 3wordchant
|
||||
password:
|
||||
from_secret: git_autonomic_zone_token_3wc
|
||||
@ -25,11 +26,7 @@ steps:
|
||||
DOMAIN: nextload.swarm-demo.autonomic.zone
|
||||
STACK_NAME: nextload-demo_autonomic_zone
|
||||
SECRET_PAYLOAD_SECRET_VERSION: v1
|
||||
SECRET_TOKEN_VERSION: v1
|
||||
SECRET_MONGO_PASSWORD_VERSION: v1
|
||||
NGINX_CONF_VERSION: v1
|
||||
REPOSITORY: "autonomic-cooperative/nextload"
|
||||
DRONE_URL: "https://drone.autonomic.zone"
|
||||
PAYLOAD_URL: "https://nextload.swarm-demo.autonomic.zone/admin" # Not needed anymore?
|
||||
depends_on:
|
||||
- publish nextload container
|
||||
- publish nextjs container
|
||||
|
@ -1,7 +1,7 @@
|
||||
NAME=nextload
|
||||
STACK_NAME=nextload
|
||||
|
||||
PAYLOAD_SECRET=jawliejfilwajefSEANlawefawfewag349jwgo3gj4w
|
||||
MONGODB_USER=mongo
|
||||
MONGODB_PASSWORD=mongo
|
||||
MONGODB_HOST=mongo
|
||||
# POSTGRES_URI=postgresql://postgres:password123@127.0.0.1:5432/next-payload-3
|
||||
|
||||
MONGO_USER=mongo
|
||||
MONGO_PASSWORD=mongo
|
||||
MONGO_HOST=mongo
|
||||
|
5
.github/ISSUE_TEMPLATE/config.yml
vendored
5
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,5 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Beta Issues
|
||||
url: https://github.com/payloadcms/payload/issues/new/choose
|
||||
about: Any issues should be opened on the main repository
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -41,3 +41,5 @@ next-env.d.ts
|
||||
.env
|
||||
|
||||
/media
|
||||
|
||||
/types/payload-types.ts
|
48
Dockerfile
48
Dockerfile
@ -1,37 +1,49 @@
|
||||
# Build stage
|
||||
FROM node:20-slim as builder
|
||||
FROM node:20-slim as base
|
||||
|
||||
WORKDIR /base
|
||||
|
||||
|
||||
# Local Development
|
||||
FROM base AS dev
|
||||
ENTRYPOINT []
|
||||
CMD ["pnpm", "dev:next"]
|
||||
|
||||
|
||||
# Production: build
|
||||
FROM base AS builder
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable
|
||||
|
||||
|
||||
WORKDIR /builder
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
|
||||
|
||||
ENV NODE_ENV=production
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
|
||||
ENV NODE_ENV=production
|
||||
RUN pnpm generate:types
|
||||
RUN pnpm build
|
||||
|
||||
# Production stage: serve the application
|
||||
# Production: copy build artifacts
|
||||
FROM node:20-slim as runner
|
||||
WORKDIR /runner
|
||||
WORKDIR /prod
|
||||
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable
|
||||
|
||||
## Copy build artifacts from the build stage
|
||||
COPY --from=builder /builder/package.json ./
|
||||
#COPY --from=builder /builder/node_modules ./node_modules
|
||||
COPY --from=builder /builder/.next/standalone ./.next/standalone/
|
||||
COPY --from=builder /builder/.next/static ./.next/static
|
||||
COPY --from=builder /builder/public ./public
|
||||
COPY --from=builder /builder/next.config.mjs ./
|
||||
COPY --from=builder /base/package.json ./
|
||||
COPY --from=builder /base/.next/standalone ./.next/standalone/
|
||||
COPY --from=builder /base/.next/static ./.next/standalone/.next/static
|
||||
COPY --from=builder /base/public ./.next/standalone/public
|
||||
COPY --from=builder /base/next.config.mjs ./
|
||||
|
||||
FROM runner as server
|
||||
EXPOSE 3000
|
||||
# Production: serve the website
|
||||
FROM runner as prod
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable
|
||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
RUN chmod +x /docker-entrypoint.sh
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["pnpm", "start:standalone"]
|
||||
|
49
Makefile
Normal file
49
Makefile
Normal file
@ -0,0 +1,49 @@
|
||||
.PHONY: sync_db
|
||||
|
||||
# Define variables
|
||||
REMOTE_USER=tma
|
||||
REMOTE_SERVER=swarm-demo.autonomic.zone
|
||||
REMOTE_PORT=222
|
||||
REMOTE_CONTAINER_PATH=/data/db/mongodump
|
||||
LOCAL_PATH=/tmp/mongodump
|
||||
LOCAL_DB=test
|
||||
LOCAL_CONTAINER_NAME=nextload-mongo-1
|
||||
REMOTE_VOLUME_NAME = nextload-demo_autonomic_zone_payload_uploads
|
||||
LOCAL_VOLUME_NAME = nextload_payload_uploads
|
||||
ENV_FILE=.env
|
||||
|
||||
include $(ENV_FILE)
|
||||
|
||||
sync_db:
|
||||
@echo "Step 1: Dump the database on production"
|
||||
docker --context swarm-demo.autonomic.zone exec -it $$(docker --context swarm-demo.autonomic.zone ps -q -f name=nextload-demo_autonomic_zone_mongo) \
|
||||
bash -c 'rm -rf $(REMOTE_CONTAINER_PATH) && mongodump -u mongo -p "$$(cat /run/secrets/mongo_password)" -o $(REMOTE_CONTAINER_PATH) && ls -l $(REMOTE_CONTAINER_PATH)'
|
||||
|
||||
@echo "Step 2: Copy the dump from the remote MongoDB container to the local machine"
|
||||
rm -rf $(LOCAL_PATH)
|
||||
mkdir -p $(LOCAL_PATH) # Create the target directory if it doesn't exist
|
||||
ssh -p $(REMOTE_PORT) $(REMOTE_USER)@$(REMOTE_SERVER) \
|
||||
"docker exec $$(docker --context swarm-demo.autonomic.zone ps -q -f name=nextload-demo_autonomic_zone_mongo) \
|
||||
tar -cC $(REMOTE_CONTAINER_PATH) ." | tar -xC $(LOCAL_PATH)
|
||||
|
||||
@echo "Step 3: Copy the dump from local machine to MongoDB container"
|
||||
docker cp $(LOCAL_PATH)/ $(LOCAL_CONTAINER_NAME):/tmp/mongodump
|
||||
|
||||
@echo "Step 4: Drop the existing local database and restore the dump"
|
||||
docker exec -it $(LOCAL_CONTAINER_NAME) mongorestore --drop --username $(MONGO_USER) --password $(MONGO_PASSWORD) --authenticationDatabase admin --db $(LOCAL_DB) /tmp/mongodump/$(LOCAL_DB)
|
||||
|
||||
sync_media:
|
||||
@echo "Step 1: Create a tar archive of the remote Docker volume"
|
||||
rm -rf /tmp/$(REMOTE_VOLUME_NAME)
|
||||
mkdir -p /tmp/$(REMOTE_VOLUME_NAME)
|
||||
ssh -p $(REMOTE_PORT) $(REMOTE_USER)@$(REMOTE_SERVER) \
|
||||
"docker run --rm -v $(REMOTE_VOLUME_NAME):/volume -v /tmp:/backup alpine tar -czf /backup/$(REMOTE_VOLUME_NAME).tar.gz -C /volume ."
|
||||
|
||||
@echo "Step 2: Copy the media from remote volume to local volume"
|
||||
scp -P $(REMOTE_PORT) $(REMOTE_USER)@$(REMOTE_SERVER):/tmp/$(REMOTE_VOLUME_NAME).tar.gz /tmp/$(REMOTE_VOLUME_NAME).tar.gz
|
||||
docker run --rm -v /tmp:/volume -v $(LOCAL_VOLUME_NAME):/backup alpine tar -xzf /volume/$(REMOTE_VOLUME_NAME).tar.gz -C /backup
|
||||
|
||||
@echo "Step 3: Cleanup temporary files"
|
||||
rm /tmp/$(REMOTE_VOLUME_NAME).tar.gz
|
||||
|
||||
@echo "Media synchronization complete."
|
86
README.md
86
README.md
@ -1,85 +1,43 @@
|
||||
# Payload 3.0 Beta Demo
|
||||
## Get started with nextload
|
||||
### Prerequisites:
|
||||
**node**
|
||||
Using a version manager for installing node is recommended, see [nvm](https://github.com/nvm-sh/nvm) or [fnm](https://github.com/Schniz/fnm)
|
||||
|
||||
This repo showcases a demo of the Payload 3.0 Beta running completely within Next.js.
|
||||
**pnpm**
|
||||
`corepack enable pnpm`
|
||||
|
||||
> [!IMPORTANT]
|
||||
> It's extremely important to note that as of now, this demo contains BETA software and you are 100% guaranteed to run into bugs / weird stuff.
|
||||
>
|
||||
> We're actively working toward a stable release as fast as we possibly can.
|
||||
|
||||
### Highlights
|
||||
|
||||
1. Payload is now Next.js-native
|
||||
1. Turbopack works out of the box (this will get faster over time, expect more here)
|
||||
1. The Payload admin UI is built with React Server Components and automatically eliminates server-side code from your admin bundle, completely alleviating the need to use Webpack aliases to remove hooks, access control, etc.
|
||||
1. Payload is now fully-ESM across the board
|
||||
1. GraphQL is now initialized only when you hit the GraphQL endpoint, and does not affect overhead of REST API routes
|
||||
1. All UI components have been abstracted into a separate `@payloadcms/ui` package, which will be fully documented and exposed for your re-use once we hit stable 3.0 or before
|
||||
1. You can run your own Next.js site alongside of Payload in the same app
|
||||
1. You can now deploy Payload to Vercel and Netlify, and there will be official support for Vercel Blob Storage and Netlify Blobs coming soon (so no S3 needed for files)
|
||||
1. Server-side HMR works out of the box, with no need for `nodemon` or similar. When the Payload config changes, your app will automatically re-initialize Payload seamlessly in the background
|
||||
1. All custom React components can be server components by default, and you can decide if you want them to be server components or client components
|
||||
1. Sharp has been abstracted to be an optional dependency
|
||||
1. Payload now relies on the Web Request / Response APIs rather than the Node Request / Response
|
||||
1. Express can still be used with Next.js' Custom Server functionality
|
||||
1. Payload itself has slimmed down significantly and can now be fully portable, run anywhere. You can leverage the Payload Local API completely outside of Next.js if you want.
|
||||
1. The data layer, including the shape of the database Payload used and the API responses in 2.0, has not been affected whatsoever
|
||||
|
||||
### Work to come
|
||||
|
||||
We are making this available to our community so that we can gather your feedback and test the new approach that Payload is taking. Don't expect it to be fully functional yet. There are some things that we are aware of that are not yet completed, but we're going to keep blazing through the remaining items as fast as we can to reach stable 3.0 as quickly and efficiently as possible. Here are a few of the items that we are still working on (not a full list):
|
||||
|
||||
1. Documentation
|
||||
1. Vercel Blob Storage and Netlify Blobs adapter
|
||||
1. Lots of bugs for sure
|
||||
1. 100% of tests passing
|
||||
1. Compiler speed improvements (turbo is beta still, it is slower than it should be. it will get faster)
|
||||
1. Overall speed improvements
|
||||
1. An install script to be able to install Payload easily into any existing Next.js app
|
||||
1. A full list of breaking changes for 2.0 -> 3.0, including an in-depth migration guide
|
||||
|
||||
### Existing Next.js project
|
||||
|
||||
You can install Payload into your existing Next.js project using this command:
|
||||
**docker**
|
||||
[get docker script](https://get.docker.com/):
|
||||
```
|
||||
npx create-payload-app@beta
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
sudo sh get-docker.sh
|
||||
```
|
||||
Contents from `src/app` will have to be moved into a new directory `src/app/(app)` so that Payload's root layout and routes can remain isolated from the rest of your app.
|
||||
|
||||
### Using this repo
|
||||
### Start developing
|
||||
1. **Copy the environment variables**
|
||||
|
||||
To try out this repo yourself, follow the steps below:
|
||||
`cp .env.local.example .env.example`
|
||||
|
||||
1. Clone the repo to your computer (`git clone git@github.com:payloadcms/payload-3.0-demo.git`)
|
||||
2. `cd` into the new folder by running `cd ./payload-3.0-demo`
|
||||
3. Copy the `.env.local.example` by running `cp .env.local.example .env.example` in the repo, then fill out the values including the connection string to your DB
|
||||
4. Install dependencies with whatever package manager you use (`pnpm o`, `npm install`, `yarn`, etc.). `pnpm` is highly recommended. The usage of yarn v1 is discouraged.
|
||||
5. Start your database. For local postgresql use `.\start-database.sh` to start it in docker container.
|
||||
6. Fire it up (`pnpm dev`, `npm run dev`, `yarn dev`, etc.)
|
||||
7. Visit https://localhost:3000 and log in with the user created within the config's `onInit` method
|
||||
2. **Install dependencies**
|
||||
|
||||
### Follow along with breaking changes
|
||||
`pnpm install`
|
||||
|
||||
There is a possibility that we will make breaking changes before releasing the full stable version of Payload 3.0.
|
||||
3. **Run dev container**
|
||||
|
||||
**To follow along with breaking changes in advance of the full, stable release,** you can keep an eye on the [CHANGELOG.md](https://github.com/payloadcms/payload-3.0-demo/blob/main/CHANGELOG.md).
|
||||
`pnpm dev` or `docker compose up`
|
||||
|
||||
### Notes
|
||||
- payload-types.ts file will be generated when starting the dev container, but can also be generated manually with `pnpm generate:types`
|
||||
- Dev container will use `node_modules`, so make sure to run `pmpm install` prior to `pnpm dev`
|
||||
|
||||
### Technical details
|
||||
Nextload is a fork of [payload 3 demo](https://github.com/payloadcms/payload-3.0-demo)
|
||||
|
||||
**The app folder**
|
||||
|
||||
You'll see that Payload requires a few files to be present in your `/app` folder. There are files for the admin UI as well as files for all route handlers. We've consolidated all admin views into a single `page.tsx` and consolidated most of the REST endpoints into a single `route.ts` file for simplicity, but also for development performance. With this pattern, you only have to compile the admin UI / REST API / GraphQL API a single time - and from there, it will be lightning-fast.
|
||||
|
||||
**The `next.config.js` `withPayload` function**
|
||||
|
||||
You'll see in the Next.js config that we have a `withPayload` function installed. This function is required for Payload to operate, and it ensures compatibility with packages that Payload needs such as `drizzle-kit`, `sharp`, `pino`, and `mongodb`.
|
||||
|
||||
**Using a TypeScript alias to point to your Payload config**
|
||||
|
||||
In the `tsconfig.json` within this repo, you'll see that we have `paths` set up to point `@payload-config` to the Payload config, which is located in the root. You can put your config wherever you want. By default, the `page.tsx` files and `route.ts` files within the `/app` folder use this alias. In the future, we might make it optional to use `paths` - and by default, we might just hard-code relative path imports to the config. We would like to hear your feedback on this part. What do you prefer? Use `paths` or just use relative imports?
|
||||
|
||||
---
|
||||
|
||||
### Find a bug?
|
||||
|
||||
Open an issue on this repo at `https://github.com/payloadcms/payload-3.0-demo` with as much detail as you can provide and we will tackle them as fast as we can. Let's get stable!
|
||||
|
22
docker-compose.db.yml
Normal file
22
docker-compose.db.yml
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
services:
|
||||
mongo:
|
||||
image: mongo:6.0.5
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- mongo:/data/db
|
||||
command:
|
||||
- --storageEngine=wiredTiger
|
||||
environment:
|
||||
- "MONGO_INITDB_ROOT_USERNAME=mongo"
|
||||
- "MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}"
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 27017:27017
|
||||
|
||||
networks:
|
||||
internal:
|
||||
|
||||
volumes:
|
||||
mongo:
|
@ -4,24 +4,23 @@ version: "3.8"
|
||||
services:
|
||||
nextjs:
|
||||
image: git.autonomic.zone/autonomic-cooperative/nextload:latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- "NAME=${STACK_NAME}"
|
||||
# Payload stuff propably not needed as the local API is used?
|
||||
- "PAYLOAD_URL"
|
||||
- "PAYLOAD_SECRET_FILE=/run/secrets/payload_secret"
|
||||
- "BASE_URL=nextload.swarm-demo.autonomic.zone"
|
||||
- "MONGODB_USER=mongo"
|
||||
- "MONGODB_HOST=${STACK_NAME}_mongo"
|
||||
- "MONGODB_PORT=27017"
|
||||
- "MONGODB_PASSWORD_FILE=/run/secrets/mongo_password"
|
||||
- "TOKEN_FILE=/run/secrets/token"
|
||||
- "REPOSITORY"
|
||||
- "DRONE_URL"
|
||||
- "PORT=3000"
|
||||
- "HOSTNAME=0.0.0.0"
|
||||
secrets:
|
||||
- mongo_password
|
||||
- payload_secret
|
||||
- token
|
||||
volumes:
|
||||
- payload_uploads:/prod/dist/media
|
||||
- payload_uploads:/prod/.next/standalone/media
|
||||
networks:
|
||||
- proxy
|
||||
- internal
|
||||
@ -36,6 +35,8 @@ services:
|
||||
- "traefik.http.routers.${STACK_NAME}-nextload.rule=Host(`${DOMAIN}`)"
|
||||
- "traefik.http.routers.${STACK_NAME}-nextload.entrypoints=web-secure"
|
||||
- "traefik.http.routers.${STACK_NAME}-nextload.tls.certresolver=production"
|
||||
depends_on:
|
||||
- mongo
|
||||
|
||||
mongo:
|
||||
image: mongo:6.0.5
|
||||
@ -61,14 +62,10 @@ secrets:
|
||||
payload_secret:
|
||||
external: true
|
||||
name: ${STACK_NAME}_payload_secret_${SECRET_PAYLOAD_SECRET_VERSION}
|
||||
token:
|
||||
external: true
|
||||
name: ${STACK_NAME}_token_${SECRET_TOKEN_VERSION}
|
||||
mongo_password:
|
||||
external: true
|
||||
name: ${STACK_NAME}_mongo_password_${SECRET_MONGO_PASSWORD_VERSION}
|
||||
|
||||
volumes:
|
||||
mongo:
|
||||
html_content:
|
||||
payload_uploads:
|
||||
|
@ -1,52 +1,31 @@
|
||||
---
|
||||
services:
|
||||
# astro:
|
||||
# container_name: ${NAME}-astro
|
||||
# image: git.autonomic.zone/autonomic-cooperative/astro-payload-test-astro:latest
|
||||
# restart: unless-stopped
|
||||
# build:
|
||||
# context: astro
|
||||
# command: ["yarn", "dev"]
|
||||
# environment:
|
||||
# DEV: 1
|
||||
# networks:
|
||||
# - front
|
||||
# volumes:
|
||||
# - ./astro:/base
|
||||
# - /base/node_modules/
|
||||
# ports:
|
||||
# - 3000:3000
|
||||
# depends_on:
|
||||
# - payload
|
||||
|
||||
payload:
|
||||
image: git.autonomic.zone/autonomic-cooperative/nextload:latest
|
||||
container_name: ${NAME}-payload
|
||||
nextjs:
|
||||
image: git.autonomic.zone/autonomic-cooperative/nextload-dev:latest
|
||||
restart: unless-stopped
|
||||
# build:
|
||||
# context: payload
|
||||
# target: dev
|
||||
build:
|
||||
context: ./
|
||||
target: dev
|
||||
environment:
|
||||
DEV: 1
|
||||
NAME: ${NAME}
|
||||
NODE_ENV: development
|
||||
# PAYLOAD_URL: "http://localhost:${PAYLOAD_PORT}"
|
||||
# PAYLOAD_PORT: ${PAYLOAD_PORT}
|
||||
PAYLOAD_SECRET: ${PAYLOAD_SECRET}
|
||||
MONGODB_URI: "mongodb://$MONGODB_USER:$MONGODB_PASSWORD@$MONGODB_HOST:27017"
|
||||
# volumes:
|
||||
# - ./payload/src:/base/src
|
||||
# # - ./astro/src/types.ts:/types.ts
|
||||
# - payload_media:/base/src/media
|
||||
- "NAME=${STACK_NAME}"
|
||||
- "PAYLOAD_SECRET=${PAYLOAD_SECRET}"
|
||||
- "MONGODB_USER=mongo"
|
||||
- "MONGODB_HOST=${STACK_NAME}_mongo"
|
||||
- "MONGODB_PORT=27017"
|
||||
- "MONGODB_PASSWORD=${MONGO_PASSWORD}"
|
||||
- "REPOSITORY"
|
||||
- "PORT=3000"
|
||||
- "HOSTNAME=0.0.0.0"
|
||||
- "MONGODB_URI=mongodb://${MONGO_USER}:${MONGO_PASSWORD}@mongo:27017"
|
||||
volumes:
|
||||
- payload_uploads:/base/media
|
||||
- ./:/base
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
- front
|
||||
- back
|
||||
depends_on:
|
||||
- mongo
|
||||
|
||||
mongo:
|
||||
container_name: ${NAME}-mongo
|
||||
image: mongo:6.0.5
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
@ -54,15 +33,16 @@ services:
|
||||
command:
|
||||
- --storageEngine=wiredTiger
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: ${MONGODB_USER}
|
||||
MONGO_INITDB_ROOT_PASSWORD: ${MONGODB_PASSWORD}
|
||||
- "MONGO_INITDB_ROOT_USERNAME=mongo"
|
||||
- "MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}"
|
||||
networks:
|
||||
- back
|
||||
- internal
|
||||
ports:
|
||||
- 27017:27017
|
||||
|
||||
networks:
|
||||
front:
|
||||
back:
|
||||
internal:
|
||||
|
||||
volumes:
|
||||
volumes:
|
||||
mongo:
|
||||
payload_media:
|
||||
payload_uploads:
|
||||
|
@ -23,10 +23,30 @@ file_env() {
|
||||
unset "$fileVar"
|
||||
}
|
||||
|
||||
urlencode() {
|
||||
raw="$1"
|
||||
encoded=""
|
||||
length=$(echo -n "$raw" | wc -c)
|
||||
i=0
|
||||
|
||||
while [ $i -lt $length ]; do
|
||||
c=$(echo "$raw" | cut -c $((i + 1)))
|
||||
case "$c" in
|
||||
[a-zA-Z0-9.~_-]) encoded="$encoded$c" ;;
|
||||
*) encoded="$encoded$(printf '%%%02X' "'$c")" ;;
|
||||
esac
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
echo "$encoded"
|
||||
}
|
||||
|
||||
file_env "TOKEN"
|
||||
file_env "MONGODB_PASSWORD"
|
||||
file_env "PAYLOAD_SECRET"
|
||||
|
||||
export MONGODB_URI="mongodb://$MONGODB_USER:$MONGODB_PASSWORD@$MONGODB_HOST:$MONGODB_PORT"
|
||||
MONGODB_PASSWORD_ENCODED=$(urlencode "$MONGODB_PASSWORD")
|
||||
|
||||
export MONGODB_URI="mongodb://$MONGODB_USER:$MONGODB_PASSWORD_ENCODED@$MONGODB_HOST:$MONGODB_PORT"
|
||||
|
||||
"$@"
|
||||
|
@ -2,11 +2,25 @@ import { withPayload } from '@payloadcms/next/withPayload'
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
// Your Next.js config here
|
||||
experimental: {
|
||||
reactCompiler: false,
|
||||
},
|
||||
output: 'standalone',
|
||||
env: {
|
||||
PORT: process.env.PORT,
|
||||
HOSTNAME: process.env.HOSTNAME,
|
||||
},
|
||||
// Disable minification & chunking for debugging
|
||||
webpack(config, { dev }) {
|
||||
config.optimization.minimize = false
|
||||
config.optimization.splitChunks = {
|
||||
cacheGroups: {
|
||||
default: false,
|
||||
},
|
||||
}
|
||||
config.optimization.runtimeChunk = false
|
||||
return config
|
||||
},
|
||||
}
|
||||
|
||||
export default withPayload(nextConfig)
|
||||
|
22
package.json
22
package.json
@ -4,7 +4,9 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "cross-env NODE_OPTIONS=--no-deprecation next dev",
|
||||
"dev": "docker compose up",
|
||||
"dev:db": "docker compose -f docker-compose.db.yaml up",
|
||||
"dev:next": "cross-env NODE_OPTIONS=--no-deprecation next dev",
|
||||
"devturbo": "cross-env NODE_OPTIONS=--no-deprecation next dev --turbo",
|
||||
"devsafe": "rm -rf .next && cross-env NODE_OPTIONS=--no-deprecation next dev",
|
||||
"build": "cross-env NODE_OPTIONS=--no-deprecation next build",
|
||||
@ -21,25 +23,36 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@payloadcms/db-mongodb": "3.0.0-beta.40",
|
||||
"@payloadcms/live-preview": "3.0.0-beta.35",
|
||||
"@payloadcms/live-preview-react": "3.0.0-beta.35",
|
||||
"@payloadcms/next": "3.0.0-beta.40",
|
||||
"@payloadcms/plugin-nested-docs": "3.0.0-beta.35",
|
||||
"@payloadcms/richtext-lexical": "3.0.0-beta.40",
|
||||
"@payloadcms/ui": "3.0.0-beta.40",
|
||||
"babel-plugin-react-compiler": "^0.0.0-experimental-592953e-20240517",
|
||||
"clsx": "^2.1.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"deepmerge": "^4.3.1",
|
||||
"graphql": "^16.8.1",
|
||||
"next": "15.0.0-rc.0",
|
||||
"payload": "3.0.0-beta.40",
|
||||
"react": "19.0.0-rc-f994737d14-20240522",
|
||||
"react-dom": "19.0.0-rc-f994737d14-20240522",
|
||||
"sharp": "0.32.6",
|
||||
"babel-plugin-react-compiler": "^0.0.0-experimental-592953e-20240517"
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.12.12",
|
||||
"@types/react": "npm:types-react@19.0.0-beta.2",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-beta.2",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-next": "14.2.3",
|
||||
"typescript": "^5.4.5"
|
||||
"postcss": "^8.4.38",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"typescript": "^5.4.5",
|
||||
"@types/lodash": "^4.17.4"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
@ -50,5 +63,6 @@
|
||||
"overrides": {
|
||||
"@types/react": "npm:types-react@19.0.0-beta.2",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-beta.2"
|
||||
}
|
||||
},
|
||||
"packageManager": "pnpm@9.4.0+sha512.f549b8a52c9d2b8536762f99c0722205efc5af913e77835dbccc3b0b0b2ca9e7dc8022b78062c17291c48e88749c70ce88eb5a74f1fa8c4bf5e18bb46c8bd83a"
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import path from 'path'
|
||||
// import { postgresAdapter } from '@payloadcms/db-postgres'
|
||||
import { en } from 'payload/i18n/en'
|
||||
import {
|
||||
AlignFeature,
|
||||
@ -19,95 +18,58 @@ import {
|
||||
UnorderedListFeature,
|
||||
UploadFeature,
|
||||
} from '@payloadcms/richtext-lexical'
|
||||
//import { slateEditor } from '@payloadcms/richtext-slate'
|
||||
import { mongooseAdapter } from '@payloadcms/db-mongodb'
|
||||
import { buildConfig } from 'payload/config'
|
||||
import sharp from 'sharp'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import Media from '@payload/collections/Media'
|
||||
import Authors from '@payload/collections/Authors'
|
||||
import Posts from '@payload/collections/Posts'
|
||||
import Users from '@payload/collections/Users'
|
||||
import Pages from '@payload/collections/Pages'
|
||||
import { COLLECTION_SLUG_PAGE, COLLECTION_SLUG_POST } from '@/app/(payload)/collections/config'
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
export default buildConfig({
|
||||
//editor: slateEditor({}),
|
||||
editor: lexicalEditor(),
|
||||
collections: [
|
||||
{
|
||||
slug: 'users',
|
||||
auth: true,
|
||||
access: {
|
||||
delete: () => false,
|
||||
update: () => false,
|
||||
},
|
||||
fields: [],
|
||||
},
|
||||
{
|
||||
slug: 'pages',
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'media',
|
||||
upload: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
secret: process.env.PAYLOAD_SECRET || '',
|
||||
typescript: {
|
||||
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
||||
},
|
||||
// db: postgresAdapter({
|
||||
// pool: {
|
||||
// connectionString: process.env.POSTGRES_URI || ''
|
||||
// }
|
||||
// }),
|
||||
db: mongooseAdapter({
|
||||
url: process.env.MONGODB_URI || '',
|
||||
}),
|
||||
|
||||
/**
|
||||
* Payload can now accept specific translations from 'payload/i18n/en'
|
||||
* This is completely optional and will default to English if not provided
|
||||
*/
|
||||
i18n: {
|
||||
supportedLanguages: { en },
|
||||
},
|
||||
|
||||
collections: [Users, Posts, Authors, Media, Pages],
|
||||
admin: {
|
||||
autoLogin: {
|
||||
email: 'dev@payloadcms.com',
|
||||
email: 'admin@nextload.test',
|
||||
password: 'test',
|
||||
prefillOnly: true,
|
||||
},
|
||||
livePreview: {
|
||||
url: ({ data, locale, collectionConfig }) =>
|
||||
`${process.env.BASE_URL}/${collectionConfig?.slug || ''}/preview${data.path}${
|
||||
locale ? `?locale=${locale.code}` : ''
|
||||
}`,
|
||||
collections: [COLLECTION_SLUG_PAGE, COLLECTION_SLUG_POST],
|
||||
},
|
||||
},
|
||||
editor: lexicalEditor(),
|
||||
secret: process.env.PAYLOAD_SECRET || '',
|
||||
typescript: {
|
||||
outputFile: path.resolve(dirname, 'types/payload-types.ts'),
|
||||
},
|
||||
db: mongooseAdapter({
|
||||
url: process.env.MONGODB_URI || '',
|
||||
}),
|
||||
async onInit(payload) {
|
||||
const existingUsers = await payload.find({
|
||||
collection: 'users',
|
||||
limit: 1,
|
||||
limit: 2,
|
||||
})
|
||||
|
||||
if (existingUsers.docs.length === 0) {
|
||||
if (existingUsers.docs.length === 0 || existingUsers.docs.length === 1) {
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: 'dev@payloadcms.com',
|
||||
email: 'admin@nextload.test',
|
||||
password: 'test',
|
||||
roles: ['admin'],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
449
pnpm-lock.yaml
449
pnpm-lock.yaml
@ -15,24 +15,42 @@ importers:
|
||||
'@payloadcms/db-mongodb':
|
||||
specifier: 3.0.0-beta.40
|
||||
version: 3.0.0-beta.40(@aws-sdk/client-sso-oidc@3.588.0)(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))
|
||||
'@payloadcms/live-preview':
|
||||
specifier: 3.0.0-beta.35
|
||||
version: 3.0.0-beta.35
|
||||
'@payloadcms/live-preview-react':
|
||||
specifier: 3.0.0-beta.35
|
||||
version: 3.0.0-beta.35(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)
|
||||
'@payloadcms/next':
|
||||
specifier: 3.0.0-beta.40
|
||||
version: 3.0.0-beta.40(graphql@16.8.1)(monaco-editor@0.49.0)(next@15.0.0-rc.0(babel-plugin-react-compiler@0.0.0-experimental-938cd9a-20240601)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(sass@1.77.4))(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(types-react@19.0.0-beta.2)(typescript@5.4.5)
|
||||
'@payloadcms/plugin-nested-docs':
|
||||
specifier: 3.0.0-beta.35
|
||||
version: 3.0.0-beta.35(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))
|
||||
'@payloadcms/richtext-lexical':
|
||||
specifier: 3.0.0-beta.40
|
||||
version: 3.0.0-beta.40(@faceless-ui/modal@2.0.2(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(@faceless-ui/scroll-info@1.3.0(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(@lexical/headless@0.15.0)(@lexical/link@0.15.0)(@lexical/list@0.15.0)(@lexical/mark@0.15.0)(@lexical/markdown@0.15.0)(@lexical/react@0.15.0(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(yjs@13.6.15))(@lexical/rich-text@0.15.0)(@lexical/selection@0.15.0)(@lexical/utils@0.15.0)(@payloadcms/next@3.0.0-beta.40(graphql@16.8.1)(monaco-editor@0.49.0)(next@15.0.0-rc.0(babel-plugin-react-compiler@0.0.0-experimental-938cd9a-20240601)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(sass@1.77.4))(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(types-react@19.0.0-beta.2)(typescript@5.4.5))(@payloadcms/translations@3.0.0-beta.29)(@payloadcms/ui@3.0.0-beta.40(monaco-editor@0.49.0)(next@15.0.0-rc.0(babel-plugin-react-compiler@0.0.0-experimental-938cd9a-20240601)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(sass@1.77.4))(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(types-react@19.0.0-beta.2))(lexical@0.15.0)(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)
|
||||
version: 3.0.0-beta.40(tqwuhpzhdzlcn7wsspnixuamku)
|
||||
'@payloadcms/ui':
|
||||
specifier: 3.0.0-beta.40
|
||||
version: 3.0.0-beta.40(monaco-editor@0.49.0)(next@15.0.0-rc.0(babel-plugin-react-compiler@0.0.0-experimental-938cd9a-20240601)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(sass@1.77.4))(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(types-react@19.0.0-beta.2)
|
||||
babel-plugin-react-compiler:
|
||||
specifier: ^0.0.0-experimental-592953e-20240517
|
||||
version: 0.0.0-experimental-938cd9a-20240601
|
||||
clsx:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
cross-env:
|
||||
specifier: ^7.0.3
|
||||
version: 7.0.3
|
||||
deepmerge:
|
||||
specifier: ^4.3.1
|
||||
version: 4.3.1
|
||||
graphql:
|
||||
specifier: ^16.8.1
|
||||
version: 16.8.1
|
||||
lodash:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
next:
|
||||
specifier: 15.0.0-rc.0
|
||||
version: 15.0.0-rc.0(babel-plugin-react-compiler@0.0.0-experimental-938cd9a-20240601)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(sass@1.77.4)
|
||||
@ -48,7 +66,13 @@ importers:
|
||||
sharp:
|
||||
specifier: 0.32.6
|
||||
version: 0.32.6
|
||||
tailwind-merge:
|
||||
specifier: ^2.3.0
|
||||
version: 2.3.0
|
||||
devDependencies:
|
||||
'@types/lodash':
|
||||
specifier: ^4.17.4
|
||||
version: 4.17.4
|
||||
'@types/node':
|
||||
specifier: ^20.12.12
|
||||
version: 20.14.1
|
||||
@ -58,18 +82,31 @@ importers:
|
||||
'@types/react-dom':
|
||||
specifier: npm:types-react-dom@19.0.0-beta.2
|
||||
version: types-react-dom@19.0.0-beta.2
|
||||
autoprefixer:
|
||||
specifier: ^10.4.19
|
||||
version: 10.4.19(postcss@8.4.38)
|
||||
eslint:
|
||||
specifier: ^8.57.0
|
||||
version: 8.57.0
|
||||
eslint-config-next:
|
||||
specifier: 14.2.3
|
||||
version: 14.2.3(eslint@8.57.0)(typescript@5.4.5)
|
||||
postcss:
|
||||
specifier: ^8.4.38
|
||||
version: 8.4.38
|
||||
tailwindcss:
|
||||
specifier: ^3.4.4
|
||||
version: 3.4.4
|
||||
typescript:
|
||||
specifier: ^5.4.5
|
||||
version: 5.4.5
|
||||
|
||||
packages:
|
||||
|
||||
'@alloc/quick-lru@5.2.0':
|
||||
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
'@aws-crypto/ie11-detection@3.0.0':
|
||||
resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==}
|
||||
|
||||
@ -496,6 +533,24 @@ packages:
|
||||
resolution: {integrity: sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.5':
|
||||
resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
'@jridgewell/resolve-uri@3.1.2':
|
||||
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
'@jridgewell/set-array@1.2.1':
|
||||
resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.4.15':
|
||||
resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.25':
|
||||
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||
|
||||
'@jsdevtools/ono@7.1.3':
|
||||
resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
|
||||
|
||||
@ -672,6 +727,15 @@ packages:
|
||||
graphql: ^16.8.1
|
||||
payload: 3.0.0-beta.40
|
||||
|
||||
'@payloadcms/live-preview-react@3.0.0-beta.35':
|
||||
resolution: {integrity: sha512-OAkuNILhSpFnHuUOThZ2c1D3DzHA3liUpgxG5VnbnMJzYThR7XE7R3jkeCEs+7V3bpy+oKyNxEZAc/jqufMhzA==}
|
||||
peerDependencies:
|
||||
react: ^18.2.0 || ^19.0.0
|
||||
react-dom: ^18.2.0 || ^19.0.0
|
||||
|
||||
'@payloadcms/live-preview@3.0.0-beta.35':
|
||||
resolution: {integrity: sha512-t0JdtfYYc4xU8F/3dj0iwaSoPhc/n2XXe6qsEKYtuKqFRNs00aX2fm1FSrQ8HG1onWnu7g+1VnEjsJeajnT7hw==}
|
||||
|
||||
'@payloadcms/next@3.0.0-beta.40':
|
||||
resolution: {integrity: sha512-B/6uXGyrp0L8J6afSZ2hgB8pWe69O7PTdEDT0MG6gUAIg+EVxn54kFqA8YsR5l68Fa8q5xOPrliBfd58OAOYng==}
|
||||
engines: {node: '>=18.20.2'}
|
||||
@ -680,6 +744,11 @@ packages:
|
||||
next: ^15.0.0-rc.0
|
||||
payload: 3.0.0-beta.40
|
||||
|
||||
'@payloadcms/plugin-nested-docs@3.0.0-beta.35':
|
||||
resolution: {integrity: sha512-rrtGmvjD38jX74Z3+WhwW+PCDYClp7/RDbuimjqmfjSvNJnDagwnp1WMjkEF0w37S1Wbi+DmFmLA6GtBVfj8Ng==}
|
||||
peerDependencies:
|
||||
payload: 3.0.0-beta.35
|
||||
|
||||
'@payloadcms/richtext-lexical@3.0.0-beta.40':
|
||||
resolution: {integrity: sha512-erSfkn+GO8A+7yFOKbHrF3i1i2awXkGfurJsuJCetBm3M9Vb5++ZfgsbWpR1c3USSvt6+fLonGWwpYF4wD/XsQ==}
|
||||
engines: {node: '>=18.20.2'}
|
||||
@ -703,9 +772,6 @@ packages:
|
||||
react: ^19.0.0 || ^19.0.0-rc-f994737d14-20240522
|
||||
react-dom: ^19.0.0 || ^19.0.0-rc-f994737d14-20240522
|
||||
|
||||
'@payloadcms/translations@3.0.0-beta.29':
|
||||
resolution: {integrity: sha512-mkjniP89wZiYKK6RbVavOlpu8kqKGG8VGGJC8KgEaYoLGHofIW8aDQwHuqjMBFfqhP6I5HFCeqZnZLKCRjuEvQ==}
|
||||
|
||||
'@payloadcms/translations@3.0.0-beta.40':
|
||||
resolution: {integrity: sha512-Y6I2yZypxpa1gRDO5YQCnvf9MFRMy1ybWNQam0I3F/JDd46bJwNT0pDD521mE2eqdM7+Nw8PwU5c55hng4kdYw==}
|
||||
|
||||
@ -1121,6 +1187,9 @@ packages:
|
||||
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
arg@5.0.2:
|
||||
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
|
||||
|
||||
argparse@2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
|
||||
@ -1177,6 +1246,13 @@ packages:
|
||||
resolution: {integrity: sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==}
|
||||
engines: {node: '>=10.12.0'}
|
||||
|
||||
autoprefixer@10.4.19:
|
||||
resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
postcss: ^8.1.0
|
||||
|
||||
available-typed-arrays@1.0.7:
|
||||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -1245,6 +1321,11 @@ packages:
|
||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
browserslist@4.23.1:
|
||||
resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==}
|
||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||
hasBin: true
|
||||
|
||||
bson-objectid@2.0.4:
|
||||
resolution: {integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==}
|
||||
|
||||
@ -1279,9 +1360,16 @@ packages:
|
||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
camelcase-css@2.0.1:
|
||||
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
caniuse-lite@1.0.30001627:
|
||||
resolution: {integrity: sha512-4zgNiB8nTyV/tHhwZrFs88ryjls/lHiqFhrxCW4qSTeuRByBVnPYpDInchOIySWknznucaf31Z4KYqjfbrecVw==}
|
||||
|
||||
caniuse-lite@1.0.30001636:
|
||||
resolution: {integrity: sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==}
|
||||
|
||||
chalk@2.4.2:
|
||||
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
|
||||
engines: {node: '>=4'}
|
||||
@ -1344,6 +1432,10 @@ packages:
|
||||
commander@2.20.3:
|
||||
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||
|
||||
commander@4.1.1:
|
||||
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
concat-map@0.0.1:
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
|
||||
@ -1373,6 +1465,11 @@ packages:
|
||||
crypt@0.0.2:
|
||||
resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
|
||||
|
||||
cssesc@3.0.0:
|
||||
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
|
||||
cssfilter@0.0.10:
|
||||
resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==}
|
||||
|
||||
@ -1466,6 +1563,9 @@ packages:
|
||||
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
didyoumean@1.2.2:
|
||||
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
||||
|
||||
diff@5.2.0:
|
||||
resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
@ -1474,6 +1574,9 @@ packages:
|
||||
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
dlv@1.1.3:
|
||||
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
|
||||
|
||||
doctrine@2.1.0:
|
||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -1495,6 +1598,9 @@ packages:
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
||||
|
||||
electron-to-chromium@1.4.810:
|
||||
resolution: {integrity: sha512-Kaxhu4T7SJGpRQx99tq216gCq2nMxJo+uuT6uzz9l8TVN2stL7M06MIIXAtr9jsrLs2Glflgf2vMQRepxawOdQ==}
|
||||
|
||||
emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
|
||||
@ -1563,6 +1669,10 @@ packages:
|
||||
es6-weak-map@2.0.3:
|
||||
resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==}
|
||||
|
||||
escalade@3.1.2:
|
||||
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
escape-string-regexp@1.0.5:
|
||||
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
@ -1778,6 +1888,9 @@ packages:
|
||||
resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
fraction.js@4.3.7:
|
||||
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
|
||||
|
||||
fs-constants@1.0.0:
|
||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||
|
||||
@ -2113,6 +2226,10 @@ packages:
|
||||
resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
jiti@1.21.6:
|
||||
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
|
||||
hasBin: true
|
||||
|
||||
joi@17.13.1:
|
||||
resolution: {integrity: sha512-vaBlIKCyo4FCUtCm7Eu4QZd/q02bWcxfUO6YSXAZOWF6gzcLBeba8kwotUdYJjDLW8Cz8RywsSOqiNJZW0mNvg==}
|
||||
|
||||
@ -2209,6 +2326,14 @@ packages:
|
||||
engines: {node: '>=16'}
|
||||
hasBin: true
|
||||
|
||||
lilconfig@2.1.0:
|
||||
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
lilconfig@3.1.2:
|
||||
resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
lines-and-columns@1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
|
||||
@ -2384,14 +2509,25 @@ packages:
|
||||
node-addon-api@6.1.0:
|
||||
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
|
||||
|
||||
node-releases@2.0.14:
|
||||
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
|
||||
|
||||
normalize-path@3.0.0:
|
||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
normalize-range@0.1.2:
|
||||
resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
object-hash@3.0.0:
|
||||
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
object-inspect@1.13.1:
|
||||
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
|
||||
|
||||
@ -2541,6 +2677,10 @@ packages:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
pify@2.3.0:
|
||||
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
pino-abstract-transport@1.0.0:
|
||||
resolution: {integrity: sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==}
|
||||
|
||||
@ -2558,6 +2698,10 @@ packages:
|
||||
resolution: {integrity: sha512-olUADJByk4twxccmAxb1RiGKOSvddHugCV3wkqjyv+3Sooa2KLrmXrKEWOKi0XPCLasRR5jBXxioE1jxUa4KzQ==}
|
||||
hasBin: true
|
||||
|
||||
pirates@4.0.6:
|
||||
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
pkg-up@3.1.0:
|
||||
resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==}
|
||||
engines: {node: '>=8'}
|
||||
@ -2570,10 +2714,51 @@ packages:
|
||||
resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
postcss-import@15.1.0:
|
||||
resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
postcss: ^8.0.0
|
||||
|
||||
postcss-js@4.0.1:
|
||||
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
|
||||
engines: {node: ^12 || ^14 || >= 16}
|
||||
peerDependencies:
|
||||
postcss: ^8.4.21
|
||||
|
||||
postcss-load-config@4.0.2:
|
||||
resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
|
||||
engines: {node: '>= 14'}
|
||||
peerDependencies:
|
||||
postcss: '>=8.0.9'
|
||||
ts-node: '>=9.0.0'
|
||||
peerDependenciesMeta:
|
||||
postcss:
|
||||
optional: true
|
||||
ts-node:
|
||||
optional: true
|
||||
|
||||
postcss-nested@6.0.1:
|
||||
resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==}
|
||||
engines: {node: '>=12.0'}
|
||||
peerDependencies:
|
||||
postcss: ^8.2.14
|
||||
|
||||
postcss-selector-parser@6.1.0:
|
||||
resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
postcss-value-parser@4.2.0:
|
||||
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
|
||||
|
||||
postcss@8.4.31:
|
||||
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
postcss@8.4.38:
|
||||
resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
prebuild-install@7.1.2:
|
||||
resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -2713,6 +2898,9 @@ packages:
|
||||
resolution: {integrity: sha512-SeU2v5Xy6FotVhKz0pMS2gvYP7HlkF0qgTskj3JzA1vlxcb3dQjxlm9t0ZlJqcgoyI3VFAw7bomuDMdgy1nBuw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
read-cache@1.0.0:
|
||||
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
|
||||
|
||||
readable-stream@3.6.2:
|
||||
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||
engines: {node: '>= 6'}
|
||||
@ -2993,6 +3181,11 @@ packages:
|
||||
stylis@4.2.0:
|
||||
resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
|
||||
|
||||
sucrase@3.35.0:
|
||||
resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
hasBin: true
|
||||
|
||||
supports-color@5.5.0:
|
||||
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
|
||||
engines: {node: '>=4'}
|
||||
@ -3011,6 +3204,14 @@ packages:
|
||||
tabbable@6.2.0:
|
||||
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
|
||||
|
||||
tailwind-merge@2.3.0:
|
||||
resolution: {integrity: sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==}
|
||||
|
||||
tailwindcss@3.4.4:
|
||||
resolution: {integrity: sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
|
||||
tapable@2.2.1:
|
||||
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
|
||||
engines: {node: '>=6'}
|
||||
@ -3086,6 +3287,9 @@ packages:
|
||||
peerDependencies:
|
||||
typescript: '>=3.7.0'
|
||||
|
||||
ts-interface-checker@0.1.13:
|
||||
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
||||
|
||||
tsconfig-paths@3.15.0:
|
||||
resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
|
||||
|
||||
@ -3146,6 +3350,12 @@ packages:
|
||||
resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
update-browserslist-db@1.0.16:
|
||||
resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
browserslist: '>= 4.21.0'
|
||||
|
||||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
@ -3238,6 +3448,11 @@ packages:
|
||||
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
yaml@2.4.5:
|
||||
resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==}
|
||||
engines: {node: '>= 14'}
|
||||
hasBin: true
|
||||
|
||||
yjs@13.6.15:
|
||||
resolution: {integrity: sha512-moFv4uNYhp8BFxIk3AkpoAnnjts7gwdpiG8RtyFiKbMtxKCS0zVZ5wPaaGpwC3V2N/K8TK8MwtSI3+WO9CHWjQ==}
|
||||
engines: {node: '>=16.0.0', npm: '>=8.0.0'}
|
||||
@ -3261,6 +3476,8 @@ packages:
|
||||
|
||||
snapshots:
|
||||
|
||||
'@alloc/quick-lru@5.2.0': {}
|
||||
|
||||
'@aws-crypto/ie11-detection@3.0.0':
|
||||
dependencies:
|
||||
tslib: 1.14.1
|
||||
@ -3304,7 +3521,7 @@ snapshots:
|
||||
'@aws-sdk/client-sso-oidc': 3.588.0
|
||||
'@aws-sdk/client-sts': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)
|
||||
'@aws-sdk/core': 3.588.0
|
||||
'@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0)
|
||||
'@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))
|
||||
'@aws-sdk/middleware-host-header': 3.577.0
|
||||
'@aws-sdk/middleware-logger': 3.577.0
|
||||
'@aws-sdk/middleware-recursion-detection': 3.577.0
|
||||
@ -3350,7 +3567,7 @@ snapshots:
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/client-sts': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)
|
||||
'@aws-sdk/core': 3.588.0
|
||||
'@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0)
|
||||
'@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))
|
||||
'@aws-sdk/middleware-host-header': 3.577.0
|
||||
'@aws-sdk/middleware-logger': 3.577.0
|
||||
'@aws-sdk/middleware-recursion-detection': 3.577.0
|
||||
@ -3440,7 +3657,7 @@ snapshots:
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/client-sso-oidc': 3.588.0
|
||||
'@aws-sdk/core': 3.588.0
|
||||
'@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0)
|
||||
'@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))
|
||||
'@aws-sdk/middleware-host-header': 3.577.0
|
||||
'@aws-sdk/middleware-logger': 3.577.0
|
||||
'@aws-sdk/middleware-recursion-detection': 3.577.0
|
||||
@ -3524,14 +3741,14 @@ snapshots:
|
||||
tslib: 2.6.2
|
||||
optional: true
|
||||
|
||||
'@aws-sdk/credential-provider-ini@3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0)':
|
||||
'@aws-sdk/credential-provider-ini@3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))':
|
||||
dependencies:
|
||||
'@aws-sdk/client-sts': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)
|
||||
'@aws-sdk/credential-provider-env': 3.587.0
|
||||
'@aws-sdk/credential-provider-http': 3.587.0
|
||||
'@aws-sdk/credential-provider-process': 3.587.0
|
||||
'@aws-sdk/credential-provider-sso': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)
|
||||
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.588.0)
|
||||
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/credential-provider-imds': 3.1.0
|
||||
'@smithy/property-provider': 3.1.0
|
||||
@ -3543,14 +3760,14 @@ snapshots:
|
||||
- aws-crt
|
||||
optional: true
|
||||
|
||||
'@aws-sdk/credential-provider-node@3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0)':
|
||||
'@aws-sdk/credential-provider-node@3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))':
|
||||
dependencies:
|
||||
'@aws-sdk/credential-provider-env': 3.587.0
|
||||
'@aws-sdk/credential-provider-http': 3.587.0
|
||||
'@aws-sdk/credential-provider-ini': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0)
|
||||
'@aws-sdk/credential-provider-ini': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))
|
||||
'@aws-sdk/credential-provider-process': 3.587.0
|
||||
'@aws-sdk/credential-provider-sso': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)
|
||||
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.588.0)
|
||||
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/credential-provider-imds': 3.1.0
|
||||
'@smithy/property-provider': 3.1.0
|
||||
@ -3586,7 +3803,7 @@ snapshots:
|
||||
- aws-crt
|
||||
optional: true
|
||||
|
||||
'@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.588.0)':
|
||||
'@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))':
|
||||
dependencies:
|
||||
'@aws-sdk/client-sts': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)
|
||||
'@aws-sdk/types': 3.577.0
|
||||
@ -3603,11 +3820,11 @@ snapshots:
|
||||
'@aws-sdk/credential-provider-cognito-identity': 3.588.0
|
||||
'@aws-sdk/credential-provider-env': 3.587.0
|
||||
'@aws-sdk/credential-provider-http': 3.587.0
|
||||
'@aws-sdk/credential-provider-ini': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0)
|
||||
'@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0)
|
||||
'@aws-sdk/credential-provider-ini': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))
|
||||
'@aws-sdk/credential-provider-node': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))
|
||||
'@aws-sdk/credential-provider-process': 3.587.0
|
||||
'@aws-sdk/credential-provider-sso': 3.588.0(@aws-sdk/client-sso-oidc@3.588.0)
|
||||
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.588.0)
|
||||
'@aws-sdk/credential-provider-web-identity': 3.587.0(@aws-sdk/client-sts@3.588.0(@aws-sdk/client-sso-oidc@3.588.0))
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/credential-provider-imds': 3.1.0
|
||||
'@smithy/property-provider': 3.1.0
|
||||
@ -4028,6 +4245,23 @@ snapshots:
|
||||
'@types/istanbul-reports': 1.1.2
|
||||
'@types/yargs': 13.0.12
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.5':
|
||||
dependencies:
|
||||
'@jridgewell/set-array': 1.2.1
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
|
||||
'@jridgewell/resolve-uri@3.1.2': {}
|
||||
|
||||
'@jridgewell/set-array@1.2.1': {}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.4.15': {}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.25':
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
|
||||
'@jsdevtools/ono@7.1.3': {}
|
||||
|
||||
'@lexical/clipboard@0.15.0':
|
||||
@ -4266,6 +4500,14 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
'@payloadcms/live-preview-react@3.0.0-beta.35(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)':
|
||||
dependencies:
|
||||
'@payloadcms/live-preview': 3.0.0-beta.35
|
||||
react: 19.0.0-rc-f994737d14-20240522
|
||||
react-dom: 19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522)
|
||||
|
||||
'@payloadcms/live-preview@3.0.0-beta.35': {}
|
||||
|
||||
'@payloadcms/next@3.0.0-beta.40(graphql@16.8.1)(monaco-editor@0.49.0)(next@15.0.0-rc.0(babel-plugin-react-compiler@0.0.0-experimental-938cd9a-20240601)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(sass@1.77.4))(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(types-react@19.0.0-beta.2)(typescript@5.4.5)':
|
||||
dependencies:
|
||||
'@dnd-kit/core': 6.0.8(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)
|
||||
@ -4295,8 +4537,12 @@ snapshots:
|
||||
- typescript
|
||||
- utf-8-validate
|
||||
|
||||
? '@payloadcms/richtext-lexical@3.0.0-beta.40(@faceless-ui/modal@2.0.2(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(@faceless-ui/scroll-info@1.3.0(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(@lexical/headless@0.15.0)(@lexical/link@0.15.0)(@lexical/list@0.15.0)(@lexical/mark@0.15.0)(@lexical/markdown@0.15.0)(@lexical/react@0.15.0(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(yjs@13.6.15))(@lexical/rich-text@0.15.0)(@lexical/selection@0.15.0)(@lexical/utils@0.15.0)(@payloadcms/next@3.0.0-beta.40(graphql@16.8.1)(monaco-editor@0.49.0)(next@15.0.0-rc.0(babel-plugin-react-compiler@0.0.0-experimental-938cd9a-20240601)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(sass@1.77.4))(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(types-react@19.0.0-beta.2)(typescript@5.4.5))(@payloadcms/translations@3.0.0-beta.29)(@payloadcms/ui@3.0.0-beta.40(monaco-editor@0.49.0)(next@15.0.0-rc.0(babel-plugin-react-compiler@0.0.0-experimental-938cd9a-20240601)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(sass@1.77.4))(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(types-react@19.0.0-beta.2))(lexical@0.15.0)(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)'
|
||||
: dependencies:
|
||||
'@payloadcms/plugin-nested-docs@3.0.0-beta.35(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))':
|
||||
dependencies:
|
||||
payload: 3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5)
|
||||
|
||||
'@payloadcms/richtext-lexical@3.0.0-beta.40(tqwuhpzhdzlcn7wsspnixuamku)':
|
||||
dependencies:
|
||||
'@faceless-ui/modal': 2.0.2(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)
|
||||
'@faceless-ui/scroll-info': 1.3.0(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)
|
||||
'@lexical/headless': 0.15.0
|
||||
@ -4309,7 +4555,7 @@ snapshots:
|
||||
'@lexical/selection': 0.15.0
|
||||
'@lexical/utils': 0.15.0
|
||||
'@payloadcms/next': 3.0.0-beta.40(graphql@16.8.1)(monaco-editor@0.49.0)(next@15.0.0-rc.0(babel-plugin-react-compiler@0.0.0-experimental-938cd9a-20240601)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(sass@1.77.4))(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(types-react@19.0.0-beta.2)(typescript@5.4.5)
|
||||
'@payloadcms/translations': 3.0.0-beta.29
|
||||
'@payloadcms/translations': 3.0.0-beta.40
|
||||
'@payloadcms/ui': 3.0.0-beta.40(monaco-editor@0.49.0)(next@15.0.0-rc.0(babel-plugin-react-compiler@0.0.0-experimental-938cd9a-20240601)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(sass@1.77.4))(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(types-react@19.0.0-beta.2)
|
||||
'@types/uuid': 9.0.8
|
||||
bson-objectid: 2.0.4
|
||||
@ -4324,8 +4570,6 @@ snapshots:
|
||||
react-error-boundary: 4.0.13(react@19.0.0-rc-f994737d14-20240522)
|
||||
uuid: 9.0.1
|
||||
|
||||
'@payloadcms/translations@3.0.0-beta.29': {}
|
||||
|
||||
'@payloadcms/translations@3.0.0-beta.40': {}
|
||||
|
||||
'@payloadcms/ui@3.0.0-beta.40(monaco-editor@0.49.0)(next@15.0.0-rc.0(babel-plugin-react-compiler@0.0.0-experimental-938cd9a-20240601)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(sass@1.77.4))(payload@3.0.0-beta.40(@swc/core@1.5.24(@swc/helpers@0.5.11))(@swc/types@0.1.7)(graphql@16.8.1)(typescript@5.4.5))(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(types-react@19.0.0-beta.2)':
|
||||
@ -4876,6 +5120,8 @@ snapshots:
|
||||
normalize-path: 3.0.0
|
||||
picomatch: 2.3.1
|
||||
|
||||
arg@5.0.2: {}
|
||||
|
||||
argparse@2.0.1: {}
|
||||
|
||||
aria-query@5.3.0:
|
||||
@ -4962,6 +5208,16 @@ snapshots:
|
||||
|
||||
atomically@1.7.0: {}
|
||||
|
||||
autoprefixer@10.4.19(postcss@8.4.38):
|
||||
dependencies:
|
||||
browserslist: 4.23.1
|
||||
caniuse-lite: 1.0.30001627
|
||||
fraction.js: 4.3.7
|
||||
normalize-range: 0.1.2
|
||||
picocolors: 1.0.1
|
||||
postcss: 8.4.38
|
||||
postcss-value-parser: 4.2.0
|
||||
|
||||
available-typed-arrays@1.0.7:
|
||||
dependencies:
|
||||
possible-typed-array-names: 1.0.0
|
||||
@ -5045,6 +5301,13 @@ snapshots:
|
||||
dependencies:
|
||||
fill-range: 7.1.1
|
||||
|
||||
browserslist@4.23.1:
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001636
|
||||
electron-to-chromium: 1.4.810
|
||||
node-releases: 2.0.14
|
||||
update-browserslist-db: 1.0.16(browserslist@4.23.1)
|
||||
|
||||
bson-objectid@2.0.4: {}
|
||||
|
||||
bson@4.7.2:
|
||||
@ -5081,8 +5344,12 @@ snapshots:
|
||||
|
||||
callsites@3.1.0: {}
|
||||
|
||||
camelcase-css@2.0.1: {}
|
||||
|
||||
caniuse-lite@1.0.30001627: {}
|
||||
|
||||
caniuse-lite@1.0.30001636: {}
|
||||
|
||||
chalk@2.4.2:
|
||||
dependencies:
|
||||
ansi-styles: 3.2.1
|
||||
@ -5152,6 +5419,8 @@ snapshots:
|
||||
|
||||
commander@2.20.3: {}
|
||||
|
||||
commander@4.1.1: {}
|
||||
|
||||
concat-map@0.0.1: {}
|
||||
|
||||
conf@10.2.0:
|
||||
@ -5193,6 +5462,8 @@ snapshots:
|
||||
|
||||
crypt@0.0.2: {}
|
||||
|
||||
cssesc@3.0.0: {}
|
||||
|
||||
cssfilter@0.0.10: {}
|
||||
|
||||
csstype@3.1.3: {}
|
||||
@ -5308,12 +5579,16 @@ snapshots:
|
||||
|
||||
detect-libc@2.0.3: {}
|
||||
|
||||
didyoumean@1.2.2: {}
|
||||
|
||||
diff@5.2.0: {}
|
||||
|
||||
dir-glob@3.0.1:
|
||||
dependencies:
|
||||
path-type: 4.0.0
|
||||
|
||||
dlv@1.1.3: {}
|
||||
|
||||
doctrine@2.1.0:
|
||||
dependencies:
|
||||
esutils: 2.0.3
|
||||
@ -5337,6 +5612,8 @@ snapshots:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
electron-to-chromium@1.4.810: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
|
||||
emoji-regex@9.2.2: {}
|
||||
@ -5485,6 +5762,8 @@ snapshots:
|
||||
es6-iterator: 2.0.3
|
||||
es6-symbol: 3.1.4
|
||||
|
||||
escalade@3.1.2: {}
|
||||
|
||||
escape-string-regexp@1.0.5: {}
|
||||
|
||||
escape-string-regexp@4.0.0: {}
|
||||
@ -5496,8 +5775,8 @@ snapshots:
|
||||
'@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
|
||||
eslint-plugin-react: 7.34.2(eslint@8.57.0)
|
||||
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0)
|
||||
@ -5515,13 +5794,13 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0):
|
||||
eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0):
|
||||
dependencies:
|
||||
debug: 4.3.5
|
||||
enhanced-resolve: 5.16.1
|
||||
eslint: 8.57.0
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
|
||||
fast-glob: 3.3.2
|
||||
get-tsconfig: 4.7.5
|
||||
is-core-module: 2.13.1
|
||||
@ -5532,18 +5811,18 @@ snapshots:
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0):
|
||||
eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
|
||||
eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0):
|
||||
dependencies:
|
||||
array-includes: 3.1.8
|
||||
array.prototype.findlastindex: 1.2.5
|
||||
@ -5553,7 +5832,7 @@ snapshots:
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.13.1
|
||||
is-glob: 4.0.3
|
||||
@ -5799,6 +6078,8 @@ snapshots:
|
||||
cross-spawn: 7.0.3
|
||||
signal-exit: 4.1.0
|
||||
|
||||
fraction.js@4.3.7: {}
|
||||
|
||||
fs-constants@1.0.0: {}
|
||||
|
||||
fs.realpath@1.0.0: {}
|
||||
@ -6125,6 +6406,8 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@pkgjs/parseargs': 0.11.0
|
||||
|
||||
jiti@1.21.6: {}
|
||||
|
||||
joi@17.13.1:
|
||||
dependencies:
|
||||
'@hapi/hoek': 9.3.0
|
||||
@ -6230,6 +6513,10 @@ snapshots:
|
||||
dependencies:
|
||||
isomorphic.js: 0.2.5
|
||||
|
||||
lilconfig@2.1.0: {}
|
||||
|
||||
lilconfig@3.1.2: {}
|
||||
|
||||
lines-and-columns@1.2.4: {}
|
||||
|
||||
locate-path@3.0.0:
|
||||
@ -6415,10 +6702,16 @@ snapshots:
|
||||
|
||||
node-addon-api@6.1.0: {}
|
||||
|
||||
node-releases@2.0.14: {}
|
||||
|
||||
normalize-path@3.0.0: {}
|
||||
|
||||
normalize-range@0.1.2: {}
|
||||
|
||||
object-assign@4.1.1: {}
|
||||
|
||||
object-hash@3.0.0: {}
|
||||
|
||||
object-inspect@1.13.1: {}
|
||||
|
||||
object-is@1.1.6:
|
||||
@ -6591,6 +6884,8 @@ snapshots:
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
||||
pify@2.3.0: {}
|
||||
|
||||
pino-abstract-transport@1.0.0:
|
||||
dependencies:
|
||||
readable-stream: 4.5.2
|
||||
@ -6634,6 +6929,8 @@ snapshots:
|
||||
sonic-boom: 3.8.1
|
||||
thread-stream: 2.7.0
|
||||
|
||||
pirates@4.0.6: {}
|
||||
|
||||
pkg-up@3.1.0:
|
||||
dependencies:
|
||||
find-up: 3.0.0
|
||||
@ -6642,12 +6939,49 @@ snapshots:
|
||||
|
||||
possible-typed-array-names@1.0.0: {}
|
||||
|
||||
postcss-import@15.1.0(postcss@8.4.38):
|
||||
dependencies:
|
||||
postcss: 8.4.38
|
||||
postcss-value-parser: 4.2.0
|
||||
read-cache: 1.0.0
|
||||
resolve: 1.22.8
|
||||
|
||||
postcss-js@4.0.1(postcss@8.4.38):
|
||||
dependencies:
|
||||
camelcase-css: 2.0.1
|
||||
postcss: 8.4.38
|
||||
|
||||
postcss-load-config@4.0.2(postcss@8.4.38):
|
||||
dependencies:
|
||||
lilconfig: 3.1.2
|
||||
yaml: 2.4.5
|
||||
optionalDependencies:
|
||||
postcss: 8.4.38
|
||||
|
||||
postcss-nested@6.0.1(postcss@8.4.38):
|
||||
dependencies:
|
||||
postcss: 8.4.38
|
||||
postcss-selector-parser: 6.1.0
|
||||
|
||||
postcss-selector-parser@6.1.0:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
postcss-value-parser@4.2.0: {}
|
||||
|
||||
postcss@8.4.31:
|
||||
dependencies:
|
||||
nanoid: 3.3.7
|
||||
picocolors: 1.0.1
|
||||
source-map-js: 1.2.0
|
||||
|
||||
postcss@8.4.38:
|
||||
dependencies:
|
||||
nanoid: 3.3.7
|
||||
picocolors: 1.0.1
|
||||
source-map-js: 1.2.0
|
||||
|
||||
prebuild-install@7.1.2:
|
||||
dependencies:
|
||||
detect-libc: 2.0.3
|
||||
@ -6809,6 +7143,10 @@ snapshots:
|
||||
|
||||
react@19.0.0-rc-f994737d14-20240522: {}
|
||||
|
||||
read-cache@1.0.0:
|
||||
dependencies:
|
||||
pify: 2.3.0
|
||||
|
||||
readable-stream@3.6.2:
|
||||
dependencies:
|
||||
inherits: 2.0.4
|
||||
@ -7137,6 +7475,16 @@ snapshots:
|
||||
|
||||
stylis@4.2.0: {}
|
||||
|
||||
sucrase@3.35.0:
|
||||
dependencies:
|
||||
'@jridgewell/gen-mapping': 0.3.5
|
||||
commander: 4.1.1
|
||||
glob: 10.3.10
|
||||
lines-and-columns: 1.2.4
|
||||
mz: 2.7.0
|
||||
pirates: 4.0.6
|
||||
ts-interface-checker: 0.1.13
|
||||
|
||||
supports-color@5.5.0:
|
||||
dependencies:
|
||||
has-flag: 3.0.0
|
||||
@ -7151,6 +7499,37 @@ snapshots:
|
||||
|
||||
tabbable@6.2.0: {}
|
||||
|
||||
tailwind-merge@2.3.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.6
|
||||
|
||||
tailwindcss@3.4.4:
|
||||
dependencies:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
arg: 5.0.2
|
||||
chokidar: 3.6.0
|
||||
didyoumean: 1.2.2
|
||||
dlv: 1.1.3
|
||||
fast-glob: 3.3.2
|
||||
glob-parent: 6.0.2
|
||||
is-glob: 4.0.3
|
||||
jiti: 1.21.6
|
||||
lilconfig: 2.1.0
|
||||
micromatch: 4.0.7
|
||||
normalize-path: 3.0.0
|
||||
object-hash: 3.0.0
|
||||
picocolors: 1.0.1
|
||||
postcss: 8.4.38
|
||||
postcss-import: 15.1.0(postcss@8.4.38)
|
||||
postcss-js: 4.0.1(postcss@8.4.38)
|
||||
postcss-load-config: 4.0.2(postcss@8.4.38)
|
||||
postcss-nested: 6.0.1(postcss@8.4.38)
|
||||
postcss-selector-parser: 6.1.0
|
||||
resolve: 1.22.8
|
||||
sucrase: 3.35.0
|
||||
transitivePeerDependencies:
|
||||
- ts-node
|
||||
|
||||
tapable@2.2.1: {}
|
||||
|
||||
tar-fs@2.1.1:
|
||||
@ -7239,6 +7618,8 @@ snapshots:
|
||||
dependencies:
|
||||
typescript: 5.4.5
|
||||
|
||||
ts-interface-checker@0.1.13: {}
|
||||
|
||||
tsconfig-paths@3.15.0:
|
||||
dependencies:
|
||||
'@types/json5': 0.0.29
|
||||
@ -7316,6 +7697,12 @@ snapshots:
|
||||
|
||||
unicorn-magic@0.1.0: {}
|
||||
|
||||
update-browserslist-db@1.0.16(browserslist@4.23.1):
|
||||
dependencies:
|
||||
browserslist: 4.23.1
|
||||
escalade: 3.1.2
|
||||
picocolors: 1.0.1
|
||||
|
||||
uri-js@4.4.1:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
@ -7411,6 +7798,8 @@ snapshots:
|
||||
|
||||
yaml@1.10.2: {}
|
||||
|
||||
yaml@2.4.5: {}
|
||||
|
||||
yjs@13.6.15:
|
||||
dependencies:
|
||||
lib0: 0.2.94
|
||||
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
115
src/app/(app)/global.css
Normal file
115
src/app/(app)/global.css
Normal file
@ -0,0 +1,115 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.light {
|
||||
|
||||
--black: 10, 16, 19;
|
||||
--white: 243, 252, 248;
|
||||
--absolute-black: 0, 0, 0;
|
||||
--absolute-white: 255, 255, 255;
|
||||
|
||||
/* Use these in tailwind.config.cjs */
|
||||
--primary: var(--black);
|
||||
--secondary: var(--black);
|
||||
--tertiary: var(--black);
|
||||
|
||||
--text: var(--black);
|
||||
--textInverted: var(--absolute-white);
|
||||
--link: var(--black);
|
||||
--background: var(--white);
|
||||
}
|
||||
|
||||
.dark {
|
||||
|
||||
--black: 10, 16, 19;
|
||||
--white: 243, 252, 248;
|
||||
--absolute-black: 0, 0, 0;
|
||||
--absolute-white: 255, 255, 255;
|
||||
|
||||
/* Use these in tailwind.config.cjs */
|
||||
--primary: var(--white);
|
||||
--secondary: var(--white);
|
||||
--tertiary: var(--white);
|
||||
|
||||
--text: var(--white);
|
||||
--textInverted: var(--absolute-black);
|
||||
--link: var(--white);
|
||||
--background: var(--black);
|
||||
}
|
||||
|
||||
.autonomic {
|
||||
/* Palette */
|
||||
/* RGBA instead of hex so that opacity will work */
|
||||
--absolute-white: 255, 255, 255;
|
||||
--white: 243, 252, 248;
|
||||
--shocking-pink: 253, 0, 159;
|
||||
--shamrock-green: 0, 198, 88;
|
||||
--bubblegum-pink: 255, 133, 203;
|
||||
--bright-orange: 255, 96, 21;
|
||||
|
||||
/* Use these in tailwind.config.cjs */
|
||||
--primary: var(--shocking-pink);
|
||||
--secondary: var(--shamrock-green);
|
||||
--tertiary: var(--bright-orange);
|
||||
|
||||
--text: var(--shocking-pink);
|
||||
--textInverted: var(--absolute-white);
|
||||
--link: var(--shamrock-green);
|
||||
--background: var(--white);
|
||||
}
|
||||
|
||||
@layer components {
|
||||
|
||||
:root {
|
||||
@apply ring-secondary;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
@apply mb-2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-5xl font-bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply text-4xl font-semibold;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-2xl font-semibold;
|
||||
}
|
||||
|
||||
h4, h5, h6 {
|
||||
@apply text-2xl font-medium;
|
||||
}
|
||||
|
||||
p, span, li, a {
|
||||
@apply text-xl;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-link underline;
|
||||
}
|
||||
|
||||
ol {
|
||||
@apply list-decimal;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply list-disc;
|
||||
}
|
||||
|
||||
select {
|
||||
@apply bg-background border-primary border px-2 h-8 text-lg;
|
||||
}
|
||||
|
||||
input {
|
||||
@apply bg-background border-primary border px-2 h-8 text-lg;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
@apply border-l-8 border-primary text-primary pl-4 ml-2 font-serif text-2xl;
|
||||
}
|
||||
}
|
@ -1,191 +0,0 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #ffffff;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
main {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding-block: 80px;
|
||||
border-inline-width: 1px;
|
||||
border-inline-style: solid;
|
||||
border-image: linear-gradient(180deg, #ffffff00, #ffffff00, #ffffff1a, #ffffff00) 1;
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
padding-block: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
article {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
padding: 60px 80px;
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
padding: 40px 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2.6px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #ffffff;
|
||||
font-size: 4rem;
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
letter-spacing: -0.02rem;
|
||||
margin: 0;
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
font-weight: 300;
|
||||
line-height: 28px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #ffffff;
|
||||
text-decoration: underline;
|
||||
transition: color 0.2s ease-out;
|
||||
|
||||
&:hover {
|
||||
color: #ffffff80;
|
||||
}
|
||||
}
|
||||
|
||||
.codeBlock {
|
||||
position: relative;
|
||||
background-color: #00000066;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
pre {
|
||||
margin: 0;
|
||||
padding: 60px 80px;
|
||||
overflow-x: auto;
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
padding: 40px 40px;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(50% - 50vw);
|
||||
width: 100vw;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, #ffffff00, #ffffff1a, #ffffff1a, #ffffff00);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: url('/crosshair.svg');
|
||||
display: block;
|
||||
height: 19px;
|
||||
width: 19px;
|
||||
position: absolute;
|
||||
top: -9px;
|
||||
left: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 14px;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: calc(50% - 50vw);
|
||||
width: 100vw;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, #ffffff00, #ffffff1a, #ffffff1a, #ffffff00);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: url('/crosshair.svg');
|
||||
display: block;
|
||||
height: 19px;
|
||||
width: 19px;
|
||||
position: absolute;
|
||||
bottom: -9px;
|
||||
right: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
.background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
|
||||
div.blur {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('/blur.png');
|
||||
background-repeat: repeat;
|
||||
background-size: 400px 400px;
|
||||
background-blend-mode: soft-light, normal;
|
||||
backdrop-filter: blur(60px);
|
||||
}
|
||||
|
||||
div.gradient {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('/gradient.webp');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
z-index: -2;
|
||||
}
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
import React from 'react'
|
||||
import './globals.scss'
|
||||
import { Inter } from 'next/font/google'
|
||||
import './global.css'
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ['latin'],
|
||||
display: 'swap',
|
||||
})
|
||||
import Header from '@/components/Header'
|
||||
import Footer from '@/components/Footer'
|
||||
|
||||
/* Our app sits here to not cause any conflicts with payload's root layout */
|
||||
const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
return (
|
||||
<html className={inter.className}>
|
||||
<body>{children}</body>
|
||||
<html>
|
||||
<body className="autonomic min-h-screen flex flex-col mx-auto max-w-7xl px-6 text-primary bg-background">
|
||||
<Header />
|
||||
<main className="flex flex-col gap-4 flex-grow">{children}</main>
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
@ -1,50 +1,44 @@
|
||||
import { Badge } from '@/components/Badge'
|
||||
import { Background } from '@/components/Background'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import Header from '@/components/Header'
|
||||
import Footer from '@/components/Footer'
|
||||
import { getPayloadHMR } from '@payloadcms/next/utilities'
|
||||
import configPromise from '@payload-config'
|
||||
import PostList from '@/components/Blocks/PostList'
|
||||
import { PaginatedDocs } from 'payload/database'
|
||||
import { Post } from 'types/payload-types'
|
||||
import { COLLECTION_SLUG_POST } from '../(payload)/collections/config'
|
||||
|
||||
interface Props {}
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
async function getPosts() {
|
||||
const payload = await getPayloadHMR({
|
||||
config: configPromise,
|
||||
})
|
||||
|
||||
const posts: PaginatedDocs<Post> = await payload.find({
|
||||
collection: COLLECTION_SLUG_POST,
|
||||
})
|
||||
|
||||
return posts
|
||||
}
|
||||
|
||||
const Page = async (props: Props) => {
|
||||
const posts = await getPosts()
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<>
|
||||
<main>
|
||||
<article>
|
||||
<Badge />
|
||||
<h1>Payload 3.0</h1>
|
||||
<p>
|
||||
This BETA is rapidly evolving, you can report any bugs against{' '}
|
||||
<Link href="https://github.com/payloadcms/payload-3.0-demo/issues" target="_blank">
|
||||
the repo
|
||||
</Link>{' '}
|
||||
or in the{' '}
|
||||
<Link
|
||||
href="https://discord.com/channels/967097582721572934/1215659716538273832"
|
||||
target="_blank"
|
||||
>
|
||||
dedicated channel in Discord
|
||||
</Link>
|
||||
. Payload is running at <Link href="/admin">/admin</Link>. An example of a custom route
|
||||
running the Local API can be found at <Link href="/my-route">/my-route</Link>.
|
||||
</p>
|
||||
<p>You can use the Local API in your server components like this:</p>
|
||||
</article>
|
||||
<div className="codeBlock">
|
||||
<pre>
|
||||
<code>
|
||||
{`import { getPayloadHMR } from '@payloadcms/next/utilities'
|
||||
import configPromise from '@payload-config'
|
||||
const payload = await getPayloadHMR({ config: configPromise })
|
||||
|
||||
const data = await payload.find({
|
||||
collection: 'posts',
|
||||
})
|
||||
|
||||
return <Posts data={data} />
|
||||
`}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</main>
|
||||
<Background />
|
||||
<h1 className="">Nextload</h1>
|
||||
<p className="mt-3">
|
||||
{`Nextload is a pre-configured setup for Nextjs and PayloadCMS that makes it easy to get started with building your website. With Nextload, you'll have a complete development environment that you can run locally using Docker. This makes it easy to test and develop your website before deploying it to a production environment.`}
|
||||
<br />
|
||||
{`When you're ready to deploy the website on your own server, Nextload comes with a production environment that requires the use of Traefik as a reverse proxy. This setup provides a secure and scalable production environment for your website.`}
|
||||
</p>
|
||||
<section className="mt-4">
|
||||
<PostList posts={posts.docs} />
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
35
src/app/(app)/pages/[[...path]]/page.tsx
Normal file
35
src/app/(app)/pages/[[...path]]/page.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import Blocks from '@/components/Blocks'
|
||||
import { COLLECTION_SLUG_PAGE } from '@payload/collections/config'
|
||||
import { getDocument } from '@/utils/getDocument'
|
||||
import { generateMeta } from '@/utils/generateMeta'
|
||||
import { Metadata } from 'next'
|
||||
import { notFound } from 'next/navigation'
|
||||
|
||||
type PageArgs = {
|
||||
params: {
|
||||
path: string[]
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: PageArgs): Promise<Metadata> {
|
||||
const page = await getDocument({
|
||||
collection: COLLECTION_SLUG_PAGE,
|
||||
path: params.path,
|
||||
depth: 3,
|
||||
})
|
||||
if (!page) notFound()
|
||||
|
||||
return generateMeta(params?.path)
|
||||
}
|
||||
|
||||
const Page = async ({ params }: PageArgs) => {
|
||||
const page = await getDocument({
|
||||
collection: COLLECTION_SLUG_PAGE,
|
||||
path: params.path,
|
||||
depth: 3,
|
||||
})
|
||||
if (!page) notFound()
|
||||
return <Blocks blocks={page?.blocks} locale="" />
|
||||
}
|
||||
|
||||
export default Page
|
23
src/app/(app)/pages/preview/[[...path]]/page.tsx
Normal file
23
src/app/(app)/pages/preview/[[...path]]/page.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import PreviewBlocks from '@/components/PreviewBlocks'
|
||||
import { getCurrentUser } from '@/lib/payload'
|
||||
import { COLLECTION_SLUG_PAGE } from '@payload/collections/config'
|
||||
import { getDocument } from '@/utils/getDocument'
|
||||
import { unstable_noStore as noStore } from 'next/cache'
|
||||
import { notFound } from 'next/navigation'
|
||||
|
||||
const PreviewCatchAllPage = async ({ params }: { params: { path: string[] } }) => {
|
||||
noStore()
|
||||
const [page] = await Promise.all([
|
||||
getDocument({
|
||||
collection: COLLECTION_SLUG_PAGE,
|
||||
path: params.path,
|
||||
depth: 3,
|
||||
cache: false,
|
||||
}),
|
||||
])
|
||||
if (!page) notFound()
|
||||
|
||||
return <PreviewBlocks initialData={page} locale="" url={process.env.BASE_URL || ''} />
|
||||
}
|
||||
|
||||
export default PreviewCatchAllPage
|
36
src/app/(app)/posts/[[...path]]/page.tsx
Normal file
36
src/app/(app)/posts/[[...path]]/page.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import Blocks from '@/components/Blocks'
|
||||
import { COLLECTION_SLUG_POST } from '@payload/collections/config'
|
||||
import { getDocument } from '@/utils/getDocument'
|
||||
import { generateMeta } from '@/utils/generateMeta'
|
||||
import { Metadata } from 'next'
|
||||
import { notFound } from 'next/navigation'
|
||||
import PostPage from '@/components/PostPage'
|
||||
|
||||
type PageArgs = {
|
||||
params: {
|
||||
path: string[]
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: PageArgs): Promise<Metadata> {
|
||||
const page = await getDocument({
|
||||
collection: COLLECTION_SLUG_POST,
|
||||
path: params.path,
|
||||
depth: 3,
|
||||
})
|
||||
if (!page) notFound()
|
||||
|
||||
return generateMeta(params?.path)
|
||||
}
|
||||
|
||||
const Page = async ({ params }: PageArgs) => {
|
||||
const post = await getDocument({
|
||||
collection: COLLECTION_SLUG_POST,
|
||||
path: params.path,
|
||||
depth: 3,
|
||||
})
|
||||
if (!post) notFound()
|
||||
return <PostPage post={post} locale="" />
|
||||
}
|
||||
|
||||
export default Page
|
24
src/app/(app)/posts/preview/[[...path]]/page.tsx
Normal file
24
src/app/(app)/posts/preview/[[...path]]/page.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import PreviewBlocks from '@/components/PreviewBlocks'
|
||||
import { getCurrentUser } from '@/lib/payload'
|
||||
import { COLLECTION_SLUG_POST } from '@payload/collections/config'
|
||||
import { getDocument } from '@/utils/getDocument'
|
||||
import { unstable_noStore as noStore } from 'next/cache'
|
||||
import { notFound } from 'next/navigation'
|
||||
import PreviewPostPage from '@/components/PreviewPostPage'
|
||||
|
||||
const PreviewCatchAllPage = async ({ params }: { params: { path: string[] } }) => {
|
||||
noStore()
|
||||
const [page] = await Promise.all([
|
||||
getDocument({
|
||||
collection: COLLECTION_SLUG_POST,
|
||||
path: params.path,
|
||||
depth: 3,
|
||||
cache: false,
|
||||
}),
|
||||
])
|
||||
if (!page) notFound()
|
||||
|
||||
return <PreviewPostPage initialData={page} locale="" url={process.env.BASE_URL || ''} />
|
||||
}
|
||||
|
||||
export default PreviewCatchAllPage
|
65
src/app/(payload)/access/isAdmin.ts
Normal file
65
src/app/(payload)/access/isAdmin.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { Access } from 'payload/types'
|
||||
import type { User } from 'types/payload-types'
|
||||
|
||||
export const isAdmin = ({ req: { user } }: any) => {
|
||||
if (!user || !user.roles) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (user.roles?.includes('admin')) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export const isAdminOrCreatedBy = ({ req: { user } }: any) => {
|
||||
if (!user || !user.roles) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (user.roles?.includes('admin')) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (user) {
|
||||
return {
|
||||
createdBy: {
|
||||
equals: user.id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export const isAdminOrSelf = ({ req: { user } }: any) => {
|
||||
if (!user || !user.roles) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (user.roles?.includes('admin')) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Non-admin: can only access themselves
|
||||
return {
|
||||
id: {
|
||||
equals: user.id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const isAdminOrPublished = ({ req: { user } }: any) => {
|
||||
if (user && user.roles) {
|
||||
if (user.roles?.includes('admin')) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
_status: {
|
||||
equals: 'published',
|
||||
},
|
||||
}
|
||||
}
|
14
src/app/(payload)/access/isEditor.ts
Normal file
14
src/app/(payload)/access/isEditor.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { Access, FieldAccess } from 'payload/types'
|
||||
import type { User } from 'types/payload-types'
|
||||
|
||||
export const isEditor = ({ req: { user } }: any) => {
|
||||
if (!user || !user.roles) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (user?.roles?.some((role: string) => ['editor', 'admin'].includes(role))) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
14
src/app/(payload)/access/isUser.ts
Normal file
14
src/app/(payload)/access/isUser.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { Access, FieldAccess } from 'payload/types'
|
||||
import type { User } from 'types/payload-types'
|
||||
|
||||
export const isUser = ({ req: { user } }: any) => {
|
||||
if (!user || !user.roles) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (user?.roles?.some((role: string) => ['user', 'editor', 'admin'].includes(role))) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
14
src/app/(payload)/blocks/author.ts
Normal file
14
src/app/(payload)/blocks/author.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import type { Block } from 'payload/types'
|
||||
|
||||
const Author: Block = {
|
||||
slug: 'Author',
|
||||
fields: [
|
||||
{
|
||||
name: 'author',
|
||||
type: 'relationship',
|
||||
relationTo: 'authors',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default Author
|
5
src/app/(payload)/blocks/index.ts
Normal file
5
src/app/(payload)/blocks/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import RichText from '@payload/blocks/rich-text'
|
||||
import Author from '@payload/blocks/author'
|
||||
|
||||
// eslint-disable-next-line import/no-anonymous-default-export
|
||||
export default [RichText, Author]
|
14
src/app/(payload)/blocks/rich-text.ts
Normal file
14
src/app/(payload)/blocks/rich-text.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import type { Block } from 'payload/types'
|
||||
|
||||
const RichText: Block = {
|
||||
slug: 'RichText',
|
||||
interfaceName: 'RichTextBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export default RichText
|
48
src/app/(payload)/collections/Authors.ts
Normal file
48
src/app/(payload)/collections/Authors.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { isEditor } from '@payload/access/isEditor'
|
||||
import { isUser } from '@payload/access/isUser'
|
||||
import { COLLECTION_SLUG_AUTHOR } from './config'
|
||||
|
||||
const Authors: CollectionConfig = {
|
||||
slug: COLLECTION_SLUG_AUTHOR,
|
||||
admin: {
|
||||
defaultColumns: ['name'],
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
access: {
|
||||
//TODO: Author can CRUD own post
|
||||
create: isUser,
|
||||
read: () => true,
|
||||
update: isEditor,
|
||||
delete: isEditor,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'avatar',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'bio',
|
||||
type: 'text',
|
||||
required: false,
|
||||
},
|
||||
|
||||
{
|
||||
name: 'user',
|
||||
type: 'upload',
|
||||
relationTo: 'users',
|
||||
admin: {
|
||||
description: 'The selected user will be able to edit this author',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default Authors
|
24
src/app/(payload)/collections/Media.ts
Normal file
24
src/app/(payload)/collections/Media.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { isUser } from '@payload/access/isUser'
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { COLLECTION_SLUG_MEDIA } from './config'
|
||||
|
||||
export const Media: CollectionConfig = {
|
||||
slug: COLLECTION_SLUG_MEDIA,
|
||||
admin: {},
|
||||
access: {
|
||||
read: (): boolean => true,
|
||||
create: isUser,
|
||||
update: isUser,
|
||||
delete: isUser,
|
||||
},
|
||||
upload: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'alt',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default Media
|
62
src/app/(payload)/collections/Pages.ts
Normal file
62
src/app/(payload)/collections/Pages.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { slugField, pathField } from '@payload/fields/'
|
||||
import { blocksField } from '@payload/fields/blocks'
|
||||
import { COLLECTION_SLUG_PAGE } from './config'
|
||||
import { createBreadcrumbsField } from '@payloadcms/plugin-nested-docs'
|
||||
import { revalidateTag } from 'next/cache'
|
||||
import { generateDocumentCacheKey } from '@/utils/getDocument'
|
||||
import { isAdmin, isAdminOrPublished } from '@payload/access/isAdmin'
|
||||
|
||||
const Pages: CollectionConfig = {
|
||||
slug: COLLECTION_SLUG_PAGE,
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
defaultColumns: ['title', 'path', 'updatedAt', 'createdAt'],
|
||||
},
|
||||
versions: {
|
||||
drafts: {
|
||||
autosave: false,
|
||||
},
|
||||
maxPerDoc: 10,
|
||||
},
|
||||
access: {
|
||||
read: isAdminOrPublished,
|
||||
create: isAdmin,
|
||||
update: isAdmin,
|
||||
delete: isAdmin,
|
||||
},
|
||||
hooks: {
|
||||
afterChange: [
|
||||
async ({ doc, collection }) => {
|
||||
revalidateTag(generateDocumentCacheKey(collection.slug, doc.path))
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
label: 'Content',
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'title',
|
||||
},
|
||||
blocksField(),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
slugField(),
|
||||
pathField(),
|
||||
createBreadcrumbsField(COLLECTION_SLUG_PAGE, {
|
||||
name: 'breadcrumbs',
|
||||
admin: {
|
||||
disabled: true,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
export default Pages
|
84
src/app/(payload)/collections/Posts.ts
Normal file
84
src/app/(payload)/collections/Posts.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { isEditor } from '@payload/access/isEditor'
|
||||
import { isUser } from '@payload/access/isUser'
|
||||
import { revalidateTag } from 'next/cache'
|
||||
import { generateDocumentCacheKey } from '@/utils/getDocument'
|
||||
import { slugField, pathField } from '@payload/fields/'
|
||||
import { blocksField } from '@payload/fields/blocks'
|
||||
import { COLLECTION_SLUG_POST } from './config'
|
||||
|
||||
const Posts: CollectionConfig = {
|
||||
slug: COLLECTION_SLUG_POST,
|
||||
versions: {
|
||||
drafts: {
|
||||
autosave: false,
|
||||
},
|
||||
maxPerDoc: 10,
|
||||
},
|
||||
admin: {
|
||||
defaultColumns: ['title', 'author', 'status'],
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
access: {
|
||||
//TODO: Author can CRUD own post
|
||||
create: isUser,
|
||||
read: () => true,
|
||||
update: isEditor,
|
||||
delete: isEditor,
|
||||
},
|
||||
hooks: {
|
||||
afterChange: [
|
||||
async ({ doc, collection }) => {
|
||||
revalidateTag(generateDocumentCacheKey(collection.slug, doc.path))
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'summary',
|
||||
type: 'text',
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: 'publishedDate',
|
||||
type: 'date',
|
||||
required: false,
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'thumbnail',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
label: 'Content',
|
||||
fields: [blocksField()],
|
||||
},
|
||||
],
|
||||
},
|
||||
//TODO: Add author as block?
|
||||
{
|
||||
name: 'author',
|
||||
type: 'relationship',
|
||||
relationTo: 'authors',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
slugField(),
|
||||
pathField(),
|
||||
],
|
||||
}
|
||||
|
||||
export default Posts
|
41
src/app/(payload)/collections/Users.ts
Normal file
41
src/app/(payload)/collections/Users.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { isAdmin, isAdminOrSelf } from '@payload/access/isAdmin'
|
||||
import { COLLECTION_SLUG_USER } from './config'
|
||||
|
||||
const Users: CollectionConfig = {
|
||||
slug: COLLECTION_SLUG_USER,
|
||||
auth: true,
|
||||
admin: {
|
||||
defaultColumns: ['roles', 'email'],
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
access: {
|
||||
create: isAdmin,
|
||||
read: isAdminOrSelf,
|
||||
update: isAdminOrSelf,
|
||||
delete: isAdmin,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'roles',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: 'Admin', value: 'admin' }, //CRUD, role creation
|
||||
{ label: 'Editor', value: 'editor' }, //CRUD
|
||||
{ label: 'User', value: 'user' }, //cRud, CRUD own entries
|
||||
],
|
||||
required: true,
|
||||
defaultValue: 'user',
|
||||
// JWT so that role is accessible from 'req.user'
|
||||
saveToJWT: true,
|
||||
hasMany: true,
|
||||
access: {
|
||||
create: isAdmin,
|
||||
read: () => true,
|
||||
update: isAdmin,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default Users
|
5
src/app/(payload)/collections/config.ts
Normal file
5
src/app/(payload)/collections/config.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const COLLECTION_SLUG_USER = 'users' as const
|
||||
export const COLLECTION_SLUG_PAGE = 'pages' as const
|
||||
export const COLLECTION_SLUG_POST = 'posts' as const
|
||||
export const COLLECTION_SLUG_MEDIA = 'media' as const
|
||||
export const COLLECTION_SLUG_AUTHOR = 'authors' as const
|
16
src/app/(payload)/fields/blocks.ts
Executable file
16
src/app/(payload)/fields/blocks.ts
Executable file
@ -0,0 +1,16 @@
|
||||
import type { Field } from 'payload/types'
|
||||
import blocks from '@payload/blocks'
|
||||
import deepMerge from 'deepmerge'
|
||||
|
||||
type BlocksField = (overrides?: Partial<Field>) => Field
|
||||
|
||||
export const blocksField: BlocksField = (overrides) => {
|
||||
return deepMerge<Field, Partial<Field>>(
|
||||
{
|
||||
name: 'blocks',
|
||||
type: 'blocks',
|
||||
blocks,
|
||||
},
|
||||
overrides || {},
|
||||
)
|
||||
}
|
2
src/app/(payload)/fields/index.ts
Normal file
2
src/app/(payload)/fields/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { default as pathField } from "./path";
|
||||
export { default as slugField } from "./slug";
|
122
src/app/(payload)/fields/path.ts
Normal file
122
src/app/(payload)/fields/path.ts
Normal file
@ -0,0 +1,122 @@
|
||||
import { COLLECTION_SLUG_PAGE } from '@payload/collections/config'
|
||||
import generateBreadcrumbsUrl from '@/utils/generateBreadcrumbsUrl'
|
||||
import { getParents } from '@payloadcms/plugin-nested-docs'
|
||||
import deepmerge from 'deepmerge'
|
||||
import { APIError } from 'payload/errors'
|
||||
import type { Field, Payload, Where } from 'payload/types'
|
||||
import type { Config } from 'types/payload-types'
|
||||
import generateRandomString from '@/utils/generateRandomString'
|
||||
|
||||
type Collection = keyof Config['collections']
|
||||
type WillPathConflictParams = {
|
||||
payload: Payload
|
||||
path: string
|
||||
originalDoc?: { id?: string }
|
||||
collection: Collection
|
||||
uniquePathFieldCollections?: Collection[]
|
||||
}
|
||||
|
||||
export const willPathConflict = async ({
|
||||
payload,
|
||||
path,
|
||||
originalDoc,
|
||||
collection,
|
||||
uniquePathFieldCollections = [],
|
||||
}: WillPathConflictParams): Promise<boolean> => {
|
||||
if (!payload || !uniquePathFieldCollections.includes(collection)) return false
|
||||
|
||||
const queries = uniquePathFieldCollections.map((targetCollection) => {
|
||||
const whereCondition: Where = {
|
||||
path: { equals: path },
|
||||
}
|
||||
if (originalDoc?.id && collection === targetCollection) {
|
||||
whereCondition.id = { not_equals: originalDoc.id }
|
||||
}
|
||||
|
||||
return payload.find({
|
||||
collection: targetCollection,
|
||||
where: whereCondition,
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
})
|
||||
})
|
||||
|
||||
const results = await Promise.allSettled(queries)
|
||||
return results.some((result) => result.status === 'fulfilled' && result.value.docs.length > 0)
|
||||
}
|
||||
type GetNewPathParams = {
|
||||
req: any
|
||||
collection: Collection
|
||||
currentDoc: any
|
||||
operation?: string
|
||||
}
|
||||
|
||||
export async function getNewPath({
|
||||
req,
|
||||
collection,
|
||||
currentDoc,
|
||||
operation,
|
||||
}: GetNewPathParams): Promise<string> {
|
||||
const isAutoSave = operation === 'create' && currentDoc?._status === 'draft'
|
||||
if (isAutoSave || currentDoc?.slug == null || !collection)
|
||||
return `/${currentDoc?.id || generateRandomString(20)}`
|
||||
const newPath = currentDoc?.breadcrumbs?.at(-1)?.url
|
||||
if (newPath) return newPath
|
||||
const docs = await getParents(
|
||||
req,
|
||||
{ parentFieldSlug: 'parent' } as any,
|
||||
collection as any,
|
||||
currentDoc,
|
||||
[currentDoc],
|
||||
)
|
||||
|
||||
return generateBreadcrumbsUrl(docs, currentDoc)
|
||||
}
|
||||
|
||||
const pathField = (overrides?: Partial<Field>): Field =>
|
||||
deepmerge<Field, Partial<Field>>(
|
||||
{
|
||||
type: 'text',
|
||||
name: 'path',
|
||||
unique: true,
|
||||
index: true,
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
async ({ collection, req, siblingData, originalDoc, operation }) => {
|
||||
const currentDoc = { ...originalDoc, ...siblingData }
|
||||
const newPath = await getNewPath({
|
||||
req,
|
||||
collection: collection?.slug as Collection,
|
||||
currentDoc,
|
||||
operation,
|
||||
})
|
||||
const isNewPathConflicting = await willPathConflict({
|
||||
payload: req.payload,
|
||||
path: newPath,
|
||||
originalDoc,
|
||||
collection: collection ? (collection.slug as Collection) : COLLECTION_SLUG_PAGE,
|
||||
uniquePathFieldCollections: [COLLECTION_SLUG_PAGE], // Add more collections as needed
|
||||
})
|
||||
|
||||
if (isNewPathConflicting) {
|
||||
const error = new APIError(
|
||||
'This will create a conflict with an existing path.',
|
||||
400,
|
||||
[{ field: 'slug', message: 'This will create a conflict with an existing path.' }],
|
||||
false,
|
||||
)
|
||||
throw error
|
||||
}
|
||||
return newPath
|
||||
},
|
||||
],
|
||||
},
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
readOnly: true,
|
||||
},
|
||||
},
|
||||
overrides || {},
|
||||
)
|
||||
|
||||
export default pathField
|
49
src/app/(payload)/fields/slug.ts
Normal file
49
src/app/(payload)/fields/slug.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import type { Field, FieldHook } from 'payload/types'
|
||||
import deepMerge from 'deepmerge'
|
||||
|
||||
const format = (val: string): string =>
|
||||
val
|
||||
.replace(/ /g, '-')
|
||||
.replace(/[^\w-]+/g, '')
|
||||
.toLowerCase()
|
||||
|
||||
const formatSlug =
|
||||
(fallback: string): FieldHook =>
|
||||
({ operation, value, originalDoc, data }) => {
|
||||
if (typeof value === 'string' && value.length > 0) {
|
||||
return format(value)
|
||||
}
|
||||
|
||||
if (operation === 'create') {
|
||||
const fallbackData = (data && data[fallback]) || (originalDoc && originalDoc[fallback])
|
||||
|
||||
if (fallbackData && typeof fallbackData === 'string') {
|
||||
return format(fallbackData)
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
type Slug = (fieldToUse?: string, overrides?: Partial<Field>) => Field
|
||||
|
||||
const slugField: Slug = (fieldToUse = 'title', overrides = {}) => {
|
||||
return deepMerge<Field, Partial<Field>>(
|
||||
{
|
||||
name: 'slug',
|
||||
label: 'Slug',
|
||||
type: 'text',
|
||||
index: true,
|
||||
required: false, // Need to be false so that we can use beforeValidate hook to set slug.
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
hooks: {
|
||||
beforeValidate: [formatSlug(fieldToUse)],
|
||||
},
|
||||
},
|
||||
overrides,
|
||||
)
|
||||
}
|
||||
|
||||
export default slugField
|
@ -1,14 +0,0 @@
|
||||
import { getPayloadHMR } from '@payloadcms/next/utilities'
|
||||
import configPromise from '@payload-config'
|
||||
|
||||
export const GET = async () => {
|
||||
const payload = await getPayloadHMR({
|
||||
config: configPromise,
|
||||
})
|
||||
|
||||
const data = await payload.find({
|
||||
collection: 'users',
|
||||
})
|
||||
|
||||
return Response.json(data)
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
export const Background = () => {
|
||||
return (
|
||||
<div className="background">
|
||||
<div className="blur" />
|
||||
<div className="gradient" />
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
export const Badge = () => {
|
||||
return (
|
||||
<span className="badge">
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.35899 1.59033L16.956 6.233V15.0452L11.2355 18.4097V9.59751L3.62941 4.96095L9.35899 1.59033Z"
|
||||
fill="#ffffff"
|
||||
/>
|
||||
<path d="M8.77667 17.9211V11.0447L3.04407 14.4153L8.77667 17.9211Z" fill="#ffffff" />
|
||||
</svg>
|
||||
Beta
|
||||
</span>
|
||||
)
|
||||
}
|
33
src/components/Blocks/Author.tsx
Normal file
33
src/components/Blocks/Author.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React from 'react'
|
||||
import Image from 'next/image'
|
||||
import type { Author } from 'types/payload-types'
|
||||
|
||||
interface Props {
|
||||
author: Author
|
||||
}
|
||||
|
||||
const AuthorComponent: React.FC<Props> = ({ author }) => {
|
||||
return (
|
||||
<>
|
||||
{author && (
|
||||
<div className="flex gap-6 border-t-2 border-secondary py-4 text-secondary">
|
||||
{typeof author.avatar === 'object' && (
|
||||
<Image
|
||||
src={author.avatar.url || ''}
|
||||
width={100}
|
||||
height={10}
|
||||
alt={author.avatar.alt || ''}
|
||||
layout="fixed"
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-col">
|
||||
<h3 className="">{author.name}</h3>
|
||||
<p className="text-sm font-light">{author.bio}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default AuthorComponent
|
30
src/components/Blocks/PostList.tsx
Normal file
30
src/components/Blocks/PostList.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { Post } from 'types/payload-types'
|
||||
import PostEntry from '@/components/PostEntry'
|
||||
import { getPayloadHMR } from '@payloadcms/next/utilities'
|
||||
import configPromise from '@payload-config'
|
||||
import { PaginatedDocs } from 'payload/database'
|
||||
import { COLLECTION_SLUG_POST } from '@payload/collections/config'
|
||||
import { GetServerSideProps } from 'next'
|
||||
|
||||
type Props = {
|
||||
posts: Post[]
|
||||
}
|
||||
|
||||
const PostList = ({ posts }: Props) => {
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<h2 className="text-secondary mb-4">Posts</h2>
|
||||
<div className="border-y-2 flex flex-col divide-y-2 border-secondary divide-secondary">
|
||||
{posts.length > 0 ? (
|
||||
posts.map(
|
||||
(post, index) => typeof post === 'object' && <PostEntry key={index} post={post} />,
|
||||
)
|
||||
) : (
|
||||
<p>No posts available</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PostList
|
22
src/components/Blocks/RichText.tsx
Normal file
22
src/components/Blocks/RichText.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import type { AdditionalBlockProps } from '@/components/Blocks'
|
||||
import Container from '@/components/Container'
|
||||
import LexicalContent from '@/components/LexicalContent'
|
||||
import type { RichTextBlock } from 'types/payload-types'
|
||||
|
||||
export default function RichText({ content, locale }: RichTextBlock & AdditionalBlockProps) {
|
||||
if (content?.root?.children?.length === 0) return null
|
||||
return (
|
||||
<section className="py-10 first:mt-16">
|
||||
<Container>
|
||||
<div className="prose dark:prose-invert md:prose-lg">
|
||||
<LexicalContent
|
||||
// @ts-ignore
|
||||
childrenNodes={content?.root?.children}
|
||||
locale={locale}
|
||||
lazyLoadImages={false}
|
||||
/>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
33
src/components/Blocks/index.tsx
Normal file
33
src/components/Blocks/index.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import Author from './Author'
|
||||
import RichText from './RichText'
|
||||
|
||||
export type AdditionalBlockProps = {
|
||||
blockIndex: number
|
||||
locale: string
|
||||
}
|
||||
|
||||
const blockComponents = {
|
||||
Author: Author,
|
||||
RichText: RichText,
|
||||
}
|
||||
|
||||
const Blocks = ({ blocks, locale }: any) => {
|
||||
return (
|
||||
<>
|
||||
{blocks
|
||||
?.filter(
|
||||
(block: any) =>
|
||||
block && block.blockType && blockComponents.hasOwnProperty(block.blockType),
|
||||
)
|
||||
.map((block: any, ix: number) => {
|
||||
// @ts-ignore
|
||||
const BlockComponent = blockComponents[block.blockType] ?? null
|
||||
return BlockComponent ? (
|
||||
<BlockComponent key={ix} {...block} blockIndex={ix} locale={locale} />
|
||||
) : null
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Blocks
|
10
src/components/Container.tsx
Executable file
10
src/components/Container.tsx
Executable file
@ -0,0 +1,10 @@
|
||||
import cn from '@/utils/cn'
|
||||
import type { ComponentPropsWithoutRef } from 'react'
|
||||
|
||||
const Container = ({ children, className }: ComponentPropsWithoutRef<'div'>) => {
|
||||
return (
|
||||
<div className={cn('container mx-auto w-full max-w-screen-lg px-3', className)}>{children}</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Container
|
15
src/components/Footer.tsx
Normal file
15
src/components/Footer.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
/* import ThemeSwitcher from '@/components/ThemeSwitcher' */
|
||||
import { getCurrentYear } from '@/utils/date'
|
||||
|
||||
type Props = {}
|
||||
|
||||
export default function Footer({}: Props) {
|
||||
return (
|
||||
<footer className="flex justify-between items-center py-4">
|
||||
<p className="text-lg font-semibold">
|
||||
© {getCurrentYear()} Autonomic. Template distributed under AGPL 3.0.
|
||||
</p>
|
||||
{/* <ThemeSwitcher /> */}
|
||||
</footer>
|
||||
)
|
||||
}
|
39
src/components/Header.tsx
Normal file
39
src/components/Header.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import React from 'react'
|
||||
|
||||
type Props = {}
|
||||
|
||||
export default function Header({}: Props) {
|
||||
const links = [
|
||||
{
|
||||
label: 'About',
|
||||
link: '/about',
|
||||
},
|
||||
{
|
||||
label: 'Services',
|
||||
link: '/services',
|
||||
},
|
||||
{
|
||||
label: 'Contact',
|
||||
link: '/contact',
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<header className="flex justify-between py-6">
|
||||
<div>
|
||||
<a href="/" className="decoration-transparent">
|
||||
<span className="text-2xl font-extrabold ">Logo</span>
|
||||
</a>
|
||||
</div>
|
||||
<nav>
|
||||
<ul className="flex gap-4 font-bold list-none">
|
||||
{links.map((item, index) => (
|
||||
<li className="decoration-transparent" key={`link-${index}`}>
|
||||
<a href={item.link}>{item.label}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
}
|
51
src/components/LexicalContent/RichTextNodeFormat.ts
Normal file
51
src/components/LexicalContent/RichTextNodeFormat.ts
Normal file
@ -0,0 +1,51 @@
|
||||
//This copy-and-pasted from somewhere in lexical here: https://github.com/facebook/lexical/blob/c2ceee223f46543d12c574e62155e619f9a18a5d/packages/lexical/src/LexicalConstants.ts
|
||||
|
||||
// DOM
|
||||
export const DOM_ELEMENT_TYPE = 1
|
||||
export const DOM_TEXT_TYPE = 3
|
||||
|
||||
// Reconciling
|
||||
export const NO_DIRTY_NODES = 0
|
||||
export const HAS_DIRTY_NODES = 1
|
||||
export const FULL_RECONCILE = 2
|
||||
|
||||
// Text node modes
|
||||
export const IS_NORMAL = 0
|
||||
export const IS_TOKEN = 1
|
||||
export const IS_SEGMENTED = 2
|
||||
// IS_INERT = 3
|
||||
|
||||
// Text node formatting
|
||||
export const IS_BOLD = 1
|
||||
export const IS_ITALIC = 1 << 1
|
||||
export const IS_STRIKETHROUGH = 1 << 2
|
||||
export const IS_UNDERLINE = 1 << 3
|
||||
export const IS_CODE = 1 << 4
|
||||
export const IS_SUBSCRIPT = 1 << 5
|
||||
export const IS_SUPERSCRIPT = 1 << 6
|
||||
export const IS_HIGHLIGHT = 1 << 7
|
||||
|
||||
export const IS_ALL_FORMATTING = IS_BOLD | IS_ITALIC | IS_STRIKETHROUGH | IS_UNDERLINE | IS_CODE | IS_SUBSCRIPT | IS_SUPERSCRIPT | IS_HIGHLIGHT
|
||||
|
||||
export const IS_DIRECTIONLESS = 1
|
||||
export const IS_UNMERGEABLE = 1 << 1
|
||||
|
||||
// Element node formatting
|
||||
export const IS_ALIGN_LEFT = 1
|
||||
export const IS_ALIGN_CENTER = 2
|
||||
export const IS_ALIGN_RIGHT = 3
|
||||
export const IS_ALIGN_JUSTIFY = 4
|
||||
export const IS_ALIGN_START = 5
|
||||
export const IS_ALIGN_END = 6
|
||||
|
||||
export const TEXT_TYPE_TO_FORMAT: Record<TextFormatType | string, number> = {
|
||||
bold: IS_BOLD,
|
||||
code: IS_CODE,
|
||||
italic: IS_ITALIC,
|
||||
strikethrough: IS_STRIKETHROUGH,
|
||||
subscript: IS_SUBSCRIPT,
|
||||
superscript: IS_SUPERSCRIPT,
|
||||
underline: IS_UNDERLINE
|
||||
}
|
||||
|
||||
export type TextFormatType = 'bold' | 'underline' | 'strikethrough' | 'italic' | 'code' | 'subscript' | 'superscript'
|
213
src/components/LexicalContent/index.tsx
Normal file
213
src/components/LexicalContent/index.tsx
Normal file
@ -0,0 +1,213 @@
|
||||
/* eslint-disable react/no-children-prop */
|
||||
import normalizePath from '@/utils/normalizePath'
|
||||
import clsx from 'clsx'
|
||||
import Link from 'next/link'
|
||||
import React, { CSSProperties, type FC, type ReactElement } from 'react'
|
||||
import Image from 'next/image'
|
||||
import {
|
||||
IS_BOLD,
|
||||
IS_CODE,
|
||||
IS_ITALIC,
|
||||
IS_STRIKETHROUGH,
|
||||
IS_SUBSCRIPT,
|
||||
IS_SUPERSCRIPT,
|
||||
IS_UNDERLINE,
|
||||
} from './RichTextNodeFormat'
|
||||
|
||||
type SerializedLexicalNode = {
|
||||
children?: SerializedLexicalNode[]
|
||||
direction: string
|
||||
format: number
|
||||
indent?: string | number
|
||||
type: string
|
||||
version: number
|
||||
style?: string
|
||||
mode?: string
|
||||
text?: string
|
||||
[other: string]: any
|
||||
}
|
||||
|
||||
type TextComponentProps = {
|
||||
children: ReactElement | string
|
||||
format: number
|
||||
}
|
||||
|
||||
const getLinkForDocument = (doc: any, locale?: string): string => {
|
||||
let path = doc?.path
|
||||
if (!path || path.startsWith('/home') || path === '/' || path === '') path = '/'
|
||||
return normalizePath(`/${locale}${path}`)
|
||||
}
|
||||
|
||||
function gcd(a: number, b: number): number {
|
||||
return b === 0 ? a : gcd(b, a % b)
|
||||
}
|
||||
|
||||
function calculateAspectRatio(width: number, height: number): string {
|
||||
const divisor = gcd(width, height)
|
||||
const simplifiedWidth = width / divisor
|
||||
const simplifiedHeight = height / divisor
|
||||
|
||||
return `${simplifiedWidth}x${simplifiedHeight}`
|
||||
}
|
||||
|
||||
const TextComponent: FC<TextComponentProps> = ({ children, format }) => {
|
||||
const formatFunctions: { [key: number]: (child: ReactElement | string) => ReactElement } = {
|
||||
[IS_BOLD]: (child) => <strong>{child}</strong>,
|
||||
[IS_ITALIC]: (child) => <em>{child}</em>,
|
||||
[IS_STRIKETHROUGH]: (child) => <del>{child}</del>,
|
||||
[IS_UNDERLINE]: (child) => <u>{child}</u>,
|
||||
[IS_CODE]: (child) => <code>{child}</code>,
|
||||
[IS_SUBSCRIPT]: (child) => <sub>{child}</sub>,
|
||||
[IS_SUPERSCRIPT]: (child) => <sup>{child}</sup>,
|
||||
}
|
||||
|
||||
const formattedText = Object.entries(formatFunctions).reduce(
|
||||
(formattedText, [key, formatter]) => {
|
||||
return format & Number(key) ? formatter(formattedText) : formattedText
|
||||
},
|
||||
children,
|
||||
)
|
||||
|
||||
return <>{formattedText}</>
|
||||
}
|
||||
|
||||
const SerializedLink: React.FC<{
|
||||
node: SerializedLexicalNode
|
||||
locale: string
|
||||
children: React.JSX.Element | null
|
||||
}> = ({ node, locale, children }) => {
|
||||
const { doc, url, newTab, linkType } = node.fields as any
|
||||
const document = doc?.value
|
||||
const href = linkType === 'custom' ? url : getLinkForDocument(document, locale)
|
||||
const target = newTab ? '_blank' : undefined
|
||||
|
||||
return (
|
||||
<Link href={href} target={target}>
|
||||
{children}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
const getNodeClassNames = (node: SerializedLexicalNode) => {
|
||||
const attributes: Record<string, any> = {}
|
||||
if (!node) return attributes
|
||||
|
||||
let classNames = ''
|
||||
if (String(node?.format).toString()?.includes('left') && node.direction !== 'ltr')
|
||||
classNames += 'text-left '
|
||||
if (String(node?.format).toString()?.includes('center')) classNames += 'text-center '
|
||||
if (String(node?.format).toString()?.includes('right') && node.direction !== 'rtl')
|
||||
classNames += 'text-right '
|
||||
|
||||
if (classNames.length > 0) attributes.className = classNames.trim()
|
||||
|
||||
const indent = parseInt(`${node?.indent || 0}`)
|
||||
if (!isNaN(indent) && indent !== 0) {
|
||||
attributes.style = { '--indent': `${indent * 10}px` } as CSSProperties
|
||||
attributes.className = `${attributes.className ?? ''} ml-[--indent]`.trim()
|
||||
}
|
||||
|
||||
return attributes
|
||||
}
|
||||
|
||||
const LexicalContent: React.FC<{
|
||||
childrenNodes: SerializedLexicalNode[]
|
||||
locale: string
|
||||
className?: string
|
||||
lazyLoadImages: boolean
|
||||
}> = ({ childrenNodes, locale, lazyLoadImages = false }) => {
|
||||
if (!Array.isArray(childrenNodes)) return null
|
||||
|
||||
const renderedChildren = childrenNodes.map((node, ix) => {
|
||||
if (!node) return null
|
||||
const attributes = getNodeClassNames(node || '')
|
||||
if (node.type === 'text') {
|
||||
return (
|
||||
<TextComponent key={ix} format={node.format}>
|
||||
<>
|
||||
{Object.keys(attributes).length > 0 && <span {...attributes}>{node?.text || ''}</span>}
|
||||
{(Object.keys(attributes).length === 0 && node?.text) || ''}
|
||||
</>
|
||||
</TextComponent>
|
||||
)
|
||||
}
|
||||
|
||||
const serializedChildren = node.children ? (
|
||||
<LexicalContent
|
||||
key={ix}
|
||||
childrenNodes={node.children}
|
||||
locale={locale}
|
||||
lazyLoadImages={lazyLoadImages}
|
||||
/>
|
||||
) : null
|
||||
switch (node.type) {
|
||||
case 'linebreak':
|
||||
return <br key={ix} />
|
||||
case 'link':
|
||||
return <SerializedLink key={ix} node={node} locale={locale} children={serializedChildren} />
|
||||
case 'list':
|
||||
const ListTag = node.listType === 'bullet' ? 'ul' : 'ol'
|
||||
attributes.className = clsx(
|
||||
attributes.className,
|
||||
'mb-4 pl-8',
|
||||
ListTag === 'ol' ? 'list-decimal' : 'list-disc',
|
||||
)
|
||||
return (
|
||||
<ListTag key={ix} {...attributes}>
|
||||
{serializedChildren}
|
||||
</ListTag>
|
||||
)
|
||||
case 'listitem':
|
||||
return (
|
||||
<li key={ix} {...attributes}>
|
||||
{serializedChildren}
|
||||
</li>
|
||||
)
|
||||
case 'heading':
|
||||
const HeadingTag = node.tag as keyof React.JSX.IntrinsicElements
|
||||
return (
|
||||
<HeadingTag key={ix} {...attributes}>
|
||||
{serializedChildren}
|
||||
</HeadingTag>
|
||||
)
|
||||
case 'quote':
|
||||
return (
|
||||
<blockquote key={ix} {...attributes}>
|
||||
{serializedChildren}
|
||||
</blockquote>
|
||||
)
|
||||
case 'upload':
|
||||
const upload = node?.value
|
||||
if (!upload) return null
|
||||
const imageAspectRatio = calculateAspectRatio(upload.width, upload.height)
|
||||
return (
|
||||
<Image
|
||||
key={ix}
|
||||
width={upload.width}
|
||||
height={upload.height}
|
||||
src={upload?.url}
|
||||
loading={lazyLoadImages ? 'lazy' : 'eager'}
|
||||
fetchPriority={lazyLoadImages ? 'low' : 'high'}
|
||||
sizes="(max-width: 768px) 65ch, 100vw"
|
||||
className="max-w-[calc(100%+40px)] translate-x-[-20px]"
|
||||
alt={upload?.alt || upload.filename}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
if (
|
||||
Array.isArray(serializedChildren?.props?.childrenNodes) &&
|
||||
serializedChildren?.props?.childrenNodes.length === 0
|
||||
)
|
||||
return <br key={ix} />
|
||||
return (
|
||||
<p key={ix} {...attributes}>
|
||||
{serializedChildren}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
return <>{renderedChildren.filter((node) => node !== null)}</>
|
||||
}
|
||||
|
||||
export default LexicalContent
|
45
src/components/PostEntry.tsx
Normal file
45
src/components/PostEntry.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import { Post } from 'types/payload-types'
|
||||
import Image from 'next/image'
|
||||
import { COLLECTION_SLUG_POST } from '@/app/(payload)/collections/config'
|
||||
|
||||
interface Props {
|
||||
post: Post
|
||||
}
|
||||
|
||||
export default function PostEntry(props: Props) {
|
||||
if (typeof props.post.thumbnail === 'string') return
|
||||
|
||||
return (
|
||||
<a
|
||||
className="py-4 border-secondary decoration-transparent"
|
||||
href={`/${COLLECTION_SLUG_POST}${props.post.path}`}
|
||||
>
|
||||
<article className="flex px-5 py-3 gap-8">
|
||||
<Image
|
||||
src={props.post.thumbnail.url || ''}
|
||||
width={150}
|
||||
height={150}
|
||||
alt={props.post.thumbnail.alt || ''}
|
||||
layout="fixed"
|
||||
/>
|
||||
|
||||
<div className="flex flex-col gap-4 w-full">
|
||||
<div className="flex justify-between w-full">
|
||||
<h3 className="">{props.post.title}</h3>
|
||||
{props.post.publishedDate && (
|
||||
<p className="font-light">
|
||||
{new Date(props.post.publishedDate).toLocaleDateString('de-DE')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{props.post.summary && <p className="max-w-prose">{props.post.summary}</p>}
|
||||
</div>
|
||||
{/* {props.post.author.name && (
|
||||
<p>
|
||||
{props.post.author.name}
|
||||
</p>
|
||||
)} */}
|
||||
</article>
|
||||
</a>
|
||||
)
|
||||
}
|
20
src/components/PostPage.tsx
Normal file
20
src/components/PostPage.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import React from 'react'
|
||||
import { Post } from 'types/payload-types'
|
||||
import Blocks from './Blocks'
|
||||
import Author from './Blocks/Author'
|
||||
|
||||
interface Props {
|
||||
post: Post
|
||||
locale: string
|
||||
}
|
||||
|
||||
export default function PostPage(props: Props) {
|
||||
return (
|
||||
<article className="leading-relaxed">
|
||||
<Blocks blocks={props?.post.blocks} locale="" />
|
||||
{props?.post.author && typeof props?.post.author !== 'string' && (
|
||||
<Author author={props?.post.author} />
|
||||
)}
|
||||
</article>
|
||||
)
|
||||
}
|
23
src/components/PreviewBlocks.tsx
Normal file
23
src/components/PreviewBlocks.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
'use client'
|
||||
|
||||
import Blocks from '@/components/Blocks'
|
||||
import type { Page } from 'types/payload-types'
|
||||
import { useLivePreview } from '@payloadcms/live-preview-react'
|
||||
|
||||
export default function PreviewBlocks({
|
||||
initialData,
|
||||
locale,
|
||||
url,
|
||||
}: {
|
||||
initialData?: Page | null
|
||||
locale: string
|
||||
url: string
|
||||
}) {
|
||||
const { data } = useLivePreview({
|
||||
serverURL: url,
|
||||
depth: 3,
|
||||
initialData: initialData,
|
||||
})
|
||||
|
||||
return <Blocks blocks={data?.blocks || []} locale={locale} />
|
||||
}
|
36
src/components/PreviewPostPage.tsx
Normal file
36
src/components/PreviewPostPage.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
'use client'
|
||||
|
||||
import type { Post } from 'types/payload-types'
|
||||
import { useLivePreview } from '@payloadcms/live-preview-react'
|
||||
import PostPage from './PostPage'
|
||||
|
||||
const defaultPost: Post = {
|
||||
id: 'default-id',
|
||||
title: 'Title',
|
||||
thumbnail: '',
|
||||
updatedAt: '',
|
||||
createdAt: '',
|
||||
}
|
||||
|
||||
export default function PreviewBlocks({
|
||||
initialData,
|
||||
locale,
|
||||
url,
|
||||
}: {
|
||||
initialData?: Post | null
|
||||
locale: string
|
||||
url: string
|
||||
}) {
|
||||
const { data } = useLivePreview({
|
||||
serverURL: url,
|
||||
depth: 3,
|
||||
initialData: initialData,
|
||||
})
|
||||
|
||||
const post = {
|
||||
...defaultPost,
|
||||
...data,
|
||||
}
|
||||
|
||||
return <PostPage post={post} locale={locale} />
|
||||
}
|
17
src/components/ThemeSwitcher.tsx
Normal file
17
src/components/ThemeSwitcher.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
import { handleThemeChange, switchTheme, initializeThemeSelector } from '@/utils/theme'
|
||||
|
||||
interface Props {}
|
||||
|
||||
export default function ThemeSwitcher({}: Props) {
|
||||
initializeThemeSelector()
|
||||
|
||||
return (
|
||||
<select id="theme-selector">
|
||||
<option value="autonomic">Autonomic</option>
|
||||
<option value="light">Light</option>
|
||||
<option value="dark">Dark</option>
|
||||
</select>
|
||||
)
|
||||
}
|
19
src/lib/payload/actions.ts
Normal file
19
src/lib/payload/actions.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/* 'use server'
|
||||
|
||||
import { SESSION_STRATEGY } from '@/lib/auth/config'
|
||||
import { COLLECTION_SLUG_SESSIONS } from '@/payload/collections/config'
|
||||
import { revalidateTag } from 'next/cache'
|
||||
import type { Payload } from 'payload'
|
||||
import type { User } from '~/payload-types'
|
||||
|
||||
export const revalidateUser = async (user: User, payload: Payload) => {
|
||||
revalidateTag(`payload-user-${user.id}`)
|
||||
revalidateTag(`payload-user-email-${user.email}`)
|
||||
if (SESSION_STRATEGY === 'database') {
|
||||
const { docs: sessions } = await (await payload).find({ where: { user: { equals: user.id } }, collection: COLLECTION_SLUG_SESSIONS })
|
||||
sessions.forEach((session) => {
|
||||
revalidateTag(`payload-user-session-${session.sessionToken}`)
|
||||
})
|
||||
}
|
||||
}
|
||||
*/
|
21
src/lib/payload/index.ts
Normal file
21
src/lib/payload/index.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import configPromise from '@payload-config'
|
||||
import { getPayloadHMR as getPayloadInstance } from '@payloadcms/next/utilities'
|
||||
import { headers as getHeaders } from 'next/headers'
|
||||
import type { User } from 'types/payload-types'
|
||||
|
||||
export async function getPayload(): ReturnType<typeof getPayloadInstance> {
|
||||
return getPayloadInstance({ config: await configPromise })
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current user with out needing to import the payload instance & headers.
|
||||
*
|
||||
* @description The difference between this function and the one in the auth/edge.ts file is that here we get
|
||||
* payload instance, just to make other parts of you code cleaner. We can't get the payload instance in the
|
||||
* auth/edge.ts file because that could cause a import loop.
|
||||
*/
|
||||
export async function getCurrentUser(): Promise<User | null> {
|
||||
const headers = getHeaders()
|
||||
const payload = await getPayload()
|
||||
return (await payload.auth({ headers })).user
|
||||
}
|
6
src/utils/cn.ts
Executable file
6
src/utils/cn.ts
Executable file
@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export default function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
4
src/utils/date.ts
Normal file
4
src/utils/date.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const getCurrentYear = (): number => {
|
||||
const currentYear = new Date().getFullYear()
|
||||
return currentYear
|
||||
}
|
7
src/utils/generateBreadcrumbsUrl.ts
Normal file
7
src/utils/generateBreadcrumbsUrl.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export default function generateBreadcrumbsUrl(docs: any, lastDoc: any) {
|
||||
let prefix = ''
|
||||
// You might want different prefixes for different collections.
|
||||
switch (lastDoc._collection) {
|
||||
}
|
||||
return docs.reduce((url: any, doc: any) => `${url}/${doc.slug ?? ''}`, prefix)
|
||||
}
|
37
src/utils/generateMeta.ts
Normal file
37
src/utils/generateMeta.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import type { Metadata } from 'next'
|
||||
import _get from 'lodash/get'
|
||||
import deepmerge from 'deepmerge'
|
||||
import { getDocument } from '@/utils/getDocument'
|
||||
import normalizePath from './normalizePath'
|
||||
|
||||
const defaultTitle = 'Nextload'
|
||||
const defaultDescription = 'An open-source website built with Payload and Next.js.'
|
||||
const siteName = 'Nextload'
|
||||
|
||||
const defaultOpenGraph: Metadata['openGraph'] = {
|
||||
type: 'website',
|
||||
description: defaultDescription,
|
||||
siteName,
|
||||
title: defaultTitle,
|
||||
}
|
||||
|
||||
export const generateMeta = async (path: string | string[]): Promise<Metadata> => {
|
||||
const doc = await getDocument({
|
||||
collection: 'pages',
|
||||
path,
|
||||
depth: 1,
|
||||
})
|
||||
const metaTitle = _get(doc, 'meta.title', null)
|
||||
const title = metaTitle ?? (_get(doc, 'title', defaultTitle) as string)
|
||||
const description = _get(doc, 'meta.description', defaultDescription)
|
||||
const ogImage = _get(doc, 'meta.image.url', `/api/og${normalizePath(path, true)}image.jpg`)
|
||||
|
||||
return {
|
||||
description,
|
||||
openGraph: deepmerge(defaultOpenGraph, {
|
||||
description,
|
||||
images: ogImage ? [{ url: ogImage }] : undefined,
|
||||
}),
|
||||
title: { absolute: title },
|
||||
}
|
||||
}
|
13
src/utils/generateRandomString.ts
Normal file
13
src/utils/generateRandomString.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export default function generateRandomString(
|
||||
length: number,
|
||||
characters: string = 'abcdefghijklmnopqrstuvwxyz0123456789',
|
||||
): string {
|
||||
let result = ''
|
||||
const charactersLength = characters.length
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
80
src/utils/getDocument.ts
Normal file
80
src/utils/getDocument.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import type { Config } from 'types/payload-types'
|
||||
import { unstable_cache } from 'next/cache'
|
||||
import normalizePath from '@/utils/normalizePath'
|
||||
import { getCurrentUser, getPayload } from '@/lib/payload'
|
||||
import { draftMode } from 'next/headers'
|
||||
|
||||
type Collection = keyof Config['collections'] | string
|
||||
type Path = string | string[]
|
||||
type CacheOption = 'noDraft' | true | false
|
||||
|
||||
export const generateDocumentCacheKey = (collection: Collection, path?: Path): string => {
|
||||
return `${collection}_path_${normalizePath(path, false)}`
|
||||
}
|
||||
|
||||
export const generateDocumentCacheParams = (collection: Collection, path?: Path): string[] => {
|
||||
return [collection, normalizePath(path)]
|
||||
}
|
||||
|
||||
export const conditionalCache = async <T>(
|
||||
fetchFunction: () => Promise<T>,
|
||||
cacheKey: string,
|
||||
cache: boolean | undefined,
|
||||
revalidate: false | number | undefined,
|
||||
): Promise<T> => {
|
||||
if (!cache) {
|
||||
return fetchFunction()
|
||||
}
|
||||
return unstable_cache(fetchFunction, [cacheKey], { revalidate, tags: [cacheKey] })()
|
||||
}
|
||||
|
||||
interface GetDocumentParams<K extends keyof Config['collections']> {
|
||||
collection: K
|
||||
path?: Path
|
||||
depth?: number
|
||||
cache?: CacheOption
|
||||
revalidate?: false | number | undefined
|
||||
}
|
||||
|
||||
export const getDocument = async <K extends keyof Config['collections']>({
|
||||
collection,
|
||||
path,
|
||||
depth = 0,
|
||||
cache = 'noDraft',
|
||||
revalidate = false,
|
||||
}: GetDocumentParams<K>): Promise<Config['collections'][K] | null> => {
|
||||
const { isEnabled: draft } = draftMode()
|
||||
const payload = await getPayload()
|
||||
const user = draft ? await getCurrentUser() : null
|
||||
|
||||
const normalizedPath = normalizePath(path, false)
|
||||
const where = { path: { equals: normalizedPath } }
|
||||
|
||||
const cacheKey = generateDocumentCacheKey(collection, path)
|
||||
const shouldCache = draft ? false : !!cache
|
||||
return conditionalCache(
|
||||
async () => {
|
||||
return await payload
|
||||
.find({
|
||||
collection,
|
||||
draft,
|
||||
depth,
|
||||
limit: 1,
|
||||
overrideAccess: false,
|
||||
user,
|
||||
where,
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error fetching document:', error)
|
||||
return null
|
||||
})
|
||||
.then((result) => {
|
||||
if (!result || !result.docs || result.docs.length === 0) return null
|
||||
return result.docs.at(0) as Config['collections'][K] | null
|
||||
})
|
||||
},
|
||||
cacheKey,
|
||||
shouldCache,
|
||||
revalidate,
|
||||
)
|
||||
}
|
9
src/utils/normalizePath.ts
Normal file
9
src/utils/normalizePath.ts
Normal file
@ -0,0 +1,9 @@
|
||||
const normalizePath = (path?: string | string[], keepTrailingSlash: boolean = false): string => {
|
||||
if (!path) return '/'
|
||||
if (Array.isArray(path)) path = path.join('/')
|
||||
path = `/${path}/`.replace(/\/+/g, '/')
|
||||
path = path !== '/' && !keepTrailingSlash ? path.replace(/\/$/, '') : path
|
||||
return path
|
||||
}
|
||||
|
||||
export default normalizePath
|
21
src/utils/theme.ts
Normal file
21
src/utils/theme.ts
Normal file
@ -0,0 +1,21 @@
|
||||
export function switchTheme(themeClass: string): void {
|
||||
const bodyElement = document.body
|
||||
const classesToRemove = ['light', 'dark', 'autonomic']
|
||||
|
||||
bodyElement.classList.remove(...classesToRemove)
|
||||
bodyElement.classList.add(themeClass)
|
||||
}
|
||||
|
||||
export function handleThemeChange(event: Event): void {
|
||||
const selectElement = event.target as HTMLSelectElement
|
||||
const selectedTheme = selectElement.value
|
||||
|
||||
switchTheme(selectedTheme)
|
||||
}
|
||||
|
||||
export function initializeThemeSelector(): void {
|
||||
const themeSelector = document.getElementById('theme-selector')
|
||||
if (themeSelector) {
|
||||
themeSelector.addEventListener('change', handleThemeChange)
|
||||
}
|
||||
}
|
19
tailwind.config.js
Normal file
19
tailwind.config.js
Normal file
@ -0,0 +1,19 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ['./src/app/(app)/**/*.{html,tsx}', './src/components/**/*'],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: 'rgba(var(--primary))',
|
||||
secondary: 'rgba(var(--secondary))',
|
||||
tertiary: 'rgba(var(--tertiary))',
|
||||
text: 'rgba(var(--text))',
|
||||
textInverted: 'rgba(var(--textInverted))',
|
||||
link: 'rgba(var(--link))',
|
||||
background: 'rgba(var(--background))',
|
||||
},
|
||||
},
|
||||
},
|
||||
safelist: [],
|
||||
plugins: [],
|
||||
}
|
@ -26,6 +26,12 @@
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
],
|
||||
"@payload/*": [
|
||||
"./src/app/(payload)/*"
|
||||
],
|
||||
"@app/*": [
|
||||
"./src/app/(app)/*"
|
||||
],
|
||||
"@payload-config": [
|
||||
"./payload.config.ts"
|
||||
]
|
||||
|
@ -9,8 +9,10 @@
|
||||
export interface Config {
|
||||
collections: {
|
||||
users: User;
|
||||
pages: Page;
|
||||
posts: Post;
|
||||
authors: Author;
|
||||
media: Media;
|
||||
pages: Page;
|
||||
'payload-preferences': PayloadPreference;
|
||||
'payload-migrations': PayloadMigration;
|
||||
};
|
||||
@ -26,6 +28,7 @@ export interface Config {
|
||||
*/
|
||||
export interface User {
|
||||
id: string;
|
||||
roles: ('admin' | 'editor' | 'user')[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
email: string;
|
||||
@ -39,11 +42,57 @@ export interface User {
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "pages".
|
||||
* via the `definition` "posts".
|
||||
*/
|
||||
export interface Page {
|
||||
export interface Post {
|
||||
id: string;
|
||||
title?: string | null;
|
||||
title: string;
|
||||
summary?: string | null;
|
||||
publishedDate?: string | null;
|
||||
thumbnail: string | Media;
|
||||
'content-title'?: string | null;
|
||||
blocks?:
|
||||
| (
|
||||
| RichTextBlock
|
||||
| {
|
||||
author?: (string | null) | Author;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'Author';
|
||||
}
|
||||
)[]
|
||||
| null;
|
||||
author?: (string | null) | Author;
|
||||
slug?: string | null;
|
||||
path?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
_status?: ('draft' | 'published') | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "media".
|
||||
*/
|
||||
export interface Media {
|
||||
id: string;
|
||||
alt: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string | null;
|
||||
thumbnailURL?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
focalX?: number | null;
|
||||
focalY?: number | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "RichTextBlock".
|
||||
*/
|
||||
export interface RichTextBlock {
|
||||
content?: {
|
||||
root: {
|
||||
type: string;
|
||||
@ -59,25 +108,54 @@ export interface Page {
|
||||
};
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'RichText';
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "authors".
|
||||
*/
|
||||
export interface Author {
|
||||
id: string;
|
||||
avatar: string | Media;
|
||||
name: string;
|
||||
bio?: string | null;
|
||||
user?: string | User | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "media".
|
||||
* via the `definition` "pages".
|
||||
*/
|
||||
export interface Media {
|
||||
export interface Page {
|
||||
id: string;
|
||||
text?: string | null;
|
||||
title?: string | null;
|
||||
blocks?:
|
||||
| (
|
||||
| RichTextBlock
|
||||
| {
|
||||
author?: (string | null) | Author;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'Author';
|
||||
}
|
||||
)[]
|
||||
| null;
|
||||
slug?: string | null;
|
||||
path?: string | null;
|
||||
breadcrumbs?:
|
||||
| {
|
||||
doc?: (string | null) | Page;
|
||||
url?: string | null;
|
||||
label?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string | null;
|
||||
thumbnailURL?: string | null;
|
||||
filename?: string | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
_status?: ('draft' | 'published') | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
Loading…
Reference in New Issue
Block a user