1
1
mirror of https://github.com/theoludwig/theoludwig.git synced 2025-05-29 22:37:44 +02:00

Compare commits

...

204 Commits

Author SHA1 Message Date
b16699f5aa build(deps): update latest 2025-05-29 20:58:40 +02:00
e044b4caea build(deps): update Node.js to v24.0.2 to address security issue
Ref: https://nodejs.org/en/blog/release/v24.0.2
2025-05-20 21:13:02 +02:00
d795025860 chore: remove not needed --experimental-strip-types 2025-05-11 18:04:26 +02:00
a43bfb4a0d feat(portfolio): add Fusey 2025-05-11 17:28:02 +02:00
69af1bccc3 build: update to Node.js v24.0.0, pnpm v10, Tailwind CSS v4 2025-05-11 16:59:11 +02:00
cec70161f7 fix(blog): add useful command to Git cheatsheet post 2025-05-07 19:54:06 +02:00
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
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
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
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
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
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
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
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 f64acb68c7.
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
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
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
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
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
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 c2c9b59c7a.
2024-04-06 20:27:04 +02:00
0febee5b51 refactor: rename to primary color 2024-04-06 20:25:02 +02:00
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
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
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
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
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
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
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 fdab2a7ea8.
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
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
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
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
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
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
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
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
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
7c0f11ab7d chore(release): 2.7.3 [skip ci] 2023-05-29 15:45:42 +00:00
670897fa78 fix: improve spelling consistency 2023-05-29 17:44:26 +02:00
b88246b668 chore: usage of next start 2023-05-29 17:33:45 +02:00
87fbfe4940 chore(release): 2.7.2 [skip ci] 2023-05-29 15:29:07 +00:00
271aa60247 test: update with new changes 2023-05-29 17:26:06 +02:00
ba34e314c9 fix: update name with full name and nickname 2023-05-29 17:10:14 +02:00
f41bc644b1 fix(deps): remove next-pwa dependency 2023-05-29 16:24:49 +02:00
a18cec4826 chore(release): 2.7.1 [skip ci] 2023-05-21 16:27:24 +00:00
61e589f0f4 fix: responsive on blog post with code blocks and katex 2023-05-21 18:21:46 +02:00
dc5c3cee41 chore(release): 2.7.0 [skip ci] 2023-05-21 12:49:17 +00:00
20cb0c21d5 feat(posts): add programming-challenges 2023-05-21 14:42:53 +02:00
e5232c1394 build(deps): update latest 2023-05-21 12:15:08 +02:00
fd51609713 chore(release): 2.6.1 [skip ci] 2023-05-13 17:15:54 +00:00
edf16c2562 fix(deps): update latest 2023-05-13 19:09:54 +02:00
94e0d190ae chore(release): 2.6.0 [skip ci] 2023-05-10 18:12:22 +00:00
b1cf7f8517 chore: remove unneeded Lighthouse checking 2023-05-09 23:22:33 +02:00
a1a715d3b9 feat: add Numerize as work experience 2023-05-09 23:06:10 +02:00
eede46fb41 build(deps): update latest 2023-05-09 22:56:42 +02:00
e32c53caa1 chore(release): 2.5.6 [skip ci] 2023-04-02 21:18:14 +00:00
361ea37deb chore: fix CI issues 2023-04-02 23:16:51 +02:00
d49a8a7470 fix: update dependencies to latest 2023-04-02 22:44:09 +02:00
a4996c8251 chore: remove useless runner-dependencies in Dockerfile 2023-01-11 17:42:29 +01:00
b25451e631 chore(release): 2.5.5 [skip ci] 2023-01-10 23:05:24 +00:00
042a861f58 fix: update dependencies to latest 2023-01-10 23:56:46 +01:00
d76db36dbc chore(release): 2.5.4 [skip ci] 2022-12-08 08:54:03 +00:00
99d9dcf334 fix: improve Resume 2022-12-08 09:52:39 +01:00
ece5ded1b4 chore(release): 2.5.3 [skip ci] 2022-11-29 09:33:10 +00:00
1514600998 fix: improve Resume 2022-11-29 10:29:02 +01:00
5f5b328895 chore(release): 2.5.2 [skip ci] 2022-11-19 19:43:26 +00:00
c88887a322 fix: better resume 2022-11-19 20:24:13 +01:00
014044573a chore(release): 2.5.1 [skip ci] 2022-11-10 11:35:11 +00:00
df009c3f7b fix(posts): update broken link in thream-v1.0.0.md 2022-11-10 12:31:48 +01:00
5c85ca2ef1 chore: fix cypress unit tests 2022-11-08 11:00:31 +01:00
07f7942496 chore(release): 2.5.0 [skip ci] 2022-10-27 17:24:30 +00:00
213a3fa182 build(deps): bump Next.js to v13 2022-10-27 19:13:29 +02:00
28d9211583 fix(posts): update git-ultimate-guide 2022-10-23 20:15:07 +02:00
4d085cb148 fix: update biography description 2022-10-23 18:38:37 +02:00
e6c583f2cd ci: fix timeout 2022-10-20 23:57:53 +02:00
232b54588a feat(skills): add PHP and Laravel 2022-10-20 22:44:40 +02:00
c419fb3bb4 chore: remove usage of styled-jsx 2022-10-20 22:44:32 +02:00
03e7e22d74 chore: reduce docker image size 2022-10-20 22:44:32 +02:00
e85c241ed1 feat(posts): add git-ultimate-guide 2022-10-20 22:43:25 +02:00
c1877297f8 refactor: minor changes 2022-08-27 02:30:55 +02:00
83231197dd chore(release): 2.4.1 [skip ci] 2022-08-23 11:33:38 +00:00
a2fe2205bc fix(resume): wrong base path for assets 2022-08-23 13:31:17 +02:00
e1f3dceb07 chore(release): 2.4.0 [skip ci] 2022-08-23 10:33:09 +00:00
0f89fee52f feat: add giscus comments system for blog posts 2022-08-23 12:23:31 +02:00
2fcc7ac384 chore(release): 2.3.2 [skip ci] 2022-07-28 21:06:12 +00:00
9351edf626 chore: use the right resume.json 2022-07-28 23:01:19 +02:00
1f4aa54211 chore: remove jest -> cypress for unit tests 2022-07-28 22:51:12 +02:00
8bc1471cbb chore: easier development for jsonresume-theme-custom thanks to vite 2022-07-28 21:20:41 +02:00
1ebdab18a5 fix: update about, now second year of university 2022-07-23 23:00:58 +02:00
b9b76e839a build(deps): update latest 2022-07-01 23:12:47 +02:00
380 changed files with 21724 additions and 54949 deletions

