1
1
mirror of https://github.com/theoludwig/theoludwig.git synced 2025-02-08 21:59:39 +01:00

Compare commits

...

148 Commits

Author SHA1 Message Date
f70a66e251
fix: replace standard open source contributions by nodejs.org 2025-02-08 20:56:56 +01:00
38eb296088
feat: themeColor metadata 2025-02-08 20:51:22 +01:00
43d91bfc28
chore: fix storybook configuration 2025-02-08 20:48:19 +01:00
b63cc3a66e
chore: cleaner setup 2025-02-08 20:00:47 +01:00
semantic-release-bot
270920111a
chore(release): 4.1.3 [skip ci] 2025-01-23 12:17:18 +00:00
d91feb8de4
fix: use Plausible 2025-01-23 13:16:20 +01:00
e68cb08a6f
fix: update Node.js to v22.13.1 (security release)
Ref: https://nodejs.org/en/blog/release/v22.13.1
2025-01-23 13:11:57 +01:00
semantic-release-bot
09d677bd37
chore(release): 4.1.2 [skip ci] 2024-12-06 22:22:48 +00:00
db1159f20c
fix(blog): issue with CSS loading
Ref: https://github.com/nodejs/node/issues/56155
2024-12-06 23:16:40 +01:00
semantic-release-bot
af5c845e4b
chore(release): 4.1.1 [skip ci] 2024-12-06 08:35:37 +00:00
3f66dfe46e
fix: error 404 not found 2024-12-06 09:30:49 +01:00
d52a0c6f08
build(deps): update latest 2024-12-06 09:30:44 +01:00
semantic-release-bot
251b0b4038
chore(release): 4.1.0 [skip ci] 2024-11-09 20:10:23 +00:00
a5baffe9eb
fix(ui): button outline, hover effect 2024-11-09 21:01:31 +01:00
1351e4122d
fix(blog): shiki syntax highlighting for txt 2024-11-09 20:21:09 +01:00
4c69d5a852
refactor(ui): allow all tailwind css colors 2024-11-09 20:14:30 +01:00
9e840b8dae
build(deps): update Next.js to v15 and ESLint to v9 2024-11-09 19:50:22 +01:00
59153a7a69
style: fix ESLint 2024-10-13 00:00:44 +02:00
0a7094005c
chore: config updates 2024-10-12 23:51:58 +02:00
12f1d6cdf2
chore: try to fix CI with Playwright 2024-09-12 00:14:58 +02:00
0d7b33727b
feat: add in progress Engineering study + IRCAD until 2027 on CV 2024-09-12 00:05:59 +02:00
386f407f21
chore: simplify TypeScript config 2024-09-11 23:53:26 +02:00
semantic-release-bot
6853ac6884
chore(release): 4.0.0 [skip ci] 2024-07-31 22:55:33 +00:00
b199aedf77
feat: add Locale switch to Curriculum Vitae (not visible in print mode) 2024-08-01 00:48:22 +02:00
da4b483a3c
fix: a11y issues with curriculum-vitae 2024-08-01 00:36:45 +02:00
012fea869f
feat: translate Curriculum Vitae in both English and French 2024-08-01 00:26:46 +02:00
a596d1c443
feat: components structure Curriculum Vitae 2024-07-31 22:27:51 +02:00
b4611e4a7f
feat: init Curriculum Vitae 2024-07-31 19:23:14 +02:00
b5c50728de
refactor: components struture 2024-07-31 11:41:39 +02:00
ceeeb2f9c5
fix: add missing unstable_setRequestLocale to enable static rendering 2024-07-31 11:00:30 +02:00
semantic-release-bot
c094b37bca
chore(release): 4.0.0-staging.1 [skip ci] 2024-07-30 22:57:33 +00:00
8dde7f5b42
ci: install playwright --with-deps 2024-07-31 00:47:05 +02:00
cef5ead09f
chore: ignore curriculum-vitae 2024-07-30 23:59:33 +02:00
7bde328b96
perf!: monorepo setup + fully static + webp images
BREAKING CHANGE: minimum supported Node.js >= 22.0.0 and pnpm >= 9.5.0
2024-07-30 23:59:06 +02:00
semantic-release-bot
0f44e64c0c
chore(release): 3.3.2 [skip ci] 2024-07-20 08:34:00 +00:00
84c192bbef
chore: usage of main instead of master 2024-07-20 10:31:14 +02:00
6f78a0686c
fix: locale text with font-semibold 2024-07-20 10:28:17 +02:00
2897d181c5
Revert "fix: stop using flag image, use emoji instead"
This reverts commit f64acb68c72869a7461757668d5c4c0ceb30ee96.
2024-07-20 10:26:19 +02:00
f94ce7d7bc
fix: update Node.js to v20.15.1 (security release) 2024-07-20 10:21:16 +02:00
semantic-release-bot
dd09092842
chore(release): 3.3.1 [skip ci] 2024-07-06 21:01:51 +00:00
f64acb68c7
fix: stop using flag image, use emoji instead 2024-07-06 02:33:49 +02:00
semantic-release-bot
3074945c54
chore(release): 3.3.0 [skip ci] 2024-05-23 20:35:01 +00:00
fc0dfdda5f
chore(blog): update shiki to v1.6.0 and update next-mdx-remote to v5.0.0 2024-05-23 22:30:13 +02:00
f62964c62a
ci: update GitHub Actions 2024-05-23 21:41:05 +02:00
8ec113c9cb
feat(blog): update Git Ultimate Guide to add trick about cherry-pick and diff-commits alias 2024-05-23 10:29:35 +02:00
semantic-release-bot
8a59e9034f
chore(release): 3.2.6 [skip ci] 2024-05-21 18:23:28 +00:00
d7121ea833
style: fix tailwindcss linting 2024-05-21 20:18:05 +02:00
c10f690622
build(deps): update dependencies to latest 2024-05-21 20:15:57 +02:00
6915072ab9
chore: delete unused config 2024-05-21 19:31:45 +02:00
dd803bcc51
test: fix should display hello-world blog post 2024-05-21 19:17:29 +02:00
efa33f26ec
fix(blog): headings should be aligned with the text, not shifted 2024-05-21 19:06:12 +02:00
semantic-release-bot
5f3dfad988
chore(release): 3.2.5 [skip ci] 2024-05-16 08:09:25 +00:00
b231381cb3
fix: client-side age calculation, more glanular check for isMounted
Allows to render as much as possible on the server side.
While keeping the calculation of the age on the client side to avoid hydratation mismatch.
2024-05-16 10:06:43 +02:00
bbb2e56512
fix: usage of correct heading levels and html tags 2024-05-16 09:56:19 +02:00
66cf6d7438
fix: add scroll behavior: smooth 2024-05-16 09:32:20 +02:00
2a635bf3ba
fix: add hover effects 2024-05-16 09:26:05 +02:00
semantic-release-bot
9f79b88202
chore(release): 3.2.4 [skip ci] 2024-04-13 17:17:11 +00:00
23d9caf578
style: fix eslint 2024-04-13 19:13:48 +02:00
7febe6d1f9
fix(blog): typos in posts 2024-04-13 19:03:18 +02:00
c4650c34d9
build(deps): update latest 2024-04-13 18:54:36 +02:00
0eb780485c
fix(footer): show 0.0.0-development version in Footer in development 2024-04-06 20:40:25 +02:00
cd5e92b64a
fix: hydratation error with age calculation 2024-04-06 20:32:09 +02:00
982b148329
Revert "fix(portfolio): update link to Carolo (carolo.org)"
This reverts commit c2c9b59c7aa4ad0c185a9901a2bde4dd16a9d80c.
2024-04-06 20:27:04 +02:00
0febee5b51
refactor: rename to primary color 2024-04-06 20:25:02 +02:00
semantic-release-bot
3502f51735
chore(release): 3.2.3 [skip ci] 2024-02-15 08:41:01 +00:00
493df4e2f2
style: fix prettier 2024-02-15 09:35:58 +01:00
c2c9b59c7a
fix(portfolio): update link to Carolo (carolo.org) 2024-02-15 09:34:02 +01:00
f6e3008ab9
fix(blog): add command to commit in the past in Git Ultimate Guide 2024-02-15 09:30:34 +01:00
15e94cec64
fix: update dependencies to latest to address security issues Node.js v20.11.1
Ref: https://nodejs.org/en/blog/vulnerability/february-2024-security-releases
2024-02-15 09:27:03 +01:00
semantic-release-bot
5185c6758b
chore(release): 3.2.2 [skip ci] 2024-02-02 16:31:35 +00:00
b633eef833
fix: remove npm vulnerability by updating html-w3c-validator 2024-02-02 17:30:25 +01:00
d2e627ff13
chore: cleaner configs 2024-01-29 21:26:59 +01:00
semantic-release-bot
1e0567b538
chore(release): 3.2.1 [skip ci] 2024-01-28 15:15:48 +00:00
c8d32c6acc
test: correct selector for Main Title of page 2024-01-28 16:13:02 +01:00
05503cda26
chore: only report errors for html validation 2024-01-28 16:04:00 +01:00
303b6f3011
fix: correct responsive for Header Title 2024-01-28 15:45:45 +01:00
0272cf7080
docs(license): add email address 2024-01-28 15:42:23 +01:00
e8ea42a260
fix: wrong font weight on hover link 2024-01-28 15:42:01 +01:00
semantic-release-bot
f337e14260
chore(release): 3.2.0 [skip ci] 2024-01-28 12:16:11 +00:00
f5020cad19
chore: usage of eslint-plugin-tailwindcss 2024-01-28 03:21:11 +01:00
b8ceefb2f6
feat: new logo v1 2024-01-28 01:56:47 +01:00
1523c8cac0
fix: wording typos 2024-01-25 14:46:03 +01:00
548ddc8425
style: format JSONC files with Prettier correctly 2024-01-24 21:49:30 +01:00
bac65ad61a
fix: improve wording 2024-01-23 23:59:10 +01:00
b91f3165b7
fix(blog): add depreciation notice on Thream post 2024-01-23 22:29:21 +01:00
5478e202a7
fix(open source): replace nrwl/nx by DefinitelyTyped 2024-01-23 22:13:39 +01:00
a89b5932c2
fix: update dependencies to latest 2024-01-23 22:01:50 +01:00
semantic-release-bot
339e42acfa
chore(release): 3.1.2 [skip ci] 2023-12-28 05:24:14 +00:00
c123815a86
fix(portfolio): remove Thream project as it is now deprecated 2023-12-28 06:21:32 +01:00
dd26a277a2
fix: update dependencies to latest 2023-12-28 06:21:24 +01:00
semantic-release-bot
62222dbb0c
chore(release): 3.1.1 [skip ci] 2023-11-07 20:34:11 +00:00
ee0a02bc8b
chore: downgrade commitlint temporarily to release new versions 2023-11-07 21:33:05 +01:00
2e04053ec3
fix: update CV with latest education courses 2023-11-07 21:14:43 +01:00
45a9a69122
fix: update dependencies to latest 2023-11-07 20:57:52 +01:00
e566ef6c38
chore: better Prettier config for easier reviews 2023-10-23 23:11:59 +02:00
semantic-release-bot
c7ad15a465
chore(release): 3.1.0 [skip ci] 2023-09-18 20:09:29 +00:00
f4a842efb5
build: downgrade semantic-release to v21.1.2
Ref: https://github.com/semantic-release/semantic-release/issues/2968
2023-09-18 22:08:04 +02:00
424c97019b
fix: update dependencies to latest 2023-09-18 22:00:11 +02:00
c0508dc0b9
build: ignore ESLint errors for Production build
It improves performance when extra checking is not necessary.
2023-09-14 12:26:19 +02:00
f04d8a0c11
Revert "build: ignore ESLint and TypeScript errors for Production build"
This reverts commit fdab2a7ea8026867cdc493361c85ba907dfe998b.
2023-09-14 12:19:26 +02:00
d29064745c
feat: add IRCAD as work experience 2023-09-14 12:11:18 +02:00
95febe2a99
feat: add 3rd year of BUT Informatique as education 2023-09-14 12:01:20 +02:00
fdab2a7ea8
build: ignore ESLint and TypeScript errors for Production build
It improves performance when extra checking is not necessary.
2023-09-14 11:49:52 +02:00
35211fa279
fix: try/catch inside middleware when checking locale 2023-08-24 23:09:33 +02:00
137cceffa1
build(deps): update latest 2023-08-24 22:38:09 +02:00
semantic-release-bot
f6bfc466de
chore(release): 3.0.0 [skip ci] 2023-08-01 17:41:12 +00:00
e4cf714d95
test: fix styles import for unit tests 2023-08-01 19:39:09 +02:00
d3c86b2a26
chore: update Dockerfile 2023-08-01 19:34:58 +02:00
d2578abeec
fix: loader improvements 2023-08-01 18:59:45 +02:00
e51e3bdc19
test: fix e2e tests + 500 error page 2023-08-01 18:18:16 +02:00
56520830e9
refactor: blog directory 2023-08-01 17:44:08 +02:00
2e0138194c
refactor: avoid usage of React.FC to use JSX.Element (to stay consistent) 2023-08-01 17:22:09 +02:00
4b2e7bae90
feat: rewrite blog to Next.js v13 app directory
Improvement: Support light theme in code block
2023-08-01 17:07:19 +02:00
caa6a90418
refactor: implement light/dark themes using cookies 2023-08-01 14:11:46 +02:00
e82db952db
docs: update interests 2023-08-01 13:15:03 +02:00
6b29ce9b15
feat: rewrite to Next.js v13 app directory
Improvements:
- Hide switch theme input (ugly little white square)
- i18n without subpath (e.g: /fr or /en), same url whatever the locale used
2023-07-31 19:06:46 +02:00
5640f1b434
build(deps): bump Node.js to 20.0.0 and npm to 9.0.0
BREAKING CHANGE: minimum supported Node.js >= 20.0.0 and npm >= 9.0.0
2023-07-30 19:03:36 +02:00
6d0dcb50a7
refactor: 'use client' when appropriate 2023-07-30 18:50:14 +02:00
70603f1444
chore: remove build error with Docker copy wrong node_modules 2023-07-30 18:27:15 +02:00
f42fdbfd0c
chore: rename jsonresume-theme-custom to curriculum-vitae 2023-07-28 11:53:04 +02:00
6a3f335f9f
fix(posts): update git blog post 2023-07-28 11:40:19 +02:00
f1509d0af1
chore: rename docker-compose.yml to compose.yaml
Ref: https://docs.docker.com/compose/compose-file/03-compose-file/
2023-07-28 11:38:34 +02:00
semantic-release-bot
49599d25ed
chore(release): 2.13.0 [skip ci] 2023-07-22 17:47:02 +00:00
65e0f4f8b6
fix: avoid scrolling when changing language 2023-07-22 19:40:28 +02:00
8d60c2d53a
feat: add Carolo project in Portfolio 2023-07-22 19:39:57 +02:00
0bbebeab99
build(deps): update latest
Some checks failed
Analyze / analyze (javascript) (push) Failing after 1m24s
Build / build (push) Successful in 3m0s
Lint / lint (push) Successful in 2m6s
Test / test-unit (push) Successful in 1m56s
Test / test-e2e (push) Successful in 3m17s
2023-07-19 00:09:28 +02:00
semantic-release-bot
643e0e5821
chore(release): 2.12.1 [skip ci] 2023-07-14 22:03:03 +00:00
872b018673
style: fix prettier 2023-07-14 23:58:50 +02:00
2644cb0fb5
fix: update /curriculum-vitae to /curriculum-vitae/index.html 2023-07-14 23:54:29 +02:00
bc719578d2
fix: remove vercel cli + update dependencies to latest 2023-07-14 23:50:20 +02:00
semantic-release-bot
117c41b1c3
chore(release): 2.12.0 [skip ci] 2023-07-02 14:59:12 +00:00
b92704b77d
feat: increase duration work experience Numerize 2023-07-02 16:50:32 +02:00
bab7581283
fix: update dependencies to latest 2023-07-02 16:42:39 +02:00
semantic-release-bot
988fceb2aa
chore(release): 2.11.0 [skip ci] 2023-06-18 10:23:59 +00:00
5211ba1489
feat(skills): add Arch Linux 2023-06-18 12:18:24 +02:00
semantic-release-bot
6886480cef
chore(release): 2.10.0 [skip ci] 2023-06-16 21:30:51 +00:00
d78e50638e
test: fix with new anchor link behavior in blog posts 2023-06-16 23:26:09 +02:00
3b76195d71
feat(blog): add anchor links for titles/headers 2023-06-16 23:14:25 +02:00
2dc63ba933
chore: maintenance 2023-06-16 22:56:53 +02:00
336f067c52
fix(posts): add explanations for Git (cherry-pick + merge squash) 2023-06-16 22:36:20 +02:00
5fd7f77b6d
fix: justify align text in blog posts 2023-06-16 21:48:47 +02:00
semantic-release-bot
db0c708c04
chore(release): 2.9.0 [skip ci] 2023-05-31 18:39:59 +00:00
9d44671fed
feat: continue migrating to full name instead of nickname 2023-05-31 20:09:08 +02:00
semantic-release-bot
7bcc5f972c
chore(release): 2.8.0 [skip ci] 2023-05-30 19:57:02 +00:00
61172d59e3
feat: migrate progressively to full name instead of nickname 2023-05-30 21:51:27 +02:00
semantic-release-bot
7c0f11ab7d
chore(release): 2.7.3 [skip ci] 2023-05-29 15:45:42 +00:00
Divlo
670897fa78
fix: improve spelling consistency 2023-05-29 17:44:26 +02:00
Divlo
b88246b668
chore: usage of next start 2023-05-29 17:33:45 +02:00
371 changed files with 21428 additions and 30259 deletions

