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

Compare commits

...

32 Commits

Author SHA1 Message Date
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
79 changed files with 4482 additions and 12757 deletions

View File

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

View File

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

View File

@ -6,3 +6,4 @@ services:
volumes: volumes:
- '..:/workspace:cached' - '..:/workspace:cached'
command: 'sleep infinity' command: 'sleep infinity'
network_mode: 'host'

View File

@ -1,5 +1,4 @@
.*
!.npmrc
build build
.next
coverage coverage
node_modules node_modules

View File

@ -1,2 +1,2 @@
COMPOSE_PROJECT_NAME=divlo COMPOSE_PROJECT_NAME=theoludwig
PORT=3000 PORT=3000

View File

@ -4,12 +4,13 @@
"parserOptions": { "parserOptions": {
"project": "./tsconfig.json" "project": "./tsconfig.json"
}, },
"env": {
"node": true,
"browser": true
},
"rules": { "rules": {
"prettier/prettier": "error", "prettier/prettier": "error"
"@next/next/no-img-element": "off" },
} "overrides": [
{
"files": ["*.ts", "*.tsx"],
"parser": "@typescript-eslint/parser"
}
]
} }

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

@ -10,7 +10,7 @@ jobs:
build: build:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.5.2' - uses: 'actions/checkout@v3.5.3'
- name: 'Setup Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.6.0' uses: 'actions/setup-node@v3.6.0'

View File

@ -10,7 +10,7 @@ jobs:
lint: lint:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.5.2' - uses: 'actions/checkout@v3.5.3'
- name: 'Setup Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.6.0' uses: 'actions/setup-node@v3.6.0'

View File

@ -8,7 +8,7 @@ jobs:
release: release:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.5.2' - uses: 'actions/checkout@v3.5.3'
with: with:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
@ -35,10 +35,3 @@ jobs:
GH_TOKEN: ${{ secrets.GH_TOKEN }} GH_TOKEN: ${{ secrets.GH_TOKEN }}
GIT_COMMITTER_NAME: ${{ secrets.GIT_NAME }} GIT_COMMITTER_NAME: ${{ secrets.GIT_NAME }}
GIT_COMMITTER_EMAIL: ${{ secrets.GIT_EMAIL }} 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

@ -10,7 +10,7 @@ jobs:
test-unit: test-unit:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.5.2' - uses: 'actions/checkout@v3.5.3'
- name: 'Setup Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.6.0' uses: 'actions/setup-node@v3.6.0'
@ -27,7 +27,7 @@ jobs:
test-e2e: test-e2e:
runs-on: 'ubuntu-latest' runs-on: 'ubuntu-latest'
steps: steps:
- uses: 'actions/checkout@v3.5.0' - uses: 'actions/checkout@v3.5.3'
- name: 'Setup Node.js' - name: 'Setup Node.js'
uses: 'actions/setup-node@v3.6.0' uses: 'actions/setup-node@v3.6.0'

1
.gitignore vendored
View File

@ -48,7 +48,6 @@ npm-debug.log*
# misc # misc
.DS_Store .DS_Store
.lighthouseci .lighthouseci
.vercel
# typescript # typescript
*.tsbuildinfo *.tsbuildinfo

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,7 +29,7 @@ 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) [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/theoludwig/theoludwig)
### Prerequisites ### Prerequisites
@ -40,10 +40,10 @@ The commit message guidelines adheres to [Conventional Commits](https://www.conv
```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
@ -68,4 +68,4 @@ docker compose up --build
### Services started ### Services started
- website: `http://127.0.0.1:3000` - `website`: <http://127.0.0.1:3000>

View File

@ -1,9 +1,9 @@
FROM node:18.16.0 AS builder-dependencies FROM node:20.5.0 AS builder-dependencies
WORKDIR /usr/src/application WORKDIR /usr/src/application
COPY ./package*.json ./ COPY ./package*.json ./
RUN npm clean-install RUN npm clean-install
FROM node:18.16.0 AS builder FROM node:20.5.0 AS builder
WORKDIR /usr/src/application WORKDIR /usr/src/application
COPY --from=builder-dependencies /usr/src/application/node_modules ./node_modules COPY --from=builder-dependencies /usr/src/application/node_modules ./node_modules
COPY ./ ./ COPY ./ ./

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) Divlo Copyright (c) Théo LUDWIG
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/">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=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.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": "Divlo", "name": "Théo LUDWIG",
"pronouns": "He/Him", "pronouns": "He/Him",
"birthDate": "31/03/2003", "birthDate": "31/03/2003",
"nationality": "Alsace, France", "nationality": "Alsace, France",
"interests": ["Open-Source enthusiast", "Passionate about High-Tech"], "interests": ["Open-Source enthusiast", "Passionate about High-Tech"],
"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" />
<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" />
</p> </p>

View File

