1 Commits

Author SHA1 Message Date
3wc
8a329feb3e Tidy up environment variables for local dev
All checks were successful
continuous-integration/drone/push Build is passing
2024-05-18 14:38:21 -03:00
49 changed files with 3572 additions and 5397 deletions

View File

@ -4,7 +4,7 @@ name: publish pipeline
steps:
- name: publish astro container
image: plugins/docker
settings: &docker-build-settings
settings:
username: 3wordchant
password:
from_secret: git_autonomic_zone_token_3wc
@ -14,39 +14,23 @@ steps:
registry: git.autonomic.zone
context: astro
dockerfile: astro/Dockerfile
when: &exclude-event-custom
branch:
- main
event:
exclude:
- custom
- name: publish payload dev container
image: plugins/docker
settings: &payload-build-settings
<<: *docker-build-settings
# NOTE: edit this if you want your image called something else
repo: git.autonomic.zone/autonomic-cooperative/astro-payload-test-payload-dev
context: payload
dockerfile: payload/Dockerfile
target: dev
when:
<<: *exclude-event-custom
- name: publish payload prod container
- name: publish payload container
image: plugins/docker
settings:
<<: *payload-build-settings
username: 3wordchant
password:
from_secret: git_autonomic_zone_token_3wc
# NOTE: edit this if you want your image called something else
repo: git.autonomic.zone/autonomic-cooperative/astro-payload-test-payload
auto_tag: true
registry: git.autonomic.zone
context: payload
dockerfile: payload/Dockerfile
target: prod
when:
<<: *exclude-event-custom
# See https://docz.autonomic.zone/doc/setting-up-auto-deployment-using-drone-I4j2onjaKT
- name: deploy stack
image: git.coopcloud.tech/coop-cloud/stack-ssh-deploy:latest
settings:
compose: docker-compose.prod.yml
stack: paystro_swarm-demo_autonomic_zone
host: swarm-demo.autonomic.zone
deploy_key:
@ -59,13 +43,21 @@ steps:
SECRET_MONGO_PASSWORD_VERSION: v1
NGINX_CONF_VERSION: v1
REPOSITORY: "autonomic-cooperative/astro-payload-test"
DRONE_URL: "https://drone.autonomic.zone"
PAYLOAD_URL: "https://admin.paystro.swarm-demo.autonomic.zone"
depends_on:
- publish payload prod container
when:
<<: *exclude-event-custom
# - publish astro container
- publish payload container
trigger:
branch:
- main
event:
exclude:
- custom
---
kind: pipeline
name: build astro
steps:
- name: build astro content
image: git.autonomic.zone/autonomic-cooperative/astro-payload-test-astro:latest
environment:
@ -74,9 +66,6 @@ steps:
- cd astro
- mv /base/node_modules .
- yarn build
depends_on:
- deploy stack
- name: copy built content to stack
image: git.coopcloud.tech/coop-cloud/docker-cp-deploy:latest
settings:
@ -88,5 +77,7 @@ steps:
dest: /usr/share/nginx/html/
deploy_key:
from_secret: drone_ssh_swarm-demo.autonomic.zone
depends_on:
- build astro content
trigger:
event:
- custom

View File

@ -1,7 +1,8 @@
# This file is just for local dev; see .drone.yml for live deployment
# This file is just for local dev; see <somewhere else> for live deployment
NAME=astroad
PAYLOAD_PORT=3001
PAYLOAD_URL=http://localhost:3003
PAYLOAD_PORT=3003
##############################################################################
# Infinite nerd depth settings, you probably don't need to change these #

3
.gitignore vendored
View File

@ -1,6 +1,3 @@
/.env
data
yarn-debug.log*
yarn-error.log*
#payload-types.ts

103
README.md
View File