View File

@ -1 +0,0 @@
{ "extends": ["@commitlint/config-conventional"] }

View File

@ -1 +0,0 @@
FROM mcr.microsoft.com/devcontainers/javascript-node:18

View File

@ -1,25 +0,0 @@
{
"name": "Divlo",
"dockerComposeFile": "./docker-compose.yml",
"service": "workspace",
"workspaceFolder": "/workspace",
"customizations": {
"vscode": {
"settings": {
"remote.autoForwardPorts": false
},
"extensions": [
"editorconfig.editorconfig",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"bradlc.vscode-tailwindcss",
"mikestead.dotenv",
"davidanson.vscode-markdownlint",
"ms-azuretools.vscode-docker"
]
}
},
"forwardPorts": [3000],
"postAttachCommand": ["npm", "install"],
"remoteUser": "node"
}

View File

@ -1,8 +0,0 @@
services:
workspace:
build:
context: './'
dockerfile: './Dockerfile'
volumes:
- '..:/workspace:cached'
command: 'sleep infinity'

View File

@ -1,5 +1,38 @@
.* **/.git
!.npmrc **/.turbo
build **/.next
coverage **/out
node_modules **/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
# misc
.DS_Store
*.pem
Dockerfile
README.md
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@ -1,4 +1,4 @@
# For more information see: https://editorconfig.org/ # https://editorconfig.org/
root = true root = true