@ -11,7 +11,7 @@ export const Footer: React.FC<FooterProps> = (props) => {
const { version } = props const { version } = props
const versionLink = useMemo(() => { const versionLink = useMemo(() => {
return `https://github.com/Divlo/Divlo/releases/tag/v${version}` return `https://github.com/theoludwig/theoludwig/releases/tag/v${version}`
}, [version]) }, [version])
return ( return (
@ -21,7 +21,7 @@ export const Footer: React.FC<FooterProps> = (props) => {
href='/' href='/'
className='text-yellow hover:underline dark:text-yellow-dark' className='text-yellow hover:underline dark:text-yellow-dark'
> >
Divlo Théo LUDWIG
</Link>{' '} </Link>{' '}
| {t('common:all-rights-reserved')} | {t('common:all-rights-reserved')}
</p> </p>

View File

@ -9,10 +9,10 @@ interface HeadProps {
export const Head: React.FC<HeadProps> = (props) => { export const Head: React.FC<HeadProps> = (props) => {
const { const {
title = 'Divlo', title = 'Théo LUDWIG',
image = 'https://divlo.fr/images/icons/icon-96x96.png', image = 'https://theoludwig.fr/images/icon-96x96.png',
description = 'Divlo - Developer Full Stack • Passionate about High-Tech', description = 'Théo LUDWIG - Developer Full Stack • Passionate about High-Tech',
url = 'https://divlo.fr/' url = 'https://theoludwig.fr/'
} = props } = props
return ( return (
@ -23,7 +23,7 @@ export const Head: React.FC<HeadProps> = (props) => {
{/* Meta Tag */} {/* Meta Tag */}
<meta name='viewport' content='width=device-width, initial-scale=1.0' /> <meta name='viewport' content='width=device-width, initial-scale=1.0' />
<meta name='description' content={description} /> <meta name='description' content={description} />
<meta name='Language' content='fr, en' /> <meta name='Language' content='fr-FR, en-US' />
<meta name='theme-color' content='#ffd800' /> <meta name='theme-color' content='#ffd800' />
{/* Open Graph Metadata */} {/* Open Graph Metadata */}
@ -32,7 +32,7 @@ export const Head: React.FC<HeadProps> = (props) => {
<meta property='og:url' content={url} /> <meta property='og:url' content={url} />
<meta property='og:image' content={image} /> <meta property='og:image' content={image} />
<meta property='og:description' content={description} /> <meta property='og:description' content={description} />
<meta property='og:locale' content='fr_FR, en_US' /> <meta property='og:locale' content='fr-FR, en-US' />
<meta property='og:site_name' content={title} /> <meta property='og:site_name' content={title} />
{/* Twitter card Metadata */} {/* Twitter card Metadata */}
@ -40,18 +40,6 @@ export const Head: React.FC<HeadProps> = (props) => {
<meta name='twitter:description' content={description} /> <meta name='twitter:description' content={description} />
<meta name='twitter:title' content={title} /> <meta name='twitter:title' content={title} />
<meta name='twitter:image' content={image} /> <meta name='twitter:image' content={image} />
{/* Google Verification */}
<meta
name='google-site-verification'
content='j9CQEbSuYydXytr6gdkTfam_xX_pU97NSpVH3Bq-6f4'
/>
{/* PWA Data */}
<link rel='manifest' href='/manifest.json' />
<meta name='apple-mobile-web-app-capable' content='yes' />
<meta name='mobile-web-app-capable' content='yes' />
<link rel='apple-touch-icon' href={image} />
</NextHead> </NextHead>
) )
} }

View File

@ -37,7 +37,7 @@ export const Language: React.FC = () => {
}, []) }, [])
const handleLanguage = async (language: string): Promise<void> => { const handleLanguage = async (language: string): Promise<void> => {
await setLanguage(language) await setLanguage(language, false)
} }
return ( return (

View File

@ -19,11 +19,12 @@ export const Header: React.FC<HeaderProps> = (props) => {
quality={100} quality={100}
width={60} width={60}
height={60} height={60}
src='/images/divlo_icon_small.png' src='/images/icon_small.png'
alt='Divlo' alt='Théo LUDWIG'
priority
/> />
<strong className='ml-1 hidden font-headline font-semibold text-yellow dark:text-yellow-dark xs:block'> <strong className='ml-1 hidden font-headline font-semibold text-yellow dark:text-yellow-dark xs:block'>
Divlo Théo LUDWIG
</strong> </strong>
</div> </div>
</Link> </Link>
@ -37,7 +38,7 @@ export const Header: React.FC<HeaderProps> = (props) => {
Blog Blog
</Link> </Link>
</div> </div>
{showLanguage && <Language />} {showLanguage ? <Language /> : null}
<SwitchTheme /> <SwitchTheme />
</div> </div>
</header> </header>

View File

@ -12,22 +12,22 @@ export const OpenSource: React.FC = () => {
<Repository <Repository
name='nodejs/node' name='nodejs/node'
description='Node.js JavaScript runtime 🐢🚀' description='Node.js JavaScript runtime 🐢🚀'
href='https://github.com/nodejs/node/commits?author=Divlo' href='https://github.com/nodejs/node/commits?author=theoludwig'
/> />
<Repository <Repository
name='standard/standard' name='standard/standard'
description='🌟 JavaScript Style Guide, with linter & automatic code fixer' description='🌟 JavaScript Style Guide, with linter & automatic code fixer'
href='https://github.com/standard/standard/commits?author=Divlo' href='https://github.com/standard/standard/commits?author=theoludwig'
/> />
<Repository <Repository
name='nrwl/nx' name='nrwl/nx'
description='Smart, Extensible Build Framework' description='Smart, Extensible Build Framework'
href='https://github.com/nrwl/nx/commits?author=Divlo' href='https://github.com/nrwl/nx/commits?author=theoludwig'
/> />
<Repository <Repository
name='vercel/next.js' name='vercel/next.js'
description='The React Framework for Production' description='The React Framework for Production'
href='https://github.com/vercel/next.js/commits?author=Divlo' href='https://github.com/vercel/next.js/commits?author=theoludwig'
/> />
</div> </div>
</div> </div>

View File

@ -6,18 +6,18 @@ export const ProfileDescriptionBottom: React.FC = () => {
return ( return (
<p className='mb-8 mt-8 text-base font-normal text-gray dark:text-gray-dark'> <p className='mb-8 mt-8 text-base font-normal text-gray dark:text-gray-dark'>
{t('home:about.description-bottom')} {t('home:about.description-bottom')}
{lang === 'fr' && ( {lang === 'fr' ? (
<> <>
<br /> <br />
<br /> <br />
<a <a
href='/curriculum-vitae' href='/curriculum-vitae/index.html'
className='text-yellow hover:underline dark:text-yellow-dark' className='text-yellow hover:underline dark:text-yellow-dark'
> >
Curriculum vitæ Curriculum vitæ
</a> </a>
</> </>
)} ) : null}
</p> </p>
) )
} }

View File

@ -5,11 +5,8 @@ export const ProfileInformation: React.FC = () => {
return ( return (
<div className='mb-6 border-b-2 border-gray-600 pb-2 font-headline dark:border-gray-400'> <div className='mb-6 border-b-2 border-gray-600 pb-2 font-headline dark:border-gray-400'>
<h1 className='mb-2 text-4xl'> <h1 className='mb-2 text-4xl font-semibold text-yellow dark:text-yellow-dark'>
{t('home:about.i-am')}{' '} Théo LUDWIG
<strong className='font-semibold text-yellow dark:text-yellow-dark'>
Divlo
</strong>
</h1> </h1>
<h2 className='mb-3 text-base'>{t('home:about.description')}</h2> <h2 className='mb-3 text-base'>{t('home:about.description')}</h2>
</div> </div>

View File

@ -1,7 +1,7 @@
import useTranslation from 'next-translate/useTranslation' import useTranslation from 'next-translate/useTranslation'
import { useMemo } from 'react' import { useMemo } from 'react'
import { DIVLO_BIRTHDAY, DIVLO_BIRTHDAY_DATE, getAge } from 'utils/getAge' import { BIRTH_DATE, BIRTH_DATE_STRING, getAge } from 'utils/getAge'
import { ProfileItem } from './ProfileItem' import { ProfileItem } from './ProfileItem'
@ -9,21 +9,24 @@ export const ProfileList: React.FC = () => {
const { t } = useTranslation('home') const { t } = useTranslation('home')
const age = useMemo(() => { const age = useMemo(() => {
return getAge(DIVLO_BIRTHDAY) return getAge(BIRTH_DATE)
}, []) }, [])
return ( return (
<ul className='m-0 list-none p-0'> <ul className='m-0 list-none p-0'>
<ProfileItem title={t('home:about.full-name')} value='Théo LUDWIG' /> <ProfileItem
title={t('home:about.pronouns')}
value={t('home:about.pronouns-value')}
/>
<ProfileItem <ProfileItem
title={t('home:about.birth-date')} title={t('home:about.birth-date')}
value={`${DIVLO_BIRTHDAY_DATE} (${age} ${t('home:about.years-old')})`} value={`${BIRTH_DATE_STRING} (${age} ${t('home:about.years-old')})`}
/> />
<ProfileItem title={t('home:about.nationality')} value='Alsace, France' /> <ProfileItem title={t('home:about.nationality')} value='Alsace, France' />
<ProfileItem <ProfileItem
title='Email' title='Email'
value='contact@divlo.fr' value='contact@theoludwig.fr'
link='mailto:contact@divlo.fr' link='mailto:contact@theoludwig.fr'
/> />
</ul> </ul>
) )

View File

@ -1,11 +1,11 @@
import Image from 'next/image' import Image from 'next/image'
import DivloLogo from 'public/images/divlo_logo.png' import Logo from 'public/images/logo.png'
export const ProfileLogo: React.FC = () => { export const ProfileLogo: React.FC = () => {
return ( return (
<div className='max-h-[370px] max-w-[370px] px-2 py-6'> <div className='max-h-[370px] max-w-[370px] px-2 py-6'>
<Image quality={100} src={DivloLogo} alt='Divlo' priority /> <Image quality={100} src={Logo} alt='Théo LUDWIG' priority />
</div> </div>
) )
} }

View File

@ -10,28 +10,34 @@ import { NPMIcon } from './SocialMediaIcons/NPMIcon'
export const SocialMediaList: React.FC = () => { export const SocialMediaList: React.FC = () => {
return ( return (
<ul className='social-media-list m-0 mt-2 list-none py-4 text-center'> <ul className='social-media-list m-0 mt-2 list-none py-4 text-center'>
<SocialMediaItem link='https://github.com/Divlo' ariaLabel='GitHub'> <SocialMediaItem link='https://github.com/theoludwig' ariaLabel='GitHub'>
<GitHubIcon /> <GitHubIcon />
</SocialMediaItem> </SocialMediaItem>
<SocialMediaItem link='https://gitlab.com/Divlo' ariaLabel='GitLab'> <SocialMediaItem link='https://gitlab.com/theoludwig' ariaLabel='GitLab'>
<GitLabIcon /> <GitLabIcon />
</SocialMediaItem> </SocialMediaItem>
<SocialMediaItem link='https://www.npmjs.com/~divlo' ariaLabel='NPM'> <SocialMediaItem link='https://www.npmjs.com/~theoludwig' ariaLabel='NPM'>
<NPMIcon /> <NPMIcon />
</SocialMediaItem> </SocialMediaItem>
<SocialMediaItem link='https://twitter.com/Divlo_FR' ariaLabel='Twitter'> <SocialMediaItem
link='https://twitter.com/theoludwig_'
ariaLabel='Twitter'
>
<TwitterIcon /> <TwitterIcon />
</SocialMediaItem> </SocialMediaItem>
<SocialMediaItem <SocialMediaItem
link='https://www.youtube.com/c/Divlo' link='https://www.youtube.com/@theo_ludwig'
ariaLabel='YouTube' ariaLabel='YouTube'
> >
<YouTubeIcon /> <YouTubeIcon />
</SocialMediaItem> </SocialMediaItem>
<SocialMediaItem link='https://www.twitch.tv/divlo' ariaLabel='Twitch'> <SocialMediaItem
link='https://www.twitch.tv/theoludwig'
ariaLabel='Twitch'
>
<TwitchIcon /> <TwitchIcon />
</SocialMediaItem> </SocialMediaItem>
<SocialMediaItem link='mailto:contact@divlo.fr' ariaLabel='Email'> <SocialMediaItem link='mailto:contact@theoludwig.fr' ariaLabel='Email'>
<EmailIcon /> <EmailIcon />
</SocialMediaItem> </SocialMediaItem>
</ul> </ul>

View File

@ -33,10 +33,10 @@ export const SkillComponent: React.FC<SkillComponentProps> = (props) => {
> >
<div className='text-center'> <div className='text-center'>
<Image <Image
className='inline h-auto w-auto' className='inline h-16 w-16'
quality={100} quality={100}
width={60} width={64}
height={60} height={64}
alt={skill} alt={skill}
src={image} src={image}
/> />

View File

@ -9,21 +9,20 @@ export const Skills: React.FC = () => {
return ( return (
<> <>
<SkillsSection title={t('home:skills.languages')}> <SkillsSection title={t('home:skills.languages')}>
<SkillComponent skill='JavaScript' />
<SkillComponent skill='TypeScript' /> <SkillComponent skill='TypeScript' />
<SkillComponent skill='Python' /> <SkillComponent skill='Python' />
<SkillComponent skill='C/C++' /> <SkillComponent skill='C/C++' />
<SkillComponent skill='PHP' /> <SkillComponent skill='PHP' />
</SkillsSection> </SkillsSection>
<SkillsSection title='Front-end'> <SkillsSection title='Frontend'>
<SkillComponent skill='HTML' /> <SkillComponent skill='HTML' />
<SkillComponent skill='CSS' /> <SkillComponent skill='CSS' />
<SkillComponent skill='Tailwind CSS' /> <SkillComponent skill='Tailwind CSS' />
<SkillComponent skill='React.js (+ Next.js)' /> <SkillComponent skill='React.js (+ Next.js)' />
</SkillsSection> </SkillsSection>
<SkillsSection title='Back-end'> <SkillsSection title='Backend'>
<SkillComponent skill='Laravel' /> <SkillComponent skill='Laravel' />
<SkillComponent skill='Node.js' /> <SkillComponent skill='Node.js' />
<SkillComponent skill='Fastify' /> <SkillComponent skill='Fastify' />
@ -32,7 +31,7 @@ export const Skills: React.FC = () => {
<SkillsSection title={t('home:skills.software-tools')}> <SkillsSection title={t('home:skills.software-tools')}>
<SkillComponent skill='GNU/Linux' /> <SkillComponent skill='GNU/Linux' />
<SkillComponent skill='Ubuntu' /> <SkillComponent skill='Arch Linux' />
<SkillComponent skill='Visual Studio Code' /> <SkillComponent skill='Visual Studio Code' />
<SkillComponent skill='Git' /> <SkillComponent skill='Git' />
<SkillComponent skill='Docker' /> <SkillComponent skill='Docker' />

View File

@ -88,20 +88,20 @@ export const skills = {
}, },
'Visual Studio Code': { 'Visual Studio Code': {
link: 'https://code.visualstudio.com/', link: 'https://code.visualstudio.com/',
image: '/images/skills/Visual_Studio_Code.png' image: '/images/skills/VisualStudioCode.png'
}, },
Git: { Git: {
link: 'https://git-scm.com/', link: 'https://git-scm.com/',
image: '/images/skills/Git.png' image: '/images/skills/Git.png'
}, },
Hyper: {
link: 'https://hyper.is/',
image: '/images/skills/Hyper.svg'
},
Ubuntu: { Ubuntu: {
link: 'https://ubuntu.com/', link: 'https://ubuntu.com/',
image: '/images/skills/Ubuntu.png' image: '/images/skills/Ubuntu.png'
}, },
'Arch Linux': {
link: 'https://archlinux.org/',
image: '/images/skills/ArchLinux.png'
},
'GNU/Linux': { 'GNU/Linux': {
link: 'https://www.gnu.org/', link: 'https://www.gnu.org/',
image: '/images/skills/GNU-Linux.png' image: '/images/skills/GNU-Linux.png'

View File

@ -8,13 +8,13 @@ export const RevealFade: React.FC<React.PropsWithChildren> = (props) => {
useEffect(() => { useEffect(() => {
const observer = new window.IntersectionObserver( const observer = new window.IntersectionObserver(
(entries, observer) => { (entries, observer) => {
entries.forEach((entry) => { for (const entry of entries) {
if (entry.isIntersecting) { if (entry.isIntersecting) {
entry.target.className = entry.target.className =
'opacity-100 visible translate-y-0 transition-all duration-700 ease-in-out' 'opacity-100 visible translate-y-0 transition-all duration-700 ease-in-out'
observer.unobserve(entry.target) observer.unobserve(entry.target)
} }
}) }
}, },
{ {
root: null, root: null,

View File

@ -23,7 +23,9 @@ export const Section: React.FC<SectionProps> = (props) => {
<div className='w-full px-3'> <div className='w-full px-3'>
<ShadowContainer style={{ marginTop: 50 }}> <ShadowContainer style={{ marginTop: 50 }}>
<section {...rest}> <section {...rest}>
{heading != null && <SectionHeading>{heading}</SectionHeading>} {heading != null ? (
<SectionHeading>{heading}</SectionHeading>
) : null}
<div className='w-full px-3'>{children}</div> <div className='w-full px-3'>{children}</div>
</section> </section>
</ShadowContainer> </ShadowContainer>
@ -34,7 +36,7 @@ export const Section: React.FC<SectionProps> = (props) => {
if (withoutShadowContainer) { if (withoutShadowContainer) {
return ( return (
<section {...rest}> <section {...rest}>
{heading != null && <SectionHeading>{heading}</SectionHeading>} {heading != null ? <SectionHeading>{heading}</SectionHeading> : null}
<div className='w-full px-3'>{children}</div> <div className='w-full px-3'>{children}</div>
</section> </section>
) )
@ -42,16 +44,18 @@ export const Section: React.FC<SectionProps> = (props) => {
return ( return (
<section {...rest}> <section {...rest}>
{heading != null && ( {heading != null ? (
<SectionHeading style={{ ...(description != null && { margin: 0 }) }}> <SectionHeading
style={{ ...(description != null ? { margin: 0 } : {}) }}
>
{heading} {heading}
</SectionHeading> </SectionHeading>
)} ) : null}
{description != null && ( {description != null ? (
<p style={{ marginTop: 7 }} className='text-center'> <p style={{ marginTop: 7 }} className='text-center'>
{description} {description}
</p> </p>
)} ) : null}
<div className='w-full px-3'> <div className='w-full px-3'>
<ShadowContainer> <ShadowContainer>
<div className='w-full px-16 py-4 leading-8'>{children}</div> <div className='w-full px-16 py-4 leading-8'>{children}</div>

View File

@ -4,13 +4,13 @@ describe('<Footer />', () => {
it('should render with appropriate link tag version', () => { it('should render with appropriate link tag version', () => {
const version = '1.0.0' const version = '1.0.0'
cy.mount(<Footer version={version} />) cy.mount(<Footer version={version} />)
cy.contains('Divlo') cy.contains('Théo LUDWIG')
.get('[data-cy=version-link]') .get('[data-cy=version-link]')
.should('have.text', version) .should('have.text', version)
.should( .should(
'have.attr', 'have.attr',
'href', 'href',
`https://github.com/Divlo/Divlo/releases/tag/v${version}` `https://github.com/theoludwig/theoludwig/releases/tag/v${version}`
) )
}) })
}) })

View File

@ -38,7 +38,7 @@ describe('Common > Header', () => {
describe('Switch Language', () => { describe('Switch Language', () => {
it('should switch language from EN (default) to FR', () => { it('should switch language from EN (default) to FR', () => {
cy.get('h1').contains('I am Divlo') cy.get('h1').contains('Théo LUDWIG')
cy.get('[data-cy=language-flag-text]').contains('EN') cy.get('[data-cy=language-flag-text]').contains('EN')
cy.get('[data-cy=languages-list]').should('not.be.visible') cy.get('[data-cy=languages-list]').should('not.be.visible')
cy.get('[data-cy=language-click]').click() cy.get('[data-cy=language-click]').click()
@ -46,7 +46,7 @@ describe('Common > Header', () => {
cy.get('[data-cy=languages-list] > li:first-child').contains('FR').click() cy.get('[data-cy=languages-list] > li:first-child').contains('FR').click()
cy.get('[data-cy=languages-list]').should('not.be.visible') cy.get('[data-cy=languages-list]').should('not.be.visible')
cy.get('[data-cy=language-flag-text]').contains('FR') cy.get('[data-cy=language-flag-text]').contains('FR')
cy.get('h1').contains('Je suis Divlo') cy.get('h1').contains('Théo LUDWIG')
}) })
it('should close the language list menu when clicking outside', () => { it('should close the language list menu when clicking outside', () => {

View File

@ -3,7 +3,7 @@ describe('Page /blog/[slug]', () => {
cy.visit('/blog/hello-world') cy.visit('/blog/hello-world')
cy.get('[data-cy=language-flag-text]').should('not.exist') cy.get('[data-cy=language-flag-text]').should('not.exist')
cy.get('h1').should('have.text', '👋 Hello, world!') cy.get('h1').should('have.text', '👋 Hello, world!')
cy.get('.prose a').should('have.attr', 'target', '_blank') cy.get('.prose a:visible').should('have.attr', 'target', '_blank')
}) })
it("should redirect to /404 if the blog post doesn't exist", () => { it("should redirect to /404 if the blog post doesn't exist", () => {

View File

@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />

View File

@ -1,7 +1,8 @@
services: services:
divlo: theoludwig:
container_name: ${COMPOSE_PROJECT_NAME} container_name: ${COMPOSE_PROJECT_NAME}
image: 'divlo' image: 'theoludwig'
restart: 'unless-stopped'
build: build:
context: './' context: './'
ports: ports:

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!doctype html>
<html lang="fr"> <html lang="fr-FR">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />

View File

@ -12,16 +12,16 @@
"modern-normalize": "2.0.0" "modern-normalize": "2.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "20.2.1", "@types/node": "20.4.4",
"date-and-time": "3.0.0", "date-and-time": "3.0.2",
"vite": "4.3.8", "vite": "4.4.6",
"vite-plugin-html": "3.2.0" "vite-plugin-html": "3.2.0"
} }
}, },
"node_modules/@esbuild/android-arm": { "node_modules/@esbuild/android-arm": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.15.tgz",
"integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", "integrity": "sha512-wlkQBWb79/jeEEoRmrxt/yhn5T1lU236OCNpnfRzaCJHZ/5gf82uYx1qmADTBWE0AR/v7FiozE1auk2riyQd3w==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -35,9 +35,9 @@
} }
}, },
"node_modules/@esbuild/android-arm64": { "node_modules/@esbuild/android-arm64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.15.tgz",
"integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", "integrity": "sha512-NI/gnWcMl2kXt1HJKOn2H69SYn4YNheKo6NZt1hyfKWdMbaGadxjZIkcj4Gjk/WPxnbFXs9/3HjGHaknCqjrww==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -51,9 +51,9 @@
} }
}, },
"node_modules/@esbuild/android-x64": { "node_modules/@esbuild/android-x64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.15.tgz",
"integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", "integrity": "sha512-FM9NQamSaEm/IZIhegF76aiLnng1kEsZl2eve/emxDeReVfRuRNmvT28l6hoFD9TsCxpK+i4v8LPpEj74T7yjA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -67,9 +67,9 @@
} }
}, },
"node_modules/@esbuild/darwin-arm64": { "node_modules/@esbuild/darwin-arm64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.15.tgz",
"integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", "integrity": "sha512-XmrFwEOYauKte9QjS6hz60FpOCnw4zaPAb7XV7O4lx1r39XjJhTN7ZpXqJh4sN6q60zbP6QwAVVA8N/wUyBH/w==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -83,9 +83,9 @@
} }
}, },
"node_modules/@esbuild/darwin-x64": { "node_modules/@esbuild/darwin-x64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.15.tgz",
"integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", "integrity": "sha512-bMqBmpw1e//7Fh5GLetSZaeo9zSC4/CMtrVFdj+bqKPGJuKyfNJ5Nf2m3LknKZTS+Q4oyPiON+v3eaJ59sLB5A==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -99,9 +99,9 @@
} }
}, },
"node_modules/@esbuild/freebsd-arm64": { "node_modules/@esbuild/freebsd-arm64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.15.tgz",
"integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", "integrity": "sha512-LoTK5N3bOmNI9zVLCeTgnk5Rk0WdUTrr9dyDAQGVMrNTh9EAPuNwSTCgaKOKiDpverOa0htPcO9NwslSE5xuLA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -115,9 +115,9 @@
} }
}, },
"node_modules/@esbuild/freebsd-x64": { "node_modules/@esbuild/freebsd-x64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.15.tgz",
"integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", "integrity": "sha512-62jX5n30VzgrjAjOk5orYeHFq6sqjvsIj1QesXvn5OZtdt5Gdj0vUNJy9NIpjfdNdqr76jjtzBJKf+h2uzYuTQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -131,9 +131,9 @@
} }
}, },
"node_modules/@esbuild/linux-arm": { "node_modules/@esbuild/linux-arm": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.15.tgz",
"integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", "integrity": "sha512-dT4URUv6ir45ZkBqhwZwyFV6cH61k8MttIwhThp2BGiVtagYvCToF+Bggyx2VI57RG4Fbt21f9TmXaYx0DeUJg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -147,9 +147,9 @@
} }
}, },
"node_modules/@esbuild/linux-arm64": { "node_modules/@esbuild/linux-arm64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.15.tgz",
"integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", "integrity": "sha512-BWncQeuWDgYv0jTNzJjaNgleduV4tMbQjmk/zpPh/lUdMcNEAxy+jvneDJ6RJkrqloG7tB9S9rCrtfk/kuplsQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -163,9 +163,9 @@
} }
}, },
"node_modules/@esbuild/linux-ia32": { "node_modules/@esbuild/linux-ia32": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.15.tgz",
"integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", "integrity": "sha512-JPXORvgHRHITqfms1dWT/GbEY89u848dC08o0yK3fNskhp0t2TuNUnsrrSgOdH28ceb1hJuwyr8R/1RnyPwocw==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -179,9 +179,9 @@
} }
}, },
"node_modules/@esbuild/linux-loong64": { "node_modules/@esbuild/linux-loong64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.15.tgz",
"integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", "integrity": "sha512-kArPI0DopjJCEplsVj/H+2Qgzz7vdFSacHNsgoAKpPS6W/Ndh8Oe24HRDQ5QCu4jHgN6XOtfFfLpRx3TXv/mEg==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@ -195,9 +195,9 @@
} }
}, },
"node_modules/@esbuild/linux-mips64el": { "node_modules/@esbuild/linux-mips64el": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.15.tgz",
"integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", "integrity": "sha512-b/tmngUfO02E00c1XnNTw/0DmloKjb6XQeqxaYuzGwHe0fHVgx5/D6CWi+XH1DvkszjBUkK9BX7n1ARTOst59w==",
"cpu": [ "cpu": [
"mips64el" "mips64el"
], ],
@ -211,9 +211,9 @@
} }
}, },
"node_modules/@esbuild/linux-ppc64": { "node_modules/@esbuild/linux-ppc64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.15.tgz",
"integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", "integrity": "sha512-KXPY69MWw79QJkyvUYb2ex/OgnN/8N/Aw5UDPlgoRtoEfcBqfeLodPr42UojV3NdkoO4u10NXQdamWm1YEzSKw==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -227,9 +227,9 @@
} }
}, },
"node_modules/@esbuild/linux-riscv64": { "node_modules/@esbuild/linux-riscv64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.15.tgz",
"integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", "integrity": "sha512-komK3NEAeeGRnvFEjX1SfVg6EmkfIi5aKzevdvJqMydYr9N+pRQK0PGJXk+bhoPZwOUgLO4l99FZmLGk/L1jWg==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@ -243,9 +243,9 @@
} }
}, },
"node_modules/@esbuild/linux-s390x": { "node_modules/@esbuild/linux-s390x": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.15.tgz",
"integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", "integrity": "sha512-632T5Ts6gQ2WiMLWRRyeflPAm44u2E/s/TJvn+BP6M5mnHSk93cieaypj3VSMYO2ePTCRqAFXtuYi1yv8uZJNA==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@ -259,9 +259,9 @@
} }
}, },
"node_modules/@esbuild/linux-x64": { "node_modules/@esbuild/linux-x64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.15.tgz",
"integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", "integrity": "sha512-MsHtX0NgvRHsoOtYkuxyk4Vkmvk3PLRWfA4okK7c+6dT0Fu4SUqXAr9y4Q3d8vUf1VWWb6YutpL4XNe400iQ1g==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -275,9 +275,9 @@
} }
}, },
"node_modules/@esbuild/netbsd-x64": { "node_modules/@esbuild/netbsd-x64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.15.tgz",
"integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", "integrity": "sha512-djST6s+jQiwxMIVQ5rlt24JFIAr4uwUnzceuFL7BQT4CbrRtqBPueS4GjXSiIpmwVri1Icj/9pFRJ7/aScvT+A==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -291,9 +291,9 @@
} }
}, },
"node_modules/@esbuild/openbsd-x64": { "node_modules/@esbuild/openbsd-x64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.15.tgz",
"integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", "integrity": "sha512-naeRhUIvhsgeounjkF5mvrNAVMGAm6EJWiabskeE5yOeBbLp7T89tAEw0j5Jm/CZAwyLe3c67zyCWH6fsBLCpw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -307,9 +307,9 @@
} }
}, },
"node_modules/@esbuild/sunos-x64": { "node_modules/@esbuild/sunos-x64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.15.tgz",
"integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", "integrity": "sha512-qkT2+WxyKbNIKV1AEhI8QiSIgTHMcRctzSaa/I3kVgMS5dl3fOeoqkb7pW76KwxHoriImhx7Mg3TwN/auMDsyQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -323,9 +323,9 @@
} }
}, },
"node_modules/@esbuild/win32-arm64": { "node_modules/@esbuild/win32-arm64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.15.tgz",
"integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", "integrity": "sha512-HC4/feP+pB2Vb+cMPUjAnFyERs+HJN7E6KaeBlFdBv799MhD+aPJlfi/yk36SED58J9TPwI8MAcVpJgej4ud0A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -339,9 +339,9 @@
} }
}, },
"node_modules/@esbuild/win32-ia32": { "node_modules/@esbuild/win32-ia32": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.15.tgz",
"integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", "integrity": "sha512-ovjwoRXI+gf52EVF60u9sSDj7myPixPxqzD5CmkEUmvs+W9Xd0iqISVBQn8xcx4ciIaIVlWCuTbYDOXOnOL44Q==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -355,9 +355,9 @@
} }
}, },
"node_modules/@esbuild/win32-x64": { "node_modules/@esbuild/win32-x64": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.15.tgz",
"integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", "integrity": "sha512-imUxH9a3WJARyAvrG7srLyiK73XdX83NXQkjKvQ+7vPh3ZxoLrzvPkQKKw2DwZ+RV2ZB6vBfNHP8XScAmQC3aA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -403,9 +403,9 @@
} }
}, },
"node_modules/@jridgewell/source-map": { "node_modules/@jridgewell/source-map": {
"version": "0.3.3", "version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
"integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/gen-mapping": "^0.3.0",
@ -483,15 +483,15 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.2.1", "version": "20.4.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.4.tgz",
"integrity": "sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==", "integrity": "sha512-CukZhumInROvLq3+b5gLev+vgpsIqC2D0deQr/yS1WnxvmYLlJXZpaQrQiseMY+6xusl79E04UjWoqyr+t1/Ew==",
"dev": true "dev": true
}, },
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.8.2", "version": "8.10.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
"dev": true, "dev": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
@ -682,9 +682,9 @@
} }
}, },
"node_modules/date-and-time": { "node_modules/date-and-time": {
"version": "3.0.0", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-3.0.0.tgz", "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-3.0.2.tgz",
"integrity": "sha512-uuzXp/mvv6jEMLiP5QzERSQPzHqYnv9i8NZ8BS5kYeB2sakv74EewQiCS4Ahxwq3In+9fYZhGztuDHRVzIOkFQ==", "integrity": "sha512-MOqlRertOQmQI7ySbz6dKLM7Rxm9dgcPuBI9IL7NVe0UGqHPK+6hWSKVhLrVHxlSgQQtocE2R7+HFOf5aMz8vw==",
"dev": true "dev": true
}, },
"node_modules/dom-serializer": { "node_modules/dom-serializer": {
@ -753,12 +753,15 @@
} }
}, },
"node_modules/dotenv": { "node_modules/dotenv": {
"version": "16.0.3", "version": "16.3.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
},
"funding": {
"url": "https://github.com/motdotla/dotenv?sponsor=1"
} }
}, },
"node_modules/dotenv-expand": { "node_modules/dotenv-expand": {
@ -795,9 +798,9 @@
} }
}, },
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.17.19", "version": "0.18.15",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.15.tgz",
"integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", "integrity": "sha512-3WOOLhrvuTGPRzQPU6waSDWrDTnQriia72McWcn6UCi43GhCHrXH4S59hKMeez+IITmdUuUyvbU9JIp+t3xlPQ==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"bin": { "bin": {
@ -807,28 +810,28 @@
"node": ">=12" "node": ">=12"
}, },
"optionalDependencies": { "optionalDependencies": {
"@esbuild/android-arm": "0.17.19", "@esbuild/android-arm": "0.18.15",
"@esbuild/android-arm64": "0.17.19", "@esbuild/android-arm64": "0.18.15",
"@esbuild/android-x64": "0.17.19", "@esbuild/android-x64": "0.18.15",
"@esbuild/darwin-arm64": "0.17.19", "@esbuild/darwin-arm64": "0.18.15",
"@esbuild/darwin-x64": "0.17.19", "@esbuild/darwin-x64": "0.18.15",
"@esbuild/freebsd-arm64": "0.17.19", "@esbuild/freebsd-arm64": "0.18.15",
"@esbuild/freebsd-x64": "0.17.19", "@esbuild/freebsd-x64": "0.18.15",
"@esbuild/linux-arm": "0.17.19", "@esbuild/linux-arm": "0.18.15",
"@esbuild/linux-arm64": "0.17.19", "@esbuild/linux-arm64": "0.18.15",
"@esbuild/linux-ia32": "0.17.19", "@esbuild/linux-ia32": "0.18.15",
"@esbuild/linux-loong64": "0.17.19", "@esbuild/linux-loong64": "0.18.15",
"@esbuild/linux-mips64el": "0.17.19", "@esbuild/linux-mips64el": "0.18.15",
"@esbuild/linux-ppc64": "0.17.19", "@esbuild/linux-ppc64": "0.18.15",
"@esbuild/linux-riscv64": "0.17.19", "@esbuild/linux-riscv64": "0.18.15",
"@esbuild/linux-s390x": "0.17.19", "@esbuild/linux-s390x": "0.18.15",
"@esbuild/linux-x64": "0.17.19", "@esbuild/linux-x64": "0.18.15",
"@esbuild/netbsd-x64": "0.17.19", "@esbuild/netbsd-x64": "0.18.15",
"@esbuild/openbsd-x64": "0.17.19", "@esbuild/openbsd-x64": "0.18.15",
"@esbuild/sunos-x64": "0.17.19", "@esbuild/sunos-x64": "0.18.15",
"@esbuild/win32-arm64": "0.17.19", "@esbuild/win32-arm64": "0.18.15",
"@esbuild/win32-ia32": "0.17.19", "@esbuild/win32-ia32": "0.18.15",
"@esbuild/win32-x64": "0.17.19" "@esbuild/win32-x64": "0.18.15"
} }
}, },
"node_modules/estree-walker": { "node_modules/estree-walker": {
@ -838,9 +841,9 @@
"dev": true "dev": true
}, },
"node_modules/fast-glob": { "node_modules/fast-glob": {
"version": "3.2.12", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
"integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.stat": "^2.0.2",
@ -1020,9 +1023,9 @@
} }
}, },
"node_modules/jake": { "node_modules/jake": {
"version": "10.8.6", "version": "10.8.7",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.6.tgz", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
"integrity": "sha512-G43Ub9IYEFfu72sua6rzooi8V8Gz2lkfk48rW20vEWCGizeaEPlKB1Kh8JIA84yQbiAEfqlPmSpGgCKKxH3rDA==", "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"async": "^3.2.3", "async": "^3.2.3",
@ -1203,9 +1206,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.23", "version": "8.4.27",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -1270,9 +1273,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "3.22.0", "version": "3.26.3",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.22.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.3.tgz",
"integrity": "sha512-imsigcWor5Y/dC0rz2q0bBt9PabcL3TORry2hAa6O6BuMvY71bqHyfReAz5qyAqiQATD1m70qdntqBfBQjVWpQ==", "integrity": "sha512-7Tin0C8l86TkpcMtXvQu6saWH93nhG3dGQ1/+l5V2TDMceTxO7kDiK6GzbfLWNNxqJXm591PcEZUozZm51ogwQ==",
"dev": true, "dev": true,
"bin": { "bin": {
"rollup": "dist/bin/rollup" "rollup": "dist/bin/rollup"
@ -1349,13 +1352,13 @@
} }
}, },
"node_modules/terser": { "node_modules/terser": {
"version": "5.17.4", "version": "5.19.2",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.17.4.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz",
"integrity": "sha512-jcEKZw6UPrgugz/0Tuk/PVyLAPfMBJf5clnGueo45wTweoV8yh7Q7PEkhkJ5uuUbC7zAxEcG3tqNr1bstkQ8nw==", "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.2", "@jridgewell/source-map": "^0.3.3",
"acorn": "^8.5.0", "acorn": "^8.8.2",
"commander": "^2.20.0", "commander": "^2.20.0",
"source-map-support": "~0.5.20" "source-map-support": "~0.5.20"
}, },
@ -1385,9 +1388,9 @@
} }
}, },
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.5.2", "version": "2.6.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz",
"integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==", "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==",
"dev": true "dev": true
}, },
"node_modules/universalify": { "node_modules/universalify": {
@ -1400,14 +1403,14 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "4.3.8", "version": "4.4.6",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.6.tgz",
"integrity": "sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==", "integrity": "sha512-EY6Mm8vJ++S3D4tNAckaZfw3JwG3wa794Vt70M6cNJ6NxT87yhq7EC8Rcap3ahyHdo8AhCmV9PTk+vG1HiYn1A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"esbuild": "^0.17.5", "esbuild": "^0.18.10",
"postcss": "^8.4.23", "postcss": "^8.4.26",
"rollup": "^3.21.0" "rollup": "^3.25.2"
}, },
"bin": { "bin": {
"vite": "bin/vite.js" "vite": "bin/vite.js"
@ -1415,12 +1418,16 @@
"engines": { "engines": {
"node": "^14.18.0 || >=16.0.0" "node": "^14.18.0 || >=16.0.0"
}, },
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
},
"optionalDependencies": { "optionalDependencies": {
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
}, },
"peerDependencies": { "peerDependencies": {
"@types/node": ">= 14", "@types/node": ">= 14",
"less": "*", "less": "*",
"lightningcss": "^1.21.0",
"sass": "*", "sass": "*",
"stylus": "*", "stylus": "*",
"sugarss": "*", "sugarss": "*",
@ -1433,6 +1440,9 @@
"less": { "less": {
"optional": true "optional": true
}, },
"lightningcss": {
"optional": true
},
"sass": { "sass": {
"optional": true "optional": true
}, },

View File

@ -13,9 +13,9 @@
"modern-normalize": "2.0.0" "modern-normalize": "2.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "20.2.1", "@types/node": "20.4.4",
"date-and-time": "3.0.0", "date-and-time": "3.0.2",
"vite": "4.3.8", "vite": "4.4.6",
"vite-plugin-html": "3.2.0" "vite-plugin-html": "3.2.0"
} }
} }