@ -1,65 +1,66 @@
# Paystro
# Astroad
Paystro is a pre-configured setup for Astro and Payloadcms, designed to make it easy for you to start building your website. With Paystro, you'll have a complete development environment that you can run locally using Docker. This setup simplifies the testing and development of your website before deploying it to a production environment.
## Architecture
Paystro is a fork of [Astroad](https://github.com/mooxl/astroad).
Unlike Astroad where the "Astro" image is the built static site served with Nginx Paystro's Astro image is a builder image.
In Paystro, the Docker stack just contains Payload and a generic Nginx container.
## How to use this template
1. Create a new Gitea repository based on this template repo (choose at least
"git content")
2. Edit `.env.sample` to define the project name
3. Remove this notice (everything down to the `---`)
To set up deployment:
1. Make sure the server you want to deploy to is set up for Drone access,
including adding an SSH key as an organisational secret for the organisation
this project is in (see [Autonomic internal
docs](https://docz.autonomic.zone/doc/setting-up-auto-deployment-using-drone-I4j2onjaKT))
2. Edit `.drone.yml` to set variables:
- `HOST`: hostname or IP address of the server to deploy to (e.g.
`vps.example.tld`)
- `DOMAIN`: domain name of the live site (e.g. `site.example.tld`)
- `STACK_NAME`: the Docker stack name, usually `$DOMAIN` with dots replaced
with underscores (e.g. `site_example_tld`)
- `DRONE_URL`: root URL for the Drone instance (e.g.
`https://drone.example.tld`)
3. Make sure that DNS records for `$DOMAIN` and `admin.$DOMAIN`, pointing to
`$HOST`, are defined.
4. Generate secrets (`openssl rand -hex 32` works well) for `PAYLOAD_SECRET` and
`MONGO_PASSWORD`. Insert the personal user token for a Drone bot user (e.g.
`autono-bot`) as `TOKEN`). For all of them, use something like `echo "foobar"
| docker secret create paystro_swarm-demo_autonomic_zone_token_v1 -`, where
`paystro_swarm-demo_autonomic_zone` is the `STACK_NAME`.
5. Activate the repo in Drone
---
# ${REPO_NAME}
Astroad is a pre-configured setup for Astro and Payloadcms, designed to make it easy for you to start building your website. With Astroad, you'll have a complete development environment that you can run locally using Docker. This setup simplifies the testing and development of your website before deploying it to a production environment.
## Prerequisites
Before getting started, make sure you have Docker installed (and, if your Docker doesn't include `docker compose`, the separate `docker-compose` tool).
Before getting started with Astroad, make sure you have the necessary software installed:
- Docker
- Node.js
- Yarn
## Configuration
Copy `.env.sample` to `.env` and edit as appropriate (e.g. to change the port for Payload).
While there's no configuration necessary for local development, deployment via Github Workflows requires specific secrets and variables to be set.
### Secrets:
- `USER`: User on the server
- `HOST`: IP or URL of the server
- `KEY`: SSH KEY for connecting to the server
- `MONGODB_PW`: Password for MongoDB
- `MONGODB_USER`: User for MongoDB
- `PATH`: Path where the repository resides on the server
- `PAYLOAD_PORT`: Port at which Payload listens
- `PAYLOAD_SECRET`: String to encrypt Payload data
- `TOKEN`: Github Access Token for the webhook to trigger the payload.yml workflow and execute a new Astro build
### Variables:
- `ASTRO_HOST`: Hostdomain of the Frontend
- `PAYLOAD_HOST`: Hostdomain of the CMS
- `PAYLOAD_URL`: URL of the CMS
- `NAME`: Name of the Container and Project
Please remember to set these secrets and variables in your repository settings to ensure a successful deployment through Github Workflows.
Once the secrets and variables are set on GitHub, they will replace the existing ones in the `.env` file on the server during deployment. This is done by the push.yml workflow, which replaces the placeholders in the `.env` with the actual secrets and variables defined in the repository settings. Please ensure that the names of your secrets and variables match with the placeholders in the `.env` file.
## Getting started
To get started with Astroad, you'll need to have Docker and NPM || Yarn || PNPM installed on your machine.
You have two options for getting the repository:
1. Use the 'Use this template' button on the Github repository. This will create a new repository in your Github account with the same directory structure and files as Astroad. After the new repository is created, you can clone it to your local machine.
1. Alternatively, you can directly clone the Astroad repository: git clone https://github.com/mooxl/astroad.git. If you choose this option, remember to change the origin of your remote repository to a new one to avoid pushing changes directly to the Astroad repository. This can be done with the command: git remote set-url origin https://github.com/USERNAME/REPOSITORY.git where USERNAME is your username and REPOSITORY is the name of your new repository.
Once you've cloned the repository or created your own from the template, follow these steps:
1. Change into the repository directory: `cd {newName}`
1. Start the containers: `yarn dev`
This will start up the Astro, Payloadcms and Mongo containers and make them available on your local machine. Astro will be served at http://localhost:3000 and the Payload will be available at http://localhost:3001.
## Development
Launch local containers using `yarn dev` or, if you don't have yarn installed, plain `docker-compose up` / `docker compose up`.
The `docker-compose.yml` file includes everything you need to run the containers. The containers use the environment variables declared in the `.env` file, and mounted volumes to store data persistently even after the containers are stopped and started.
The `docker-compose.yml` and `docker-compose-dev.yml` files includes everything you need to run the containers. The containers use the environment variables declared in the `.env` file and mounted volumes to store data persistently even after the containers are stopped and started.
## Deployment
Whenever the repository is updated, Drone builds new Docker images for Payload and Astro, and deploys a new Docker Swarm stack to the `HOST` configured in `.drone.yml`.
Deployment is handled by a Github Actions Workflow on every push. It logs into the server via SSH, pulls or clones the latest version of the repository, and runs `yarn prod`.
Whenever changes are made to Payload content on the live site, Drone uses the Astro builder image to regenerate the static site, and publish it to the Nginx container by copying it into the Docker volume.
Because Astro is completely static, a content change in the CMS must trigger a new build of Astro. Therefore, theres a `payload.yml` workflow that gets triggered by a webhook after every content change from Payload.
Ensure you have Traefik set up as a reverse proxy before deployment. The prod script will launch your site in a production-ready environment.

3
astro/.gitignore vendored
View File

@ -16,3 +16,6 @@ pnpm-debug.log*
# macOS-specific files
.DS_Store
# types
src/types.ts

View File

@ -9,8 +9,8 @@ export default defineConfig({
build: {
inlineStylesheets: "auto",
},
server: {
port: 3000
experimental: {
viewTransitions: true,
},
integrations: [
tailwind({

View File

@ -1,6 +1,6 @@
{
"name": "paystro",
"description": "Paystro - Astro",
"name": "astroad",
"description": "Astroad - Astro",
"type": "module",
"version": "1.1",
"license": "MIT",
@ -9,11 +9,11 @@
"build": "astro build"
},
"dependencies": {
"@astrojs/image": "0.18.0",
"@astrojs/prefetch": "0.4.1",
"@astrojs/sitemap": "3.1.4",
"@astrojs/tailwind": "5.1.0",
"astro": "4.8.6",
"@astrojs/image": "^0.17.3",
"@astrojs/prefetch": "^0.3.0",
"@astrojs/sitemap": "^2.0.2",
"@astrojs/tailwind": "4.0.0",
"astro": "^2.10.12",
"css-select": "5.1.0",
"sharp": "^0.32.6",
"slate-serializers": "0.4.1",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -1,36 +0,0 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 500 500" style="width: 178px;" xml:space="preserve" data-imageid="404-page-not-found-1-77" imageName="404 Page Not Found 1" class="illustrations_image">
<style type="text/css">
.st0_404-page-not-found-1-77 { fill: var(--primary); }
.st1_404-page-not-found-1-77 { fill: var(--secondary);}
.st2_404-page-not-found-1-77{fill:var(--tertiary);}
.st3_404-page-not-found-1-77{fill:var(--secondary);}
</style>
<g id="Numbers_404-page-not-found-1-77">
<path class="st0_404-page-not-found-1-77 targetColor" d="M107.9,303.8H39.1v-27.2l65.2-101.8h31.1v104.3h23.6v24.7h-23.6v32.9h-27.4V303.8z M107.9,213.7h-0.5L67,279.1&#xA;&#9;&#9;h40.9V213.7z" style="fill: rgb(104, 225, 253);"/>
<path class="st0_404-page-not-found-1-77 targetColor" d="M409.9,303.8h-68.8v-27.2l65.2-101.8h31.1v104.3h23.6v24.7h-23.6v32.9h-27.4V303.8z M414.7,213.7h-0.5&#xA;&#9;&#9;l-40.5,65.4h40.9L414.7,213.7z" style="fill: rgb(104, 225, 253);"/>
</g>
<g id="Chraracter_404-page-not-found-1-77">
<path class="st1_404-page-not-found-1-77" d="M245.1,182.9c-40.2,0-72.7,32.5-72.8,72.7c0,40.2,32.5,72.7,72.7,72.8s72.7-32.5,72.8-72.7c0,0,0,0,0,0&#xA;&#9;&#9;C317.8,215.5,285.2,182.9,245.1,182.9z"/>
<path class="st2_404-page-not-found-1-77" d="M245.1,329.1c-40.6,0-73.5-32.9-73.5-73.4s32.9-73.5,73.4-73.5s73.5,32.9,73.5,73.4c0,0,0,0,0,0&#xA;&#9;&#9;C318.5,296.2,285.6,329,245.1,329.1z M245.1,183.6c-39.8,0-72,32.2-72,72s32.2,72,72,72s72-32.2,72-72l0,0&#xA;&#9;&#9;C317,215.9,284.8,183.7,245.1,183.6L245.1,183.6z"/>
<ellipse class="st2_404-page-not-found-1-77" cx="283.2" cy="232" rx="3.4" ry="5"/>
<path class="st2_404-page-not-found-1-77" d="M159.6,234.1l170.8-37.8l-33.6-9.8c0,0-18.3-30.2-23.1-30.8S180.6,174,180.6,174l-5.6,42.5L159.6,234.1z"/>
<path class="st2_404-page-not-found-1-77" d="M279.2,286.5c-0.3,0-0.5-0.1-0.6-0.4c-18.5-31.4-61.1-14.8-61.5-14.7c-0.4,0.1-0.8,0-0.9-0.4&#xA;&#9;&#9;c-0.1-0.4,0-0.8,0.4-0.9c0.4-0.2,44.2-17.2,63.3,15.3c0.2,0.3,0.1,0.8-0.2,1c0,0,0,0,0,0C279.4,286.5,279.3,286.5,279.2,286.5z"/>
<polygon class="st2_404-page-not-found-1-77" points="195.2,336.4 175.9,305.9 260.3,291.5 266.1,320.7 274.7,293.8 317.8,302.3 309,336.4 &#9;"/>
<path class="st1_404-page-not-found-1-77" d="M303.4,270.3l7.8-1.1l0,0l4,29c0.3,2-1.1,3.9-3.2,4.2h0l-0.5,0.1c-2,0.3-3.9-1.1-4.2-3.2l0,0L303.4,270.3&#xA;&#9;&#9;L303.4,270.3z"/>
<path class="st2_404-page-not-found-1-77" d="M311,303.2c-2.2,0-4.1-1.6-4.4-3.8l-4-29c0-0.4,0.2-0.7,0.6-0.8l7.8-1.1c0.2,0,0.4,0,0.5,0.1&#xA;&#9;&#9;c0.1,0.1,0.2,0.3,0.3,0.5l4,29c0.4,2.4-1.3,4.6-3.7,5c0,0,0,0,0,0l-0.5,0.1C311.4,303.2,311.2,303.2,311,303.2z M304.1,270.9&#xA;&#9;&#9;l3.9,28.4c0.2,1.6,1.7,2.8,3.4,2.6l0.5-0.1l0,0c1.6-0.2,2.8-1.7,2.6-3.4l-3.9-28.3L304.1,270.9z"/>
<rect x="299.3" y="243.6" transform="matrix(0.9906 -0.1371 0.1371 0.9906 -32.4796 44.3355)" class="st1_404-page-not-found-1-77" width="12.7" height="28.7"/>
<path class="st2_404-page-not-found-1-77" d="M301.3,273.7c-0.2,0-0.3,0-0.4-0.1c-0.1-0.1-0.2-0.3-0.3-0.5l-3.9-28.4c0-0.2,0-0.4,0.1-0.5&#xA;&#9;&#9;c0.1-0.1,0.3-0.2,0.5-0.3l12.5-1.7c0.4,0,0.7,0.2,0.8,0.6l3.9,28.4c0,0.4-0.2,0.7-0.6,0.8L301.3,273.7L301.3,273.7z M298.2,245.2&#xA;&#9;&#9;l3.7,27l11.2-1.5l-3.7-27L298.2,245.2z"/>
<path class="st1_404-page-not-found-1-77" d="M308.5,292.1l3.7-0.5c2.4-0.3,4.7,1.4,5,3.8l5.6,40.5c0.3,2.4-1.4,4.7-3.8,5l-3.7,0.5c-2.4,0.3-4.7-1.4-5-3.8&#xA;&#9;&#9;l-5.6-40.5C304.3,294.7,306,292.4,308.5,292.1z"/>
<path class="st2_404-page-not-found-1-77" d="M314.7,342.2c-2.6,0-4.8-1.9-5.1-4.5l-5.6-40.5c-0.4-2.8,1.6-5.4,4.4-5.8l3.7-0.5c1.4-0.2,2.7,0.2,3.8,1&#xA;&#9;&#9;c1.1,0.8,1.8,2.1,2,3.4l5.6,40.5c0.4,2.8-1.6,5.4-4.4,5.8l0,0l-3.7,0.5C315.1,342.2,314.9,342.2,314.7,342.2z M319,341L319,341z&#xA;&#9;&#9; M312.8,292.3c-0.2,0-0.3,0-0.5,0l-3.7,0.5c-2.1,0.3-3.5,2.2-3.2,4.3l5.6,40.5c0.3,2.1,2.2,3.5,4.3,3.2l3.7-0.5&#xA;&#9;&#9;c2.1-0.3,3.5-2.2,3.2-4.2c0,0,0,0,0,0l-5.6-40.5c-0.2-1-0.7-1.9-1.5-2.5C314.4,292.5,313.6,292.3,312.8,292.3L312.8,292.3z"/>
<circle class="st1_404-page-not-found-1-77" cx="302.6" cy="236.5" r="33.7"/>
<path class="st2_404-page-not-found-1-77" d="M302.6,270.9c-19,0-34.3-15.4-34.3-34.4s15.4-34.3,34.4-34.3c17.1,0,31.7,12.7,34,29.6l0,0&#xA;&#9;&#9;c2.6,18.8-10.6,36.2-29.4,38.7C305.7,270.8,304.2,270.9,302.6,270.9z M302.7,203.6c-1.5,0-3,0.1-4.5,0.3&#xA;&#9;&#9;c-18,2.5-30.6,19.1-28.1,37.2c2.5,18,19.1,30.6,37.2,28.1s30.6-19.1,28.1-37.2c0,0,0,0,0,0l0,0C333,215.7,319.1,203.6,302.7,203.6&#xA;&#9;&#9;L302.7,203.6z"/>
<circle class="st1_404-page-not-found-1-77" cx="302.6" cy="236.5" r="27.3"/>
<path class="st2_404-page-not-found-1-77" d="M302.6,264.5c-15.5,0.2-28.2-12.1-28.4-27.6c-0.2-14.3,10.4-26.5,24.6-28.2c15.3-2.1,29.5,8.6,31.6,23.9&#xA;&#9;&#9;c2.1,15.3-8.6,29.5-23.9,31.6l0,0C305.2,264.5,303.9,264.5,302.6,264.5z M302.7,209.9c-1.2,0-2.5,0.1-3.7,0.2&#xA;&#9;&#9;c-14.6,2-24.8,15.5-22.7,30c2,14.6,15.5,24.8,30,22.7c14.6-2,24.8-15.5,22.7-30c-1-7-4.7-13.3-10.3-17.6&#xA;&#9;&#9;C314.1,211.8,308.5,209.9,302.7,209.9z"/>
<path class="st1_404-page-not-found-1-77" d="M334.8,312.4c-1.8-2.4-4.2-4.3-6.9-5.7c-8-4.1-17.2-4.1-25.7-1.4c-3,1-8.8,2.3-9.1,6.3c0,1.6,1.1,3,2.7,3.5&#xA;&#9;&#9;c1.5,0.4,3.1,0.5,4.7,0.2c-2.2,0.1-4.5,0.3-6.3,1.6s-2.7,4-1.3,5.7c0.7,0.7,1.5,1.2,2.4,1.4c2,0.6,4.2,0.5,6.2-0.1&#xA;&#9;&#9;c-2.2,0.4-4.3,1.1-6.4,2c-1.2,0.5-2.6,1.5-2.5,2.9s1.4,1.9,2.5,2.3c2.4,0.8,4.9,1.3,7.5,1.4c-2.2,0.6-4.4,1.2-6.1,2.6&#xA;&#9;&#9;c-2.7,2.3-2.8,6.8,1,8.1c1.2,0.3,2.5,0.5,3.8,0.4c11.2,0,24.6-1.4,32.2-10.7c3.6-4.4,5.3-10.5,3.6-15.8&#xA;&#9;&#9;C336.7,315.3,335.8,313.7,334.8,312.4z"/>
<path class="st2_404-page-not-found-1-77" d="M301.3,344.3c-1.3,0.1-2.6-0.1-3.9-0.5c-1.7-0.5-3-1.9-3.3-3.7c-0.3-2.1,0.5-4.2,2.1-5.6&#xA;&#9;&#9;c0.9-0.7,1.9-1.3,3-1.8c-1.4-0.2-2.8-0.6-4.2-1.1c-1.9-0.6-2.9-1.6-3-2.9s0.9-2.7,2.9-3.6l1-0.4c-0.2,0-0.5-0.1-0.8-0.2&#xA;&#9;&#9;c-1.1-0.2-2.1-0.8-2.8-1.6c-0.7-0.8-1-1.9-0.8-3c0.2-1.5,1-2.9,2.3-3.8c0.4-0.3,0.9-0.5,1.4-0.8c-1.6-0.7-2.7-2.2-2.7-4&#xA;&#9;&#9;c0.3-4.1,5.4-5.6,8.7-6.6l0.9-0.3c9.4-3,18.6-2.4,26.2,1.5c2.8,1.4,5.2,3.4,7.1,5.9c1.1,1.5,2,3.1,2.5,4.9&#xA;&#9;&#9;c1.7,5.3,0.2,11.6-3.7,16.5C326.2,343,312.5,344.3,301.3,344.3L301.3,344.3z M300,325c-1.6,0.4-3.1,0.9-4.5,1.6&#xA;&#9;&#9;c-0.6,0.3-2.2,1.1-2,2.1c0.1,0.8,1.2,1.4,2.1,1.7c2.3,0.8,4.8,1.3,7.3,1.4c0.4,0,0.7,0.3,0.7,0.7c0,0.3-0.2,0.6-0.5,0.7&#xA;&#9;&#9;c-2,0.5-4.2,1.1-5.8,2.5c-1.3,1-1.9,2.7-1.6,4.3c0.2,1.3,1.2,2.3,2.4,2.6c1.1,0.3,2.3,0.5,3.5,0.4c10.8,0,24.1-1.2,31.7-10.5&#xA;&#9;&#9;c3.7-4.5,5-10.3,3.5-15.2c-0.5-1.6-1.3-3.1-2.3-4.4l0,0c-1.8-2.3-4-4.2-6.6-5.5c-7.2-3.7-16.1-4.2-25.1-1.4l-0.9,0.3&#xA;&#9;&#9;c-3,0.9-7.5,2.2-7.7,5.4c0.1,1.3,0.9,2.4,2.1,2.7c0.8,0.3,1.7,0.4,2.5,0.3c0.7-0.1,1.3-0.1,1.9-0.1c0.4,0,0.7,0.3,0.7,0.6&#xA;&#9;&#9;c0,0.4-0.2,0.7-0.6,0.8c-0.6,0.1-1.3,0.1-2,0.2c-1.4,0.1-2.8,0.5-4,1.3c-0.9,0.7-1.5,1.7-1.7,2.8c-0.1,0.7,0.1,1.4,0.5,1.9&#xA;&#9;&#9;c0.6,0.6,1.3,1,2.1,1.1c1.4,0.4,2.8,0.5,4.2,0.3c0.6-0.1,1.1-0.3,1.7-0.4c0.4-0.1,0.7,0.2,0.8,0.5c0.1,0.4-0.1,0.7-0.5,0.8&#xA;&#9;&#9;C301.1,324.8,300.6,324.9,300,325z"/>
<path class="st2_404-page-not-found-1-77" d="M261.6,263.9c-8.6,0-9.9-2.4-10.1-2.9c-0.1-0.4,0.1-0.8,0.5-0.9s0.8,0.1,0.9,0.5l0,0c0,0,1.2,2.2,10.5,1.8&#xA;&#9;&#9;c0.9,0.1,1.8-0.4,2.3-1.2c2.2-4.3-6.2-18.6-9.6-23.7c-0.2-0.3-0.1-0.8,0.2-1c0.3-0.2,0.8-0.1,1,0.2c0,0,0,0,0,0&#xA;&#9;&#9;c1.3,2,12.7,19.3,9.7,25.2c-0.7,1.3-2.1,2.1-3.5,2C262.8,263.8,262.2,263.9,261.6,263.9z"/>
<ellipse class="st3_404-page-not-found-1-77" cx="304.2" cy="235.7" rx="6.2" ry="10.6"/>
<ellipse class="st2_404-page-not-found-1-77" cx="228.5" cy="235.7" rx="4.7" ry="8.5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -1,27 +0,0 @@
---
import { Image } from "@astrojs/image/components";
import type { Author } from "@/types/payload-types";
interface Props {
author: Author;
}
const { author } = Astro.props;
---
{ (author) &&
<div class="flex gap-6 border-t-2 border-secondary py-4 text-secondary">
{(typeof author.avatar === 'object') &&
<Image
src={author.avatar.url || ""}
width={150}
height={150}
aspectRatio={1}
alt={author.avatar.alt || ""}
/>
}
<div class="flex flex-col">
<h3 class="font-semibold text-base">{author.name}</h3>
<p class="text-sm font-light">{author.bio}</p>
</div>
</div>
}

View File

@ -5,20 +5,23 @@ import { getImageSrc } from "@/utils/payload";
const { content } = Astro.props;
const contentArray = getContentArray(content);
---
<div>
{
contentArray.map((value) => {
if (typeof value === "string") {
return <section set:html={value} />;
return <article set:html={value} />;
} else {
return (
<Image
src={getImageSrc(value.src) || "/not-found.png"}
src={getImageSrc(value.src)}
width={value.width}
height={value.height}
format="webp"
alt={value.alt}
alt="hallo"
/>
);
}
})
}
</div>

View File

@ -1,11 +0,0 @@
---
import { getCurrentYear } from "@/utils/date";
import ThemeSwitcher from "./ThemeSwitcher.astro";
---
<footer class="flex justify-between items-center py-4">
<p class="text-lg font-semibold">
&copy; {getCurrentYear()} Autonomic. Template distributed under AGPL 3.0.
</p>
<ThemeSwitcher/>
</footer>

View File

@ -1,36 +0,0 @@
---
const links = [
{
label: "About",
link: "/about"
},
{
label: "Services",
link: "/services"
},
{
label: "Contact",
link: "/contact"
},
];
---
<header class="flex justify-between py-6">
<div>
<a href="/" class="decoration-transparent">
<span class="text-2xl font-extrabold ">
Logo
</span>
</a>
</div>
<nav>
<ul class="flex gap-4 font-bold list-none">
{links.map((item, index) => (
<li class="decoration-transparent">
<a href={item.link}>{item.label}</a>
</li>
))}
</ul>
</nav>
</header>

View File

@ -1,43 +0,0 @@
---
import { Image } from "@astrojs/image/components";
import type { Post } from "@/types/payload-types";
interface Props {
post: Post;
}
const { post } = Astro.props;
---
<a
class="py-4 border-secondary decoration-transparent"
href={`/posts/${post.id}/`}
>
<article class="flex px-5 py-3 gap-8">
<Image
src={post.thumbnail.url || "/not-found"}
height={150}
aspectRatio={1}
format="webp"
alt={post.thumbnail.alt}
/>
<div class="flex flex-col gap-4 w-full">
<div class="flex justify-between w-full">
<h3 class="">{post.title}</h3>
{post.publishedDate && (
<p class="font-light">
{new Date(post.publishedDate).toLocaleDateString("de-DE")}
</p>
)}
</div>
{post.summary && <p class="max-w-prose">
{post.summary}
</p>}
</div>
<!-- {post.author.name && (
<p>
{post.author.name}
</p>
)} -->
</article>
</a>

View File

@ -1,26 +0,0 @@
---
import PostEntry from "@/components/PostEntry.astro"
import type { Post } from "@/types/payload-types";
interface Props {
posts: Post[];
}
const { posts } = Astro.props;
---
<div class="flex flex-col">
<h2 class="text-secondary mb-4">Posts</h2>
<div class="border-y-2 flex flex-col divide-y-2 border-secondary divide-secondary">
{
posts.length > 0 ? (
posts.map((post) => (
typeof(post) === 'object') &&
<PostEntry post={post}/>
)
) : (
<p>No posts available</p>
)
}
</div>
</div>

View File

@ -1,12 +0,0 @@
---
---
<select id="theme-selector">
<option value="autonomic">Autonomic</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
<script>
import { handleThemeChange, switchTheme, initializeThemeSelector } from "@/utils/theme"
initializeThemeSelector()
</script>

View File

@ -1,107 +0,0 @@
@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 {
@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;
}
}

View File

@ -1,15 +0,0 @@
---
import BaseLayout from "./BaseLayout.astro";
import Header from "@/components/Header.astro";
import Footer from "@/components/Footer.astro";
const { title } = Astro.props;
---
<BaseLayout title={title}>
<Header/>
<main class="flex-grow">
<slot/>
</main>
<Footer/>
</BaseLayout>

View File

@ -4,7 +4,6 @@ export interface Props {
title: string;
}
const { title } = Astro.props;
import "@/global.css"
---
<!DOCTYPE html>
@ -31,7 +30,7 @@ import "@/global.css"
}
</style>
</head>
<body class="autonomic min-h-screen flex flex-col mx-auto max-w-7xl px-6 text-primary bg-background">
<body class="mx-auto max-w-7xl bg-gray px-6 py-8 font-plex text-gray-200">
<slot />
</body>
</html>

View File

@ -1,18 +0,0 @@
---
import ContentLayout from "@/layouts/ContentLayout.astro"
import { Image } from "@astrojs/image/components";
import notFound from "@/assets/404.svg"
---
<ContentLayout>
<div class="flex flex-col justify-center items-center gap-8">
<Image
src={notFound}
width={360}
aspectRatio={1}
format="svg"
alt={"404"}
/>
<h1>404: Page not found</h1>
</div>
</ContentLayout>

View File

@ -1,17 +1,16 @@
---
import Posts from "@/components/Posts.astro";
import ContentLayout from "@/layouts/ContentLayout.astro";
import Layout from "@/layouts/Layout.astro";
import { getPosts } from "@/utils/payload";
const posts = await getPosts();
---
<ContentLayout title="Paystro">
<main class="flex flex-col gap-4" >
<h1 class="">Paystro</h1>
<p class="mt-3">
Paystro is a pre-configured setup for Astro and Payloadcms that makes it
easy to get started with building your website. With Paystro, you'll have
<Layout title="Astroad">
<main class="" >
<h1 class="font-bold text-5xl">Astroad</h1>
<p class="mt-3 text-lg">
Astroad is a pre-configured setup for Astro and Payloadcms that makes it
easy to get started with building your website. With Astroad, 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.
@ -21,8 +20,26 @@ const posts = await getPosts();
reverse proxy. This setup provides a secure and scalable production
environment for your website.
</p>
<section class="mt-4">
<Posts posts={posts}/>
</section>
<h2 class="mt-6 font-bold text-2xl">Posts</h2>
<div class="flex gap-4 mt-3 flex-wrap">
{
posts.length > 0 ? (
posts.map((post) => (
<a href={`/posts/${post.id}/`}>
<article class="text-gray bg-gray-light px-5 py-3 rounded-md shadow-md w-64 text-center hover:-translate-y-1 transition-transform">
<h3 class="font-bold text-lg" transition:name=`title-${post.id}`>{post.title}</h3>
{post.publishedDate && (
<p>
{new Date(post.publishedDate).toLocaleDateString("de-DE")}
</p>
)}
</article>
</a>
))
) : (
<p>Add Posts in Payloadcms</p>
)
}
</div>
</main>
</ContentLayout>
</Layout>

View File

@ -1,9 +1,8 @@
---
import ContentLayout from "@/layouts/ContentLayout.astro";
import Layout from "@/layouts/Layout.astro";
import Content from "@/components/Content.astro";
import type { Post } from "@/types/payload-types";
import type { Post } from "@/types";
import { getPost, getPosts } from "@/utils/payload";
import Author from "@/components/Author.astro";
export async function getStaticPaths() {
const posts = await getPosts();
@ -19,16 +18,13 @@ const post = id && (await getPost(id));
{
post ? (
<ContentLayout title={`${post.title!}`}>
<article class="space-y-3 my-3 max-w-prose">
<h1 class="">{post.title}</h1>
<Layout title={`Astroad | ${post.title!}`}>
<div class="space-y-3 my-3">
<a href="/">BACK</a>
<h1 class="font-bold text-5xl" transition:name=`title-${post.id}`>{post.title}</h1>
{post.content && <Content content={post.content} />}
</article>
{typeof post.author === 'object' &&
<aside class="mt-8">
<Author author={post.author} />
</aside>}
</ContentLayout>
</div>
</Layout>
) : (
<div>404</div>
)

View File

@ -1,4 +0,0 @@
export const getCurrentYear = (): number => {
const currentYear = new Date().getFullYear();
return currentYear;
}

View File

@ -12,13 +12,12 @@ export const getContentArray = (content: any) => {
src: node.value.filename,
width: `${node.value.width}`,
height: `${node.value.height}`,
alt: `${node.value.alt}`,
}),
},
}).replaceAll("<p></p>", "<p>&nbsp;</p>");
const htmlImageArray: (
| string
| { src: string; width: number; height: number, alt: string }
| { src: string; width: number; height: number }
)[] = [];
let lastIndex = 0;
while (true) {
@ -34,7 +33,6 @@ export const getContentArray = (content: any) => {
src: imgTag.match(/src="(.*?)"/)![1],
width: +imgTag.match(/width="(.*?)"/)![1],
height: +imgTag.match(/height="(.*?)"/)![1],
alt: imgTag.match(/alt="(.*?)"/)![1],
};
htmlImageArray.push(remainingHtml, imgObject);
lastIndex = imgEndIndex;

View File

@ -1,4 +1,4 @@
import type { Post } from "@/types/payload-types";
import type { Post } from "@/types";
const url = import.meta.env.DEV
? "http://payload:3001"

View File

@ -1,21 +0,0 @@
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);
}
}

View File

@ -7,13 +7,11 @@ module.exports = {
},
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))",
gray: {
DEFAULT: "#111111",
light: "#888888",
dark: "#222222",
},
},
},
},