View File

@ -1,2 +1,2 @@
COMPOSE_PROJECT_NAME=divlo TZ=Europe/Paris
PORT=3000 WEBSITE_PORT=3000

View File

@ -1,10 +0,0 @@
{
"extends": ["conventions", "next/core-web-vitals", "prettier"],
"plugins": ["prettier", "unicorn"],
"parserOptions": {
"project": "./tsconfig.json"
},
"rules": {
"prettier/prettier": "error"
}
}

View File

@ -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"
--- ---
<!-- <!--

View File

@ -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. -->

View File

@ -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. -->

View File

@ -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. -->

View File

@ -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

View File

@ -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.5.2'
- name: 'Initialize CodeQL'
uses: 'github/codeql-action/init@v2'
with:
languages: ${{ matrix.language }}
- name: 'Perform CodeQL Analysis'
uses: 'github/codeql-action/analyze@v2'

View File

@ -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.5.2'
- name: 'Setup Node.js'
uses: 'actions/setup-node@v3.6.0'
with:
node-version: '18.x'
cache: 'npm'
- name: 'Install dependencies'
run: 'npm clean-install'
- name: 'Build'
run: 'npm run build'

37
.github/workflows/chromatic.yml vendored Normal file
View 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
View 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"

View File

@ -1,42 +0,0 @@
name: 'Lint'
on:
push:
branches: [develop]
pull_request:
branches: [master, develop]
jobs:
lint:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v3.5.2'
- name: 'Setup Node.js'
uses: 'actions/setup-node@v3.6.0'
with:
node-version: '18.x'
cache: 'npm'
- name: 'Install dependencies'
run: 'npm clean-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:eslint'
run: 'npm run lint:eslint'
- name: 'lint:prettier'
run: 'npm run lint:prettier'
- name: 'lint:dotenv'
uses: 'dotenv-linter/action-dotenv-linter@v2'
with:
github_token: ${{ secrets.github_token }}