View File

@ -1,5 +1,5 @@
import { DIVLO_BIRTHDAY, getAge } from '../../utils/getAge.ts' import { BIRTH_DATE, getAge } from '../../utils/getAge.ts'
const yearOld = document.getElementById('year-old') const yearOld = document.getElementById('year-old')
yearOld.textContent = getAge(DIVLO_BIRTHDAY).toString() yearOld.textContent = getAge(BIRTH_DATE).toString()

View File

@ -1,8 +1,8 @@
{ {
"about": { "about": {
"i-am": "I am",
"description": "Developer Full Stack • Open-Source enthusiast", "description": "Developer Full Stack • Open-Source enthusiast",
"full-name": "Full name", "pronouns": "Pronouns",
"pronouns-value": "He/Him",
"birth-date": "Birth date", "birth-date": "Birth date",
"years-old": "years old", "years-old": "years old",
"nationality": "Nationality", "nationality": "Nationality",
@ -17,7 +17,7 @@
}, },
{ {
"title": "Open-Source enthusiast", "title": "Open-Source enthusiast",
"description": "For me, everyone should work, solve problems, build things and think together.<br/> The website is open-source on <a class='text-yellow dark:text-yellow-dark hover:underline' href='https://github.com/Divlo/Divlo' target='_blank' rel='noopener noreferrer'>GitHub</a>." "description": "For me, everyone should work, solve problems, build things and think together.<br/> The website is open-source on <a class='text-yellow dark:text-yellow-dark hover:underline' href='https://github.com/theoludwig/theoludwig' target='_blank' rel='noopener noreferrer'>GitHub</a>."
}, },
{ {
"title": "Passionate about High-Tech", "title": "Passionate about High-Tech",
@ -34,22 +34,22 @@
"title": "Portfolio", "title": "Portfolio",
"items": [ "items": [
{ {
"title": "function.divlo.fr", "title": "Carolo",
"description": "Learn programming through project-based alias function.", "description": "Strategy board game similar to chess which allows grandiose moves (only available in French).",
"link": "https://function.divlo.fr/", "link": "https://carolo.theoludwig.fr/",
"image": "/images/portfolio/functiondivlofr.png" "image": "/images/portfolio/Carolo.png"
}, },
{ {
"title": "thream.divlo.fr", "title": "Thream",
"description": "Your open source platform to stay close with your friends and communities, talk, chat, collaborate, share and have fun.", "description": "Your open source platform to stay close with your friends and communities, talk, chat, collaborate, share and have fun.",
"link": "https://thream.divlo.fr/", "link": "https://thream.theoludwig.fr/",
"image": "/images/portfolio/threamdivlofr.png" "image": "/images/portfolio/Thream.png"
}, },
{ {
"title": "Leon", "title": "Leon",
"description": "Leon is your open-source personal assistant.", "description": "Leon is your open-source personal assistant.",
"link": "https://getleon.ai/", "link": "https://getleon.ai/",
"image": "/images/portfolio/leon.png" "image": "/images/portfolio/Leon.png"
} }
] ]
}, },

View File

@ -1,8 +1,8 @@
{ {
"about": { "about": {
"i-am": "Je suis",
"description": "Développeur Full Stack • Enthousiaste de l'Open-Source", "description": "Développeur Full Stack • Enthousiaste de l'Open-Source",
"full-name": "Prénom NOM", "pronouns": "Pronoms",
"pronouns-value": "Il/Lui",
"birth-date": "Date de naissance", "birth-date": "Date de naissance",
"years-old": "ans", "years-old": "ans",
"nationality": "Nationalité", "nationality": "Nationalité",
@ -17,7 +17,7 @@
}, },
{ {
"title": "Enthousiaste de l'Open-Source", "title": "Enthousiaste de l'Open-Source",
"description": "Pour moi, tout le monde devrait travailler, résoudre des problèmes, construire des choses et réfléchir ensemble. <br/> Le site est open-source sur <a class='text-yellow dark:text-yellow-dark hover:underline' href='https://github.com/Divlo/Divlo' target='_blank' rel='noopener noreferrer'>GitHub</a>." "description": "Pour moi, tout le monde devrait travailler, résoudre des problèmes, construire des choses et réfléchir ensemble. <br/> Le site est open-source sur <a class='text-yellow dark:text-yellow-dark hover:underline' href='https://github.com/theoludwig/theoludwig' target='_blank' rel='noopener noreferrer'>GitHub</a>."
}, },
{ {
"title": "Passionné de High-Tech", "title": "Passionné de High-Tech",
@ -34,22 +34,22 @@
"title": "Portfolio", "title": "Portfolio",
"items": [ "items": [
{ {
"title": "function.divlo.fr", "title": "Carolo",
"description": "Apprenez la programmation grâce à l'apprentissage par projet alias fonction.", "description": "Jeu de plateau stratégique similaire aux échecs qui permet des coups grandioses, reposant sur des enchaînements remarquables.",
"link": "https://function.divlo.fr/", "link": "https://carolo.theoludwig.fr/",
"image": "/images/portfolio/functiondivlofr.png" "image": "/images/portfolio/Carolo.png"
}, },
{ {
"title": "thream.divlo.fr", "title": "Thream",
"description": "Votre plateforme open source pour rester proche de vos amis et communautés, parler, discuter, collaborer, partager et amusez-vous.", "description": "Votre plateforme open source pour rester proche de vos amis et communautés, parler, discuter, collaborer, partager et amusez-vous.",
"link": "https://thream.divlo.fr/", "link": "https://thream.theoludwig.fr/",
"image": "/images/portfolio/threamdivlofr.png" "image": "/images/portfolio/Thream.png"
}, },
{ {
"title": "Leon", "title": "Leon",
"description": "Leon est votre assistant personnel open source.", "description": "Leon est votre assistant personnel open source.",
"link": "https://getleon.ai/", "link": "https://getleon.ai/",
"image": "/images/portfolio/leon.png" "image": "/images/portfolio/Leon.png"
} }
] ]
}, },

View File

@ -1,7 +1,3 @@
const nextPWA = require('next-pwa')({
disable: process.env.NODE_ENV !== 'production',
dest: 'public'
})
const nextTranslate = require('next-translate-plugin') const nextTranslate = require('next-translate-plugin')
/** @type {import("next").NextConfig} */ /** @type {import("next").NextConfig} */
@ -10,4 +6,4 @@ const nextConfig = {
output: 'standalone' output: 'standalone'
} }
module.exports = nextTranslate(nextPWA(nextConfig)) module.exports = nextTranslate(nextConfig)

16197
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
{ {
"name": "divlo", "name": "theoludwig",
"version": "2.7.0", "version": "2.13.0",
"private": true, "private": true,
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/Divlo/Divlo" "url": "https://github.com/theoludwig/theoludwig"
}, },
"engines": { "engines": {
"node": ">=16.0.0", "node": ">=16.0.0",
@ -17,35 +17,33 @@
"lint:commit": "commitlint", "lint:commit": "commitlint",
"lint:editorconfig": "editorconfig-checker", "lint:editorconfig": "editorconfig-checker",
"lint:markdown": "markdownlint-cli2", "lint:markdown": "markdownlint-cli2",
"lint:eslint": "eslint \".\" --ignore-path \".gitignore\"", "lint:eslint": "eslint . --max-warnings 0 --report-unused-disable-directives --ignore-path .gitignore",
"lint:prettier": "prettier \".\" --check --ignore-path \".gitignore\"", "lint:prettier": "prettier . --check",
"lint:staged": "lint-staged", "lint:staged": "lint-staged",
"test:unit": "cypress run --component", "test:unit": "cypress run --component",
"test:html-w3c-validator": "start-server-and-test \"start\" \"http://127.0.0.1:3000\" \"html-w3c-validator\"", "test:html-w3c-validator": "start-server-and-test \"start\" \"http://127.0.0.1:3000\" \"html-w3c-validator\"",
"test:e2e": "start-server-and-test \"start\" \"http://127.0.0.1:3000\" \"cypress run\"", "test:e2e": "start-server-and-test \"start\" http://127.0.0.1:3000 \"cypress run\"",
"test:dev": "start-server-and-test \"dev\" \"http://127.0.0.1:3000\" \"cypress open\"", "test:dev": "start-server-and-test \"dev\" \"http://127.0.0.1:3000\" \"cypress open\"",
"resume:build": "node ./jsonresume-theme-custom/build.js", "resume:build": "node ./jsonresume-theme-custom/build.js",
"release": "semantic-release", "release": "semantic-release",
"deploy": "vercel",
"postinstall": "husky install" "postinstall": "husky install"
}, },
"dependencies": { "dependencies": {
"@fontsource/montserrat": "5.0.0", "@fontsource/montserrat": "5.0.5",
"@fortawesome/fontawesome-svg-core": "6.4.0", "@fortawesome/fontawesome-svg-core": "6.4.0",
"@fortawesome/free-brands-svg-icons": "6.4.0", "@fortawesome/free-brands-svg-icons": "6.4.0",
"@fortawesome/free-solid-svg-icons": "6.4.0", "@fortawesome/free-solid-svg-icons": "6.4.0",
"@fortawesome/react-fontawesome": "0.2.0", "@fortawesome/react-fontawesome": "0.2.0",
"@giscus/react": "2.2.8", "@giscus/react": "2.3.0",
"clsx": "1.2.1", "clsx": "2.0.0",
"date-and-time": "3.0.0", "date-and-time": "3.0.2",
"gray-matter": "4.0.3", "gray-matter": "4.0.3",
"html-react-parser": "3.0.16", "html-react-parser": "4.2.0",
"katex": "0.16.7", "katex": "0.16.8",
"next": "13.4.3", "next": "13.4.12",
"next-mdx-remote": "4.4.1", "next-mdx-remote": "4.4.1",
"next-pwa": "5.6.0",
"next-themes": "0.2.1", "next-themes": "0.2.1",
"next-translate": "2.0.5", "next-translate": "2.5.2",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"read-pkg": "8.0.0", "read-pkg": "8.0.0",
@ -54,48 +52,48 @@
"rehype-slug": "5.1.0", "rehype-slug": "5.1.0",
"remark-gfm": "3.0.1", "remark-gfm": "3.0.1",
"remark-math": "5.1.1", "remark-math": "5.1.1",
"sharp": "0.32.1", "sharp": "0.32.4",
"shiki": "0.14.2", "shiki": "0.14.3",
"unified": "10.1.2", "unified": "10.1.2",
"unist-util-visit": "4.1.2", "unist-util-visit": "5.0.0",
"universal-cookie": "4.0.4" "universal-cookie": "4.0.4"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "17.6.3", "@commitlint/cli": "17.6.7",
"@commitlint/config-conventional": "17.6.3", "@commitlint/config-conventional": "17.6.7",
"@saithodev/semantic-release-backmerge": "3.2.0", "@saithodev/semantic-release-backmerge": "3.2.0",
"@semantic-release/git": "10.0.1", "@semantic-release/git": "10.0.1",
"@tailwindcss/typography": "0.5.9", "@tailwindcss/typography": "0.5.9",
"@tsconfig/strictest": "2.0.1", "@tsconfig/strictest": "2.0.1",
"@types/node": "20.2.1", "@types/node": "20.4.4",
"@types/react": "18.2.6", "@types/react": "18.2.15",
"@types/unist": "2.0.6", "@types/unist": "3.0.0",
"@typescript-eslint/eslint-plugin": "5.59.6", "@typescript-eslint/eslint-plugin": "6.1.0",
"@typescript-eslint/parser": "6.1.0",
"autoprefixer": "10.4.14", "autoprefixer": "10.4.14",
"cypress": "12.12.0", "cypress": "12.17.2",
"editorconfig-checker": "5.0.1", "editorconfig-checker": "5.1.1",
"eslint": "8.41.0", "eslint": "8.45.0",
"eslint-config-conventions": "9.0.0", "eslint-config-conventions": "11.0.1",
"eslint-config-next": "13.4.3", "eslint-config-next": "13.4.12",
"eslint-config-prettier": "8.8.0", "eslint-config-prettier": "8.8.0",
"eslint-plugin-import": "2.27.5", "eslint-plugin-import": "2.27.5",
"eslint-plugin-prettier": "4.2.1", "eslint-plugin-prettier": "5.0.0",
"eslint-plugin-promise": "6.1.1", "eslint-plugin-promise": "6.1.1",
"eslint-plugin-unicorn": "47.0.0", "eslint-plugin-unicorn": "48.0.0",
"html-w3c-validator": "1.3.0", "html-w3c-validator": "1.4.0",
"husky": "8.0.3", "husky": "8.0.3",
"jsonresume-theme-custom": "file:./jsonresume-theme-custom", "jsonresume-theme-custom": "file:./jsonresume-theme-custom",
"lint-staged": "13.2.2", "lint-staged": "13.2.3",
"markdownlint-cli2": "0.7.1", "markdownlint-cli2": "0.8.1",
"markdownlint-rule-relative-links": "1.2.0", "markdownlint-rule-relative-links": "2.1.0",
"next-translate-plugin": "2.0.5", "next-translate-plugin": "2.5.2",
"postcss": "8.4.23", "postcss": "8.4.27",
"prettier": "2.8.8", "prettier": "3.0.0",
"prettier-plugin-tailwindcss": "0.3.0", "prettier-plugin-tailwindcss": "0.4.1",
"semantic-release": "21.0.2", "semantic-release": "21.0.7",
"start-server-and-test": "2.0.0", "start-server-and-test": "2.0.0",
"tailwindcss": "3.3.2", "tailwindcss": "3.3.3",
"typescript": "5.0.4", "typescript": "5.1.6"
"vercel": "29.3.6"
} }
} }

View File

@ -13,7 +13,7 @@ const Error404: NextPage<Error404Props> = (props) => {
return ( return (
<> <>
<Head title='404 | Divlo' /> <Head title='404 | Théo LUDWIG' />
<ErrorPage <ErrorPage
statusCode={404} statusCode={404}
message={t('errors:not-found')} message={t('errors:not-found')}

View File

@ -13,7 +13,7 @@ const Error500: NextPage<Error500Props> = (props) => {
return ( return (
<> <>
<Head title='500 | Divlo' /> <Head title='500 | Théo LUDWIG' />
<ErrorPage <ErrorPage
statusCode={500} statusCode={500}
message={t('errors:server-error')} message={t('errors:server-error')}

View File

@ -1,5 +1,9 @@
import type { GetStaticProps, GetStaticPaths, NextPage } from 'next' import type { GetStaticProps, GetStaticPaths, NextPage } from 'next'
import Link from 'next/link'
import Image from 'next/image'
import { MDXRemote } from 'next-mdx-remote' import { MDXRemote } from 'next-mdx-remote'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faLink } from '@fortawesome/free-solid-svg-icons'
import date from 'date-and-time' import date from 'date-and-time'
import Giscus from '@giscus/react' import Giscus from '@giscus/react'
import { useTheme } from 'next-themes' import { useTheme } from 'next-themes'
@ -16,6 +20,26 @@ interface BlogPostPageProps extends FooterProps {
post: Post post: Post
} }
const Heading = (
props: React.DetailedHTMLProps<
React.HTMLAttributes<HTMLHeadingElement>,
HTMLHeadingElement
>
): JSX.Element => {
const { children, id = '' } = props
return (
<h2 {...props} className='group'>
<Link
href={`#${id}`}
className='invisible !text-black group-hover:visible dark:!text-white'
>
<FontAwesomeIcon className='mr-2 inline h-4 w-4' icon={faLink} />
</Link>
{children}
</h2>
)
}
const BlogPostPage: NextPage<BlogPostPageProps> = (props) => { const BlogPostPage: NextPage<BlogPostPageProps> = (props) => {
const { version, post } = props const { version, post } = props
@ -24,56 +48,70 @@ const BlogPostPage: NextPage<BlogPostPageProps> = (props) => {
return ( return (
<> <>
<Head <Head
title={`${post.frontmatter.title} | Divlo`} title={`${post.frontmatter.title} | Théo LUDWIG`}
description={post.frontmatter.description} description={post.frontmatter.description}
/> />
<Header /> <Header />
<main className='flex flex-1 flex-col flex-wrap items-center'> <main className='break-wrap-words flex flex-1 flex-col flex-wrap items-center'>
<div className='my-10 flex flex-col items-center'> <div className='my-10 flex flex-col items-center text-center'>
<h1 className='text-3xl font-semibold'>{post.frontmatter.title}</h1> <h1 className='text-3xl font-semibold'>{post.frontmatter.title}</h1>
<p className='mt-2' data-cy='blog-post-date'> <p className='mt-2' data-cy='blog-post-date'>
{date.format(new Date(post.frontmatter.publishedOn), 'DD/MM/YYYY')} {date.format(new Date(post.frontmatter.publishedOn), 'DD/MM/YYYY')}
</p> </p>
</div> </div>
<div className='prose mb-10 px-8'> <div className='prose mb-10'>
<MDXRemote <div className='px-8'>
{...post.source} <MDXRemote
components={{ {...post.source}
img: (properties) => { components={{
const { src, alt, ...props } = properties h1: Heading,
let source = src h2: Heading,
source = src?.replace('../public/', '/') h3: Heading,
return ( h4: Heading,
<span className='flex flex-col items-center justify-center'> h5: Heading,
<img src={source} alt={alt} {...props} /> h6: Heading,
</span> img: (properties) => {
) const { src = '', alt = 'Blog Image' } = properties
}, const source = src.replace('../public/', '/')
a: (props) => { return (
if (props.href?.startsWith('#') ?? false) { <span className='flex flex-col items-center justify-center'>
return <a {...props} /> <Image
src={source}
alt={alt}
width={1000}
height={1000}
className='h-auto w-auto'
/>
</span>
)
},
a: (props) => {
const { href = '' } = props
if (href.startsWith('#')) {
return <a {...props} />
}
return (
<a target='_blank' rel='noopener noreferrer' {...props} />
)
} }
return ( }}
<a target='_blank' rel='noopener noreferrer' {...props} /> />
) <Giscus
} id='comments'
}} repo='theoludwig/theoludwig'
/> repoId='MDEwOlJlcG9zaXRvcnkzNTg5NDg1NDQ='
<Giscus category='General'
id='comments' categoryId='DIC_kwDOFWUewM4CQ_WK'
repo='Divlo/Divlo' mapping='pathname'
repoId='MDEwOlJlcG9zaXRvcnkzNTg5NDg1NDQ=' reactionsEnabled='1'
category='General' emitMetadata='0'
categoryId='DIC_kwDOFWUewM4CQ_WK' inputPosition='top'
mapping='pathname' theme={theme}
reactionsEnabled='1' lang='en'
emitMetadata='0' loading='lazy'
inputPosition='top' />
theme={theme} </div>
lang='en'
loading='lazy'
/>
</div> </div>
</main> </main>
<Footer version={version} /> <Footer version={version} />

View File

@ -21,7 +21,7 @@ const BlogPage: NextPage<BlogPageProps> = (props) => {
return ( return (
<> <>
<Head title='Blog | Divlo' description={blogDescription} /> <Head title='Blog | Théo LUDWIG' description={blogDescription} />
<Header /> <Header />
<main className='flex flex-1 flex-col flex-wrap items-center'> <main className='flex flex-1 flex-col flex-wrap items-center'>

View File

@ -21,7 +21,7 @@ Git was originally authored by [Linus Torvalds](https://en.wikipedia.org/wiki/Li
Git allows: Git allows:
- to be able to work with several people on the same codebase. - to work with several people on the same codebase.
- track changes to know who did what and when. - track changes to know who did what and when.
- revert changes. - revert changes.
@ -122,6 +122,13 @@ git checkout <branch>
# Merge a branch into the current branch # Merge a branch into the current branch
git merge <branch> git merge <branch>
# Combine multiple commits of a branch into one for a merge
git merge --squash <branch>
# Change several past commits (interactive rebase)
# HEAD points to the current consulted commit.
git rebase --interactive HEAD~<number-of-commits>
# Delete a branch # Delete a branch
git branch --delete <branch> git branch --delete <branch>
git push <remote> --delete <branch> git push <remote> --delete <branch>
@ -132,14 +139,11 @@ git fetch --prune
# Revert a commit # Revert a commit
git revert <commit> git revert <commit>
# Change several past commits (interactive rebase)
# HEAD points to the current consulted commit.
git rebase --interactive HEAD~<number-of-commits>
# Reset the current branch, delete all commits since <branch> (without removing the changes) # Reset the current branch, delete all commits since <branch> (without removing the changes)
git reset --soft <branch> git reset --soft <branch>
# Apply the changes introduced by some existing commits # Apply the changes introduced by some existing commits
# (by first being on the branch where you want to apply the commit)
git cherry-pick <commit> git cherry-pick <commit>
``` ```

View File

@ -13,11 +13,11 @@ This blog is here to document my journey of learning computer science, explainin
The idea is that I will share my knowledge with you (readers), and hopefully help you to learn too. The idea is that I will share my knowledge with you (readers), and hopefully help you to learn too.
Keep in mind that I will not translate the posts in French, all the posts will be written in English, as I'm not a native English speaker, I will probably make mistakes, feel free to open pull requests on [GitHub](https://github.com/Divlo/Divlo) to correct them. 😊 Keep in mind that I will not translate the posts in French, all the posts will be written in English, as I'm not a native English speaker, I will probably make mistakes, feel free to open pull requests on [GitHub](https://github.com/theoludwig/theoludwig) to correct them. 😊
I plan to publish new posts when I have something new to share. There's no schedule, so stay tuned! I plan to publish new posts when I have something new to share. There's no schedule, so stay tuned!
To stay informed of new blog post and to ask questions, feel free to follow me on Twitter: [@Divlo_FR](https://twitter.com/Divlo_FR). To stay informed of new blog post and to ask questions, feel free to follow me on Twitter: [@theoludwig\_](https://twitter.com/theoludwig_).
## Project based learning ## Project based learning
@ -33,7 +33,7 @@ I learn something new, because it solved a "real life" problem I had encountered
In this section, I will explain what technologies I used to make this blog, and what are the technical choices I had to do. In this section, I will explain what technologies I used to make this blog, and what are the technical choices I had to do.
The code of this website is open source on [GitHub](https://github.com/Divlo/Divlo), so you can see the code and contribute to it. The code of this website is open source on [GitHub](https://github.com/theoludwig/theoludwig), so you can see the code and contribute to it.
### Technologies ### Technologies

View File

@ -41,13 +41,13 @@ Find the right balance, between abstraction and simple implementation, start sim
When you start a new project, you should focus on the core of the project, not on the details, to release as soon as possible, a working usable version of your project also called a [**Minimum Viable Product** (MVP)](https://en.wikipedia.org/wiki/Minimum_viable_product), it is better than a half-functioning, over-engineered project. When you start a new project, you should focus on the core of the project, not on the details, to release as soon as possible, a working usable version of your project also called a [**Minimum Viable Product** (MVP)](https://en.wikipedia.org/wiki/Minimum_viable_product), it is better than a half-functioning, over-engineered project.
I made this mistake while developing [Thream](https://thream.divlo.fr), your **open source** platform to stay close with your friends and communities, **talk**, chat, **collaborate**, share and **have fun**. I made this mistake while developing [Thream](https://thream.theoludwig.fr), your **open source** platform to stay close with your friends and communities, **talk**, chat, **collaborate**, share and **have fun**.
Basically, I thought it was cool, to do a "big" v1.0.0 release with a lot of features, but in fact, it was not, because I could not even show what I was developing (to the end-users, not technical people) as I was making multiple features at the same time and also mainly focused on the **REST API** side and not at all the **website (frontend)**. Basically, I thought it was cool, to do a "big" v1.0.0 release with a lot of features, but in fact, it was not, because I could not even show what I was developing (to the end-users, not technical people) as I was making multiple features at the same time and also mainly focused on the **REST API** side and not at all the **website (frontend)**.
What I recommend you to do is to start with a **v1.0.0** release as soon as possible with the minimum required features needed for your project idea, and then gradually add new features and release new versions. What I recommend you to do is to start with a **v1.0.0** release as soon as possible with the minimum required features needed for your project idea, and then gradually add new features and release new versions.
In my example for [Thream](https://thream.divlo.fr), I could release a v1.0.0 without these features: In my example for [Thream](https://thream.theoludwig.fr), I could release a v1.0.0 without these features:
- English/French translation (could be only English) - English/French translation (could be only English)
- Light/Dark theme (could be only Dark) - Light/Dark theme (could be only Dark)
@ -55,7 +55,7 @@ In my example for [Thream](https://thream.divlo.fr), I could release a v1.0.0 wi
- User public profile - User public profile
- Channels (maybe could be only one channel per guild to start with) - Channels (maybe could be only one channel per guild to start with)
And probably more, what was really required with [Thream](https://thream.divlo.fr), is that users could authenticate, create a community of friends, and then they could communicate with each other with messages in real-time, really that was enough. And probably more, what was really required with [Thream](https://thream.theoludwig.fr), is that users could authenticate, create a community of friends, and then they could communicate with each other with messages in real-time, really that was enough.
And then with this basis, I could release, v1.1.0, v1.2.0 etc. with more features, and release new versions more often to show the progress of the project, it is also more motivating to have users testing our project and to **get feedback sooner**. And then with this basis, I could release, v1.1.0, v1.2.0 etc. with more features, and release new versions more often to show the progress of the project, it is also more motivating to have users testing our project and to **get feedback sooner**.

View File

@ -333,11 +333,11 @@ def maximum_subarray_sum_linear(array: list[int]) -> int:
Problems solving is a very complicated and large topic, and also a very important skill to have as a software developer. Problems solving is a very complicated and large topic, and also a very important skill to have as a software developer.
To improve our problems solving skills, we can regularly practice with [programming challenges](https://github.com/Divlo/programming-challenges). To improve our problems solving skills, we can regularly practice with [programming challenges](https://github.com/theoludwig/programming-challenges).
## Sources ## Sources
- [Wikipedia - Competitive programming](https://en.wikipedia.org/wiki/Competitive_programming) - [Wikipedia - Competitive programming](https://en.wikipedia.org/wiki/Competitive_programming)
- [Frontend Masters - The Last Algorithms Course You'll Need](https://frontendmasters.com/courses/algorithms/) - [Frontend Masters - The Last Algorithms Course You'll Need](https://frontendmasters.com/courses/algorithms/)
- [Big-O Cheat Sheet](https://www.bigocheatsheet.com/) - [Big-O Cheat Sheet](https://www.bigocheatsheet.com/)
- [programming challenges](https://github.com/Divlo/programming-challenges) - [programming challenges](https://github.com/theoludwig/programming-challenges)

View File

@ -7,13 +7,13 @@ publishedOn: '2022-04-11T10:24:55.206Z'
Hello! 👋 Hello! 👋
After months of hard work, [Thream v1.0.0](https://www.thream.divlo.fr/) has been released! 🎉 After months of hard work, [Thream v1.0.0](https://thream.theoludwig.fr/) has been released! 🎉
[**Thream**](https://www.thream.divlo.fr/) is your open-source platform to stay close with your friends and communities, talk, chat, collaborate, share and have fun. [**Thream**](https://thream.theoludwig.fr/) is your open-source platform to stay close with your friends and communities, talk, chat, collaborate, share and have fun.
## Presentation ## Presentation
[**Thream**](https://www.thream.divlo.fr/) is a social network to stay close with your friends and communities to talk, chat, collaborate and share. [**Thream**](https://thream.theoludwig.fr/) is a social network to stay close with your friends and communities to talk, chat, collaborate and share.
The project is largely inspired by [Discord](https://discord.com), a proprietary instant messaging service, but differentiates itself by its **non-profit open source philosophy** and will integrate special features. The project is largely inspired by [Discord](https://discord.com), a proprietary instant messaging service, but differentiates itself by its **non-profit open source philosophy** and will integrate special features.
@ -23,15 +23,15 @@ The idea is that a user can create an account to authenticate with an email addr
![The Thream app on a community page](../public/images/posts/thream-v1-0-0/thream-ui.png) ![The Thream app on a community page](../public/images/posts/thream-v1-0-0/thream-ui.png)
[**Thream**](https://www.thream.divlo.fr/) is a website that works on any recent browser, accessible on [thream.divlo.fr](https://www.thream.divlo.fr/). [**Thream**](https://thream.theoludwig.fr/) is a website that works on any recent browser, accessible on [thream.theoludwig.fr](https://thream.theoludwig.fr/).
## History ## History
The idea for the project has existed since May 13, 2020, symbolized by a [publication on Twitter](https://twitter.com/Divlo_FR/status/1260638175246135296) by the creator: Divlo. The idea for the project has existed since May 13, 2020, symbolized by a [publication on Twitter](https://twitter.com/theoludwig_/status/1260638175246135296) by the creator: Théo LUDWIG.
The main goal is to put into **practice knowledge in web development** and computer science in general on a concrete project that can **easily evolve over time** where you can add many features. The main goal is to put into **practice knowledge in web development** and computer science in general on a concrete project that can **easily evolve over time** where you can add many features.
The development of the project begins under the name of **SocialProject**, on August 20, 2020, with colors close to the image of Divlo. The development of the project begins under the name of **SocialProject**, on August 20, 2020.
![SocialProject](../public/images/posts/thream-v1-0-0/social-project.jpg) ![SocialProject](../public/images/posts/thream-v1-0-0/social-project.jpg)
@ -116,4 +116,4 @@ The other interest of the project is that it is completely **open-source**, and
Feel free to give feebacks and suggestions to improve the project, and to report any bug you find. Feel free to give feebacks and suggestions to improve the project, and to report any bug you find.
**Thream** is available: [**thream.divlo.fr**](https://www.thream.divlo.fr/). **Thream** is available: [**thream.theoludwig.fr**](https://thream.theoludwig.fr/).

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View File

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View File

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 189 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,51 +0,0 @@
{
"name": "Divlo",
"short_name": "Divlo",
"icons": [
{
"src": "images/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "images/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "images/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "images/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "images/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "images/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "images/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffd800",
"background_color": "#181818",
"start_url": "/",
"display": "standalone"
}

View File

@ -6,14 +6,14 @@
"basics": { "basics": {
"name": "Théo LUDWIG", "name": "Théo LUDWIG",
"label": "Développeur Full Stack • Étudiant", "label": "Développeur Full Stack • Étudiant",
"image": "https://divlo.fr/images/logo_orange.png", "image": "https://theoludwig.fr/images/logo_orange.png",
"email": "contact@divlo.fr", "email": "contact@theoludwig.fr",
"age": "31/03/2003", "age": "31/03/2003",
"location": { "location": {
"address": "Alsace, France" "address": "Alsace, France"
}, },
"url": "https://divlo.fr", "url": "https://theoludwig.fr",
"summary": "Je suis étudiant à l'université suivant la formation \"BUT Informatique\" et me forme en autodidacte dans l'informatique en suivant des formations en ligne. <br/> Je mets en pratique tout ce que j'apprends et réalise de nombreux projets (disponible sur <a href=\"https://divlo.fr\">divlo.fr</a>)." "summary": "Je suis étudiant à l'université suivant la formation \"BUT Informatique\" et me forme en autodidacte dans l'informatique en suivant des formations en ligne. <br/> Je mets en pratique tout ce que j'apprends et réalise de nombreux projets (disponible sur <a href=\"https://theoludwig.fr\">theoludwig.fr</a>)."
}, },
"education": [ "education": [
{ {
@ -66,8 +66,8 @@
"location": "4 Rue Sophie Germain, 67720 Hœrdt", "location": "4 Rue Sophie Germain, 67720 Hœrdt",
"position": "Stagiaire Développeur Web", "position": "Stagiaire Développeur Web",
"startDate": "2023-04-11", "startDate": "2023-04-11",
"endDate": "2023-06-23", "endDate": "2023-07-26",
"duration": "3 mois" "duration": "4 mois"
}, },
{ {
"summary": "Agent administratif - Numérisation et archivage des plans électriques initialement sous format papier calque.", "summary": "Agent administratif - Numérisation et archivage des plans électriques initialement sous format papier calque.",
@ -105,7 +105,7 @@
"website": "https://www.wildcodeschool.fr/", "website": "https://www.wildcodeschool.fr/",
"name": "Wild Code School", "name": "Wild Code School",
"location": "32 Rue du Bass. d'Austerlitz, 67100 Strasbourg", "location": "32 Rue du Bass. d'Austerlitz, 67100 Strasbourg",
"position": "Initiation métier développeur web", "position": "Initiation métier Développeur web",
"startDate": "2019-06-24", "startDate": "2019-06-24",
"endDate": "2019-06-28", "endDate": "2019-06-28",
"duration": "1 semaine" "duration": "1 semaine"
@ -136,16 +136,16 @@
}, },
{ {
"keywords": ["HTML", "CSS", "Tailwind CSS", "React.js/Next.js"], "keywords": ["HTML", "CSS", "Tailwind CSS", "React.js/Next.js"],
"name": "Front-end" "name": "Frontend"
}, },
{ {
"keywords": ["Laravel", "Node.js", "Fastify", "PostgreSQL"], "keywords": ["Laravel", "Node.js", "Fastify", "PostgreSQL"],
"name": "Back-end" "name": "Backend"
}, },
{ {
"keywords": [ "keywords": [
"GNU/Linux", "GNU/Linux",
"Ubuntu", "Arch Linux",
"Visual Studio Code", "Visual Studio Code",
"Git", "Git",
"Docker" "Docker"

View File

@ -2,8 +2,25 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
.break-wrap-words {
word-wrap: break-word;
word-break: break-word;
}
.prose { .prose {
@apply !max-w-4xl text-gray dark:text-gray-300; @apply !max-w-5xl scroll-smooth text-gray dark:text-gray-300;
}
.prose p {
@apply text-justify;
}
.prose [id]::before {
content: '';
display: block;
height: 90px;
margin-top: -90px;
visibility: hidden;
} }
.prose a, .prose a,
@ -28,8 +45,6 @@
} }
.shiki { .shiki {
white-space: pre-wrap !important; white-space: pre-wrap !important;
word-break: normal !important;
word-wrap: normal;
} }
code { code {
counter-reset: step; counter-reset: step;
@ -43,4 +58,12 @@ code .line::before {
display: inline-block; display: inline-block;
text-align: right; text-align: right;
color: rgba(133, 133, 133, 0.8); color: rgba(133, 133, 133, 0.8);
word-wrap: normal;
word-break: normal;
}
.katex .base {
display: inline !important;
white-space: normal !important;
width: 100% !important;
} }

View File

@ -1,11 +1,11 @@
export const DIVLO_BIRTHDAY_DAY = '31' as const export const BIRTH_DATE_DAY = '31' as const
export const DIVLO_BIRTHDAY_MONTH = '03' as const export const BIRTH_DATE_MONTH = '03' as const
export const DIVLO_BIRTHDAY_YEAR = '2003' as const export const BIRTH_DATE_YEAR = '2003' as const
export const DIVLO_BIRTHDAY_DATE = export const BIRTH_DATE_STRING =
`${DIVLO_BIRTHDAY_DAY}/${DIVLO_BIRTHDAY_MONTH}/${DIVLO_BIRTHDAY_YEAR}` as const `${BIRTH_DATE_DAY}/${BIRTH_DATE_MONTH}/${BIRTH_DATE_YEAR}` as const
export const DIVLO_BIRTHDAY_DATE_ISO_8061 = export const BIRTH_DATE_ISO_8601 =
`${DIVLO_BIRTHDAY_YEAR}-${DIVLO_BIRTHDAY_MONTH}-${DIVLO_BIRTHDAY_DAY}` as const `${BIRTH_DATE_YEAR}-${BIRTH_DATE_MONTH}-${BIRTH_DATE_DAY}` as const
export const DIVLO_BIRTHDAY = new Date(DIVLO_BIRTHDAY_DATE_ISO_8061) export const BIRTH_DATE = new Date(BIRTH_DATE_ISO_8601)
/** /**
* Calculates the age of a person based on their birth date * Calculates the age of a person based on their birth date

View File

@ -1,5 +1,5 @@
import type { Plugin, Transformer } from 'unified' import type { Plugin, Transformer } from 'unified'
import type { Literal } from 'unist' import type { Literal, Node } from 'unist'
import { visit } from 'unist-util-visit' import { visit } from 'unist-util-visit'
import type { Highlighter } from 'shiki' import type { Highlighter } from 'shiki'
@ -7,15 +7,17 @@ export interface RemarkSyntaxHighlightingPluginOptions {
highlighter: Highlighter highlighter: Highlighter
} }
export type RemarkSyntaxHighlightingNode = Literal<string> & { export interface RemarkSyntaxHighlightingNode extends Node {
lang: string lang: string
meta: string meta: string
children: undefined children: undefined
value: string
data: Record<string, unknown>
} }
export const remarkSyntaxHighlightingPlugin: Plugin< export const remarkSyntaxHighlightingPlugin: Plugin<
[RemarkSyntaxHighlightingPluginOptions], [RemarkSyntaxHighlightingPluginOptions],
Literal<string, RemarkSyntaxHighlightingNode> Literal
> = (options) => { > = (options) => {
const transformer: Transformer<RemarkSyntaxHighlightingNode> = (tree) => { const transformer: Transformer<RemarkSyntaxHighlightingNode> = (tree) => {
visit<RemarkSyntaxHighlightingNode, string>(tree, 'code', (node) => { visit<RemarkSyntaxHighlightingNode, string>(tree, 'code', (node) => {

View File

@ -1,7 +0,0 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"github": {
"enabled": false
},
"cleanUrls": true
}