View File

@ -4,8 +4,7 @@
"types": ["@astrojs/image/client"],
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@/types/*": ["../*"]
"@/*": ["src/*"]
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -35,7 +35,6 @@ services:
- "MONGODB_PASSWORD_FILE=/run/secrets/mongo_password"
- "TOKEN_FILE=/run/secrets/token"
- "REPOSITORY"
- "DRONE_URL"
secrets:
- mongo_password
- payload_secret

View File

@ -19,12 +19,11 @@ services:
- payload
payload:
image: git.autonomic.zone/autonomic-cooperative/astro-payload-test-payload-dev:latest
image: git.autonomic.zone/autonomic-cooperative/astro-payload-test-payload:latest
container_name: ${NAME}-payload
restart: unless-stopped
build:
context: payload
target: dev
environment:
DEV: 1
NAME: ${NAME}
@ -32,11 +31,16 @@ services:
PAYLOAD_URL: "http://localhost:${PAYLOAD_PORT}"
PAYLOAD_PORT: ${PAYLOAD_PORT}
PAYLOAD_SECRET: ${PAYLOAD_SECRET}
MONGODB_URI: "mongodb://$MONGODB_USER:$MONGODB_PASSWORD@mongo:27017"
MONGODB_USER:
MONGODB_HOST: mongo
MONGODB_PASSWORD:
MONGODB_PORT: 27017
TOKEN: ${TOKEN}
volumes:
- ./payload/src:/base/src
# - ./astro/src/types.ts:/types.ts
- payload_media:/base/src/media
- ./astro/src/types.ts:/types.ts
volumes:
- payload_media:/prod/dist/media
ports:
- ${PAYLOAD_PORT}:${PAYLOAD_PORT}
networks:

View File

@ -1,13 +1,11 @@
{
"name": "paystro",
"name": "astroad",
"description": "A pre-configured setup for easy website development with Astro and Payload CMS using Docker.",
"license": "AGPL-3.0-or-later",
"version": "1.2",
"license": "MIT",
"version": "1.1",
"scripts": {
"dev": "yarn dev:docker & yarn payload:types",
"dev:docker": "docker compose up --build",
"payload:types": "yarn --cwd ./payload run generate:types:listen",
"stop": "docker compose down",
"dev:nobuild": "docker compose up"
"dev": "docker compose -f docker-compose.yml -f docker-compose-dev.yml up --build",
"prod": "docker compose -f docker-compose.yml -f docker-compose-prod.yml up -d --build",
"stop": "docker compose -f docker-compose.yml -f docker-compose-dev.yml down && docker compose -f docker-compose.yml -f docker-compose-prod.yml down"
}
}

View File

@ -1,66 +0,0 @@
/* tslint:disable */
/* eslint-disable */
/**
* This file was automatically generated by Payload.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {
collections: {
posts: Post;
users: User;
authors: Author;
media: Media;
};
globals: {};
}
export interface Post {
id: string;
title: string;
summary?: string;
publishedDate?: string;
thumbnail: string | Media;
content?: {
[k: string]: unknown;
}[];
author?: string | Author;
status: 'draft' | 'published' | 'archived';
updatedAt: string;
createdAt: string;
}
export interface Media {
id: string;
alt: string;
updatedAt: string;
createdAt: string;
url?: string;
filename?: string;
mimeType?: string;
filesize?: number;
width?: number;
height?: number;
}
export interface Author {
id: string;
avatar: string | Media;
name: string;
bio?: string;
user?: string | User;
updatedAt: string;
createdAt: string;
}
export interface User {
id: string;
roles: ('ssg' | 'admin' | 'editor' | 'user')[];
updatedAt: string;
createdAt: string;
email: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
salt?: string;
hash?: string;
loginAttempts?: number;
lockUntil?: string;
password?: string;
}

View File

@ -9,6 +9,7 @@ ENV NODE_ENV=development
EXPOSE 3001
CMD ["yarn","dev"]
FROM base AS build
ENV NODE_ENV=production
WORKDIR /build

View File

@ -1,27 +1,22 @@
{
"name": "paystro",
"description": "Paystro - Payload",
"name": "astroad",
"description": "Astroad - Payload",
"version": "1.1",
"main": "dist/server.js",
"license": "MIT",
"scripts": {
"dev": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts nodemon",
"build:payload": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts node -r tsconfig-paths/register node_modules/payload/dist/bin/index.js build ",
"build:payload": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts node -r tsconfig-paths/register node_modules/payload/dist/bin/index.js build",
"build:server": "tsc",
"build": "yarn generate:types && yarn build:payload && yarn build:server",
"build": "yarn build:payload && yarn build:server",
"serve": "cross-env PAYLOAD_CONFIG_PATH=dist/payload.config.js node -r tsconfig-paths/register dist/server.js",
"generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts node -r tsconfig-paths/register node_modules/payload/dist/bin/index.js generate:types",
"generate:types:listen": "nodemon --watch src --ext ts --exec 'npm run generate:types'"
"generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts node -r tsconfig-paths/register node_modules/payload/dist/bin/index.js generate:types"
},
"dependencies": {
"@payloadcms/bundler-webpack": "^1.0.6",
"@payloadcms/db-mongodb": "^1.5.1",
"@payloadcms/plugin-cloud": "^3.0.1",
"@payloadcms/richtext-slate": "^1.5.2",
"cross-env": "^7.0.3",
"dotenv": "^16.3.1",
"express": "^4.17.1",
"payload": "^2.18.3",
"payload": "^1.15.6",
"tsconfig-paths": "^4.2.0"
},
"devDependencies": {

View File

@ -1,12 +0,0 @@
import { Access, FieldAccess } from "payload/types";
import { User } from "@/types/payload-types";
export const isAdmin: Access<any, User> = ({ req: { user } }) => {
// Return true or false based on if the user has an admin role
return Boolean(user?.roles?.includes('admin'));
}
export const isAdminFieldLevel: FieldAccess<{ id: string }, unknown, User> = ({ req: { user } }) => {
// Return true or false based on if the user has an admin role
return Boolean(user?.roles?.includes('admin'));
}

View File

@ -1,21 +0,0 @@
import { Access } from "payload/config";
export const isAdminOrSelf: Access = ({ req: { user } }) => {
// Need to be logged in
if (user) {
// If user has role of 'admin'
if (user.roles?.includes('admin')) {
return true;
}
// If any other type of user, only provide access to themselves
return {
id: {
equals: user.id,
}
}
}
// Reject everyone else
return false;
}

View File

@ -1,12 +0,0 @@
import { Access, FieldAccess } from "payload/types";
import { User } from "@/types/payload-types";
export const isEditor: Access<any, User> = ({ req: { user } }) => {
// Return true or false based on if the user has an editor role
return Boolean(user?.roles?.some(role => ['user', 'editor', 'admin'].includes(role)));
}
export const isEditorFieldLevel: FieldAccess<{ id: string }, unknown, User> = ({ req: { user } }) => {
// Return true or false based on if the user has an editor role
return Boolean(user?.roles?.some(role => ['user', 'editor', 'admin'].includes(role)));
}

View File

@ -1,12 +0,0 @@
import { Access, FieldAccess } from "payload/types";
import { User } from "@/types/payload-types";
export const isSSG: Access<any, User> = ({ req: { user } }) => {
// Return true or false based on if the user has an ssg or admin role
return Boolean(user?.roles?.some(role => ['ssg', 'admin'].includes(role)));
}
export const isSSGFieldLevel: FieldAccess<{ id: string }, unknown, User> = ({ req: { user } }) => {
// Return true or false based on if the user has an ssg or admin role
return Boolean(user?.roles?.some(role => ['ssg', 'admin'].includes(role)));
}

View File

@ -1,13 +0,0 @@
import { Access, FieldAccess } from "payload/types";
import { User } from "@/types/payload-types";
export const isUser: Access<any, User> = ({ req: { user } }) => {
// Return true or false based on if the user has an ssg or admin role
return Boolean(user?.roles?.some(role => ['user', 'editor', 'admin'].includes(role)));
}
export const isUserFieldLevel: FieldAccess<{ id: string }, unknown, User> = ({ req: { user } }) => {
// Return true or false based on if the user has an ssg or admin role
return Boolean(user?.roles?.some(role => ['user', 'editor', 'admin'].includes(role)));
}

View File

@ -1,49 +0,0 @@
import { CollectionConfig } from "payload/types";
import { isAdmin } from "@/access/isAdmin";
import { isEditor } from "@/access/isEditor";
import { isSSG } from "@/access/isSSG";
import { isUser } from "@/access/isUser";
const Authors: CollectionConfig = {
slug: "authors",
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;

View File

@ -1,4 +1,3 @@
import { isUser } from "@/access/isUser";
import { CollectionConfig } from "payload/types";
export const Media: CollectionConfig = {
@ -6,20 +5,19 @@ export const Media: CollectionConfig = {
admin: {},
access: {
read: (): boolean => true,
create: isUser,
update: isUser,
delete: isUser,
create: () => true,
update: () => true,
},
upload: {
staticURL: "/media",
staticDir: "media",
mimeTypes: ["image/*"],
},
fields: [
{
name: "alt",
type: "text",
required: true
},
],
};

View File

@ -1,23 +1,14 @@
import { CollectionConfig } from "payload/types";
import { isAdmin } from "@/access/isAdmin";
import { isEditor } from "@/access/isEditor";
import { isSSG } from "@/access/isSSG";
import { isUser } from "@/access/isUser";
import { slateEditor } from '@payloadcms/richtext-slate'
const Posts: CollectionConfig = {
slug: "posts",
versions: true,
admin: {
defaultColumns: ["title", "author", "status"],
useAsTitle: "title",
},
access: {
//TODO: Author can CRUD own post
create: isUser,
read: () => true,
update: isEditor,
delete: isEditor,
create: () => true,
update: () => true,
},
hooks: {
afterChange: [
@ -28,7 +19,7 @@ const Posts: CollectionConfig = {
process.env.NODE_ENV !== "development" &&
console.log(
await fetch(
`${process.env.DRONE_URL}/api/repos/${process.env.REPOSITORY}/builds`,
`https://drone.autonomic.zone/api/repos/${process.env.REPOSITORY}/builds`,
{
method: "POST",
headers: {
@ -47,40 +38,28 @@ const Posts: CollectionConfig = {
{
name: "title",
type: "text",
required: true
},
{
name: "summary",
name: "hallo",
type: "text",
required: false
},
{
name: "publishedDate",
type: "date",
required: false,
admin: {
position: "sidebar",
}
},
{
name: "thumbnail",
type: "upload",
relationTo: "media",
required: true,
},
{
name: 'content',
type: 'richText',
editor: slateEditor({
name: "content",
type: "richText",
admin: {
elements: ["h2", "h3", "h4", "link", "ol", "ul", "upload", "blockquote", "indent"],
leaves: ["bold", "italic", "underline", "strikethrough"],
elements: ["h2", "h3", "h4", "link", "ol", "ul", "upload"],
leaves: ["bold", "italic", "underline"],
upload: {
collections: {
media: {
fields: [
{
name: "image",
name: "imagel",
type: "upload",
relationTo: "media",
required: true,
@ -90,21 +69,10 @@ const Posts: CollectionConfig = {
},
},
},
})
},
{
name: "author",
//TODO: Add active user as default
type: 'relationship',
relationTo: 'authors',
admin: {
position: "sidebar",
},
},
{
name: "status",
type: "select",
required: true,
options: [
{
value: "draft",
@ -114,10 +82,6 @@ const Posts: CollectionConfig = {
value: "published",
label: "Published",
},
{
value: "archived",
label: "Archived",
},
],
defaultValue: "draft",
admin: {

View File

@ -1,41 +1,20 @@
import { CollectionConfig } from 'payload/types';
import { isAdmin, isAdminFieldLevel } from '../access/isAdmin';
import { isAdminOrSelf } from '../access/isAdminOrSelf';
const Users: CollectionConfig = {
slug: 'users',
auth: true,
admin: {
defaultColumns: ["roles", "email"],
useAsTitle: 'email',
},
access: {
create: isAdmin,
read: isAdminOrSelf,
update: isAdminOrSelf,
delete: isAdmin,
read: () => true,
},
fields: [
// Email added by default
{
name: 'roles',
type: 'select',
options: [
{ label: 'ssg', value: 'ssg' }, //cRud
{ 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: isAdminFieldLevel,
read: () => true,
update: isAdminFieldLevel,
},
},
name: 'name',
type: 'text',
}
],
};

View File

@ -2,19 +2,12 @@ import { buildConfig } from "payload/config";
import path from "path";
import Posts from "@/collections/Posts";
import Users from "@/collections/Users";
import Authors from "./collections/Authors";
import Media from "@/collections/Media";
import { payloadCloud } from '@payloadcms/plugin-cloud'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { webpackBundler } from '@payloadcms/bundler-webpack'
import { slateEditor } from '@payloadcms/richtext-slate'
export default buildConfig({
serverURL: process.env.PAYLOAD_URL,
admin: {
user: Users.slug,
bundler: webpackBundler(),
webpack: (config) => ({
...config,
resolve: {
@ -26,13 +19,8 @@ export default buildConfig({
},
}),
},
collections: [Posts, Users, Authors, Media],
collections: [Posts, Users, Media],
typescript: {
outputFile: path.resolve("../", "payload-types.ts"),
outputFile: path.resolve("/", "types.ts"),
},
plugins: [payloadCloud()],
editor: slateEditor({}),
db: mongooseAdapter({
url: process.env.MONGODB_URI,
}),
});

View File

@ -1,17 +0,0 @@
import { Payload } from "payload";
import { User } from "@/types/payload-types";
export const seed = async (payload: Payload): Promise<void> => {
// Local API methods skip all access control by default
// so we can easily create an admin user directly in init
/* Disable to prevent mistakes */
/* await payload.create<User>({
collection: 'users',
data: {
email: 'astro@ssg.js',
password: 'password',
roles: ['ssg']
}
}) */
}

View File

@ -10,7 +10,7 @@ app.get("/", (_, res) => {
payload.init({
secret: process.env.PAYLOAD_SECRET,
//mongoURL: process.env.MONGODB_URI,
mongoURL: process.env.MONGODB_URI,
express: app,
onInit: () => {
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`);

View File

@ -7,8 +7,7 @@
"skipLibCheck": true,
"outDir": "./dist",
"paths": {
"@/*": ["./src/*", "./dist/*", "./dist/src/*"],
"@/types/*": ["../*"]
"@/*": ["./src/*", "./dist/*", "./dist/src/*"]
},
"jsx": "react"
},

File diff suppressed because it is too large Load Diff