View File

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

View File

@ -1,2 +0,0 @@
ARG VARIANT="16"
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
# For more information see: https://editorconfig.org/
# https://editorconfig.org/
root = true
@ -9,3 +9,6 @@ end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
indent_size = 4

View File

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

View File

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

View File

@ -1,13 +1,13 @@
---
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"
---
<!--
Please provide a clear and concise description of what the bug is. Include
screenshots if needed. Please make sure your issue has not already been fixed.
Please provide a clear and concise description of what the bug is. Include
screenshots if needed. Please make sure your issue has not already been fixed.
-->
## Steps To Reproduce

View File

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

View File

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

View File

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

View File

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

View File

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

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

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.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
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.4.0"
with:
node-version: "24.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"

49
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,49 @@
name: "CI"
on:
push:
branches: [develop]
pull_request:
branches: [develop, staging, main]
jobs:
ci:
timeout-minutes: 30
runs-on: "ubuntu-latest"
env:
CI: "1"
TZ: "Europe/Paris"
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.4.0"
with:
node-version: "24.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,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'

View File

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

View File

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

63
.gitignore vendored
View File

@ -1,37 +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
jsonresume-theme-custom/theme/index.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/
@ -39,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

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://localhost:3000/",
"http://localhost:3000/blog",
"http://localhost:3000/blog/hello-world"
],
"files": ["./public/curriculum-vitae.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,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": {}
}
}