View File

@ -1,44 +0,0 @@
name: 'Release'
on:
push:
branches: [master]
jobs:
release:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v3.5.2'
with:
fetch-depth: 0
persist-credentials: false
- name: 'Import GPG key'
uses: 'crazy-max/ghaction-import-gpg@v5.3.0'
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
git_user_signingkey: true
git_commit_gpgsign: true
- name: 'Setup Node.js'
uses: 'actions/setup-node@v3.6.0'
with:
node-version: '18.x'
cache: 'npm'
- name: 'Install dependencies'
run: 'npm clean-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 }}

View File

@ -1,48 +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.5.2'
- name: 'Setup Node.js'
uses: 'actions/setup-node@v3.6.0'
with:
node-version: '18.x'
cache: 'npm'
- name: 'Install dependencies'
run: 'npm clean-install'
- name: 'Unit Test'
run: 'npm run test:unit'
test-e2e:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v3.5.0'
- name: 'Setup Node.js'
uses: 'actions/setup-node@v3.6.0'
with:
node-version: '18.x'
cache: 'npm'
- name: 'Install dependencies'
run: 'npm clean-install'
- name: 'Build'
run: 'npm run build'
- name: 'html-w3c-validator'
run: 'npm run test:html-w3c-validator'
- name: 'End To End (e2e) Test'
run: 'npm run test:e2e'

