Compare commits

...

21 Commits
v0.1 ... main

Author SHA1 Message Date
Guillaume Dorce f9cf446671 install sharp for images 2023-08-12 19:40:51 +02:00
Guillaume Dorce 2aa9f0462f create EditorRender, fix data init in column component, render on home 2023-06-04 19:03:10 +02:00
Guillaume Dorce 984b1cf428 add files colection to upload files to pb 2023-06-04 16:30:06 +02:00
Guillaume Dorce bb48ae89a2 fix data retrieving in the column editor 2023-06-04 16:01:45 +02:00
Guillaume Dorce d3ba83e9ed render x columns properly 2023-06-02 22:17:04 +02:00
Guillaume Dorce e4d7cb003b edit page with a get parameter 2023-06-02 21:54:56 +02:00
Guillaume Dorce fe0084a946 nested editorjs in columns. hardcoded to 2 for now 2023-05-30 17:25:15 +02:00
Guillaume Dorce de946b7e7c remove docker-build action 2023-05-29 12:13:52 +02:00
Guillaume Dorce a5eb0ec073
Update docker-image.yml 2023-05-26 20:49:37 +02:00
Guillaume Dorce f9c04216db
Update stack-definition.yml
fully working conf
2023-05-26 20:48:46 +02:00
Guillaume Dorce d7bee941da
Update stack-definition.yml 2023-05-26 19:49:52 +02:00
Guillaume Dorce d9bb913e82
Update stack-definition.yml 2023-05-26 19:44:41 +02:00
Guillaume Dorce 6f0dd1703d
Update stack-definition.yml 2023-05-26 19:41:31 +02:00
Guillaume Dorce c8ed0a4823
Update deploy-portainer.yml 2023-05-26 19:19:20 +02:00
Guillaume Dorce 4c3b541472
Update stack-definition.yml 2023-05-26 19:14:55 +02:00
Guillaume Dorce 68eb61795f
Update deploy-portainer.yml 2023-05-26 19:12:18 +02:00
Guillaume Dorce c6f6401e81 config for github actions environnement 2023-05-26 16:17:04 +02:00
Guillaume Dorce e48ad1b1e1
Create stack-definition.yml for portainer 2023-05-26 15:48:37 +02:00
Guillaume Dorce 5f91eae7a9
Create deploy-portainer.yml 2023-05-26 15:43:16 +02:00
Guillaume Dorce 73afd42d9e fix config for docker and import in getServerSideProps 2023-05-26 15:12:07 +02:00
Guillaume Dorce 3c36d1c169
Create docker-image.yml 2023-05-26 12:34:38 +02:00
17 changed files with 666 additions and 121 deletions

53
.github/workflows/deploy-portainer.yml vendored Normal file
View File

@ -0,0 +1,53 @@
name: Deploy
on:
workflow_dispatch:
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
timeout-minutes: 5
environment: "Prod Grossebeuteu"
env:
GITHUB_REF: ${{ github.ref }}
DOCKER_REGISTRY: ghcr.io
DOCKER_IMAGE: polynux/pchl
steps:
- uses: actions/checkout@v2
- name: Creating envs
run: |
echo "IMAGE_TAG=sha-$(git rev-parse --short HEAD)" >> $GITHUB_ENV
echo "DOCKER_IMAGE_URI=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}" >> $GITHUB_ENV
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build docker image and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ env.DOCKER_IMAGE_URI }}:${{ env.IMAGE_TAG }},${{ env.DOCKER_IMAGE_URI }}:latest
- name: Sleep for 10 seconds
run: sleep 10s
shell: bash
- name: Deploy stack to Portainer
uses: carlrygart/portainer-stack-deploy@v1.3.0
with:
portainer-host: ${{ secrets.PORTAINER_HOST }}
username: ${{ secrets.PORTAINER_USERNAME }}
password: ${{ secrets.PORTAINER_PASSWORD }}
stack-name: 'pchl'
stack-definition: 'stack-definition.yml'
template-variables: '{"PB_API": "${{ secrets.PB_API }}"}'
image: ${{ env.DOCKER_IMAGE_URI }}:${{ env.IMAGE_TAG }}

