Compare commits
204 Commits
Author | SHA1 | Date | |
---|---|---|---|
f70a66e251 | |||
38eb296088 | |||
43d91bfc28 | |||
b63cc3a66e | |||
|
270920111a | ||
d91feb8de4 | |||
e68cb08a6f | |||
|
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 |
@ -1 +0,0 @@
|
||||
{ "extends": ["@commitlint/config-conventional"] }
|
@ -1,2 +0,0 @@
|
||||
ARG VARIANT="16"
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
|
@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "divlo",
|
||||
"dockerComposeFile": "./docker-compose.yml",
|
||||
"service": "workspace",
|
||||
"workspaceFolder": "/workspace",
|
||||
"settings": {
|
||||
"remote.autoForwardPorts": false
|
||||
},
|
||||
"extensions": [
|
||||
"editorconfig.editorconfig",
|
||||
"esbenp.prettier-vscode",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"divlo.vscode-styled-jsx-syntax",
|
||||
"divlo.vscode-styled-jsx-languageserver",
|
||||
"bradlc.vscode-tailwindcss",
|
||||
"mikestead.dotenv",
|
||||
"davidanson.vscode-markdownlint",
|
||||
"ms-azuretools.vscode-docker"
|
||||
],
|
||||
"forwardPorts": [3000],
|
||||
"postAttachCommand": ["npm", "install"],
|
||||
"remoteUser": "node"
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
version: '3.0'
|
||||
|
||||
services:
|
||||
workspace:
|
||||
build:
|
||||
context: './'
|
||||
dockerfile: './Dockerfile'
|
||||
volumes:
|
||||
- '..:/workspace:cached'
|
||||
command: 'sleep infinity'
|
@ -1,12 +1,38 @@
|
||||
.vscode
|
||||
.git
|
||||
**/.git
|
||||
**/.turbo
|
||||
**/.next
|
||||
**/out
|
||||
**/dist
|
||||
**/build
|
||||
**/storybook-static
|
||||
**/coverage
|
||||
**/node_modules
|
||||
|
||||
# envs
|
||||
.env
|
||||
build
|
||||
.next
|
||||
coverage
|
||||
node_modules
|
||||
tmp
|
||||
temp
|
||||
.env.production
|
||||
.env.development
|
||||
secrets
|
||||
|
||||
# IDEs and editors
|
||||
.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
.vscode
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.lighthouseci
|
||||
*.pem
|
||||
Dockerfile
|
||||
README.md
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
@ -1,4 +1,4 @@
|
||||
# For more information see: https://editorconfig.org/
|
||||
# https://editorconfig.org/
|
||||
|
||||
root = true
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
COMPOSE_PROJECT_NAME=divlo.fr
|
||||
PORT=3000
|
||||
TZ=Europe/Paris
|
||||
WEBSITE_PORT=3000
|
||||
|
@ -1,8 +0,0 @@
|
||||
.next
|
||||
.lighthouseci
|
||||
storybook-static
|
||||
coverage
|
||||
node_modules
|
||||
next-env.d.ts
|
||||
**/workbox-*.js
|
||||
**/sw.js
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": ["conventions", "next/core-web-vitals", "prettier"],
|
||||
"plugins": ["prettier", "unicorn"],
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"browser": true,
|
||||
"jest": true
|
||||
},
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"unicorn/prefer-node-protocol": "off",
|
||||
"@typescript-eslint/no-misused-promises": "off"
|
||||
}
|
||||
}
|
8
.github/ISSUE_TEMPLATE/BUG.md
vendored
@ -1,8 +1,8 @@
|
||||
---
|
||||
name: '🐛 Bug Report'
|
||||
about: 'Report an unexpected problem or unintended behavior.'
|
||||
title: '[Bug]'
|
||||
labels: 'bug'
|
||||
name: "🐛 Bug Report"
|
||||
about: "Report an unexpected problem or unintended behavior."
|
||||
title: "[Bug]"
|
||||
labels: "bug"
|
||||
---
|
||||
|
||||
<!--
|
||||
|
8
.github/ISSUE_TEMPLATE/DOCUMENTATION.md
vendored
@ -1,8 +1,8 @@
|
||||
---
|
||||
name: '📜 Documentation'
|
||||
about: 'Correct spelling errors, improvements or additions to documentation files (README, CONTRIBUTING...).'
|
||||
title: '[Documentation]'
|
||||
labels: 'documentation'
|
||||
name: "📜 Documentation"
|
||||
about: "Correct spelling errors, improvements or additions to documentation files (README, CONTRIBUTING...)."
|
||||
title: "[Documentation]"
|
||||
labels: "documentation"
|
||||
---
|
||||
|
||||
<!-- 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'
|
||||
about: 'Suggest a new feature idea.'
|
||||
title: '[Feature]'
|
||||
labels: 'feature request'
|
||||
name: "✨ Feature Request"
|
||||
about: "Suggest a new feature idea."
|
||||
title: "[Feature]"
|
||||
labels: "feature request"
|
||||
---
|
||||
|
||||
<!-- Please make sure your issue has not already been fixed. -->
|
||||
|
8
.github/ISSUE_TEMPLATE/IMPROVEMENT.md
vendored
@ -1,8 +1,8 @@
|
||||
---
|
||||
name: '🔧 Improvement'
|
||||
about: 'Improve structure/format/performance/refactor/tests of the code.'
|
||||
title: '[Improvement]'
|
||||
labels: 'improvement'
|
||||
name: "🔧 Improvement"
|
||||
about: "Improve structure/format/performance/refactor/tests of the code."
|
||||
title: "[Improvement]"
|
||||
labels: "improvement"
|
||||
---
|
||||
|
||||
<!-- Please make sure your issue has not already been fixed. -->
|
||||
|
8
.github/ISSUE_TEMPLATE/QUESTION.md
vendored
@ -1,8 +1,8 @@
|
||||
---
|
||||
name: '🙋 Question'
|
||||
about: 'Further information is requested.'
|
||||
title: '[Question]'
|
||||
labels: 'question'
|
||||
name: "🙋 Question"
|
||||
about: "Further information is requested."
|
||||
title: "[Question]"
|
||||
labels: "question"
|
||||
---
|
||||
|
||||
### Question
|
||||
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,6 +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. -->
|
||||
|
||||
## What changes this PR introduce?
|
||||
# What changes this PR introduce?
|
||||
|
||||
## List any relevant issue numbers
|
||||
|
||||
|
27
.github/workflows/analyze.yml
vendored
@ -1,27 +0,0 @@
|
||||
name: 'Analyze'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop]
|
||||
pull_request:
|
||||
branches: [master, develop]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
runs-on: 'ubuntu-latest'
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ['javascript']
|
||||
|
||||
steps:
|
||||
- uses: 'actions/checkout@v3.0.0'
|
||||
|
||||
- name: 'Initialize CodeQL'
|
||||
uses: 'github/codeql-action/init@v1'
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: 'Perform CodeQL Analysis'
|
||||
uses: 'github/codeql-action/analyze@v1'
|
25
.github/workflows/build.yml
vendored
@ -1,25 +0,0 @@
|
||||
name: 'Build'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop]
|
||||
pull_request:
|
||||
branches: [master, develop]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: 'actions/checkout@v3.0.0'
|
||||
|
||||
- name: 'Use Node.js'
|
||||
uses: 'actions/setup-node@v3.0.0'
|
||||
with:
|
||||
node-version: '16.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Install'
|
||||
run: 'npm install'
|
||||
|
||||
- name: 'Build'
|
||||
run: 'npm run build'
|
37
.github/workflows/chromatic.yml
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
name: "Chromatic"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop]
|
||||
pull_request:
|
||||
branches: [develop, staging, main]
|
||||
|
||||
jobs:
|
||||
chromatic:
|
||||
timeout-minutes: 30
|
||||
runs-on: "ubuntu-latest"
|
||||
env:
|
||||
DO_NOT_TRACK: "1"
|
||||
TURBO_TELEMETRY_DISABLED: "1"
|
||||
NEXT_TELEMETRY_DISABLED: "1"
|
||||
steps:
|
||||
- uses: "actions/checkout@v4.2.2"
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: "pnpm/action-setup@v4.1.0"
|
||||
|
||||
- name: "Setup Node.js"
|
||||
uses: "actions/setup-node@v4.2.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"
|
47
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
name: "CI"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop]
|
||||
pull_request:
|
||||
branches: [develop, staging, main]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
timeout-minutes: 30
|
||||
runs-on: "ubuntu-latest"
|
||||
env:
|
||||
DO_NOT_TRACK: "1"
|
||||
TURBO_TELEMETRY_DISABLED: "1"
|
||||
NEXT_TELEMETRY_DISABLED: "1"
|
||||
steps:
|
||||
- uses: "actions/checkout@v4.2.2"
|
||||
|
||||
- uses: "pnpm/action-setup@v4.1.0"
|
||||
|
||||
- name: "Setup Node.js"
|
||||
uses: "actions/setup-node@v4.2.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"
|
47
.github/workflows/lint.yml
vendored
@ -1,47 +0,0 @@
|
||||
name: 'Lint'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop]
|
||||
pull_request:
|
||||
branches: [master, develop]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: 'actions/checkout@v3.0.0'
|
||||
|
||||
- name: 'Use Node.js'
|
||||
uses: 'actions/setup-node@v3.0.0'
|
||||
with:
|
||||
node-version: '16.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Install'
|
||||
run: 'npm install'
|
||||
|
||||
- name: 'lint:commit'
|
||||
run: 'npm run lint:commit -- --to "${{ github.sha }}"'
|
||||
|
||||
- name: 'lint:editorconfig'
|
||||
run: 'npm run lint:editorconfig'
|
||||
|
||||
- name: 'lint:markdown'
|
||||
run: 'npm run lint:markdown'
|
||||
|
||||
- name: 'lint:typescript'
|
||||
run: 'npm run lint:typescript'
|
||||
|
||||
- name: 'lint:prettier'
|
||||
run: 'npm run lint:prettier'
|
||||
|
||||
- name: 'lint:dotenv'
|
||||
uses: 'dotenv-linter/action-dotenv-linter@v2'
|
||||
with:
|
||||
github_token: ${{ secrets.github_token }}
|
||||
|
||||
- name: 'lint:docker'
|
||||
uses: 'hadolint/hadolint-action@v1.6.0'
|
||||
with:
|
||||
dockerfile: './Dockerfile'
|
44
.github/workflows/release.yml
vendored
@ -1,44 +0,0 @@
|
||||
name: 'Release'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: 'actions/checkout@v3.0.0'
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: 'Import GPG key'
|
||||
uses: 'crazy-max/ghaction-import-gpg@v4'
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
git_user_signingkey: true
|
||||
git_commit_gpgsign: true
|
||||
|
||||
- name: 'Use Node.js'
|
||||
uses: 'actions/setup-node@v3.0.0'
|
||||
with:
|
||||
node-version: '16.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Install'
|
||||
run: 'npm install'
|
||||
|
||||
- name: 'Release'
|
||||
run: 'npm run release'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
GIT_COMMITTER_NAME: ${{ secrets.GIT_NAME }}
|
||||
GIT_COMMITTER_EMAIL: ${{ secrets.GIT_EMAIL }}
|
||||
|
||||
- name: 'Deploy to Vercel'
|
||||
run: 'npm run deploy -- --token="${VERCEL_TOKEN}" --prod'
|
||||
env:
|
||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
70
.github/workflows/test.yml
vendored
@ -1,70 +0,0 @@
|
||||
name: 'Test'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop]
|
||||
pull_request:
|
||||
branches: [master, develop]
|
||||
|
||||
jobs:
|
||||
test-unit:
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: 'actions/checkout@v3.0.0'
|
||||
|
||||
- name: 'Use Node.js'
|
||||
uses: 'actions/setup-node@v3.0.0'
|
||||
with:
|
||||
node-version: '16.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Install'
|
||||
run: 'npm install'
|
||||
|
||||
- name: 'Unit Test'
|
||||
run: 'npm run test:unit'
|
||||
|
||||
test-lighthouse:
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: 'actions/checkout@v3.0.0'
|
||||
|
||||
- name: 'Use Node.js'
|
||||
uses: 'actions/setup-node@v3.0.0'
|
||||
with:
|
||||
node-version: '16.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Install'
|
||||
run: 'npm install'
|
||||
|
||||
- name: 'Build'
|
||||
run: 'npm run build'
|
||||
|
||||
- name: 'html-w3c-validator'
|
||||
run: 'npm run test:html-w3c-validator'
|
||||
|
||||
- name: 'Lighthouse'
|
||||
run: 'npm run test:lighthouse'
|
||||
env:
|
||||
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
|
||||
|
||||
test-e2e:
|
||||
runs-on: 'ubuntu-latest'
|
||||
steps:
|
||||
- uses: 'actions/checkout@v3.0.0'
|
||||
|
||||
- name: 'Use Node.js'
|
||||
uses: 'actions/setup-node@v3.0.0'
|
||||
with:
|
||||
node-version: '16.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 'Install'
|
||||
run: 'npm install'
|
||||
|
||||
- name: 'Build'
|
||||
run: 'npm run build'
|
||||
|
||||
- name: 'End To End (e2e) Test'
|
||||
run: 'npm run test:e2e'
|
62
.gitignore
vendored
@ -1,36 +1,38 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
.npm
|
||||
|
||||
# next.js
|
||||
.next
|
||||
out
|
||||
|
||||
# production
|
||||
build
|
||||
dist
|
||||
public/*.html
|
||||
# PWA
|
||||
public/workbox-*.js
|
||||
public/sw.js
|
||||
package-lock.json
|
||||
.pnpm-store
|
||||
.pnp
|
||||
.pnp.js
|
||||
.yarn/install-state.gz
|
||||
|
||||
# testing
|
||||
coverage
|
||||
cypress/screenshots
|
||||
cypress/videos
|
||||
cypress/downloads
|
||||
|
||||
# envs
|
||||
.env
|
||||
.env.production
|
||||
# production
|
||||
.next/
|
||||
out/
|
||||
dist/
|
||||
build/
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
.turbo
|
||||
bin/
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Storybook
|
||||
*storybook.log
|
||||
storybook-static
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
@ -38,14 +40,14 @@ npm-debug.log*
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
# local env files
|
||||
.env
|
||||
.env.production
|
||||
.env*.local
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.lighthouseci
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
# next-env.d.ts
|
||||
|
20
.gitpod.yml
@ -1,20 +0,0 @@
|
||||
image: 'gitpod/workspace-full'
|
||||
|
||||
tasks:
|
||||
- before: 'cp .env.example .env'
|
||||
init: 'npm install'
|
||||
command: 'npm run dev'
|
||||
|
||||
ports:
|
||||
- port: 3000
|
||||
onOpen: 'open-preview'
|
||||
|
||||
github:
|
||||
prebuilds:
|
||||
master: true
|
||||
branches: true
|
||||
pullRequests: true
|
||||
pullRequestsFromForks: true
|
||||
addComment: true
|
||||
addBadge: true
|
||||
addLabel: true
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"urls": [
|
||||
"http://localhost:3000/",
|
||||
"http://localhost:3000/blog",
|
||||
"http://localhost:3000/blog/hello-world"
|
||||
],
|
||||
"files": ["./public/curriculum-vitae.html"]
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npm run lint:commit -- --edit
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npm run lint:staged
|
@ -1,30 +0,0 @@
|
||||
{
|
||||
"ci": {
|
||||
"collect": {
|
||||
"startServerCommand": "npm run start",
|
||||
"startServerReadyPattern": "ready on",
|
||||
"startServerReadyTimeout": 20000,
|
||||
"url": [
|
||||
"http://localhost:3000/",
|
||||
"http://localhost:3000/blog",
|
||||
"http://localhost:3000/blog/hello-world"
|
||||
],
|
||||
"numberOfRuns": 1
|
||||
},
|
||||
"assert": {
|
||||
"preset": "lighthouse:recommended",
|
||||
"assertions": {
|
||||
"csp-xss": "warning",
|
||||
"non-composited-animations": "warning",
|
||||
"unused-javascript": "warning",
|
||||
"image-size-responsive": "warning",
|
||||
"unsized-images": "warning",
|
||||
"color-contrast": "warning"
|
||||
}
|
||||
},
|
||||
"upload": {
|
||||
"target": "temporary-public-storage"
|
||||
},
|
||||
"server": {}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"*": ["editorconfig-checker"],
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
"prettier --write",
|
||||
"eslint --fix",
|
||||
"jest --findRelatedTests"
|
||||
],
|
||||
"*.{css,scss,sass,json,jsonc,yml,yaml}": ["prettier --write"],
|
||||
"*.{md,mdx}": ["prettier --write", "markdownlint --dot --fix"],
|
||||
"resume.json": ["resume validate"]
|
||||
}
|
16
.markdownlint-cli2.mjs
Normal file
@ -0,0 +1,16 @@
|
||||
import relativeLinksRule from "markdownlint-rule-relative-links"
|
||||
|
||||
const config = {
|
||||
config: {
|
||||
extends: "markdownlint/style/prettier",
|
||||
default: true,
|
||||
"relative-links": true,
|
||||
"no-duplicate-heading": false,
|
||||
"no-inline-html": false,
|
||||
},
|
||||
globs: ["**/*.md"],
|
||||
ignores: ["**/node_modules"],
|
||||
customRules: [relativeLinksRule],
|
||||
}
|
||||
|
||||
export default config
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"default": true,
|
||||
"MD013": false,
|
||||
"MD024": false,
|
||||
"MD033": false,
|
||||
"MD041": false
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
.next
|
||||
.lighthouseci
|
||||
storybook-static
|
||||
coverage
|
||||
node_modules
|
||||
next-env.d.ts
|
||||
**/workbox-*.js
|
||||
**/sw.js
|
||||
*.hbs
|
13
.prettierrc.json
Normal file → Executable file
@ -1,6 +1,13 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"jsxSingleQuote": true,
|
||||
"semi": false,
|
||||
"trailingComma": "none"
|
||||
"plugins": ["prettier-plugin-tailwindcss"],
|
||||
"tailwindFunctions": ["classNames", "cva"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "pnpm-lock.yaml",
|
||||
"options": {
|
||||
"rangeEnd": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
{
|
||||
"branches": ["master"],
|
||||
"plugins": [
|
||||
[
|
||||
"@semantic-release/commit-analyzer",
|
||||
{
|
||||
"preset": "conventionalcommits"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/release-notes-generator",
|
||||
{
|
||||
"preset": "conventionalcommits"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/npm",
|
||||
{
|
||||
"npmPublish": false
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/git",
|
||||
{
|
||||
"assets": ["package.json", "package-lock.json"],
|
||||
"message": "chore(release): ${nextRelease.version} [skip ci]"
|
||||
}
|
||||
],
|
||||
"@semantic-release/github",
|
||||
[
|
||||
"@saithodev/semantic-release-backmerge",
|
||||
{
|
||||
"branches": [{ "from": "master", "to": "develop" }],
|
||||
"backmergeStrategy": "merge"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
8
.vscode/extensions.json
vendored
@ -3,11 +3,11 @@
|
||||
"editorconfig.editorconfig",
|
||||
"esbenp.prettier-vscode",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"divlo.vscode-styled-jsx-syntax",
|
||||
"divlo.vscode-styled-jsx-languageserver",
|
||||
"davidanson.vscode-markdownlint",
|
||||
"bradlc.vscode-tailwindcss",
|
||||
"mikestead.dotenv",
|
||||
"davidanson.vscode-markdownlint",
|
||||
"ms-azuretools.vscode-docker"
|
||||
"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",
|
||||
},
|
||||
}
|
17
.vscode/settings.json
vendored
@ -1,10 +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": true
|
||||
}
|
||||
"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": false,
|
||||
"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
|
||||
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 community leaders are obligated to respect the privacy and security of the
|
||||
|
@ -1,6 +1,10 @@
|
||||
# 💡 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
|
||||
|
||||
@ -11,79 +15,77 @@ Thanks a lot for your interest in contributing to **divlo.fr**! 🎉
|
||||
|
||||
## 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 linting.
|
||||
|
||||
- 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
|
||||
|
||||
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.
|
||||
|
||||
### 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.
|
||||
The commit message guidelines adheres to [Conventional Commits](https://www.conventionalcommits.org/) and [Semantic Versioning](https://semver.org/) for releases.
|
||||
|
||||
## Getting Started
|
||||
|
||||
[](https://gitpod.io/#https://github.com/Divlo/Divlo)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- [Node.js](https://nodejs.org/) >= 16.0.0
|
||||
- [npm](https://www.npmjs.com/) >= 8.0.0
|
||||
- [Node.js](https://nodejs.org/) >= 22.12.0 [(`nvm install 22`)](https://nvm.sh)
|
||||
- [pnpm](https://pnpm.io/) >= 10.2.1 [(`corepack enable`)](https://nodejs.org/docs/latest-v22.x/api/corepack.html)
|
||||
- [Docker](https://www.docker.com/)
|
||||
|
||||
### Installation
|
||||
|
||||
```sh
|
||||
# Clone the repository
|
||||
git clone https://github.com/Divlo/Divlo.git
|
||||
git clone git@github.com:theoludwig/theoludwig.git
|
||||
|
||||
# Go to the project root
|
||||
cd Divlo
|
||||
cd theoludwig
|
||||
|
||||
# Configure environment variables
|
||||
cp .env.example .env
|
||||
cp apps/website/.env.example apps/website/.env
|
||||
|
||||
# Install
|
||||
npm install
|
||||
# Install dependencies
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# Install Playwright browser binaries and their dependencies (tests)
|
||||
pnpm exec playwright install --with-deps
|
||||
```
|
||||
|
||||
### Local Development environment
|
||||
### Development
|
||||
|
||||
```sh
|
||||
# Run website
|
||||
npm run dev
|
||||
# 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
|
||||
# Setup and run all the services for you
|
||||
docker-compose up --build
|
||||
VERSION=$(git describe --tags) docker compose up --build --detach
|
||||
```
|
||||
|
||||
### Services started
|
||||
#### Services started
|
||||
|
||||
- website : `http://localhost:3000`
|
||||
`theoludwig`: <http://localhost:3000>
|
||||
|
23
Dockerfile
@ -1,23 +0,0 @@
|
||||
FROM node:16.14.0 AS dependencies
|
||||
WORKDIR /usr/src/app
|
||||
COPY ./package*.json ./
|
||||
RUN npm install
|
||||
|
||||
FROM node:16.14.0 AS builder
|
||||
WORKDIR /usr/src/app
|
||||
COPY ./ ./
|
||||
COPY --from=dependencies /usr/src/app/node_modules ./node_modules
|
||||
RUN npm run build
|
||||
|
||||
FROM node:16.14.0 AS runner
|
||||
WORKDIR /usr/src/app
|
||||
ENV NODE_ENV=production
|
||||
COPY --from=builder /usr/src/app/next.config.js ./next.config.js
|
||||
COPY --from=builder /usr/src/app/public ./public
|
||||
COPY --from=builder /usr/src/app/.next ./.next
|
||||
COPY --from=builder /usr/src/app/i18n.json ./i18n.json
|
||||
COPY --from=builder /usr/src/app/locales ./locales
|
||||
COPY --from=builder /usr/src/app/pages ./pages
|
||||
COPY --from=builder /usr/src/app/node_modules ./node_modules
|
||||
RUN npx next telemetry disable
|
||||
CMD ["node_modules/.bin/next", "start", "--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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
42
README.md
@ -1,18 +1,18 @@
|
||||
<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">
|
||||
<strong>Developer Full Stack Junior • Passionate about High-Tech</strong>
|
||||
<strong>Developer Full Stack • Open-Source Enthusiast</strong>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<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/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/~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/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/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/divlo"><img alt="Twitch" src="https://img.shields.io/badge/-Twitch-9147FF?style=flat&labelColor=9147FF&logo=twitch&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@divlo.fr"><img alt="Email" src="https://img.shields.io/badge/-contact@divlo.fr-2F7EBE?style=flat&labelColor=2F7EBE&logo=minutemailer&logoColor=white"/></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://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://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://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://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.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://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="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>
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
@ -21,20 +21,16 @@
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Divlo",
|
||||
"name": "Théo LUDWIG",
|
||||
"pronouns": "He/Him",
|
||||
"birthDate": "31/03/2003",
|
||||
"birthDate": "2003-03-31",
|
||||
"nationality": "Alsace, France",
|
||||
"interests": [
|
||||
"Developer Full Stack Junior",
|
||||
"Passionate about High-Tech",
|
||||
"Open-Source enthusiast"
|
||||
],
|
||||
"interests": ["Developer Full Stack", "Open-Source Enthusiast"],
|
||||
"skills": {
|
||||
"programmingLanguages": ["JavaScript", "TypeScript", "Python", "C/C++"],
|
||||
"frontEnd": ["HTML", "CSS", "Tailwind CSS", "React.js (+ Next.js)"],
|
||||
"backEnd": ["Node.js", "Fastify", "Prisma", "PostgreSQL", "MySQL"],
|
||||
"tools": ["GNU/Linux", "Ubuntu", "Visual Studio Code", "Git", "Docker"]
|
||||
"programmingLanguages": ["JavaScript/TypeScript", "Python", "C/C++", "PHP"],
|
||||
"frontend": ["HTML/CSS", "Tailwind CSS", "React.js/Next.js"],
|
||||
"backend": ["Laravel", "Node.js", "Fastify", "PostgreSQL"],
|
||||
"tools": ["GNU/Linux", "Arch Linux", "Visual Studio Code", "Git", "Docker"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -44,6 +40,6 @@
|
||||
## 📈 Statistics
|
||||
|
||||
<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/top-langs/?username=Divlo&hide=html,css,javascript&langs_count=8&layout=compact&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=theoludwig&hide=html,css,javascript&langs_count=8&layout=compact&theme=dark" alt="Théo LUDWIG's Programming Languages" />
|
||||
</p>
|
||||
|
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
|
57
apps/storybook/.storybook/preview.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import "@repo/config-tailwind/styles.css"
|
||||
import "./storybook-css-overrides.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 = {
|
||||
globals: {
|
||||
a11y: {
|
||||
manual: true,
|
||||
},
|
||||
},
|
||||
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
|
3
apps/storybook/.storybook/storybook-css-overrides.css
Normal file
@ -0,0 +1,3 @@
|
||||
body {
|
||||
overflow: auto !important;
|
||||
}
|
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/config-eslint"
|
||||
|
||||
export default typescriptESLint.config(...config, {
|
||||
files: ["**/*.ts", "**/*.tsx"],
|
||||
languageOptions: {
|
||||
parser: typescriptESLint.parser,
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
})
|
84
apps/storybook/http-server.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import http from "node:http"
|
||||
import fs from "node:fs"
|
||||
import path from "node:path"
|
||||
import util from "node:util"
|
||||
import mime from "mime"
|
||||
|
||||
const MIMETYPE_DEFAULT = "application/octet-stream"
|
||||
|
||||
const args = util.parseArgs({
|
||||
options: {
|
||||
path: { type: "string", default: "public", required: true },
|
||||
port: { type: "string", default: "3000", required: true },
|
||||
host: { type: "string", default: "0.0.0.0" },
|
||||
},
|
||||
})
|
||||
|
||||
const host = args.values.host
|
||||
const basePath = args.values.path
|
||||
|
||||
const port = Number.parseInt(args.values.port, 10)
|
||||
if (Number.isNaN(port)) {
|
||||
console.error("Error: Invalid port number.")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const serverURL = `http://${host}:${port}`
|
||||
|
||||
const server = http.createServer(async (request, response) => {
|
||||
if (request.url == null) {
|
||||
response.writeHead(400, { "Content-Type": "text/plain" })
|
||||
response.end("Bad Request")
|
||||
return
|
||||
}
|
||||
const url = new URL(request.url, serverURL)
|
||||
const urlPath = url.pathname
|
||||
const filePath = path.join(process.cwd(), basePath, urlPath)
|
||||
try {
|
||||
const stat = await fs.promises.stat(filePath)
|
||||
if (stat.isDirectory()) {
|
||||
const indexFile = path.join(filePath, "index.html")
|
||||
try {
|
||||
const fileContent = await fs.promises.readFile(indexFile)
|
||||
response.writeHead(200, { "Content-Type": "text/html" })
|
||||
response.end(fileContent)
|
||||
} catch {
|
||||
response.writeHead(403, { "Content-Type": "text/plain" })
|
||||
response.end("Error: Directory listing not allowed.")
|
||||
}
|
||||
} else {
|
||||
const mimeType = mime.getType(filePath) ?? MIMETYPE_DEFAULT
|
||||
const fileContent = await fs.promises.readFile(filePath)
|
||||
response.writeHead(200, { "Content-Type": mimeType })
|
||||
response.end(fileContent)
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
||||
response.writeHead(404, { "Content-Type": "text/plain" })
|
||||
response.end("Error: File not found.")
|
||||
} else {
|
||||
response.writeHead(500, { "Content-Type": "text/plain" })
|
||||
response.end("Error: Internal Server Error.")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const gracefulShutdown = (): void => {
|
||||
server.close()
|
||||
process.exit(0)
|
||||
}
|
||||
process.on("SIGTERM", gracefulShutdown)
|
||||
process.on("SIGINT", gracefulShutdown)
|
||||
|
||||
server.listen(
|
||||
{
|
||||
host,
|
||||
port,
|
||||
},
|
||||
() => {
|
||||
console.log(
|
||||
`HTTP Server is listening at ${util.styleText("cyan", serverURL)}`,
|
||||
)
|
||||
console.log(`Serving files from: \`${basePath}\``)
|
||||
},
|
||||
)
|
57
apps/storybook/package.json
Normal file
@ -0,0 +1,57 @@
|
||||
{
|
||||
"name": "@repo/storybook",
|
||||
"version": "0.0.0-develop",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "storybook build",
|
||||
"dev": "storybook dev --port 6006 --no-open",
|
||||
"start": "node --experimental-strip-types http-server.ts --path=storybook-static --port=6006",
|
||||
"test": "start-server-and-test \"start\" http://localhost:6006 \"test:storybook\"",
|
||||
"test:dev": "start-server-and-test \"dev\" http://localhost: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:",
|
||||
"mime": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@repo/config-eslint": "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:",
|
||||
"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": ["http-server.ts", "./.storybook/**/*.ts", "./.storybook/**/*.tsx"]
|
||||
}
|
9
apps/storybook/turbo.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"$schema": "../../node_modules/turbo/schema.json",
|
||||
"extends": ["//"],
|
||||
"tasks": {
|
||||
"test": {
|
||||
"dependsOn": ["^test", "build"]
|
||||
}
|
||||
}
|
||||
}
|
4
apps/website/.env.example
Normal file
@ -0,0 +1,4 @@
|
||||
TZ=Europe/Paris
|
||||
HOSTNAME=0.0.0.0
|
||||
PORT=3000
|
||||
NEXT_TELEMETRY_DISABLED=1
|
42
apps/website/Dockerfile
Normal file
@ -0,0 +1,42 @@
|
||||
FROM node:22.13.1-slim AS node-pnpm
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN npm install --global corepack@0.31.0 && corepack enable
|
||||
ENV TURBO_TELEMETRY_DISABLED=1
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV DO_NOT_TRACK=1
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
FROM node-pnpm AS builder
|
||||
COPY ./ ./
|
||||
RUN pnpm install --global turbo@2.4.0
|
||||
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
|
||||
|
||||
ARG VERSION="0.0.0-develop"
|
||||
RUN pnpm install --global replace-in-files-cli@3.0.0
|
||||
RUN VERSION_STRIPPED=${VERSION#v} && replace-in-files --regex='version": *"[^"]*' --replacement='"version": "'"$VERSION_STRIPPED"'"' '**/package.json' '!**/node_modules/**'
|
||||
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 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
|
95
apps/website/app/[locale]/layout.tsx
Normal file
@ -0,0 +1,95 @@
|
||||
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, Viewport } from "next"
|
||||
import { NextIntlClientProvider } from "next-intl"
|
||||
import {
|
||||
getMessages,
|
||||
getTranslations,
|
||||
setRequestLocale,
|
||||
} from "next-intl/server"
|
||||
import Script from "next/script"
|
||||
|
||||
const DOMAIN = "theoludwig.fr"
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: "#00aeff",
|
||||
}
|
||||
|
||||
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://${DOMAIN}`)
|
||||
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>
|
||||
|
||||
<Script
|
||||
defer
|
||||
data-domain={DOMAIN}
|
||||
src="https://plausible.theoludwig.fr/js/script.js"
|
||||
/>
|
||||
</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/config-eslint/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).*)",
|
||||
],
|
||||
}
|
2
next-env.d.ts → apps/website/next-env.d.ts
vendored
@ -2,4 +2,4 @@
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
// see https://nextjs.org/docs/app/api-reference/config/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": "0.0.0-develop",
|
||||
"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/config-eslint": "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 |