60
.gitignore vendored
View File

@ -1,36 +1,38 @@
# 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
public/curriculum-vitae
# PWA
public/workbox-*.js
public/sw.js
# testing # testing
coverage coverage
cypress/screenshots
cypress/videos
cypress/downloads
# envs # production
.env .next/
.env.production out/
dist/
build/
# misc
.DS_Store
*.pem
.turbo
bin/
# debug # debug
npm-debug.log* npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Storybook
*storybook.log
storybook-static
# IDEs and editors # IDEs and editors
/.idea .idea
.project .project
.classpath .classpath
.c9/ .c9/
@ -38,18 +40,14 @@ npm-debug.log*
.settings/ .settings/
*.sublime-workspace *.sublime-workspace
# IDE - VSCode # local env files
.vscode/* .env
!.vscode/settings.json .env.production
!.vscode/tasks.json .env*.local
!.vscode/launch.json
!.vscode/extensions.json
# misc # vercel
.DS_Store
.lighthouseci
.vercel .vercel
# typescript # typescript
*.tsbuildinfo *.tsbuildinfo
next-env.d.ts # next-env.d.ts

View File

@ -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

View File

@ -1,8 +0,0 @@
{
"urls": [
"http://127.0.0.1:3000/",
"http://127.0.0.1:3000/blog",
"http://127.0.0.1:3000/blog/hello-world"
],
"files": ["./public/curriculum-vitae/index.html"]
}

View File

@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint:commit -- --edit

View File

@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint:staged

View File

@ -1,6 +0,0 @@
{
"*": ["editorconfig-checker"],
"*.{js,jsx,ts,tsx}": ["prettier --write", "eslint --fix"],
"*.{css,scss,sass,json,jsonc,yml,yaml}": ["prettier --write"],
"*.{md,mdx}": ["prettier --write", "markdownlint-cli2 --fix"]
}

View File

@ -1,12 +0,0 @@
{
"config": {
"default": true,
"relative-links": true,
"extends": "markdownlint/style/prettier",
"MD024": false,
"MD033": false
},
"globs": ["**/*.{md,mdx}"],
"ignores": ["**/node_modules"],
"customRules": ["markdownlint-rule-relative-links"]
}

