Compare commits
449 Commits
Author | SHA1 | Date | |
---|---|---|---|
09d677bd37
|
|||
db1159f20c
|
|||
af5c845e4b
|
|||
3f66dfe46e
|
|||
d52a0c6f08
|
|||
251b0b4038
|
|||
a5baffe9eb
|
|||
1351e4122d
|
|||
4c69d5a852
|
|||
9e840b8dae
|
|||
59153a7a69
|
|||
0a7094005c
|
|||
12f1d6cdf2
|
|||
0d7b33727b
|
|||
386f407f21
|
|||
6853ac6884
|
|||
b199aedf77
|
|||
da4b483a3c
|
|||
012fea869f
|
|||
a596d1c443
|
|||
b4611e4a7f
|
|||
b5c50728de
|
|||
ceeeb2f9c5
|
|||
c094b37bca
|
|||
8dde7f5b42
|
|||
cef5ead09f
|
|||
7bde328b96
|
|||
0f44e64c0c
|
|||
84c192bbef
|
|||
6f78a0686c
|
|||
2897d181c5
|
|||
f94ce7d7bc
|
|||
dd09092842
|
|||
f64acb68c7
|
|||
3074945c54
|
|||
fc0dfdda5f
|
|||
f62964c62a
|
|||
8ec113c9cb
|
|||
8a59e9034f
|
|||
d7121ea833
|
|||
c10f690622
|
|||
6915072ab9
|
|||
dd803bcc51
|
|||
efa33f26ec
|
|||
5f3dfad988
|
|||
b231381cb3
|
|||
bbb2e56512
|
|||
66cf6d7438
|
|||
2a635bf3ba
|
|||
9f79b88202
|
|||
23d9caf578
|
|||
7febe6d1f9
|
|||
c4650c34d9
|
|||
0eb780485c
|
|||
cd5e92b64a
|
|||
982b148329
|
|||
0febee5b51
|
|||
3502f51735
|
|||
493df4e2f2
|
|||
c2c9b59c7a
|
|||
f6e3008ab9
|
|||
15e94cec64
|
|||
5185c6758b
|
|||
b633eef833
|
|||
d2e627ff13
|
|||
1e0567b538
|
|||
c8d32c6acc
|
|||
05503cda26
|
|||
303b6f3011
|
|||
0272cf7080
|
|||
e8ea42a260
|
|||
f337e14260
|
|||
f5020cad19
|
|||
b8ceefb2f6
|
|||
1523c8cac0
|
|||
548ddc8425
|
|||
bac65ad61a
|
|||
b91f3165b7
|
|||
5478e202a7
|
|||
a89b5932c2
|
|||
339e42acfa
|
|||
c123815a86
|
|||
dd26a277a2
|
|||
62222dbb0c
|
|||
ee0a02bc8b
|
|||
2e04053ec3
|
|||
45a9a69122
|
|||
e566ef6c38
|
|||
c7ad15a465
|
|||
f4a842efb5
|
|||
424c97019b
|
|||
c0508dc0b9
|
|||
f04d8a0c11
|
|||
d29064745c
|
|||
95febe2a99
|
|||
fdab2a7ea8
|
|||
35211fa279
|
|||
137cceffa1
|
|||
f6bfc466de
|
|||
e4cf714d95
|
|||
d3c86b2a26
|
|||
d2578abeec
|
|||
e51e3bdc19
|
|||
56520830e9
|
|||
2e0138194c
|
|||
4b2e7bae90
|
|||
caa6a90418
|
|||
e82db952db
|
|||
6b29ce9b15
|
|||
5640f1b434
|
|||
6d0dcb50a7
|
|||
70603f1444
|
|||
f42fdbfd0c
|
|||
6a3f335f9f
|
|||
f1509d0af1
|
|||
49599d25ed
|
|||
65e0f4f8b6
|
|||
8d60c2d53a
|
|||
0bbebeab99
|
|||
643e0e5821
|
|||
872b018673
|
|||
2644cb0fb5
|
|||
bc719578d2
|
|||
117c41b1c3
|
|||
b92704b77d
|
|||
bab7581283
|
|||
988fceb2aa
|
|||
5211ba1489
|
|||
6886480cef
|
|||
d78e50638e
|
|||
3b76195d71
|
|||
2dc63ba933
|
|||
336f067c52
|
|||
5fd7f77b6d
|
|||
db0c708c04
|
|||
9d44671fed
|
|||
7bcc5f972c | |||
61172d59e3 | |||
7c0f11ab7d | |||
670897fa78 | |||
b88246b668 | |||
87fbfe4940 | |||
271aa60247 | |||
ba34e314c9 | |||
f41bc644b1 | |||
a18cec4826 | |||
61e589f0f4 | |||
dc5c3cee41 | |||
20cb0c21d5 | |||
e5232c1394 | |||
fd51609713 | |||
edf16c2562 | |||
94e0d190ae | |||
b1cf7f8517 | |||
a1a715d3b9 | |||
eede46fb41 | |||
e32c53caa1 | |||
361ea37deb | |||
d49a8a7470 | |||
a4996c8251 | |||
b25451e631 | |||
042a861f58 | |||
d76db36dbc | |||
99d9dcf334 | |||
ece5ded1b4 | |||
1514600998 | |||
5f5b328895 | |||
c88887a322 | |||
014044573a | |||
df009c3f7b | |||
5c85ca2ef1 | |||
07f7942496 | |||
213a3fa182 | |||
28d9211583 | |||
4d085cb148 | |||
e6c583f2cd | |||
232b54588a | |||
c419fb3bb4 | |||
03e7e22d74 | |||
e85c241ed1 | |||
c1877297f8 | |||
83231197dd | |||
a2fe2205bc | |||
e1f3dceb07 | |||
0f89fee52f | |||
2fcc7ac384 | |||
9351edf626 | |||
1f4aa54211 | |||
8bc1471cbb | |||
1ebdab18a5 | |||
b9b76e839a | |||
bc065a2e19 | |||
5d3a287b27 | |||
fb689c9bc1 | |||
2c3a70df2a | |||
bce254a355 | |||
f67d331416 | |||
6abc881e94 | |||
a67d6665ea | |||
1152039663 | |||
919ebd5f3e | |||
94212f9b5c | |||
bf9347f685 | |||
896b6051e8 | |||
b5f3552c07 | |||
5fbae8601f | |||
48d35776a9 | |||
8b9e58c47c | |||
33078ece66 | |||
a2da9618af | |||
a467ea7aff | |||
0e0036b737 | |||
729e540d04 | |||
e5f4615f7f | |||
0bf89f4df5 | |||
bcb184e49c | |||
1505b81233 | |||
a30355582e | |||
a4effb52f9 | |||
52bba0ef9c | |||
8ecfeca50d | |||
fd0740d12a | |||
bd2dc9c9af | |||
a53888ab42 | |||
624e79eecd | |||
049ec367fc | |||
56f22d0c9b | |||
9adb67662e | |||
010087088f | |||
35d4396e80 | |||
934118737a | |||
b692dac926 | |||
dd582652ab | |||
337352de0c | |||
c513268cbb | |||
4fdcb2b667 | |||
377b8e91a6 | |||
fce29c9d4a | |||
c198f47aa9 | |||
8e051332cd | |||
9f3436e1df | |||
2f2373e62f | |||
c6b455dd10 | |||
4e089b41f2 | |||
6c102b1b35 | |||
52b10944b7 | |||
db36eb3e7a | |||
c739ad951d | |||
2802ff029f | |||
1a7457b44b | |||
ff210f879d | |||
607454b360 | |||
d1522fbf44 | |||
b82eae7499 | |||
73527ce8fe | |||
0cd885ee70 | |||
2cb2df975f | |||
37f5843adb | |||
d794d38f14 | |||
fc5ba28b8a | |||
b5945150b8 | |||
aa12d626d2 | |||
6ac4782b7d | |||
0aa998d593 | |||
56f975e53c | |||
5a16d24ea1 | |||
52267005ec | |||
99b9b12ac9 | |||
2cae77481f | |||
e98b47a459 | |||
4cc87758c1 | |||
1bb0f31223 | |||
af2dd0bd60 | |||
63d7485c8d | |||
74fde0ea40 | |||
0d2b318818 | |||
266b3f8589 | |||
f7d304ca80 | |||
63017953d7 | |||
20600eb976 | |||
7f920b77aa | |||
4f5dfc63ea | |||
712805df93 | |||
cd68f597c9 | |||
7ec3fe8ced | |||
90d22b2c7f | |||
4b06fd0522 | |||
b4427f36c2 | |||
b758c64e02 | |||
04469b83ea | |||
36d54666a0 | |||
a34cefec6e | |||
5c343395df | |||
028815a7b6 | |||
a2ad591d6d | |||
7087911756 | |||
35b1c4169f | |||
4c351b8179 | |||
701dccc018 | |||
5133765f94 | |||
3b208c6614 | |||
52870fd6a4 | |||
3a278fec10 | |||
669f592a9f | |||
9c0a3ea1af | |||
fa8d70bf82 | |||
3293fd488e | |||
426bee09da | |||
dbc6c84895 | |||
fab539c9d7 | |||
176ab64a37 | |||
1b56bbc694 | |||
0f9a968081 | |||
6b9ff4100d | |||
870bc3d26b | |||
41e4b93427 | |||
72ae4ef01d | |||
748259b57c | |||
fafd606c18 | |||
b8c3022532 | |||
46adaee53f | |||
508114152c | |||
b2852d172c | |||
16e3b1e465 | |||
ae610ff816 | |||
7c001f3c30 | |||
7eada755e1 | |||
6909304f15 | |||
25b2f05170 | |||
0cc83a811c | |||
78b14c2620 | |||
eebdf0edd2 | |||
62e8005081 | |||
6473e9da7d | |||
1805997f59 | |||
fb25c12883 | |||
849b758fab | |||
ccf5d42c19 | |||
2d68ce59ca | |||
4e6531e341 | |||
8f2d0817ce | |||
7674401e7c | |||
61983dfc4a | |||
ed47407b7d | |||
0a79754978 | |||
725afecbf3 | |||
1bf79e55e1 | |||
3a369c49fa | |||
e78ccf3db4 | |||
acafe71f31 | |||
3ef876b737 | |||
b30bbc99e9 | |||
235c072c21 | |||
f5bdd85b73 | |||
b81ae5a9a6 | |||
1ea5e3f323 | |||
f6eaef54b9 | |||
5b14361d74 | |||
d1f9c0eb2f | |||
95b27abec1 | |||
228e987d8b | |||
7c44102afd | |||
b8410e5628 | |||
d6f0b12b17 | |||
b02e31c373 | |||
e012d41929 | |||
4bd77b45e4 | |||
e43f572588 | |||
9aecb3cab9 | |||
f1256ab23f | |||
892bf0e87a | |||
61ef6c5525 | |||
38405d658e | |||
f3b7c315f0 | |||
6950286eec | |||
60f966c493 | |||
7af4d3c512 | |||
d9b53480be | |||
a574a8ffd1 | |||
b0a34c6162 | |||
ea04f0f189 | |||
1403cdf80c | |||
40e676cfc7 | |||
5f654020d5 | |||
a3ec87bf52 | |||
88588355fd | |||
c329c56094 | |||
08a5454cf4 | |||
8faf47c06e | |||
d7f778de28 | |||
cd3cc50e00 | |||
755f2da03a | |||
7ef9f79b97 | |||
2c53a1409c | |||
1e2d5c0f3e | |||
6db7ed2f5e | |||
9b8102cbdc | |||
e0bc1fed49 | |||
c230f5bb51 | |||
6f4819b689 | |||
fd67737754 | |||
6f94865917 | |||
1e4167e209 | |||
655ed6f6f6 | |||
8fe73be90b | |||
e925b73606 | |||
b902b9a122 | |||
1044302118 | |||
df15232312 | |||
f5d273688d | |||
993dd1e30e | |||
83f90e24c7 | |||
c3fd177ff5 | |||
c5f8b4fb13 | |||
a4e48de57e | |||
e3aa2a4d50 | |||
88c44ed31f | |||
d3d1ca7beb | |||
8d758bc1d7 | |||
34b5f123b4 | |||
809f4612b5 | |||
1f48f7a296 | |||
56258dc06b | |||
3fea7d48f6 | |||
f49ca1f4f2 | |||
e9d9139263 | |||
98e7987b04 | |||
4dc145fe75 | |||
c8b12cd618 | |||
97cf63f643 | |||
cd20e25082 | |||
c62e66a86a | |||
26f24329c7 | |||
bb86fb500a | |||
b78e8b1e02 | |||
2e87d6b51f | |||
4439e73986 | |||
af065afe67 | |||
088510a62b | |||
e0150361b1 | |||
4b7d184c91 | |||
3e18536c2e | |||
8027e2deed | |||
c21abdcc81 | |||
3382177e27 | |||
73352d4414 | |||
f11425b2c2 | |||
039f4d172b | |||
b0a608c1fa |
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": [
|
|
||||||
[
|
|
||||||
"next/babel",
|
|
||||||
{
|
|
||||||
"styled-jsx": {
|
|
||||||
"plugins": ["@styled-jsx/plugin-sass"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
{ "extends": ["@commitlint/config-conventional"] }
|
|
@ -1,11 +1,38 @@
|
|||||||
|
**/.git
|
||||||
|
**/.turbo
|
||||||
|
**/.next
|
||||||
|
**/out
|
||||||
|
**/dist
|
||||||
|
**/build
|
||||||
|
**/storybook-static
|
||||||
|
**/coverage
|
||||||
|
**/node_modules
|
||||||
|
|
||||||
|
# envs
|
||||||
|
.env
|
||||||
|
.env.production
|
||||||
|
.env.development
|
||||||
|
secrets
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
.vscode
|
.vscode
|
||||||
.git
|
|
||||||
.next
|
# misc
|
||||||
build
|
.DS_Store
|
||||||
coverage
|
*.pem
|
||||||
dist
|
Dockerfile
|
||||||
node_modules
|
README.md
|
||||||
out
|
|
||||||
**/workbox-*.js
|
# vercel
|
||||||
**/sw.js
|
.vercel
|
||||||
**/__test__/**
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# For more information see: https://editorconfig.org/
|
# https://editorconfig.org/
|
||||||
|
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
|
@ -1,6 +1,2 @@
|
|||||||
COMPOSE_PROJECT_NAME=divlo.fr-website
|
TZ=UTC
|
||||||
PORT=3000
|
WEBSITE_PORT=3000
|
||||||
EMAIL_HOST=divlo.fr-maildev
|
|
||||||
EMAIL_USER=reply@divlo-website.fr
|
|
||||||
EMAIL_PASSWORD=password
|
|
||||||
EMAIL_PORT=25
|
|
||||||
|
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
* text=auto eol=lf
|
8
.github/ISSUE_TEMPLATE/BUG.md
vendored
@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
name: '🐛 Bug Report'
|
name: "🐛 Bug Report"
|
||||||
about: 'Report an unexpected problem or unintended behavior.'
|
about: "Report an unexpected problem or unintended behavior."
|
||||||
title: '[Bug]'
|
title: "[Bug]"
|
||||||
labels: 'bug'
|
labels: "bug"
|
||||||
---
|
---
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
8
.github/ISSUE_TEMPLATE/DOCUMENTATION.md
vendored
@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
name: '📜 Documentation'
|
name: "📜 Documentation"
|
||||||
about: 'Correct spelling errors, improvements or additions to documentation files (README, CONTRIBUTING...).'
|
about: "Correct spelling errors, improvements or additions to documentation files (README, CONTRIBUTING...)."
|
||||||
title: '[Documentation]'
|
title: "[Documentation]"
|
||||||
labels: 'documentation'
|
labels: "documentation"
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Please make sure your issue has not already been fixed. -->
|
<!-- Please make sure your issue has not already been fixed. -->
|
||||||
|
8
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
name: '✨ Feature Request'
|
name: "✨ Feature Request"
|
||||||
about: 'Suggest a new feature idea.'
|
about: "Suggest a new feature idea."
|
||||||
title: '[Feature]'
|
title: "[Feature]"
|
||||||
labels: 'feature request'
|
labels: "feature request"
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Please make sure your issue has not already been fixed. -->
|
<!-- Please make sure your issue has not already been fixed. -->
|
||||||
|
8
.github/ISSUE_TEMPLATE/IMPROVEMENT.md
vendored
@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
name: '🔧 Improvement'
|
name: "🔧 Improvement"
|
||||||
about: 'Improve structure/format/performance/refactor/tests of the code.'
|
about: "Improve structure/format/performance/refactor/tests of the code."
|
||||||
title: '[Improvement]'
|
title: "[Improvement]"
|
||||||
labels: 'improvement'
|
labels: "improvement"
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Please make sure your issue has not already been fixed. -->
|
<!-- Please make sure your issue has not already been fixed. -->
|
||||||
|
8
.github/ISSUE_TEMPLATE/QUESTION.md
vendored
@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
name: '🙋 Question'
|
name: "🙋 Question"
|
||||||
about: 'Further information is requested.'
|
about: "Further information is requested."
|
||||||
title: '[Question]'
|
title: "[Question]"
|
||||||
labels: 'question'
|
labels: "question"
|
||||||
---
|
---
|
||||||
|
|
||||||
### Question
|
### Question
|
||||||
|
11
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,13 +1,6 @@
|
|||||||
<!--
|
<!-- Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time. -->
|
||||||
|
|
||||||
Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time.
|
# What changes this PR introduce?
|
||||||
|
|
||||||
Before submitting your contribution, please take a moment to review this document:
|
|
||||||
https://github.com/Divlo/Divlo/blob/master/.github/CONTRIBUTING.md
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
## What changes this PR introduce?
|
|
||||||
|
|
||||||
## List any relevant issue numbers
|
## List any relevant issue numbers
|
||||||
|
|
||||||
|
16
.github/dependabot.yml
vendored
@ -1,16 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: 'github-actions'
|
|
||||||
directory: '/'
|
|
||||||
schedule:
|
|
||||||
interval: 'daily'
|
|
||||||
|
|
||||||
- package-ecosystem: 'docker'
|
|
||||||
directory: '/'
|
|
||||||
schedule:
|
|
||||||
interval: 'daily'
|
|
||||||
|
|
||||||
- package-ecosystem: 'npm'
|
|
||||||
directory: '/'
|
|
||||||
schedule:
|
|
||||||
interval: 'daily'
|
|
38
.github/workflows/Divlo.yml
vendored
@ -1,38 +0,0 @@
|
|||||||
name: 'Divlo'
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [master, development]
|
|
||||||
pull_request:
|
|
||||||
branches: [master, development]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ci:
|
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node-version: [14.x]
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v2'
|
|
||||||
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: 'actions/setup-node@v2.1.5'
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
|
|
||||||
- name: 'Cache dependencies'
|
|
||||||
uses: 'actions/cache@v2.1.5'
|
|
||||||
with:
|
|
||||||
path: '.npm'
|
|
||||||
key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
|
|
||||||
- run: 'npm install --global npm@7'
|
|
||||||
- run: 'npm ci --cache .npm --prefer-offline'
|
|
||||||
- run: 'npm run lint:commit -- --to "${{ github.sha }}"'
|
|
||||||
- run: 'npm run lint:docker'
|
|
||||||
- run: 'npm run lint:editorconfig'
|
|
||||||
- run: 'npm run lint:markdown'
|
|
||||||
- run: 'npm run lint:typescript'
|
|
||||||
- run: 'npm run build'
|
|
||||||
- run: 'npm run lighthouse'
|
|
||||||
- run: 'npm run test'
|
|
33
.github/workflows/chromatic.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
name: "Chromatic"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [develop]
|
||||||
|
pull_request:
|
||||||
|
branches: [develop, staging, main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
chromatic:
|
||||||
|
timeout-minutes: 30
|
||||||
|
runs-on: "ubuntu-latest"
|
||||||
|
steps:
|
||||||
|
- uses: "actions/checkout@v4.2.2"
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: "pnpm/action-setup@v4.0.0"
|
||||||
|
|
||||||
|
- name: "Setup Node.js"
|
||||||
|
uses: "actions/setup-node@v4.1.0"
|
||||||
|
with:
|
||||||
|
node-version: "22.x"
|
||||||
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- name: "Install dependencies"
|
||||||
|
run: "pnpm install --frozen-lockfile"
|
||||||
|
|
||||||
|
- name: "Run Chromatic"
|
||||||
|
uses: "chromaui/action@latest"
|
||||||
|
with:
|
||||||
|
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||||
|
workingDir: "apps/storybook"
|
43
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
name: "CI"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [develop]
|
||||||
|
pull_request:
|
||||||
|
branches: [develop, staging, main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ci:
|
||||||
|
timeout-minutes: 30
|
||||||
|
runs-on: "ubuntu-latest"
|
||||||
|
steps:
|
||||||
|
- uses: "actions/checkout@v4.2.2"
|
||||||
|
|
||||||
|
- uses: "pnpm/action-setup@v4.0.0"
|
||||||
|
|
||||||
|
- name: "Setup Node.js"
|
||||||
|
uses: "actions/setup-node@v4.1.0"
|
||||||
|
with:
|
||||||
|
node-version: "22.x"
|
||||||
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- name: "Install dependencies"
|
||||||
|
run: "pnpm install --frozen-lockfile"
|
||||||
|
|
||||||
|
- name: "Install Playwright"
|
||||||
|
run: "pnpm exec playwright install --with-deps"
|
||||||
|
|
||||||
|
- run: "node --run lint:editorconfig"
|
||||||
|
- run: "node --run lint:markdown"
|
||||||
|
- run: "node --run lint:typescript"
|
||||||
|
- run: "node --run lint:eslint"
|
||||||
|
- run: "node --run lint:prettier"
|
||||||
|
- run: "node --run test"
|
||||||
|
- run: "node --run build"
|
||||||
|
|
||||||
|
commitlint:
|
||||||
|
runs-on: "ubuntu-latest"
|
||||||
|
steps:
|
||||||
|
- uses: "actions/checkout@v4.2.2"
|
||||||
|
|
||||||
|
- uses: "wagoid/commitlint-github-action@v6.1.2"
|
57
.github/workflows/release.yml
vendored
@ -1,34 +1,45 @@
|
|||||||
name: 'release'
|
name: "Release"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
push:
|
||||||
workflows: [Divlo]
|
branches: [main, staging]
|
||||||
branches: [master]
|
|
||||||
types:
|
|
||||||
- 'completed'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
runs-on: 'ubuntu-latest'
|
timeout-minutes: 30
|
||||||
strategy:
|
runs-on: "ubuntu-latest"
|
||||||
matrix:
|
permissions:
|
||||||
node-version: [14.x]
|
contents: "write"
|
||||||
|
issues: "write"
|
||||||
|
pull-requests: "write"
|
||||||
|
id-token: "write"
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v2'
|
- uses: "actions/checkout@v4.2.2"
|
||||||
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: 'actions/setup-node@v2.1.5'
|
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
fetch-depth: 0
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: 'Cache dependencies'
|
- name: "Import GPG key"
|
||||||
uses: 'actions/cache@v2.1.5'
|
uses: "crazy-max/ghaction-import-gpg@v6.1.0"
|
||||||
with:
|
with:
|
||||||
path: '.npm'
|
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
|
git_user_signingkey: true
|
||||||
|
git_commit_gpgsign: true
|
||||||
|
|
||||||
- run: 'npm install --global npm@7'
|
- uses: "pnpm/action-setup@v4.0.0"
|
||||||
- run: 'npm ci --cache .npm --prefer-offline'
|
|
||||||
- run: 'npm run release'
|
- name: "Setup Node.js"
|
||||||
|
uses: "actions/setup-node@v4.1.0"
|
||||||
|
with:
|
||||||
|
node-version: "22.x"
|
||||||
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- name: "Install dependencies"
|
||||||
|
run: "pnpm install --frozen-lockfile"
|
||||||
|
|
||||||
|
- name: "Release"
|
||||||
|
run: "node --run release"
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
GIT_COMMITTER_NAME: ${{ secrets.GIT_NAME }}
|
||||||
|
GIT_COMMITTER_EMAIL: ${{ secrets.GIT_EMAIL }}
|
||||||
|
69
.gitignore
vendored
@ -1,36 +1,53 @@
|
|||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
node_modules
|
node_modules
|
||||||
.npm
|
.npm
|
||||||
|
package-lock.json
|
||||||
# next.js
|
.pnpm-store
|
||||||
.next
|
.pnp
|
||||||
out
|
.pnp.js
|
||||||
|
.yarn/install-state.gz
|
||||||
# production
|
|
||||||
build
|
|
||||||
dist
|
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
coverage
|
coverage
|
||||||
|
|
||||||
# PWA
|
# production
|
||||||
**/workbox-*.js
|
.next/
|
||||||
**/sw.js
|
out/
|
||||||
|
dist/
|
||||||
# envs
|
build/
|
||||||
.env
|
|
||||||
.env.production
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
|
|
||||||
# editors
|
|
||||||
.vscode
|
|
||||||
.theia
|
|
||||||
.idea
|
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.lighthouseci
|
*.pem
|
||||||
|
.turbo
|
||||||
|
bin/
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Storybook
|
||||||
|
*storybook.log
|
||||||
|
storybook-static
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env
|
||||||
|
.env.production
|
||||||
|
.env*.local
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
# next-env.d.ts
|
||||||
|
1
.husky/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
_
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
npm run lint:commit -- --edit
|
|
@ -1,7 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
npm run lint:docker
|
|
||||||
npm run lint:editorconfig
|
|
||||||
npm run lint:markdown
|
|
||||||
npm run lint:typescript
|
|
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"ci": {
|
|
||||||
"collect": {
|
|
||||||
"startServerCommand": "npm run start",
|
|
||||||
"startServerReadyPattern": "ready on",
|
|
||||||
"startServerReadyTimeout": 20000,
|
|
||||||
"url": ["http://localhost:3000/"],
|
|
||||||
"numberOfRuns": 3
|
|
||||||
},
|
|
||||||
"assert": {
|
|
||||||
"preset": "lighthouse:recommended",
|
|
||||||
"assertions": {
|
|
||||||
"legacy-javascript": "off",
|
|
||||||
"unused-javascript": "off",
|
|
||||||
"uses-rel-preload": "off",
|
|
||||||
"canonical": "off",
|
|
||||||
"unsized-images": "off",
|
|
||||||
"uses-responsive-images": "off",
|
|
||||||
"bypass": "warning",
|
|
||||||
"color-contrast": "warning",
|
|
||||||
"preload-lcp-image": "warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"upload": {
|
|
||||||
"target": "temporary-public-storage"
|
|
||||||
},
|
|
||||||
"server": {}
|
|
||||||
}
|
|
||||||
}
|
|
12
.markdownlint-cli2.jsonc
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"extends": "markdownlint/style/prettier",
|
||||||
|
"default": true,
|
||||||
|
"relative-links": true,
|
||||||
|
"no-duplicate-heading": false,
|
||||||
|
"no-inline-html": false,
|
||||||
|
},
|
||||||
|
"globs": ["**/*.md"],
|
||||||
|
"ignores": ["**/node_modules"],
|
||||||
|
"customRules": ["markdownlint-rule-relative-links"],
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"default": true,
|
|
||||||
"MD013": false,
|
|
||||||
"MD024": false,
|
|
||||||
"MD033": false,
|
|
||||||
"MD041": false
|
|
||||||
}
|
|
13
.prettierrc.json
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"plugins": ["prettier-plugin-tailwindcss"],
|
||||||
|
"tailwindFunctions": ["classNames", "cva"],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "pnpm-lock.yaml",
|
||||||
|
"options": {
|
||||||
|
"rangeEnd": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,12 +1,34 @@
|
|||||||
{
|
{
|
||||||
"release": {
|
"branches": ["main", { "name": "staging", "prerelease": true }],
|
||||||
"branches": ["master"]
|
|
||||||
},
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
["@semantic-release/commit-analyzer", {
|
"@semantic-release/commit-analyzer",
|
||||||
"preset": "conventionalcommits"
|
|
||||||
}],
|
|
||||||
"@semantic-release/release-notes-generator",
|
"@semantic-release/release-notes-generator",
|
||||||
"@semantic-release/github"
|
[
|
||||||
|
"@semantic-release/exec",
|
||||||
|
{
|
||||||
|
"prepareCmd": "replace-in-files --regex='version\": *\"[^\"]*' --replacement='\"version\": \"${nextRelease.version}\"' '**/package.json' '!**/node_modules/**'"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/git",
|
||||||
|
{
|
||||||
|
"assets": [
|
||||||
|
"package.json",
|
||||||
|
"apps/*/package.json",
|
||||||
|
"packages/*/package.json"
|
||||||
|
],
|
||||||
|
"message": "chore(release): ${nextRelease.version} [skip ci]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@semantic-release/github",
|
||||||
|
[
|
||||||
|
"@saithodev/semantic-release-backmerge",
|
||||||
|
{
|
||||||
|
"branches": [
|
||||||
|
{ "from": "main", "to": "develop" },
|
||||||
|
{ "from": "staging", "to": "develop" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
13
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"editorconfig.editorconfig",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"davidanson.vscode-markdownlint",
|
||||||
|
"bradlc.vscode-tailwindcss",
|
||||||
|
"mikestead.dotenv",
|
||||||
|
"ms-azuretools.vscode-docker",
|
||||||
|
"antfu.pnpm-catalog-lens",
|
||||||
|
"Lokalise.i18n-ally"
|
||||||
|
]
|
||||||
|
}
|
43
.vscode/react.code-snippets
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"React Component": {
|
||||||
|
"scope": "typescriptreact",
|
||||||
|
"prefix": "rfc",
|
||||||
|
"body": [
|
||||||
|
"export interface ${1:ComponentName}Props {}",
|
||||||
|
"",
|
||||||
|
"export const ${1:ComponentName}: React.FC<${1:ComponentName}Props> = () => {",
|
||||||
|
" return (",
|
||||||
|
" <div>",
|
||||||
|
" <h1>${1:ComponentName}</h1>",
|
||||||
|
" </div>",
|
||||||
|
" )",
|
||||||
|
"}",
|
||||||
|
"",
|
||||||
|
],
|
||||||
|
"description": "React Component",
|
||||||
|
},
|
||||||
|
"React Component Story": {
|
||||||
|
"scope": "typescriptreact",
|
||||||
|
"prefix": "rfcs",
|
||||||
|
"body": [
|
||||||
|
"import type { Meta, StoryObj } from \"@storybook/react\"",
|
||||||
|
"",
|
||||||
|
"import { ${1:ComponentName} as ${1:ComponentName}Component } from \"./${1:ComponentName}.tsx\"",
|
||||||
|
"",
|
||||||
|
"const meta = {",
|
||||||
|
" title: \"${1:ComponentName}\",",
|
||||||
|
" component: ${1:ComponentName}Component",
|
||||||
|
"} satisfies Meta<typeof ${1:ComponentName}Component>",
|
||||||
|
"",
|
||||||
|
"export default meta",
|
||||||
|
"",
|
||||||
|
"type Story = StoryObj<typeof meta>",
|
||||||
|
"",
|
||||||
|
"export const ${1:ComponentName}: Story = {",
|
||||||
|
" args: {}",
|
||||||
|
"}",
|
||||||
|
"",
|
||||||
|
],
|
||||||
|
"description": "React Component Story",
|
||||||
|
},
|
||||||
|
}
|
23
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
|
"editor.bracketPairColorization.enabled": true,
|
||||||
|
"editor.wordWrap": "on",
|
||||||
|
"prettier.configPath": ".prettierrc.json",
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll": "explicit",
|
||||||
|
"source.organizeImports": "never"
|
||||||
|
},
|
||||||
|
"tailwindCSS.experimental.classRegex": [
|
||||||
|
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
|
||||||
|
["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
|
||||||
|
],
|
||||||
|
"i18n-ally.localesPaths": ["./packages/i18n/src/translations/"],
|
||||||
|
"i18n-ally.keystyle": "nested",
|
||||||
|
"i18n-ally.sortKeys": true,
|
||||||
|
"i18n-ally.sourceLanguage": "en-US",
|
||||||
|
"i18n-ally.displayLanguage": "en-US",
|
||||||
|
"i18n-ally.enabledFrameworks": ["next-intl", "general"],
|
||||||
|
"i18n-ally.extract.autoDetect": true
|
||||||
|
}
|
@ -60,7 +60,7 @@ representative at an online or offline event.
|
|||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported to the community leaders responsible for enforcement at
|
reported to the community leaders responsible for enforcement at
|
||||||
contact@divlo.fr.
|
<contact@theoludwig.fr>.
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
# 💡 Contributing
|
# 💡 Contributing
|
||||||
|
|
||||||
Thanks a lot for your interest in contributing to **divlo.fr**! 🎉
|
Thanks a lot for your interest in contributing to **theoludwig.fr**! 🎉
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
**theoludwig.fr** adopted the [Contributor Covenant](https://www.contributor-covenant.org/) as its Code of Conduct, and we expect project participants to adhere to it. Please read [the full text](./CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated.
|
||||||
|
|
||||||
## Types of contributions
|
## Types of contributions
|
||||||
|
|
||||||
@ -11,63 +15,77 @@ Thanks a lot for your interest in contributing to **divlo.fr**! 🎉
|
|||||||
|
|
||||||
## Pull Requests
|
## Pull Requests
|
||||||
|
|
||||||
- **Please first discuss** the change you wish to make via [issue](https://github.com/Divlo/Divlo/issues) before making a change. It might avoid a waste of your time.
|
- **Please first discuss** the change you wish to make via [issue](https://github.com/theoludwig/theoludwig/issues) before making a change. It might avoid a waste of your time.
|
||||||
|
|
||||||
- Ensure your code respect [Typescript Standard Style](https://www.npmjs.com/package/ts-standard).
|
- Ensure your code respect linting.
|
||||||
|
|
||||||
- Make sure your **code passes the tests**.
|
- Make sure your **code passes the tests**.
|
||||||
|
|
||||||
If you're adding new features to **divlo.fr**, please include tests.
|
If you're adding new features to **theoludwig.fr**, please include tests.
|
||||||
|
|
||||||
## Commits
|
## Commits
|
||||||
|
|
||||||
The commit message guidelines respect [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional) and [Semantic Versioning](https://semver.org/) for releases.
|
The commit message guidelines adheres to [Conventional Commits](https://www.conventionalcommits.org/) and [Semantic Versioning](https://semver.org/) for releases.
|
||||||
|
|
||||||
### Types
|
|
||||||
|
|
||||||
Types define which kind of changes you made to the project.
|
|
||||||
|
|
||||||
| Types | Description |
|
|
||||||
| -------- | ------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| feat | A new feature. |
|
|
||||||
| fix | A bug fix. |
|
|
||||||
| docs | Documentation only changes. |
|
|
||||||
| style | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc). |
|
|
||||||
| refactor | A code change that neither fixes a bug nor adds a feature. |
|
|
||||||
| perf | A code change that improves performance. |
|
|
||||||
| test | Adding missing tests or correcting existing tests. |
|
|
||||||
| build | Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm). |
|
|
||||||
| ci | Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs). |
|
|
||||||
| chore | Other changes that don't modify src or test files. |
|
|
||||||
| revert | Reverts a previous commit. |
|
|
||||||
|
|
||||||
### Scopes
|
|
||||||
|
|
||||||
Scopes define what part of the code changed.
|
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- [Node.js](https://nodejs.org/) >= 22.0.0
|
||||||
|
- [pnpm](https://pnpm.io/) >= 9.15.0 [(`corepack enable`)](https://nodejs.org/docs/latest-v22.x/api/corepack.html)
|
||||||
|
- [Docker](https://www.docker.com/)
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Clone the repository
|
# Clone the repository
|
||||||
git clone https://github.com/Divlo/Divlo.git
|
git clone git@github.com:theoludwig/theoludwig.git
|
||||||
|
|
||||||
# Go to the project root
|
# Go to the project root
|
||||||
cd Divlo
|
cd theoludwig
|
||||||
|
|
||||||
# Configure environment variables
|
# Configure environment variables
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
|
cp apps/website/.env.example apps/website/.env
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Install Playwright browser binaries and their dependencies (tests)
|
||||||
|
pnpm exec playwright install --with-deps
|
||||||
```
|
```
|
||||||
|
|
||||||
### Development environment with [Docker](https://www.docker.com/)
|
### Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Start the development server
|
||||||
|
node --run dev
|
||||||
|
|
||||||
|
# Lint
|
||||||
|
node --run lint:editorconfig
|
||||||
|
node --run lint:markdown
|
||||||
|
node --run lint:typescript
|
||||||
|
node --run lint:eslint
|
||||||
|
node --run lint:prettier
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
node --run test
|
||||||
|
|
||||||
|
# Build
|
||||||
|
node --run build
|
||||||
|
|
||||||
|
# To execute a command in a specific package (e.g: packages/utils)
|
||||||
|
cd packages/utils
|
||||||
|
node --run test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production environment with [Docker](https://www.docker.com/)
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Setup and run all the services for you
|
# Setup and run all the services for you
|
||||||
docker-compose up --build
|
docker compose up --build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Services started
|
#### Services started
|
||||||
|
|
||||||
- website : `http://localhost:3000`
|
`theoludwig`: <http://127.0.0.1:3000>
|
||||||
- [MailDev](https://maildev.github.io/maildev/) : `http://localhost:1080`
|
|
||||||
|
10
Dockerfile
@ -1,10 +0,0 @@
|
|||||||
FROM node:14.16.1
|
|
||||||
RUN npm install --global npm@7
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY ./package*.json ./
|
|
||||||
RUN npm install
|
|
||||||
COPY ./ ./
|
|
||||||
|
|
||||||
CMD ["npm", "run", "dev", "--", "--port", "${PORT}"]
|
|
4
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
# MIT License
|
||||||
|
|
||||||
Copyright (c) Divlo
|
Copyright (c) Théo LUDWIG <contact@theoludwig.fr>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
54
README.md
@ -1,49 +1,45 @@
|
|||||||
<h1 align="center"><a href="https://divlo.fr/">Divlo</a></h1>
|
<h1 align="center"><a href="https://theoludwig.fr/">Théo LUDWIG</a></h1>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<strong>Developer Full Stack Junior • Passionate about High-Tech</strong>
|
<strong>Developer Full Stack • Open-Source Enthusiast</strong>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/Divlo/Divlo/actions?query=workflow%3A%22Divlo%22"><img src="https://github.com/Divlo/Divlo/actions/workflows/Divlo.yml/badge.svg?branch=master" alt="Divlo's CI" /></a>
|
<a href="https://github.com/theoludwig"><img alt="GitHub" src="https://img.shields.io/badge/-GitHub-5A5A5A?style=flat&labelColor=5A5A5A&logo=github&logoColor=white"/></a>
|
||||||
<a href="https://github.com/Divlo"><img alt="GitHub" src="https://img.shields.io/badge/-GitHub-5A5A5A?style=flat&labelColor=5A5A5A&logo=github&logoColor=white"/></a>
|
<a href="https://gitlab.com/theoludwig"><img alt="GitLab" src="https://img.shields.io/badge/-GitLab-303030?style=flat&labelColor=303030&logo=gitlab&logoColor=white"/></a>
|
||||||
<a href="https://gitlab.com/Divlo"><img alt="GitLab" src="https://img.shields.io/badge/-GitLab-303030?style=flat&labelColor=303030&logo=gitlab&logoColor=white"/></a>
|
<a href="https://www.npmjs.com/~theoludwig"><img alt="npm" src="https://img.shields.io/badge/-npm-c4302b?style=flat&labelColor=c4302b&logo=npm&logoColor=white"/></a>
|
||||||
<a href="https://www.npmjs.com/~divlo"><img alt="npm" src="https://img.shields.io/badge/-npm-c4302b?style=flat&labelColor=c4302b&logo=npm&logoColor=white"/></a>
|
<a href="https://twitter.com/theoludwig_"><img alt="Twitter" src="https://img.shields.io/badge/-Twitter-1ca0f1?style=flat&labelColor=1ca0f1&logo=x&logoColor=white"/></a>
|
||||||
<a href="https://twitter.com/Divlo_FR"><img alt="Twitter" src="https://img.shields.io/badge/-Twitter-1ca0f1?style=flat&labelColor=1ca0f1&logo=twitter&logoColor=white"/></a>
|
<a href="https://www.youtube.com/@theo_ludwig"><img alt="YouTube" src="https://img.shields.io/badge/-YouTube-c4302b?style=flat&labelColor=c4302b&logo=youtube&logoColor=white"/></a>
|
||||||
<a href="https://www.youtube.com/channel/UCfEKQzI3c8vmZOrsTOi5spA"><img alt="YouTube" src="https://img.shields.io/badge/-YouTube-c4302b?style=flat&labelColor=c4302b&logo=youtube&logoColor=white"/></a>
|
<a href="https://www.twitch.tv/theoludwig"><img alt="Twitch" src="https://img.shields.io/badge/-Twitch-9147FF?style=flat&labelColor=9147FF&logo=twitch&logoColor=white"/></a>
|
||||||
<a href="https://www.twitch.tv/divlo"><img alt="Twitch" src="https://img.shields.io/badge/-Twitch-9147FF?style=flat&labelColor=9147FF&logo=twitch&logoColor=white"/></a>
|
<a href="https://theoludwig.fr/"><img alt="Website" src="https://img.shields.io/badge/-Website-181818?style=flat&labelColor=181818&logo=Google-Chrome&logoColor=white"/></a>
|
||||||
<a href="https://www.divlo.fr"><img alt="Website" src="https://img.shields.io/badge/-Website-181818?style=flat&labelColor=181818&logo=Google-Chrome&logoColor=white"/></a>
|
<a href="mailto:contact@theoludwig.fr"><img alt="Email" src="https://img.shields.io/badge/-contact@theoludwig.fr-2F7EBE?style=flat&labelColor=2F7EBE&logo=minutemailer&logoColor=white"/></a>
|
||||||
<a href="mailto:contact@divlo.fr"><img alt="Email" src="https://img.shields.io/badge/-contact@divlo.fr-2F7EBE?style=flat&labelColor=2F7EBE&logo=minutemailer&logoColor=white"/></a>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
## 📜 About
|
## 📜 About
|
||||||
|
|
||||||
```typescript
|
```json
|
||||||
export interface Divlo {
|
{
|
||||||
pronouns: 'He' | 'Him'
|
"name": "Théo LUDWIG",
|
||||||
birthDate: '31/03/2003'
|
"pronouns": "He/Him",
|
||||||
nationality: 'Alsace, France'
|
"birthDate": "2003-03-31",
|
||||||
interests: [
|
"nationality": "Alsace, France",
|
||||||
'Developer Full Stack Junior',
|
"interests": ["Developer Full Stack", "Open-Source Enthusiast"],
|
||||||
'Passionate about High-Tech',
|
"skills": {
|
||||||
'Open-Source enthusiast'
|
"programmingLanguages": ["JavaScript/TypeScript", "Python", "C/C++", "PHP"],
|
||||||
]
|
"frontend": ["HTML/CSS", "Tailwind CSS", "React.js/Next.js"],
|
||||||
skills: {
|
"backend": ["Laravel", "Node.js", "Fastify", "PostgreSQL"],
|
||||||
languages: ['JavaScript', 'TypeScript', 'Python', 'Dart']
|
"tools": ["GNU/Linux", "Arch Linux", "Visual Studio Code", "Git", "Docker"]
|
||||||
frontEnd: ['HTML', 'CSS', 'SASS', 'React.js (+ Next.js)', 'Flutter']
|
|
||||||
backEnd: ['Node.js', 'Strapi', 'MySQL']
|
|
||||||
tools: ['Ubuntu', 'Hyper Terminal', 'VSCode', 'Git', 'Docker']
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
## 📈 Stats
|
## 📈 Statistics
|
||||||
|
|
||||||
<p align=center>
|
<p align=center>
|
||||||
<img height=175 align="center" src="https://github-readme-stats.vercel.app/api?username=Divlo&show_icons=true&theme=dark" />
|
<img height=175 align="center" src="https://github-readme-stats.vercel.app/api?username=theoludwig&show_icons=true&theme=dark" alt="Théo LUDWIG's GitHub Stats" />
|
||||||
<img height=175 align="center" src="https://github-readme-stats.vercel.app/api/top-langs/?username=Divlo&hide=html,css&langs_count=8&layout=compact&theme=dark" />
|
<img height=175 align="center" src="https://github-readme-stats.vercel.app/api/top-langs/?username=theoludwig&hide=html,css,javascript&langs_count=8&layout=compact&theme=dark" alt="Théo LUDWIG's Programming Languages" />
|
||||||
</p>
|
</p>
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
import { createMocks } from 'node-mocks-http'
|
|
||||||
|
|
||||||
import handleSendEmail from 'pages/api/send-email'
|
|
||||||
|
|
||||||
jest.mock('nodemailer', () => ({
|
|
||||||
createTransport: () => {
|
|
||||||
return {
|
|
||||||
sendMail: jest.fn(async () => {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
describe('POST /api/send-email', () => {
|
|
||||||
it('succeeds and send the email', async () => {
|
|
||||||
const { req, res } = createMocks({
|
|
||||||
method: 'POST',
|
|
||||||
body: {
|
|
||||||
name: 'Divlo',
|
|
||||||
email: 'contact@divlo.fr',
|
|
||||||
subject: 'Subject',
|
|
||||||
message: 'Hello world!'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
await handleSendEmail(req, res)
|
|
||||||
expect(res._getStatusCode()).toBe(201)
|
|
||||||
expect(JSON.parse(res._getData())).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
type: 'success'
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('fails with empty values', async () => {
|
|
||||||
const { req, res } = createMocks({
|
|
||||||
method: 'POST',
|
|
||||||
body: {
|
|
||||||
name: '',
|
|
||||||
email: '',
|
|
||||||
subject: '',
|
|
||||||
message: ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
await handleSendEmail(req, res)
|
|
||||||
expect(res._getStatusCode()).toBe(400)
|
|
||||||
expect(JSON.parse(res._getData())).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
type: 'requiredFields'
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('fails with invalid email', async () => {
|
|
||||||
const { req, res } = createMocks({
|
|
||||||
method: 'POST',
|
|
||||||
body: {
|
|
||||||
name: 'Name',
|
|
||||||
email: 'random wrong email',
|
|
||||||
subject: 'Subject',
|
|
||||||
message: 'Message'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
await handleSendEmail(req, res)
|
|
||||||
expect(res._getStatusCode()).toBe(400)
|
|
||||||
expect(JSON.parse(res._getData())).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
type: 'invalidEmail'
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
37
apps/storybook/.storybook/main.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import type { StorybookConfig } from "@storybook/nextjs"
|
||||||
|
|
||||||
|
const config: StorybookConfig = {
|
||||||
|
core: {
|
||||||
|
disableTelemetry: true,
|
||||||
|
},
|
||||||
|
docs: {
|
||||||
|
defaultName: "Documentation",
|
||||||
|
},
|
||||||
|
stories: [
|
||||||
|
"../../../packages/ui/src/**/*.stories.tsx",
|
||||||
|
"../../../packages/blog/src/**/*.stories.tsx",
|
||||||
|
"../stories/*.mdx",
|
||||||
|
],
|
||||||
|
addons: [
|
||||||
|
"@chromatic-com/storybook",
|
||||||
|
"@storybook/addon-essentials",
|
||||||
|
"@storybook/addon-storysource",
|
||||||
|
"@storybook/addon-a11y",
|
||||||
|
"@storybook/addon-interactions",
|
||||||
|
"storybook-dark-mode",
|
||||||
|
],
|
||||||
|
framework: {
|
||||||
|
name: "@storybook/nextjs",
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
features: {
|
||||||
|
experimentalRSC: true,
|
||||||
|
},
|
||||||
|
typescript: {
|
||||||
|
check: false,
|
||||||
|
reactDocgen: "react-docgen-typescript",
|
||||||
|
},
|
||||||
|
staticDirs: ["../../website/public"],
|
||||||
|
}
|
||||||
|
|
||||||
|
export default config
|
51
apps/storybook/.storybook/preview.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import "@repo/config-tailwind/styles.css"
|
||||||
|
import i18nMessages from "@repo/i18n/translations/en-US.json"
|
||||||
|
import { LOCALE_DEFAULT, TIMEZONE } from "@repo/utils/constants"
|
||||||
|
import type { Preview } from "@storybook/react"
|
||||||
|
import { NextIntlClientProvider } from "next-intl"
|
||||||
|
import { ThemeProvider as NextThemeProvider } from "next-themes"
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
const preview: Preview = {
|
||||||
|
parameters: {
|
||||||
|
nextjs: {
|
||||||
|
appDirectory: true,
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
storySort: {
|
||||||
|
order: ["Design System", "Layout", "Errors"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backgrounds: { disable: true },
|
||||||
|
darkMode: {
|
||||||
|
darkClass: "dark",
|
||||||
|
lightClass: "light",
|
||||||
|
classTarget: "html",
|
||||||
|
stylePreview: true,
|
||||||
|
},
|
||||||
|
controls: {
|
||||||
|
disableSaveFromUI: true,
|
||||||
|
matchers: {
|
||||||
|
color: /(background|color)$/i,
|
||||||
|
date: /date$/i,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
(Story) => {
|
||||||
|
return (
|
||||||
|
<NextThemeProvider enableColorScheme={false}>
|
||||||
|
<NextIntlClientProvider
|
||||||
|
messages={i18nMessages}
|
||||||
|
locale={LOCALE_DEFAULT}
|
||||||
|
timeZone={TIMEZONE}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</NextIntlClientProvider>
|
||||||
|
</NextThemeProvider>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
export default preview
|
35
apps/storybook/.storybook/test-runner.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import type { TestRunnerConfig } from "@storybook/test-runner"
|
||||||
|
import { getStoryContext } from "@storybook/test-runner"
|
||||||
|
|
||||||
|
import { checkA11y, configureAxe, injectAxe } from "axe-playwright"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See https://storybook.js.org/docs/writing-tests/test-runner#test-hook-api
|
||||||
|
*/
|
||||||
|
const config: TestRunnerConfig = {
|
||||||
|
async preVisit(page) {
|
||||||
|
await injectAxe(page)
|
||||||
|
},
|
||||||
|
async postVisit(page, context) {
|
||||||
|
const storyContext = await getStoryContext(page, context)
|
||||||
|
|
||||||
|
const isA11yDisabled = storyContext.parameters?.a11y?.disable as boolean
|
||||||
|
if (isA11yDisabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await configureAxe(page, {
|
||||||
|
rules: storyContext.parameters?.a11y?.config?.rules,
|
||||||
|
})
|
||||||
|
|
||||||
|
await checkA11y(page, "#storybook-root", {
|
||||||
|
verbose: false,
|
||||||
|
detailedReport: true,
|
||||||
|
detailedReportOptions: {
|
||||||
|
html: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default config
|
7
apps/storybook/chromatic.config.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"projectId": "Project:66a7a85ea85df74afbec7682",
|
||||||
|
"buildScriptName": "build",
|
||||||
|
"storybookBaseDir": "apps/storybook",
|
||||||
|
"onlyChanged": true,
|
||||||
|
"zip": true
|
||||||
|
}
|
13
apps/storybook/eslint.config.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import typescriptESLint from "typescript-eslint"
|
||||||
|
import config from "@repo/eslint-config"
|
||||||
|
|
||||||
|
export default typescriptESLint.config(...config, {
|
||||||
|
files: ["**/*.ts", "**/*.tsx"],
|
||||||
|
languageOptions: {
|
||||||
|
parser: typescriptESLint.parser,
|
||||||
|
parserOptions: {
|
||||||
|
projectService: true,
|
||||||
|
tsconfigRootDir: import.meta.dirname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
57
apps/storybook/package.json
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"name": "@repo/storybook",
|
||||||
|
"version": "4.1.2",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "storybook build",
|
||||||
|
"dev": "storybook dev --port 6006 --no-open",
|
||||||
|
"start": "http-server \"storybook-static\" --port 6006 --silent",
|
||||||
|
"test": "start-server-and-test \"start\" http://127.0.0.1:6006 \"test:storybook\"",
|
||||||
|
"test:dev": "start-server-and-test \"dev\" http://127.0.0.1:6006 \"test:storybook\"",
|
||||||
|
"test:storybook": "test-storybook --testTimeout=60000 --maxWorkers=2",
|
||||||
|
"chromatic": "chromatic"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@repo/config-tailwind": "workspace:*",
|
||||||
|
"@repo/i18n": "workspace:*",
|
||||||
|
"@repo/ui": "workspace:*",
|
||||||
|
"@repo/utils": "workspace:*",
|
||||||
|
"@repo/blog": "workspace:*",
|
||||||
|
"next": "catalog:",
|
||||||
|
"next-intl": "catalog:",
|
||||||
|
"next-themes": "catalog:",
|
||||||
|
"react": "catalog:",
|
||||||
|
"react-dom": "catalog:"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@repo/eslint-config": "workspace:*",
|
||||||
|
"@repo/config-typescript": "workspace:*",
|
||||||
|
"@chromatic-com/storybook": "catalog:",
|
||||||
|
"@playwright/test": "catalog:",
|
||||||
|
"@storybook/addon-essentials": "catalog:",
|
||||||
|
"@storybook/addon-storysource": "catalog:",
|
||||||
|
"@storybook/addon-a11y": "catalog:",
|
||||||
|
"@storybook/addon-interactions": "catalog:",
|
||||||
|
"@storybook/addon-themes": "catalog:",
|
||||||
|
"@storybook/blocks": "catalog:",
|
||||||
|
"@storybook/nextjs": "catalog:",
|
||||||
|
"@storybook/react": "catalog:",
|
||||||
|
"@storybook/test": "catalog:",
|
||||||
|
"@storybook/test-runner": "catalog:",
|
||||||
|
"@types/node": "catalog:",
|
||||||
|
"@types/react": "catalog:",
|
||||||
|
"@types/react-dom": "catalog:",
|
||||||
|
"axe-playwright": "catalog:",
|
||||||
|
"chromatic": "catalog:",
|
||||||
|
"eslint": "catalog:",
|
||||||
|
"http-server": "catalog:",
|
||||||
|
"start-server-and-test": "catalog:",
|
||||||
|
"storybook": "catalog:",
|
||||||
|
"storybook-dark-mode": "catalog:",
|
||||||
|
"postcss": "catalog:",
|
||||||
|
"tailwindcss": "catalog:",
|
||||||
|
"typescript-eslint": "catalog:",
|
||||||
|
"typescript": "catalog:"
|
||||||
|
}
|
||||||
|
}
|
7
apps/storybook/postcss.config.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
const config = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default config
|
31
apps/storybook/stories/Colors.mdx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { Meta, Title, ColorPalette, ColorItem } from "@storybook/blocks"
|
||||||
|
import tailwindConfig from "@repo/config-tailwind"
|
||||||
|
|
||||||
|
<Meta title="Design System/Colors" />
|
||||||
|
|
||||||
|
<Title>Colors</Title>
|
||||||
|
|
||||||
|
<ColorPalette>
|
||||||
|
{Object.entries(tailwindConfig.theme.extend.colors).map(
|
||||||
|
([colorName, colorValue]) => {
|
||||||
|
const colors = {}
|
||||||
|
|
||||||
|
if (typeof colorValue === "string") {
|
||||||
|
colors[colorName] = colorValue
|
||||||
|
} else {
|
||||||
|
colors.light = colorValue.DEFAULT
|
||||||
|
colors.dark = colorValue.dark
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ColorItem
|
||||||
|
key={colorName}
|
||||||
|
title={colorName}
|
||||||
|
colors={colors}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
)}
|
||||||
|
|
||||||
|
</ColorPalette>
|
13
apps/storybook/tailwind.config.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import sharedConfig from "@repo/config-tailwind"
|
||||||
|
|
||||||
|
/** @type {Pick<import('tailwindcss').Config, "presets" | "content">} */
|
||||||
|
const config = {
|
||||||
|
content: [
|
||||||
|
".storybook/preview.tsx",
|
||||||
|
"../../packages/ui/src/**/*.tsx",
|
||||||
|
"../../packages/blog/src/**/*.tsx",
|
||||||
|
],
|
||||||
|
presets: [sharedConfig],
|
||||||
|
}
|
||||||
|
|
||||||
|
export default config
|
7
apps/storybook/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "@repo/config-typescript/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": ["DOM", "DOM.Iterable", "ESNext"]
|
||||||
|
},
|
||||||
|
"include": ["./.storybook/**/*.ts", "./.storybook/**/*.tsx"]
|
||||||
|
}
|
9
apps/storybook/turbo.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://turbo.build/schema.json",
|
||||||
|
"extends": ["//"],
|
||||||
|
"tasks": {
|
||||||
|
"test": {
|
||||||
|
"dependsOn": ["^test", "build"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
apps/website/.env.example
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
TZ=UTC
|
||||||
|
HOSTNAME=0.0.0.0
|
||||||
|
PORT=3000
|
||||||
|
NEXT_TELEMETRY_DISABLED=1
|
38
apps/website/Dockerfile
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
FROM node:22.12.0-slim AS node-pnpm
|
||||||
|
ENV PNPM_HOME="/pnpm"
|
||||||
|
ENV PATH="$PNPM_HOME:$PATH"
|
||||||
|
RUN corepack enable
|
||||||
|
ENV TURBO_TELEMETRY_DISABLED=1
|
||||||
|
ENV DO_NOT_TRACK=1
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
FROM node-pnpm AS builder
|
||||||
|
COPY ./ ./
|
||||||
|
RUN pnpm install --global turbo@2.3.3
|
||||||
|
RUN turbo prune @repo/website --docker
|
||||||
|
|
||||||
|
FROM node-pnpm AS installer
|
||||||
|
ENV IS_STANDALONE=true
|
||||||
|
|
||||||
|
COPY .gitignore .gitignore
|
||||||
|
COPY --from=builder /usr/src/app/out/json/ ./
|
||||||
|
COPY --from=builder /usr/src/app/out/pnpm-lock.yaml ./pnpm-lock.yaml
|
||||||
|
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
|
||||||
|
COPY --from=builder /usr/src/app/out/full/ ./
|
||||||
|
COPY turbo.json turbo.json
|
||||||
|
RUN pnpm --filter=@repo/website... exec turbo run build
|
||||||
|
|
||||||
|
FROM node-pnpm AS runner
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV HOSTNAME=0.0.0.0
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
ENV IS_STANDALONE=true
|
||||||
|
|
||||||
|
RUN addgroup --system --gid 1001 nodejs && adduser --system --uid 1001 applicationrunner
|
||||||
|
USER applicationrunner
|
||||||
|
COPY --from=installer /usr/src/app/apps/website/next.config.js ./
|
||||||
|
COPY --from=installer /usr/src/app/apps/website/package.json ./
|
||||||
|
COPY --from=installer --chown=applicationrunner:nodejs /usr/src/app/apps/website/.next/standalone ./
|
||||||
|
COPY --from=installer --chown=applicationrunner:nodejs /usr/src/app/apps/website/.next/static ./apps/website/.next/static
|
||||||
|
COPY --from=installer --chown=applicationrunner:nodejs /usr/src/app/apps/website/public ./apps/website/public
|
||||||
|
CMD ["node", "apps/website/server.js"]
|
7
apps/website/app/[locale]/(main)/[...rest]/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { notFound } from "next/navigation"
|
||||||
|
|
||||||
|
const CatchAllPage: React.FC = () => {
|
||||||
|
return notFound()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CatchAllPage
|
66
apps/website/app/[locale]/(main)/blog/[slug]/page.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import type { Metadata } from "next"
|
||||||
|
import { notFound } from "next/navigation"
|
||||||
|
|
||||||
|
import { getBlogPostBySlug, getBlogPosts } from "@repo/blog"
|
||||||
|
import { BlogPostUI } from "@repo/blog/BlogPostUI"
|
||||||
|
import type { Locale } from "@repo/utils/constants"
|
||||||
|
import { setRequestLocale } from "next-intl/server"
|
||||||
|
|
||||||
|
interface BlogPostPageProps {
|
||||||
|
params: Promise<{
|
||||||
|
slug: string
|
||||||
|
locale: Locale
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateMetadata = async (
|
||||||
|
props: BlogPostPageProps,
|
||||||
|
): Promise<Metadata> => {
|
||||||
|
const { slug } = await props.params
|
||||||
|
const blogPost = await getBlogPostBySlug(slug)
|
||||||
|
if (blogPost == null) {
|
||||||
|
return notFound()
|
||||||
|
}
|
||||||
|
const title = `${blogPost.frontmatter.title} | Théo LUDWIG`
|
||||||
|
const description = blogPost.frontmatter.description
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
openGraph: {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateStaticParams = async (): Promise<
|
||||||
|
Array<{ slug: string }>
|
||||||
|
> => {
|
||||||
|
const posts = await getBlogPosts()
|
||||||
|
return posts.map((post) => {
|
||||||
|
return {
|
||||||
|
slug: post.slug,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const BlogPostPage: React.FC<BlogPostPageProps> = async (props) => {
|
||||||
|
const { params } = props
|
||||||
|
|
||||||
|
const { locale, slug } = await params
|
||||||
|
// Enable static rendering
|
||||||
|
setRequestLocale(locale)
|
||||||
|
|
||||||
|
const blogPost = await getBlogPostBySlug(slug)
|
||||||
|
if (blogPost == null) {
|
||||||
|
return notFound()
|
||||||
|
}
|
||||||
|
|
||||||
|
return <BlogPostUI blogPost={blogPost} />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BlogPostPage
|
57
apps/website/app/[locale]/(main)/blog/page.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { getBlogPosts } from "@repo/blog"
|
||||||
|
import { BlogPosts } from "@repo/blog/BlogPosts"
|
||||||
|
import type { LocaleProps } from "@repo/i18n/routing"
|
||||||
|
import { MainLayout } from "@repo/ui/Layout/MainLayout"
|
||||||
|
import {
|
||||||
|
Section,
|
||||||
|
SectionDescription,
|
||||||
|
SectionTitle,
|
||||||
|
} from "@repo/ui/Layout/Section"
|
||||||
|
import { LOCALE_DEFAULT } from "@repo/utils/constants"
|
||||||
|
import type { Metadata } from "next"
|
||||||
|
import { setRequestLocale } from "next-intl/server"
|
||||||
|
|
||||||
|
const title = "Blog | Théo LUDWIG"
|
||||||
|
const description =
|
||||||
|
"The latest news about my journey of learning computer science."
|
||||||
|
|
||||||
|
export const generateMetadata = async (): Promise<Metadata> => {
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
openGraph: {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
locale: LOCALE_DEFAULT,
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BlogPageProps extends LocaleProps {}
|
||||||
|
|
||||||
|
const BlogPage: React.FC<BlogPageProps> = async (props) => {
|
||||||
|
const { params } = props
|
||||||
|
|
||||||
|
const { locale } = await params
|
||||||
|
// Enable static rendering
|
||||||
|
setRequestLocale(locale)
|
||||||
|
|
||||||
|
const posts = await getBlogPosts()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MainLayout>
|
||||||
|
<Section verticalSpacing horizontalSpacing>
|
||||||
|
<SectionTitle>Blog</SectionTitle>
|
||||||
|
<SectionDescription>{description}</SectionDescription>
|
||||||
|
|
||||||
|
<BlogPosts posts={posts} />
|
||||||
|
</Section>
|
||||||
|
</MainLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BlogPage
|
10
apps/website/app/[locale]/(main)/error.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import type { ErrorServerProps } from "@repo/ui/Errors/ErrorServer"
|
||||||
|
import { ErrorServer } from "@repo/ui/Errors/ErrorServer"
|
||||||
|
|
||||||
|
const ErrorBoundaryPage: React.FC<ErrorServerProps> = (props) => {
|
||||||
|
return <ErrorServer {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ErrorBoundaryPage
|
27
apps/website/app/[locale]/(main)/layout.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import "@repo/config-tailwind/styles.css"
|
||||||
|
import type { LocaleProps } from "@repo/i18n/routing"
|
||||||
|
import { Footer } from "@repo/ui/Layout/Footer"
|
||||||
|
import { Header } from "@repo/ui/Layout/Header"
|
||||||
|
import { ThemeProvider } from "@repo/ui/Layout/Header/SwitchTheme"
|
||||||
|
import { VERSION } from "@repo/utils/constants"
|
||||||
|
import { setRequestLocale } from "next-intl/server"
|
||||||
|
|
||||||
|
interface MainLayoutProps extends React.PropsWithChildren, LocaleProps {}
|
||||||
|
|
||||||
|
const MainLayout: React.FC<MainLayoutProps> = async (props) => {
|
||||||
|
const { children, params } = props
|
||||||
|
|
||||||
|
const { locale } = await params
|
||||||
|
// Enable static rendering
|
||||||
|
setRequestLocale(locale)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeProvider>
|
||||||
|
<Header />
|
||||||
|
{children}
|
||||||
|
<Footer version={VERSION} />
|
||||||
|
</ThemeProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MainLayout
|
12
apps/website/app/[locale]/(main)/loading.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Spinner } from "@repo/ui/Design/Spinner"
|
||||||
|
import { MainLayout } from "@repo/ui/Layout/MainLayout"
|
||||||
|
|
||||||
|
const Loading: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<MainLayout center>
|
||||||
|
<Spinner size={50} />
|
||||||
|
</MainLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Loading
|
10
apps/website/app/[locale]/(main)/not-found.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { ErrorNotFound } from "@repo/ui/Errors/ErrorNotFound"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that `app/[locale]/[...rest]/page.tsx` is necessary for this page to render.
|
||||||
|
*/
|
||||||
|
const NotFound: React.FC = () => {
|
||||||
|
return <ErrorNotFound />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NotFound
|
43
apps/website/app/[locale]/(main)/page.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import type { LocaleProps } from "@repo/i18n/routing"
|
||||||
|
import { About } from "@repo/ui/Home/About"
|
||||||
|
import { Interests } from "@repo/ui/Home/Interests"
|
||||||
|
import { OpenSource } from "@repo/ui/Home/OpenSource"
|
||||||
|
import { Portfolio } from "@repo/ui/Home/Portfolio"
|
||||||
|
import { Skills } from "@repo/ui/Home/Skills"
|
||||||
|
import { MainLayout } from "@repo/ui/Layout/MainLayout"
|
||||||
|
import { RevealFade } from "@repo/ui/Layout/Section"
|
||||||
|
import { setRequestLocale } from "next-intl/server"
|
||||||
|
|
||||||
|
interface HomePageProps extends LocaleProps {}
|
||||||
|
|
||||||
|
const HomePage: React.FC<HomePageProps> = async (props) => {
|
||||||
|
const { params } = props
|
||||||
|
|
||||||
|
const { locale } = await params
|
||||||
|
// Enable static rendering
|
||||||
|
setRequestLocale(locale)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MainLayout>
|
||||||
|
<About />
|
||||||
|
|
||||||
|
<RevealFade>
|
||||||
|
<Interests />
|
||||||
|
</RevealFade>
|
||||||
|
|
||||||
|
<RevealFade>
|
||||||
|
<Skills />
|
||||||
|
</RevealFade>
|
||||||
|
|
||||||
|
<RevealFade>
|
||||||
|
<Portfolio />
|
||||||
|
</RevealFade>
|
||||||
|
|
||||||
|
<RevealFade>
|
||||||
|
<OpenSource />
|
||||||
|
</RevealFade>
|
||||||
|
</MainLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HomePage
|
22
apps/website/app/[locale]/curriculum-vitae/layout.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import "@repo/config-tailwind/styles.css"
|
||||||
|
import type { LocaleProps } from "@repo/i18n/routing"
|
||||||
|
import { ThemeProvider } from "@repo/ui/Layout/Header/SwitchTheme"
|
||||||
|
import { setRequestLocale } from "next-intl/server"
|
||||||
|
|
||||||
|
interface CurriculumVitaeLayoutProps
|
||||||
|
extends React.PropsWithChildren,
|
||||||
|
LocaleProps {}
|
||||||
|
|
||||||
|
const CurriculumVitaeLayout: React.FC<CurriculumVitaeLayoutProps> = async (
|
||||||
|
props,
|
||||||
|
) => {
|
||||||
|
const { children, params } = props
|
||||||
|
|
||||||
|
const { locale } = await params
|
||||||
|
// Enable static rendering
|
||||||
|
setRequestLocale(locale)
|
||||||
|
|
||||||
|
return <ThemeProvider forcedTheme="light">{children}</ThemeProvider>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CurriculumVitaeLayout
|
17
apps/website/app/[locale]/curriculum-vitae/page.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import type { LocaleProps } from "@repo/i18n/routing"
|
||||||
|
import { CurriculumVitae } from "@repo/ui/CurriculumVitae"
|
||||||
|
import { setRequestLocale } from "next-intl/server"
|
||||||
|
|
||||||
|
interface CurriculumVitaeProps extends LocaleProps {}
|
||||||
|
|
||||||
|
const CurriculumVitaePage: React.FC<CurriculumVitaeProps> = async (props) => {
|
||||||
|
const { params } = props
|
||||||
|
|
||||||
|
const { locale } = await params
|
||||||
|
// Enable static rendering
|
||||||
|
setRequestLocale(locale)
|
||||||
|
|
||||||
|
return <CurriculumVitae />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CurriculumVitaePage
|
82
apps/website/app/[locale]/layout.tsx
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import "@repo/config-tailwind/styles.css"
|
||||||
|
import type { LocaleProps } from "@repo/i18n/routing"
|
||||||
|
import type { Locale } from "@repo/utils/constants"
|
||||||
|
import { LOCALES } from "@repo/utils/constants"
|
||||||
|
import type { Metadata } from "next"
|
||||||
|
import { NextIntlClientProvider } from "next-intl"
|
||||||
|
import {
|
||||||
|
getMessages,
|
||||||
|
getTranslations,
|
||||||
|
setRequestLocale,
|
||||||
|
} from "next-intl/server"
|
||||||
|
|
||||||
|
export const generateMetadata = async ({
|
||||||
|
params,
|
||||||
|
}: LocaleProps): Promise<Metadata> => {
|
||||||
|
const { locale } = await params
|
||||||
|
const t = await getTranslations({ locale })
|
||||||
|
const title = t("meta.title")
|
||||||
|
const description = `${title} - ${t("meta.description")}`
|
||||||
|
const image = "/images/logo.webp"
|
||||||
|
const url = new URL("https://theoludwig.fr")
|
||||||
|
const locales = LOCALES.join(", ")
|
||||||
|
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
metadataBase: url,
|
||||||
|
openGraph: {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
url,
|
||||||
|
siteName: title,
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: image,
|
||||||
|
width: 96,
|
||||||
|
height: 96,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
locale: locales,
|
||||||
|
type: "website",
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary",
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
images: [image],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateStaticParams = (): Array<{ locale: Locale }> => {
|
||||||
|
return LOCALES.map((locale) => {
|
||||||
|
return {
|
||||||
|
locale,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LocaleLayoutProps extends React.PropsWithChildren, LocaleProps {}
|
||||||
|
|
||||||
|
const LocaleLayout: React.FC<LocaleLayoutProps> = async (props) => {
|
||||||
|
const { children, params } = props
|
||||||
|
|
||||||
|
const { locale } = await params
|
||||||
|
// Enable static rendering
|
||||||
|
setRequestLocale(locale)
|
||||||
|
|
||||||
|
const messages = await getMessages()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<html lang={locale} suppressHydrationWarning>
|
||||||
|
<body>
|
||||||
|
<NextIntlClientProvider messages={messages}>
|
||||||
|
{children}
|
||||||
|
</NextIntlClientProvider>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LocaleLayout
|
BIN
apps/website/app/favicon.ico
Normal file
After Width: | Height: | Size: 2.4 KiB |
7
apps/website/app/layout.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
interface RootLayoutProps extends React.PropsWithChildren {}
|
||||||
|
|
||||||
|
const RootLayout = ({ children }: RootLayoutProps): React.ReactNode => {
|
||||||
|
return children
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RootLayout
|
20
apps/website/app/not-found.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import Error from "next/error"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the default Next.js 404 page when a route
|
||||||
|
* is requested that doesn't match the middleware and
|
||||||
|
* therefore doesn't have a locale associated with it.
|
||||||
|
*/
|
||||||
|
const NotFound: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<body>
|
||||||
|
<Error statusCode={404} />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NotFound
|
13
apps/website/eslint.config.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import typescriptESLint from "typescript-eslint"
|
||||||
|
import configNextjs from "@repo/eslint-config/nextjs"
|
||||||
|
|
||||||
|
export default typescriptESLint.config(...configNextjs, {
|
||||||
|
files: ["**/*.ts", "**/*.tsx"],
|
||||||
|
languageOptions: {
|
||||||
|
parser: typescriptESLint.parser,
|
||||||
|
parserOptions: {
|
||||||
|
projectService: true,
|
||||||
|
tsconfigRootDir: import.meta.dirname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
3
apps/website/i18n/request.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import i18nRequestConfig from "@repo/i18n/request"
|
||||||
|
|
||||||
|
export default i18nRequestConfig
|
26
apps/website/middleware.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { routing } from "@repo/i18n/routing"
|
||||||
|
import createIntlMiddleware from "next-intl/middleware"
|
||||||
|
|
||||||
|
const intlMiddleware = createIntlMiddleware(routing)
|
||||||
|
|
||||||
|
export default intlMiddleware
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
matcher: [
|
||||||
|
// Enable a redirect to a matching locale at the root
|
||||||
|
"/",
|
||||||
|
|
||||||
|
// Next.js issue, middleware matcher should support template literals:
|
||||||
|
// https://github.com/vercel/next.js/issues/56398
|
||||||
|
"/(en-US|fr-FR)/:path*",
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Match all request paths except for the ones starting with:
|
||||||
|
* - api (API routes)
|
||||||
|
* - _next/static (static files)
|
||||||
|
* - _next/image (image optimization files)
|
||||||
|
* - favicon.ico (favicon file)
|
||||||
|
*/
|
||||||
|
"/((?!api|_next/static|_next/image|images|favicon.ico).*)",
|
||||||
|
],
|
||||||
|
}
|
5
apps/website/next-env.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/image-types/global" />
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
|
22
apps/website/next.config.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import createNextIntlPlugin from "next-intl/plugin"
|
||||||
|
|
||||||
|
const IS_STANDALONE = process.env.IS_STANDALONE === "true"
|
||||||
|
|
||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
const nextConfig = {
|
||||||
|
output: IS_STANDALONE ? "standalone" : undefined,
|
||||||
|
images: {
|
||||||
|
unoptimized: true,
|
||||||
|
},
|
||||||
|
compress: false,
|
||||||
|
eslint: {
|
||||||
|
ignoreDuringBuilds: true,
|
||||||
|
},
|
||||||
|
typescript: {
|
||||||
|
ignoreBuildErrors: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const withNextIntl = createNextIntlPlugin()
|
||||||
|
|
||||||
|
export default withNextIntl(nextConfig)
|
43
apps/website/package.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "@repo/website",
|
||||||
|
"version": "4.1.2",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"imports": {
|
||||||
|
"#*": "./*"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev --port 3000 --turbopack",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start --port 3000",
|
||||||
|
"lint:eslint": "eslint . --max-warnings 0",
|
||||||
|
"lint:typescript": "tsc --noEmit"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@repo/blog": "workspace:*",
|
||||||
|
"@repo/config-tailwind": "workspace:*",
|
||||||
|
"@repo/utils": "workspace:*",
|
||||||
|
"@repo/i18n": "workspace:*",
|
||||||
|
"@repo/ui": "workspace:*",
|
||||||
|
"@mdx-js/mdx": "catalog:",
|
||||||
|
"next-mdx-remote": "catalog:",
|
||||||
|
"shiki": "catalog:",
|
||||||
|
"next": "catalog:",
|
||||||
|
"next-intl": "catalog:",
|
||||||
|
"react": "catalog:",
|
||||||
|
"react-dom": "catalog:"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@repo/eslint-config": "workspace:*",
|
||||||
|
"@repo/config-typescript": "workspace:*",
|
||||||
|
"@types/node": "catalog:",
|
||||||
|
"@types/react": "catalog:",
|
||||||
|
"@types/react-dom": "catalog:",
|
||||||
|
"@total-typescript/ts-reset": "catalog:",
|
||||||
|
"eslint": "catalog:",
|
||||||
|
"postcss": "catalog:",
|
||||||
|
"tailwindcss": "catalog:",
|
||||||
|
"typescript-eslint": "catalog:",
|
||||||
|
"typescript": "catalog:"
|
||||||
|
}
|
||||||
|
}
|
7
apps/website/postcss.config.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
const config = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default config
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 659 B After Width: | Height: | Size: 659 B |
BIN
apps/website/public/images/logo.webp
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
apps/website/public/images/logo_background.webp
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
apps/website/public/images/portfolio/Carolo.webp
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
apps/website/public/images/portfolio/FunctionProject.webp
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
apps/website/public/images/portfolio/Leon.webp
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
apps/website/public/images/portfolio/Thream.webp
Normal file
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 22 KiB |
BIN
apps/website/public/images/posts/thream-v1-0-0/thream-ui.webp
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
apps/website/public/images/skills/ArchLinux.webp
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
apps/website/public/images/skills/C-Cpp.webp
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
apps/website/public/images/skills/CSS.webp
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
apps/website/public/images/skills/Dart.webp
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
apps/website/public/images/skills/Docker.webp
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
apps/website/public/images/skills/Fastify-dark.webp
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
apps/website/public/images/skills/Fastify-light.webp
Normal file
After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
BIN
apps/website/public/images/skills/GNU-Linux.webp
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
apps/website/public/images/skills/Git.webp
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
apps/website/public/images/skills/HTML.webp
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
apps/website/public/images/skills/JavaScript.webp
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
apps/website/public/images/skills/Laravel.webp
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
apps/website/public/images/skills/MySQL.webp
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
apps/website/public/images/skills/NodeJS.webp
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
apps/website/public/images/skills/PHP.webp
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
apps/website/public/images/skills/PostgreSQL.webp
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
apps/website/public/images/skills/Prisma-dark.webp
Normal file
After Width: | Height: | Size: 20 KiB |