View File

@ -18,17 +18,17 @@ RUN \
##### BUILDER
FROM --platform=linux/amd64 node:16-alpine3.17 AS builder
ARG PB_API
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED 1
ENV SKIP_ENV_VALIDATION 1
RUN \
if [ -f yarn.lock ]; then SKIP_ENV_VALIDATION=1 yarn build; \
elif [ -f package-lock.json ]; then SKIP_ENV_VALIDATION=1 npm run build; \
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && SKIP_ENV_VALIDATION=1 pnpm run build; \
if [ -f yarn.lock ]; then yarn build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi

View File

@ -38,6 +38,7 @@
"react-dom": "18.2.0",
"react-editor-js": "^2.1.0",
"react-icons": "^4.8.0",
"sharp": "^0.32.4",
"superjson": "1.9.1",
"zod": "^3.21.4"
},

View File

@ -82,6 +82,9 @@ dependencies:
react-icons:
specifier: ^4.8.0
version: 4.8.0(react@18.2.0)
sharp:
specifier: ^0.32.4
version: 0.32.4
superjson:
specifier: 1.9.1
version: 1.9.1
@ -459,14 +462,14 @@ packages:
resolution: {integrity: sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==}
hasBin: true
dependencies:
detect-libc: 2.0.1
detect-libc: 2.0.2
https-proxy-agent: 5.0.1
make-dir: 3.1.0
node-fetch: 2.6.11
nopt: 5.0.0
npmlog: 5.0.1
rimraf: 3.0.2
semver: 7.5.0
semver: 7.5.4
tar: 6.1.14
transitivePeerDependencies:
- encoding
@ -589,7 +592,7 @@ packages:
resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==}
dependencies:
'@gar/promisify': 1.1.3
semver: 7.5.0
semver: 7.5.4
dev: true
optional: true
@ -1148,6 +1151,10 @@ packages:
deep-equal: 2.2.1
dev: true
/b4a@1.6.4:
resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==}
dev: false
/babel-plugin-macros@3.1.0:
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
engines: {node: '>=10', npm: '>=6'}
@ -1161,6 +1168,10 @@ packages:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: false
/big-integer@1.6.51:
resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
engines: {node: '>=0.6'}
@ -1171,6 +1182,14 @@ packages:
engines: {node: '>=8'}
dev: true
/bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
dependencies:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.2
dev: false
/bplist-parser@0.2.0:
resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==}
engines: {node: '>= 5.10.0'}
@ -1203,6 +1222,13 @@ packages:
update-browserslist-db: 1.0.11(browserslist@4.21.5)
dev: true
/buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
dev: false
/bundle-name@3.0.0:
resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==}
engines: {node: '>=12'}
@ -1295,6 +1321,10 @@ packages:
fsevents: 2.3.2
dev: true
/chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
dev: false
/chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
engines: {node: '>=10'}
@ -1321,7 +1351,6 @@ packages:
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: true
/color-name@1.1.3:
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
@ -1329,13 +1358,27 @@ packages:
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
/color-string@1.9.1:
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
dependencies:
color-name: 1.1.4
simple-swizzle: 0.2.2
dev: false
/color-support@1.1.3:
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
hasBin: true
dev: true
/color@4.2.3:
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
engines: {node: '>=12.5.0'}
dependencies:
color-convert: 2.0.1
color-string: 1.9.1
dev: false
/combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
@ -1436,6 +1479,13 @@ packages:
ms: 2.1.2
dev: true
/decompress-response@6.0.0:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
engines: {node: '>=10'}
dependencies:
mimic-response: 3.1.0
dev: false
/deep-equal@2.2.1:
resolution: {integrity: sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==}
dependencies:
@ -1459,6 +1509,11 @@ packages:
which-typed-array: 1.1.9
dev: true
/deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
dev: false
/deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
@ -1509,10 +1564,9 @@ packages:
dev: true
optional: true
/detect-libc@2.0.1:
resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==}
/detect-libc@2.0.2:
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
engines: {node: '>=8'}
dev: true
/didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
@ -1589,6 +1643,12 @@ packages:
dev: true
optional: true
/end-of-stream@1.4.4:
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
dependencies:
once: 1.4.0
dev: false
/enhanced-resolve@5.14.0:
resolution: {integrity: sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==}
engines: {node: '>=10.13.0'}
@ -2024,10 +2084,19 @@ packages:
strip-final-newline: 3.0.0
dev: true
/expand-template@2.0.3:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
dev: false
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
/fast-fifo@1.3.0:
resolution: {integrity: sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==}
dev: false
/fast-glob@3.2.12:
resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
engines: {node: '>=8.6.0'}
@ -2110,6 +2179,10 @@ packages:
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
dev: true
/fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
dev: false
/fs-minipass@2.1.0:
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
engines: {node: '>= 8'}
@ -2201,6 +2274,10 @@ packages:
resolution: {integrity: sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==}
dev: true
/github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
dev: false
/glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@ -2404,6 +2481,10 @@ packages:
dev: true
optional: true
/ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: false
/ignore@5.2.4:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
@ -2441,7 +2522,10 @@ packages:
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true
/ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
dev: false
/internal-slot@1.0.5:
resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
@ -2477,6 +2561,10 @@ packages:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
dev: false
/is-arrayish@0.3.2:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
dev: false
/is-bigint@1.0.4:
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
dependencies:
@ -2767,7 +2855,6 @@ packages:
engines: {node: '>=10'}
dependencies:
yallist: 4.0.0
dev: true
/make-dir@3.1.0:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
@ -2841,6 +2928,11 @@ packages:
engines: {node: '>=12'}
dev: true
/mimic-response@3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
dev: false
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
@ -2849,7 +2941,6 @@ packages:
/minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
dev: true
/minipass-collect@1.0.2:
resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==}
@ -2915,6 +3006,10 @@ packages:
yallist: 4.0.0
dev: true
/mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
dev: false
/mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'}
@ -2942,6 +3037,10 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
/napi-build-utils@1.0.2:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
dev: false
/natural-compare-lite@1.4.0:
resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
dev: true
@ -3001,10 +3100,21 @@ packages:
- babel-plugin-macros
dev: false
/node-abi@3.45.0:
resolution: {integrity: sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==}
engines: {node: '>=10'}
dependencies:
semver: 7.5.4
dev: false
/node-addon-api@4.3.0:
resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==}
dev: true
/node-addon-api@6.1.0:
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
dev: false
/node-fetch@2.6.11:
resolution: {integrity: sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==}
engines: {node: 4.x || >=6.0.0}
@ -3030,7 +3140,7 @@ packages:
nopt: 5.0.0
npmlog: 6.0.2
rimraf: 3.0.2
semver: 7.5.0
semver: 7.5.4
tar: 6.1.14
which: 2.0.2
transitivePeerDependencies:
@ -3170,7 +3280,6 @@ packages:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
dev: true
/onetime@5.1.2:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
@ -3389,6 +3498,25 @@ packages:
source-map-js: 1.0.2
dev: true
/prebuild-install@7.1.1:
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
engines: {node: '>=10'}
hasBin: true
dependencies:
detect-libc: 2.0.2
expand-template: 2.0.3
github-from-package: 0.0.0
minimist: 1.2.8
mkdirp-classic: 0.5.3
napi-build-utils: 1.0.2
node-abi: 3.45.0
pump: 3.0.0
rc: 1.2.8
simple-get: 4.0.1
tar-fs: 2.1.1
tunnel-agent: 0.6.0
dev: false
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@ -3479,6 +3607,13 @@ packages:
react-is: 16.13.1
dev: true
/pump@3.0.0:
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
dependencies:
end-of-stream: 1.4.4
once: 1.4.0
dev: false
/punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
@ -3488,6 +3623,20 @@ packages:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
/queue-tick@1.0.1:
resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
dev: false
/rc@1.2.8:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true
dependencies:
deep-extend: 0.6.0
ini: 1.3.8
minimist: 1.2.8
strip-json-comments: 2.0.1
dev: false
/react-dom@18.2.0(react@18.2.0):
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
peerDependencies:
@ -3549,7 +3698,6 @@ packages:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
dev: true
/readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
@ -3624,7 +3772,6 @@ packages:
/safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: true
/safe-regex-test@1.0.0:
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
@ -3658,10 +3805,32 @@ packages:
lru-cache: 6.0.0
dev: true
/semver@7.5.4:
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
engines: {node: '>=10'}
hasBin: true
dependencies:
lru-cache: 6.0.0
/set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
dev: true
/sharp@0.32.4:
resolution: {integrity: sha512-exUnZewqVZC6UXqXuQ8fyJJv0M968feBi04jb9GcUHrWtkRoAKnbJt8IfwT4NJs7FskArbJ14JAFGVuooszoGg==}
engines: {node: '>=14.15.0'}
requiresBuild: true
dependencies:
color: 4.2.3
detect-libc: 2.0.2
node-addon-api: 6.1.0
prebuild-install: 7.1.1
semver: 7.5.4
simple-get: 4.0.1
tar-fs: 3.0.4
tunnel-agent: 0.6.0
dev: false
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@ -3686,6 +3855,24 @@ packages:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: true
/simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
dev: false
/simple-get@4.0.1:
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
dependencies:
decompress-response: 6.0.0
once: 1.4.0
simple-concat: 1.0.1
dev: false
/simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
dependencies:
is-arrayish: 0.3.2
dev: false
/slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
@ -3774,6 +3961,13 @@ packages:
engines: {node: '>=10.0.0'}
dev: false
/streamx@2.15.1:
resolution: {integrity: sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==}
dependencies:
fast-fifo: 1.3.0
queue-tick: 1.0.1
dev: false
/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@ -3825,7 +4019,6 @@ packages:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
dependencies:
safe-buffer: 5.2.1
dev: true
/strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
@ -3849,6 +4042,11 @@ packages:
engines: {node: '>=12'}
dev: true
/strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
dev: false
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
@ -3959,6 +4157,42 @@ packages:
engines: {node: '>=6'}
dev: true
/tar-fs@2.1.1:
resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
dependencies:
chownr: 1.1.4
mkdirp-classic: 0.5.3
pump: 3.0.0
tar-stream: 2.2.0
dev: false
/tar-fs@3.0.4:
resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==}
dependencies:
mkdirp-classic: 0.5.3
pump: 3.0.0
tar-stream: 3.1.6
dev: false
/tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
dependencies:
bl: 4.1.0
end-of-stream: 1.4.4
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.2
dev: false
/tar-stream@3.1.6:
resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
dependencies:
b4a: 1.6.4
fast-fifo: 1.3.0
streamx: 2.15.1
dev: false
/tar@6.1.14:
resolution: {integrity: sha512-piERznXu0U7/pW7cdSn7hjqySIVTYT6F76icmFk7ptU7dDYlXTm5r9A6K04R2vU3olYgoKeo1Cg3eeu5nhftAw==}
engines: {node: '>=10'}
@ -4039,6 +4273,12 @@ packages:
typescript: 4.9.5
dev: true
/tunnel-agent@0.6.0:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
dependencies:
safe-buffer: 5.2.1
dev: false
/type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@ -4120,7 +4360,6 @@ packages:
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: true
/vanilla-caret-js@1.1.0:
resolution: {integrity: sha512-vl3R4Xjqb+xnM0gYyg+wcqWGYwKKnkz58Yj29/FQB+w+yP7R8IR1DGoJnDIs05moEZiGlQUTabPMoEtnQNcrpQ==}
@ -4189,11 +4428,9 @@ packages:
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: true
/yaml@1.10.2:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}