16
.markdownlint-cli2.mjs Normal file
View 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
.npmrc
View File

@ -1 +0,0 @@
save-exact=true

13
.prettierrc.json Normal file → Executable file
View File

@ -1,6 +1,13 @@
{ {
"singleQuote": true,
"jsxSingleQuote": true,
"semi": false, "semi": false,
"trailingComma": "none" "plugins": ["prettier-plugin-tailwindcss"],
"tailwindFunctions": ["classNames", "cva"],
"overrides": [
{
"files": "pnpm-lock.yaml",
"options": {
"rangeEnd": 0
}
}
]
} }

View File

@ -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"
}
]
]
}

View File

@ -3,9 +3,11 @@
"editorconfig.editorconfig", "editorconfig.editorconfig",
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"davidanson.vscode-markdownlint",
"bradlc.vscode-tailwindcss", "bradlc.vscode-tailwindcss",
"mikestead.dotenv", "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
View 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",
},
}

19
.vscode/settings.json vendored
View File

@ -1,14 +1,23 @@
{ {
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
"editor.bracketPairColorization.enabled": true, "editor.bracketPairColorization.enabled": true,
"editor.wordWrap": "on",
"prettier.configPath": ".prettierrc.json", "prettier.configPath": ".prettierrc.json",
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll": true "source.fixAll": "explicit",
"source.organizeImports": "never"
}, },
"eslint.options": { "tailwindCSS.experimental.classRegex": [
"ignorePath": ".gitignore" ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
}, ["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
"prettier.ignorePath": ".gitignore" ],
"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
} }

View File

@ -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

View File

@ -1,10 +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 ## Code of Conduct
**divlo.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. **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
@ -15,13 +15,13 @@ 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 linting. - 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
@ -29,43 +29,63 @@ The commit message guidelines adheres to [Conventional Commits](https://www.conv
## Getting Started ## Getting Started
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/Divlo/Divlo)
### Prerequisites ### Prerequisites
- [Node.js](https://nodejs.org/) >= 16.0.0 - [Node.js](https://nodejs.org/) >= 22.12.0 [(`nvm install 22`)](https://nvm.sh)
- [npm](https://www.npmjs.com/) >= 8.0.0 - [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 ### 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 # Install dependencies
npm install pnpm install --frozen-lockfile
# Install Playwright browser binaries and their dependencies (tests)
pnpm exec playwright install --with-deps
``` ```
### Local Development environment ### Development
```sh ```sh
# Run website # Start the development server
npm run dev 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/) ### 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 VERSION=$(git describe --tags) docker compose up --build --detach
``` ```
### Services started #### Services started
- website: `http://127.0.0.1:3000` `theoludwig`: <http://localhost:3000>

View File

@ -1,21 +0,0 @@
FROM node:18.16.0 AS builder-dependencies
WORKDIR /usr/src/application
COPY ./package*.json ./
RUN npm clean-install
FROM node:18.16.0 AS builder
WORKDIR /usr/src/application
COPY --from=builder-dependencies /usr/src/application/node_modules ./node_modules
COPY ./ ./
RUN npm run build
FROM gcr.io/distroless/nodejs18-debian11:latest AS runner
WORKDIR /usr/src/application
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
COPY --from=builder /usr/src/application/.next/standalone ./
COPY --from=builder /usr/src/application/.next/static ./.next/static
COPY --from=builder /usr/src/application/public ./public
COPY --from=builder /usr/src/application/locales ./locales
COPY --from=builder /usr/src/application/next.config.js ./next.config.js
CMD ["./server.js"]

View File

@ -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

View File

@ -1,18 +1,18 @@
<h1 align="center"><a href="https://divlo.fr/">Théo LUDWIG (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 • Open-Source enthusiast</strong> <strong>Developer Full Stack • Open-Source Enthusiast</strong>
</p> </p>
<p align="center"> <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://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/Divlo"><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/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/~divlo"><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/~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/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://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/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.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/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.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.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="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@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="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> </p>
<hr /> <hr />
@ -21,16 +21,16 @@
```json ```json
{ {
"name": "Théo LUDWIG (Divlo)", "name": "Théo LUDWIG",
"pronouns": "He/Him", "pronouns": "He/Him",
"birthdate": "31/03/2003", "birthDate": "2003-03-31",
"nationality": "Alsace, France", "nationality": "Alsace, France",
"interests": ["Open-Source enthusiast", "Passionate about High-Tech"], "interests": ["Developer Full Stack", "Open-Source Enthusiast"],
"skills": { "skills": {
"programmingLanguages": ["JavaScript/TypeScript", "Python", "C/C++", "PHP"], "programmingLanguages": ["JavaScript/TypeScript", "Python", "C/C++", "PHP"],
"frontEnd": ["HTML", "CSS", "Tailwind CSS", "React.js/Next.js"], "frontend": ["HTML/CSS", "Tailwind CSS", "React.js/Next.js"],
"backEnd": ["Laravel", "Node.js", "Fastify", "PostgreSQL"], "backend": ["Laravel", "Node.js", "Fastify", "PostgreSQL"],
"tools": ["GNU/Linux", "Ubuntu", "Visual Studio Code", "Git", "Docker"] "tools": ["GNU/Linux", "Arch Linux", "Visual Studio Code", "Git", "Docker"]
} }
} }
``` ```
@ -40,6 +40,6 @@
## 📈 Statistics ## 📈 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,javascript&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>

View 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

View 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

View File

@ -0,0 +1,3 @@
body {
overflow: auto !important;
}

View 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

View File

@ -0,0 +1,7 @@
{
"projectId": "Project:66a7a85ea85df74afbec7682",
"buildScriptName": "build",
"storybookBaseDir": "apps/storybook",
"onlyChanged": true,
"zip": true
}

View 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,
},
},
})

View 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}\``)
},
)

View 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:"
}
}

View File

@ -0,0 +1,7 @@
const config = {
plugins: {
tailwindcss: {},
},
}
export default config

View 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>

View 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

View 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"]
}

View File

@ -0,0 +1,9 @@
{
"$schema": "../../node_modules/turbo/schema.json",
"extends": ["//"],
"tasks": {
"test": {
"dependsOn": ["^test", "build"]
}
}
}

View 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
View 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"]

View File

@ -0,0 +1,7 @@
import { notFound } from "next/navigation"
const CatchAllPage: React.FC = () => {
return notFound()
}
export default CatchAllPage

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,7 @@
interface RootLayoutProps extends React.PropsWithChildren {}
const RootLayout = ({ children }: RootLayoutProps): React.ReactNode => {
return children
}
export default RootLayout

View 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

View 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,
},
},
})

View File

@ -0,0 +1,3 @@
import i18nRequestConfig from "@repo/i18n/request"
export default i18nRequestConfig

View 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
View 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/api-reference/config/typescript for more information.

View 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
View 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:"
}
}

View File

@ -0,0 +1,7 @@
const config = {
plugins: {
tailwindcss: {},
},
}
export default config

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 659 B

After

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Some files were not shown because too many files have changed in this diff Show More