View File

@ -1,10 +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"]
}

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

View File

@ -1,7 +0,0 @@
{
"default": true,
"MD013": false,
"MD024": false,
"MD033": false,
"MD041": false
}

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,
"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,11 +3,10 @@
"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"
"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/nextjs\"",
"",
"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",
},
}

18
.vscode/settings.json vendored
View File

@ -1,10 +1,24 @@
{
"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.configFile": "./configs/config-tailwind/styles.css",
"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
}

View File

@ -20,21 +20,16 @@ community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
overall community
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
- The use of sexualized language or imagery, and sexual attention or advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
- Publishing others' private information, such as a physical or email address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Enforcement Responsibilities
@ -60,7 +55,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

View File

@ -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
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](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/) >= v24.0.0 [(`nvm install 24`)](https://nvm.sh)
- [pnpm](https://pnpm.io/) v10.11.0 [(`npm install --global corepack@0.32.0 && corepack enable`)](https://github.com/nodejs/corepack)
- [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>

View File

@ -1,23 +0,0 @@
FROM node:16.15.0 AS dependencies
WORKDIR /usr/src/app
COPY ./package*.json ./
RUN npm install
FROM node:16.15.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.15.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}"]

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
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/">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,27 @@
```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 +51,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>

View File

@ -0,0 +1,5 @@
{
"plugins": {
"@tailwindcss/postcss": {}
}
}

View File

@ -0,0 +1,34 @@
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-docs",
"@storybook/addon-a11y",
],
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,60 @@
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/nextjs"
import { NextIntlClientProvider } from "next-intl"
import { ThemeProvider as NextThemeProvider } from "next-themes"
import React from "react"
const preview: Preview = {
initialGlobals: {
a11y: {
manual: true,
},
},
parameters: {
docs: {
codePanel: true,
},
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,52 @@
{
"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 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-docs": "catalog:",
"@storybook/addon-a11y": "catalog:",
"@storybook/addon-themes": "catalog:",
"@storybook/nextjs": "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:",
"postcss": "catalog:",
"tailwindcss": "catalog:",
"@tailwindcss/postcss": "catalog:",
"typescript-eslint": "catalog:",
"typescript": "catalog:"
}
}

View File

@ -0,0 +1,36 @@
import {
Meta,
Title,
ColorPalette,
ColorItem,
} from "@storybook/addon-docs/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,8 @@
import sharedConfig from "@repo/config-tailwind"
/** @type {Pick<import('tailwindcss').Config, "presets" | "content">} */
const config = {
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

View File

@ -0,0 +1,5 @@
{
"plugins": {
"@tailwindcss/postcss": {}
}
}

42
apps/website/Dockerfile Normal file
View File

@ -0,0 +1,42 @@
FROM node:24.1.0-slim AS node-pnpm
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN npm install --global corepack@0.32.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.5.3
RUN turbo prune @repo/website --docker
FROM node-pnpm AS installer
ENV IS_STANDALONE=true
COPY .gitignore .gitignore
COPY --from=builder /usr/src/app/out/json/ ./
COPY --from=builder /usr/src/app/out/pnpm-lock.yaml ./pnpm-lock.yaml
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
COPY --from=builder /usr/src/app/out/full/ ./
COPY turbo.json turbo.json
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|robots.txt).*)",
],
}

View File

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

View File

@ -0,0 +1,21 @@
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,
},
eslint: {
ignoreDuringBuilds: true,
},
typescript: {
ignoreBuildErrors: true,
},
}
const withNextIntl = createNextIntlPlugin()
export default withNextIntl(nextConfig)

44
apps/website/package.json Normal file
View File

@ -0,0 +1,44 @@
{
"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:",
"@tailwindcss/postcss": "catalog:",
"typescript-eslint": "catalog:",
"typescript": "catalog:"
}
}

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: 945 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: 26 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

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