View File

@ -3,6 +3,7 @@
*/
export enum Collections {
Files = "files",
Pages = "pages",
Users = "users",
}
@ -31,6 +32,10 @@ export type AuthSystemFields<T = never> = {
// Record types for each collection
export type FilesRecord = {
file: string
}
export type PagesRecord<Tcontent = unknown> = {
content?: null | Tcontent
title?: string
@ -44,17 +49,20 @@ export type UsersRecord = {
}
// Response types include system fields and match responses from the PocketBase API
export type FilesResponse = Required<FilesRecord> & BaseSystemFields
export type PagesResponse<Tcontent = unknown> = Required<PagesRecord<Tcontent>> & BaseSystemFields
export type UsersResponse = Required<UsersRecord> & AuthSystemFields
// Types containing all Records and Responses, useful for creating typing helper functions
export type CollectionRecords = {
files: FilesRecord
pages: PagesRecord
users: UsersRecord
}
export type CollectionResponses = {
files: FilesResponse
pages: PagesResponse
users: UsersResponse
}

View File

@ -0,0 +1,111 @@
import { PagesRecord } from "@/@types/pocketbase-types";
function parseBoldText(text: string) {
const parts = text.split(/(<b>.*?<\/b>)/g);
const result = [];
for (let i = 0; i < parts.length; i++) {
if (parts[i]?.startsWith('<b>')) {
result.push(<b key={i}>{parts[i]?.slice(3, -4)}</b>)
} else {
result.push(parts[i])
}
}
return result;
}
function Paragraph({ text }: { text: string }) {
return <p className='text-xl'>{parseBoldText(text)}</p>
}
function Heading({ text, level }: { text: string, level: number }) {
switch (level) {
case 1:
return (
<>
<h1 className='font-poppins text-5xl'>{text}</h1>
<div className="line h-1 w-full bg-black"></div>
</>
)
case 2:
return <h2 className='text-2xl'>{text}</h2>
case 3:
return <h3>{text}</h3>
default:
return <h4>{text}</h4>
}
}
function Column({ blocksData }: { blocksData: Block[][] }) {
if (blocksData.length === 0) return null;
return (
<div className="mb-4 flex flex-row gap-10">
{blocksData.map((blocks, i) => {
return (<div className="flex flex-col gap-6 w-1/2" key={"col-" + i}>{blocks.map(block => {
switch (block.type) {
case 'paragraph':
return <Paragraph key={block.id} text={block.data.text} />
case 'header':
return <Heading key={block.id} text={block.data.text} level={block.data.level} />
default:
return null;
}
})}</div>)
})}
</div>
)
}
type ParagraphBlock = {
type: 'paragraph',
data: {
text: string,
},
id: string,
}
type HeaderBlock = {
type: 'header',
data: {
text: string,
level: number,
},
id: string,
}
type ColumnBlock = {
type: 'column',
data: {
blocksData: Block[][],
},
id: string,
}
type Block = ParagraphBlock | HeaderBlock | ColumnBlock;
export type Content = {
blocks: Block[],
version: string,
time: number,
}
export default function EditorRender({ data, className }: { data: PagesRecord<Content>, className?: string }) {
return (
<div className={className}>
{data.content && data.content.blocks.map((block, index): (JSX.Element | null) => {
switch (block.type) {
case 'paragraph':
return <Paragraph key={index} text={block.data.text} />
case 'header':
return <Heading key={index} text={block.data.text} level={block.data.level} />
case 'column':
return <Column key={index} blocksData={block.data.blocksData} />
default:
return <p key={index}>Unknown block type: <pre>{JSON.stringify(block, null, 2)}</pre></p>
}
})}
</div>
)
}
export { EditorRender };

View File

@ -1,26 +1,51 @@
import { memo, useEffect, useRef } from "react";
import EditorJS from "@editorjs/editorjs";
import EditorJS, { ToolConstructable } from "@editorjs/editorjs";
import type { OutputData } from "@editorjs/editorjs";
import { EDITOR_JS_TOOLS } from "@/utils/tools";
// @ts-expect-error Undo is not a valid tool
import Undo from "editorjs-undo";
// @ts-expect-error DragDrop is not a valid tool
import DragDrop from "editorjs-drag-drop";
import ColumnTool from "@/utils/editor-tools/column";
import "@/styles/editor.css";
type Props = {
data?: OutputData;
onChange(val: OutputData): void;
holder: string;
autofocus?: boolean;
};
const EditorBlock = ({ data, onChange, holder }: Props) => {
const EditorBlock = ({ data, onChange, holder, autofocus }: Props) => {
const ref = useRef<EditorJS>();
useEffect(() => {
if (!ref.current) {
const editor = new EditorJS({
holder: holder,
tools: EDITOR_JS_TOOLS,
tools: {
...EDITOR_JS_TOOLS,
column: {
class: ColumnTool as ToolConstructable,
config: {
tools: EDITOR_JS_TOOLS,
},
},
},
data,
autofocus,
onReady: () => {
new Undo({ editor });
new DragDrop(editor);
},
async onChange(api) {
const data = await api.saver.save();
onChange(data);
try {
const data = await api.saver.save();
onChange(data);
} catch (error) {
console.log("Saving failed: ", error);
}
},
});
ref.current = editor;
@ -37,4 +62,3 @@ const EditorBlock = ({ data, onChange, holder }: Props) => {
};
export default memo(EditorBlock);

View File

@ -1,7 +1,9 @@
import Image from "next/image";
import Layout from "@/layouts/Home";
import { PagesRecord } from "@/@types/pocketbase-types";
import { Content, EditorRender } from "@/components/EditorRender";
function Home() {
function Home({ data }: { data: PagesRecord<Content>}) {
return (
<Layout title="Accueil">
<Image
@ -75,8 +77,27 @@ function Home() {
</div>
</div>
</div>
<div className="container mx-auto p-8">
<EditorRender data={data} />
</div>
</Layout>
);
}
export default Home;
export async function getServerSideProps() {
const { getPageBySlug } = await import("@/utils/pb");
const { data, error } = await getPageBySlug("home");
if (error || !data) {
return {
notFound: true,
}
}
return {
props: {
data: data,
},
}
}

View File

@ -1,5 +1,4 @@
import Layout from "@/layouts/Home"
import { getPages } from "@/utils/pb"
import type { PagesRecord } from "@/@types/pocketbase-types"
export default function Test({ json }: { json: PagesRecord[]}) {
@ -18,6 +17,7 @@ export default function Test({ json }: { json: PagesRecord[]}) {
}
export async function getServerSideProps() {
const { getPages } = await import("@/utils/pb")
const {data, error} = await getPages();
if (error || !data) {

View File

@ -1,84 +1,14 @@
import type { PagesRecord } from '@/@types/pocketbase-types';
import Layout from '@/layouts/Home'
import { getPageBySlug } from '@/utils/pb'
import EditorRender from '@/components/EditorRender';
import type { Content } from '@/components/EditorRender';
function parseBoldText(text: string) {
const parts = text.split(/(<b>.*?<\/b>)/g);
const result = [];
for (let i = 0; i < parts.length; i++) {
if (parts[i]?.startsWith('<b>')) {
result.push(<b key={i}>{parts[i]?.slice(3, -4)}</b>)
} else {
result.push(parts[i])
}
}
return result;
}
function Paragraph({ text }: { text: string }) {
return <p className='text-xl'>{parseBoldText(text)}</p>
}
function Heading({ text, level }: { text: string, level: number }) {
switch (level) {
case 1:
return (
<>
<h1 className='font-poppins text-5xl'>{text}</h1>
<div className="line h-1 w-full bg-black"></div>
</>
)
case 2:
return <h2 className='text-2xl'>{text}</h2>
case 3:
return <h3>{text}</h3>
default:
return <h4>{text}</h4>
}
}
type ParagraphBlock = {
type: 'paragraph',
data: {
text: string,
},
id: string,
}
type HeaderBlock = {
type: 'header',
data: {
text: string,
level: number,
},
id: string,
}
type Block = ParagraphBlock | HeaderBlock;
type Content = {
blocks: Block[],
version: string,
time: number,
}
export default function Page({ data }: { slug: string, data: PagesRecord<Content> }) {
export default function Page({ data }: { data: PagesRecord<Content> }) {
return (
<Layout title={data.title}>
<div className="container mx-auto p-8">
<p>Here is the content rendered:</p>
<div className="flex flex-col gap-6">
{data.content && data.content.blocks.map((block, index): (JSX.Element | null) => {
switch (block.type) {
case 'paragraph':
return <Paragraph key={index} text={block.data.text} />
case 'header':
return <Heading key={index} text={block.data.text} level={block.data.level} />
default:
return <p key={index}>Unknown block type: <pre>{JSON.stringify(block, null, 2)}</pre></p>
}
})}
</div>
<EditorRender data={data} />
</div>
<pre>{JSON.stringify(data.content, null, 2)}</pre>
</Layout>
@ -86,6 +16,7 @@ export default function Page({ data }: { slug: string, data: PagesRecord<Content
}
export async function getServerSideProps({ params }: { params: { slug: string } }) {
const { getPageBySlug } = await import("@/utils/pb");
const { data, error } = await getPageBySlug(params.slug);
if (error || !data) {
return {

View File

@ -2,14 +2,15 @@ import dynamic from 'next/dynamic'
import Layout from '@/layouts/Home'
import { useState } from 'react'
import { OutputData } from "@editorjs/editorjs";
import { getPageBySlug } from '@/utils/pb';
import { api } from '@/utils/api';
const ReactEditorJS = dynamic(() => import('@/components/ReactEditor'), {
ssr: false
})
export default function Editor() {
const [data, setData] = useState<OutputData>()
export default function Editor({data: pbData, slug, title}: {data: OutputData, slug: string, title: string}) {
const [data, setData] = useState<OutputData>(pbData);
const {mutate, isLoading, data: data2, isError} = api.pages.updatePage.useMutation();
if (data2) console.log(data2)
@ -17,14 +18,14 @@ export default function Editor() {
const handleSubmit = () => {
if (!data) return
mutate({
slug: 'test',
title: 'Test',
slug,
title,
content: data
})
}
return (
<Layout title='EditorJS'>
<Layout title={'Edition de ' + title}>
<button onClick={handleSubmit}>Save</button>
{isLoading && <p>Loading...</p>}
{data2 && !isError && <p>Saved!</p>}
@ -34,7 +35,7 @@ export default function Editor() {
<div className="container mx-auto p-8">
<h2>EditorJS with React</h2>
<div>
<ReactEditorJS data={data} onChange={setData} holder='editorjs' />
<ReactEditorJS autofocus data={data} onChange={setData} holder='editorjs' />
</div>
<h2>Output</h2>
<pre>{JSON.stringify(data, null, 2)}</pre>
@ -42,3 +43,19 @@ export default function Editor() {
</Layout>
)
}
export async function getServerSideProps({query}: {query: {[key: string]: string}}) {
if (!query.page) return {notFound: true}
const data = await getPageBySlug(query.page);
if (!data.data) return {notFound: true};
return {
props: {
data: data.data.content,
slug: query.page,
title: data.data.title
}
}
}

View File

@ -1,5 +1,4 @@
import type { PagesRecord } from "@/@types/pocketbase-types";
import { getPages } from "@/utils/pb";
import Layout from "@/layouts/Home";
export default function ListPages({ data }: { data: PagesRecord[] }) {
@ -22,6 +21,7 @@ export default function ListPages({ data }: { data: PagesRecord[] }) {
}
export async function getServerSideProps() {
const { getPages } = await import("@/utils/pb");
const { data, error } = await getPages();
if (error || !data) {
return {

7
src/styles/editor.css Normal file
View File

@ -0,0 +1,7 @@
.ce-block .ce-block__content {
max-width: unset;
}
.ce-toolbar .ce-toolbar__content {
max-width: unset;
}

View File

@ -0,0 +1,97 @@
import EditorJS, { BlockToolData, OutputBlockData, ToolConstructable } from "@editorjs/editorjs";
import { EDITOR_JS_TOOLS } from "../tools";
type ColumnData = {
blocksData: OutputBlockData[][];
};
type ColumnConfig = {
tools: ToolConstructable[] | any;
};
class ColumnTool {
private data: ColumnData;
private wrapper: HTMLElement | undefined;
private tools: { [name: symbol]: any };
private editors: EditorJS[];
constructor({ data, config }: { data?: ColumnData; config?: ColumnConfig }) {
console.log("ColumnTool constructor");
console.log(data);
this.data = data ?? { blocksData: [[]] };
this.wrapper = undefined;
this.tools = config?.tools ?? EDITOR_JS_TOOLS;
this.editors = [];
}
static get toolbox() {
return {
title: "Column",
icon: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M0 96C0 60.7 28.7 32 64 32H448c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zm64 64V416H224V160H64zm384 0H288V416H448V160z"/></svg>`,
};
}
static get enableLineBreaks() {
return true;
}
createColumn() {
const column = document.createElement("div");
column.classList.add(
"flex",
"flex-col",
"w-1/2",
"border",
"border-gray-300",
"rounded-md"
);
return column;
}
render() {
if (!this.wrapper) this.wrapper = document.createElement("div");
const child = document.createElement("div");
child.classList.add("flex", "flex-row", "w-full", "space-x-4");
const blocksData: BlockToolData[] = this.data.blocksData?.length > 0 ? this.data.blocksData : [[]];
for (let i = 0; i < 2; i++) {
if (this.editors[i]) return;
const column = this.createColumn();
child.appendChild(column);
const editor = new EditorJS({
holder: column,
tools: this.tools,
async onChange(api) {
const data = await api.saver.save();
blocksData[i] = data.blocks;
},
data: {
blocks: blocksData ? blocksData[i] : [],
},
});
this.editors.push(editor);
}
this.wrapper.appendChild(child);
this.data.blocksData = blocksData;
return this.wrapper;
}
save() {
return {
blocksData: this.data.blocksData,
};
}
destroy() {
this.editors.forEach((editor) => editor.destroy());
this.wrapper?.remove();
}
}
export default ColumnTool;

View File

@ -68,4 +68,34 @@ async function getIdFromSlug(slug: string) {
}
}
export async function uploadFile(file: File) {
try {
const res = await pb.collection("files").create(file);
return { data: res };
} catch (error) {
console.log(error);
return { error };
}
}
export async function listFiles() {
try {
const res = await pb.collection("files").getFullList();
return { data: res };
} catch (error) {
console.log(error);
return { error };
}
}
export async function getFile(id: string) {
try {
const res = await pb.collection("files").getOne(id);
return { data: res };
} catch (error) {
console.log(error);
return { error };
}
}
export { pb, getPages, getPageById, getPageBySlug, createPage, updatePage, getIdFromSlug };

View File

@ -4,10 +4,7 @@ import List from "@editorjs/list";
import SimpleImage from "@editorjs/simple-image";
import Table from "@editorjs/table";
import Button from "editorjs-button";
import Undo from "editorjs-undo";
import DragDrop from "editorjs-drag-drop";
import Color from "editorjs-text-color-plugin";
import { ItalicInlineTool, StrongInlineTool, UnderlineInlineTool } from "editorjs-inline-tool";
export const EDITOR_JS_TOOLS = {
paragraph: {
@ -22,10 +19,5 @@ export const EDITOR_JS_TOOLS = {
image: SimpleImage,
table: Table,
button: Button,
undo: Undo,
dragDrop: DragDrop,
italic: ItalicInlineTool,
strong: StrongInlineTool,
underline: UnderlineInlineTool,
color: Color,
}
};

16
stack-definition.yml Normal file
View File

@ -0,0 +1,16 @@
version: '3.7'
services:
pchl:
image: ghcr.io/polynux/pchl:latest
volumes:
- pchl:/app
environment:
- PB_API={{PB_API}}
ports:
- "19080:19080"
deploy:
update_config:
order: start-first
volumes:
pchl: