Compare commits
30 Commits
Author | SHA1 | Date | |
---|---|---|---|
988fceb2aa
|
|||
5211ba1489
|
|||
6886480cef
|
|||
d78e50638e
|
|||
3b76195d71
|
|||
2dc63ba933
|
|||
336f067c52
|
|||
5fd7f77b6d
|
|||
db0c708c04
|
|||
9d44671fed
|
|||
7bcc5f972c | |||
61172d59e3 | |||
7c0f11ab7d | |||
670897fa78 | |||
b88246b668 | |||
87fbfe4940 | |||
271aa60247 | |||
ba34e314c9 | |||
f41bc644b1 | |||
a18cec4826 | |||
61e589f0f4 | |||
dc5c3cee41 | |||
20cb0c21d5 | |||
e5232c1394 | |||
fd51609713 | |||
edf16c2562 | |||
94e0d190ae | |||
b1cf7f8517 | |||
a1a715d3b9 | |||
eede46fb41 |
@ -1,20 +1,24 @@
|
|||||||
{
|
{
|
||||||
"name": "Divlo",
|
"name": "theoludwig",
|
||||||
"dockerComposeFile": "./docker-compose.yml",
|
"dockerComposeFile": "./docker-compose.yml",
|
||||||
"service": "workspace",
|
"service": "workspace",
|
||||||
"workspaceFolder": "/workspace",
|
"workspaceFolder": "/workspace",
|
||||||
"settings": {
|
"customizations": {
|
||||||
"remote.autoForwardPorts": false
|
"vscode": {
|
||||||
|
"settings": {
|
||||||
|
"remote.autoForwardPorts": false
|
||||||
|
},
|
||||||
|
"extensions": [
|
||||||
|
"editorconfig.editorconfig",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"bradlc.vscode-tailwindcss",
|
||||||
|
"mikestead.dotenv",
|
||||||
|
"davidanson.vscode-markdownlint",
|
||||||
|
"ms-azuretools.vscode-docker"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"extensions": [
|
|
||||||
"editorconfig.editorconfig",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"bradlc.vscode-tailwindcss",
|
|
||||||
"mikestead.dotenv",
|
|
||||||
"davidanson.vscode-markdownlint",
|
|
||||||
"ms-azuretools.vscode-docker"
|
|
||||||
],
|
|
||||||
"forwardPorts": [3000],
|
"forwardPorts": [3000],
|
||||||
"postAttachCommand": ["npm", "install"],
|
"postAttachCommand": ["npm", "install"],
|
||||||
"remoteUser": "node"
|
"remoteUser": "node"
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
COMPOSE_PROJECT_NAME=divlo.fr
|
COMPOSE_PROJECT_NAME=theoludwig
|
||||||
PORT=3000
|
PORT=3000
|
||||||
|
@ -4,12 +4,7 @@
|
|||||||
"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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,6 +1,6 @@
|
|||||||
<!-- Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time. -->
|
<!-- Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time. -->
|
||||||
|
|
||||||
## What changes this PR introduce?
|
# What changes this PR introduce?
|
||||||
|
|
||||||
## List any relevant issue numbers
|
## List any relevant issue numbers
|
||||||
|
|
||||||
|
2
.github/workflows/analyze.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
|||||||
language: ['javascript']
|
language: ['javascript']
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.5.0'
|
- uses: 'actions/checkout@v3.5.2'
|
||||||
|
|
||||||
- name: 'Initialize CodeQL'
|
- name: 'Initialize CodeQL'
|
||||||
uses: 'github/codeql-action/init@v2'
|
uses: 'github/codeql-action/init@v2'
|
||||||
|
8
.github/workflows/build.yml
vendored
@ -10,16 +10,16 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.5.0'
|
- uses: 'actions/checkout@v3.5.2'
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
- name: 'Setup Node.js'
|
||||||
uses: 'actions/setup-node@v3.6.0'
|
uses: 'actions/setup-node@v3.6.0'
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: 'Install'
|
- name: 'Install dependencies'
|
||||||
run: 'npm install'
|
run: 'npm clean-install'
|
||||||
|
|
||||||
- name: 'Build'
|
- name: 'Build'
|
||||||
run: 'npm run build'
|
run: 'npm run build'
|
||||||
|
8
.github/workflows/lint.yml
vendored
@ -10,16 +10,16 @@ jobs:
|
|||||||
lint:
|
lint:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.5.0'
|
- uses: 'actions/checkout@v3.5.2'
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
- name: 'Setup Node.js'
|
||||||
uses: 'actions/setup-node@v3.6.0'
|
uses: 'actions/setup-node@v3.6.0'
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: 'Install'
|
- name: 'Install dependencies'
|
||||||
run: 'npm install'
|
run: 'npm clean-install'
|
||||||
|
|
||||||
- name: 'lint:commit'
|
- name: 'lint:commit'
|
||||||
run: 'npm run lint:commit -- --to "${{ github.sha }}"'
|
run: 'npm run lint:commit -- --to "${{ github.sha }}"'
|
||||||
|
10
.github/workflows/release.yml
vendored
@ -8,26 +8,26 @@ jobs:
|
|||||||
release:
|
release:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.5.0'
|
- uses: 'actions/checkout@v3.5.2'
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: 'Import GPG key'
|
- name: 'Import GPG key'
|
||||||
uses: 'crazy-max/ghaction-import-gpg@v4'
|
uses: 'crazy-max/ghaction-import-gpg@v5.3.0'
|
||||||
with:
|
with:
|
||||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
git_user_signingkey: true
|
git_user_signingkey: true
|
||||||
git_commit_gpgsign: true
|
git_commit_gpgsign: true
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
- name: 'Setup Node.js'
|
||||||
uses: 'actions/setup-node@v3.6.0'
|
uses: 'actions/setup-node@v3.6.0'
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: 'Install'
|
- name: 'Install dependencies'
|
||||||
run: 'npm install'
|
run: 'npm clean-install'
|
||||||
|
|
||||||
- name: 'Release'
|
- name: 'Release'
|
||||||
run: 'npm run release'
|
run: 'npm run release'
|
||||||
|
38
.github/workflows/test.yml
vendored
@ -10,33 +10,33 @@ jobs:
|
|||||||
test-unit:
|
test-unit:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.5.0'
|
- uses: 'actions/checkout@v3.5.2'
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
- name: 'Setup Node.js'
|
||||||
uses: 'actions/setup-node@v3.6.0'
|
uses: 'actions/setup-node@v3.6.0'
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: 'Install'
|
- name: 'Install dependencies'
|
||||||
run: 'npm install'
|
run: 'npm clean-install'
|
||||||
|
|
||||||
- name: 'Unit Test'
|
- name: 'Unit Test'
|
||||||
run: 'npm run test:unit'
|
run: 'npm run test:unit'
|
||||||
|
|
||||||
test-lighthouse:
|
test-e2e:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.5.0'
|
- uses: 'actions/checkout@v3.5.0'
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
- name: 'Setup Node.js'
|
||||||
uses: 'actions/setup-node@v3.6.0'
|
uses: 'actions/setup-node@v3.6.0'
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: 'Install'
|
- name: 'Install dependencies'
|
||||||
run: 'npm install'
|
run: 'npm clean-install'
|
||||||
|
|
||||||
- name: 'Build'
|
- name: 'Build'
|
||||||
run: 'npm run build'
|
run: 'npm run build'
|
||||||
@ -44,27 +44,5 @@ jobs:
|
|||||||
- name: 'html-w3c-validator'
|
- name: 'html-w3c-validator'
|
||||||
run: 'npm run test:html-w3c-validator'
|
run: 'npm run test:html-w3c-validator'
|
||||||
|
|
||||||
- name: 'Lighthouse'
|
|
||||||
run: 'npm run test:lighthouse'
|
|
||||||
env:
|
|
||||||
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
|
|
||||||
|
|
||||||
test-e2e:
|
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v3.5.0'
|
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
|
||||||
uses: 'actions/setup-node@v3.6.0'
|
|
||||||
with:
|
|
||||||
node-version: '18.x'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: 'Install'
|
|
||||||
run: 'npm install'
|
|
||||||
|
|
||||||
- name: 'Build'
|
|
||||||
run: 'npm run build'
|
|
||||||
|
|
||||||
- name: 'End To End (e2e) Test'
|
- name: 'End To End (e2e) Test'
|
||||||
run: 'npm run test:e2e'
|
run: 'npm run test:e2e'
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"ci": {
|
|
||||||
"collect": {
|
|
||||||
"startServerCommand": "npm run start",
|
|
||||||
"startServerReadyPattern": "ready on",
|
|
||||||
"startServerReadyTimeout": 20000,
|
|
||||||
"url": [
|
|
||||||
"http://127.0.0.1:3000/",
|
|
||||||
"http://127.0.0.1:3000/blog",
|
|
||||||
"http://127.0.0.1:3000/blog/hello-world"
|
|
||||||
],
|
|
||||||
"numberOfRuns": 1
|
|
||||||
},
|
|
||||||
"assert": {
|
|
||||||
"preset": "lighthouse:recommended",
|
|
||||||
"assertions": {
|
|
||||||
"csp-xss": "warning",
|
|
||||||
"non-composited-animations": "warning",
|
|
||||||
"unused-javascript": "warning",
|
|
||||||
"image-size-responsive": "warning",
|
|
||||||
"unsized-images": "warning",
|
|
||||||
"color-contrast": "warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"upload": {
|
|
||||||
"target": "temporary-public-storage"
|
|
||||||
},
|
|
||||||
"server": {}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"config": {
|
||||||
|
"default": true,
|
||||||
|
"relative-links": true,
|
||||||
|
"extends": "markdownlint/style/prettier",
|
||||||
|
"MD024": false,
|
||||||
|
"MD033": false
|
||||||
|
},
|
||||||
"globs": ["**/*.{md,mdx}"],
|
"globs": ["**/*.{md,mdx}"],
|
||||||
"ignores": ["**/node_modules"],
|
"ignores": ["**/node_modules"],
|
||||||
"customRules": ["markdownlint-rule-relative-links"]
|
"customRules": ["markdownlint-rule-relative-links"]
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"default": true,
|
|
||||||
"relative-links": true,
|
|
||||||
"extends": "markdownlint/style/prettier",
|
|
||||||
"MD024": false,
|
|
||||||
"MD033": false,
|
|
||||||
"MD041": false
|
|
||||||
}
|
|
@ -60,7 +60,7 @@ representative at an online or offline event.
|
|||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported to the community leaders responsible for enforcement at
|
reported to the community leaders responsible for enforcement at
|
||||||
contact@divlo.fr.
|
<contact@theoludwig.fr>.
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
# 💡 Contributing
|
# 💡 Contributing
|
||||||
|
|
||||||
Thanks a lot for your interest in contributing to **divlo.fr**! 🎉
|
Thanks a lot for your interest in contributing to **theoludwig.fr**! 🎉
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
**theoludwig.fr** adopted the [Contributor Covenant](https://www.contributor-covenant.org/) as its Code of Conduct, and we expect project participants to adhere to it. Please read [the full text](./CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated.
|
||||||
|
|
||||||
## Types of contributions
|
## Types of contributions
|
||||||
|
|
||||||
@ -11,43 +15,21 @@ 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
|
||||||
|
|
||||||
The commit message guidelines respect [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional) and [Semantic Versioning](https://semver.org/) for releases.
|
The commit message guidelines adheres to [Conventional Commits](https://www.conventionalcommits.org/) and [Semantic Versioning](https://semver.org/) for releases.
|
||||||
|
|
||||||
### Types
|
|
||||||
|
|
||||||
Types define which kind of changes you made to the project.
|
|
||||||
|
|
||||||
| Types | Description |
|
|
||||||
| -------- | ------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| feat | A new feature. |
|
|
||||||
| fix | A bug fix. |
|
|
||||||
| docs | Documentation only changes. |
|
|
||||||
| style | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc). |
|
|
||||||
| refactor | A code change that neither fixes a bug nor adds a feature. |
|
|
||||||
| perf | A code change that improves performance. |
|
|
||||||
| test | Adding missing tests or correcting existing tests. |
|
|
||||||
| build | Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm). |
|
|
||||||
| ci | Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs). |
|
|
||||||
| chore | Other changes that don't modify src or test files. |
|
|
||||||
| revert | Reverts a previous commit. |
|
|
||||||
|
|
||||||
### Scopes
|
|
||||||
|
|
||||||
Scopes define what part of the code changed.
|
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
[](https://gitpod.io/#https://github.com/Divlo/Divlo)
|
[](https://gitpod.io/#https://github.com/theoludwig/theoludwig)
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
@ -58,10 +40,10 @@ Scopes define what part of the code changed.
|
|||||||
|
|
||||||
```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
|
||||||
@ -86,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>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
FROM node:18.15.0 AS builder-dependencies
|
FROM node:18.16.0 AS builder-dependencies
|
||||||
WORKDIR /usr/src/application
|
WORKDIR /usr/src/application
|
||||||
COPY ./package*.json ./
|
COPY ./package*.json ./
|
||||||
RUN npm install
|
RUN npm clean-install
|
||||||
|
|
||||||
FROM node:18.15.0 AS builder
|
FROM node:18.16.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 ./ ./
|
||||||
|
2
LICENSE
@ -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
|
||||||
|
30
README.md
@ -1,18 +1,18 @@
|
|||||||
<h1 align="center"><a href="https://divlo.fr/">Divlo</a></h1>
|
<h1 align="center"><a href="https://theoludwig.fr/">Théo LUDWIG</a></h1>
|
||||||
|
|
||||||
<p align="center">
|
<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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -6,7 +6,7 @@ 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 />
|
||||||
@ -17,7 +17,7 @@ export const ProfileDescriptionBottom: React.FC = () => {
|
|||||||
Curriculum vitæ
|
Curriculum vitæ
|
||||||
</a>
|
</a>
|
||||||
</>
|
</>
|
||||||
)}
|
) : null}
|
||||||
</p>
|
</p>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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}
|
||||||
/>
|
/>
|
||||||
|
@ -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' />
|
||||||
|
@ -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'
|
||||||
|
@ -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>
|
||||||
|
@ -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}`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -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', () => {
|
||||||
|
@ -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", () => {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
services:
|
services:
|
||||||
divlo.fr:
|
theoludwig:
|
||||||
container_name: ${COMPOSE_PROJECT_NAME}
|
container_name: ${COMPOSE_PROJECT_NAME}
|
||||||
image: 'divlo.fr'
|
image: 'theoludwig'
|
||||||
build:
|
build:
|
||||||
context: './'
|
context: './'
|
||||||
ports:
|
ports:
|
||||||
- '${PORT-3000}:${PORT-3000}'
|
- '${PORT-3000}:${PORT-3000}'
|
||||||
environment:
|
environment:
|
||||||
PORT: ${PORT-3000}
|
PORT: ${PORT-3000}
|
||||||
env_file: './.env'
|
env_file: '.env'
|
||||||
|
@ -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" />
|
||||||
|
379
jsonresume-theme-custom/package-lock.json
generated
@ -9,19 +9,19 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsonc-parser": "3.2.0",
|
"jsonc-parser": "3.2.0",
|
||||||
"modern-normalize": "1.1.0"
|
"modern-normalize": "2.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "18.15.11",
|
"@types/node": "20.3.1",
|
||||||
"date-and-time": "2.4.3",
|
"date-and-time": "3.0.1",
|
||||||
"vite": "4.2.1",
|
"vite": "4.3.9",
|
||||||
"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.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
|
||||||
"integrity": "sha512-sRSOVlLawAktpMvDyJIkdLI/c/kdRTOqo8t6ImVxg8yT7LQDUYV5Rp2FKeEosLr6ZCja9UjYAzyRSxGteSJPYg==",
|
"integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -35,9 +35,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm64": {
|
"node_modules/@esbuild/android-arm64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
|
||||||
"integrity": "sha512-0kOB6Y7Br3KDVgHeg8PRcvfLkq+AccreK///B4Z6fNZGr/tNHX0z2VywCc7PTeWp+bPvjA5WMvNXltHw5QjAIA==",
|
"integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -51,9 +51,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-x64": {
|
"node_modules/@esbuild/android-x64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
|
||||||
"integrity": "sha512-MzDqnNajQZ63YkaUWVl9uuhcWyEyh69HGpMIrf+acR4otMkfLJ4sUCxqwbCyPGicE9dVlrysI3lMcDBjGiBBcQ==",
|
"integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -67,9 +67,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-arm64": {
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
|
||||||
"integrity": "sha512-7siLjBc88Z4+6qkMDxPT2juf2e8SJxmsbNVKFY2ifWCDT72v5YJz9arlvBw5oB4W/e61H1+HDB/jnu8nNg0rLA==",
|
"integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -83,9 +83,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-x64": {
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
|
||||||
"integrity": "sha512-NbImBas2rXwYI52BOKTW342Tm3LTeVlaOQ4QPZ7XuWNKiO226DisFk/RyPk3T0CKZkKMuU69yOvlapJEmax7cg==",
|
"integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -99,9 +99,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-arm64": {
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
|
||||||
"integrity": "sha512-Xk9xMDjBVG6CfgoqlVczHAdJnCs0/oeFOspFap5NkYAmRCT2qTn1vJWA2f419iMtsHSLm+O8B6SLV/HlY5cYKg==",
|
"integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -115,9 +115,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-x64": {
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
|
||||||
"integrity": "sha512-3TWAnnEOdclvb2pnfsTWtdwthPfOz7qAfcwDLcfZyGJwm1SRZIMOeB5FODVhnM93mFSPsHB9b/PmxNNbSnd0RQ==",
|
"integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -131,9 +131,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm": {
|
"node_modules/@esbuild/linux-arm": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
|
||||||
"integrity": "sha512-MLTgiXWEMAMr8nmS9Gigx43zPRmEfeBfGCwxFQEMgJ5MC53QKajaclW6XDPjwJvhbebv+RzK05TQjvH3/aM4Xw==",
|
"integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -147,9 +147,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm64": {
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
|
||||||
"integrity": "sha512-T0MVnYw9KT6b83/SqyznTs/3Jg2ODWrZfNccg11XjDehIved2oQfrX/wVuev9N936BpMRaTR9I1J0tdGgUgpJA==",
|
"integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -163,9 +163,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ia32": {
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
|
||||||
"integrity": "sha512-wp02sHs015T23zsQtU4Cj57WiteiuASHlD7rXjKUyAGYzlOKDAjqK6bk5dMi2QEl/KVOcsjwL36kD+WW7vJt8Q==",
|
"integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@ -179,9 +179,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-loong64": {
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
|
||||||
"integrity": "sha512-k7FsUJjGGSxwnBmMh8d7IbObWu+sF/qbwc+xKZkBe/lTAF16RqxRCnNHA7QTd3oS2AfGBAnHlXL67shV5bBThQ==",
|
"integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
@ -195,9 +195,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-mips64el": {
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
|
||||||
"integrity": "sha512-ZLWk6czDdog+Q9kE/Jfbilu24vEe/iW/Sj2d8EVsmiixQ1rM2RKH2n36qfxK4e8tVcaXkvuV3mU5zTZviE+NVQ==",
|
"integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"mips64el"
|
"mips64el"
|
||||||
],
|
],
|
||||||
@ -211,9 +211,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ppc64": {
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
|
||||||
"integrity": "sha512-mY6dPkIRAiFHRsGfOYZC8Q9rmr8vOBZBme0/j15zFUKM99d4ILY4WpOC7i/LqoY+RE7KaMaSfvY8CqjJtuO4xg==",
|
"integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@ -227,9 +227,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-riscv64": {
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
|
||||||
"integrity": "sha512-EcyUtxffdDtWjjwIH8sKzpDRLcVtqANooMNASO59y+xmqqRYBBM7xVLQhqF7nksIbm2yHABptoioS9RAbVMWVA==",
|
"integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
@ -243,9 +243,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-s390x": {
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
|
||||||
"integrity": "sha512-BuS6Jx/ezxFuHxgsfvz7T4g4YlVrmCmg7UAwboeyNNg0OzNzKsIZXpr3Sb/ZREDXWgt48RO4UQRDBxJN3B9Rbg==",
|
"integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@ -259,9 +259,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-x64": {
|
"node_modules/@esbuild/linux-x64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
|
||||||
"integrity": "sha512-JsdS0EgEViwuKsw5tiJQo9UdQdUJYuB+Mf6HxtJSPN35vez1hlrNb1KajvKWF5Sa35j17+rW1ECEO9iNrIXbNg==",
|
"integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -275,9 +275,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/netbsd-x64": {
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
|
||||||
"integrity": "sha512-R6fKjtUysYGym6uXf6qyNephVUQAGtf3n2RCsOST/neIwPqRWcnc3ogcielOd6pT+J0RDR1RGcy0ZY7d3uHVLA==",
|
"integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -291,9 +291,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openbsd-x64": {
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
|
||||||
"integrity": "sha512-mVD4PGc26b8PI60QaPUltYKeSX0wxuy0AltC+WCTFwvKCq2+OgLP4+fFd+hZXzO2xW1HPKcytZBdjqL6FQFa7w==",
|
"integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -307,9 +307,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/sunos-x64": {
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
|
||||||
"integrity": "sha512-U6tYPovOkw3459t2CBwGcFYfFRjivcJJc1WC8Q3funIwX8x4fP+R6xL/QuTPNGOblbq/EUDxj9GU+dWKX0oWlQ==",
|
"integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -323,9 +323,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-arm64": {
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
|
||||||
"integrity": "sha512-W+Z5F++wgKAleDABemiyXVnzXgvRFs+GVKThSI+mGgleLWluv0D7Diz4oQpgdpNzh4i2nNDzQtWbjJiqutRp6Q==",
|
"integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -339,9 +339,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-ia32": {
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
|
||||||
"integrity": "sha512-Muz/+uGgheShKGqSVS1KsHtCyEzcdOn/W/Xbh6H91Etm+wiIfwZaBn1W58MeGtfI8WA961YMHFYTthBdQs4t+w==",
|
"integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@ -355,9 +355,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-x64": {
|
"node_modules/@esbuild/win32-x64": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
|
||||||
"integrity": "sha512-DjDa9ywLUUmjhV2Y9wUTIF+1XsmuFGvZoCmOWkli1XcNAh5t25cc7fgsCx4Zi/Uurep3TTLyDiKATgGEg61pkA==",
|
"integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -371,9 +371,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.2",
|
"version": "0.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||||
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
|
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/set-array": "^1.0.1",
|
"@jridgewell/set-array": "^1.0.1",
|
||||||
@ -403,9 +403,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/source-map": {
|
"node_modules/@jridgewell/source-map": {
|
||||||
"version": "0.3.2",
|
"version": "0.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz",
|
||||||
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
|
"integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.3.0",
|
"@jridgewell/gen-mapping": "^0.3.0",
|
||||||
@ -413,21 +413,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.14",
|
"version": "1.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
|
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
"version": "0.3.17",
|
"version": "0.3.18",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
|
||||||
"integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
|
"integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "3.1.0",
|
"@jridgewell/resolve-uri": "3.1.0",
|
||||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": {
|
||||||
|
"version": "1.4.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
||||||
|
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@nodelib/fs.scandir": {
|
"node_modules/@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
@ -477,15 +483,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "18.15.11",
|
"version": "20.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz",
|
||||||
"integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
|
"integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.8.2",
|
"version": "8.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz",
|
||||||
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
|
"integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
@ -612,9 +618,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/colorette": {
|
"node_modules/colorette": {
|
||||||
"version": "2.0.19",
|
"version": "2.0.20",
|
||||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
|
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
|
||||||
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
|
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/commander": {
|
"node_modules/commander": {
|
||||||
@ -676,9 +682,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/date-and-time": {
|
"node_modules/date-and-time": {
|
||||||
"version": "2.4.3",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-3.0.1.tgz",
|
||||||
"integrity": "sha512-xkS/imTmsyEdpp9ie5oV5UWolg3XkYWNySbT2W4ESWr6v4V8YrsHbhpk9fIeQcr0NFTnYbQJLXlgU1zrLItysA==",
|
"integrity": "sha512-Az1hy3IPuh7LR4duPGlgkUzZXtjoWH8pd+XVLpLXMNd+DD48sRdcsWIPbqdHCXg4izb9lPzrKtqUXPXevS9g4Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/dom-serializer": {
|
"node_modules/dom-serializer": {
|
||||||
@ -747,12 +753,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dotenv": {
|
"node_modules/dotenv": {
|
||||||
"version": "16.0.3",
|
"version": "16.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.0.tgz",
|
||||||
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
|
"integrity": "sha512-tHB+hmf8MRCkT3VVivGiG8kq9HiGTmQ3FzOKgztfpJQH1IWuZTOvKSJmHNnQPowecAmkCJhLrxdPhOr06LLqIQ==",
|
||||||
"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": {
|
||||||
@ -789,9 +798,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.17.15",
|
"version": "0.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
|
||||||
"integrity": "sha512-LBUV2VsUIc/iD9ME75qhT4aJj0r75abCVS0jakhFzOtR7TQsqQA5w0tZ+KTKnwl3kXE0MhskNdHDh/I5aCR1Zw==",
|
"integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
@ -801,28 +810,28 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@esbuild/android-arm": "0.17.15",
|
"@esbuild/android-arm": "0.17.19",
|
||||||
"@esbuild/android-arm64": "0.17.15",
|
"@esbuild/android-arm64": "0.17.19",
|
||||||
"@esbuild/android-x64": "0.17.15",
|
"@esbuild/android-x64": "0.17.19",
|
||||||
"@esbuild/darwin-arm64": "0.17.15",
|
"@esbuild/darwin-arm64": "0.17.19",
|
||||||
"@esbuild/darwin-x64": "0.17.15",
|
"@esbuild/darwin-x64": "0.17.19",
|
||||||
"@esbuild/freebsd-arm64": "0.17.15",
|
"@esbuild/freebsd-arm64": "0.17.19",
|
||||||
"@esbuild/freebsd-x64": "0.17.15",
|
"@esbuild/freebsd-x64": "0.17.19",
|
||||||
"@esbuild/linux-arm": "0.17.15",
|
"@esbuild/linux-arm": "0.17.19",
|
||||||
"@esbuild/linux-arm64": "0.17.15",
|
"@esbuild/linux-arm64": "0.17.19",
|
||||||
"@esbuild/linux-ia32": "0.17.15",
|
"@esbuild/linux-ia32": "0.17.19",
|
||||||
"@esbuild/linux-loong64": "0.17.15",
|
"@esbuild/linux-loong64": "0.17.19",
|
||||||
"@esbuild/linux-mips64el": "0.17.15",
|
"@esbuild/linux-mips64el": "0.17.19",
|
||||||
"@esbuild/linux-ppc64": "0.17.15",
|
"@esbuild/linux-ppc64": "0.17.19",
|
||||||
"@esbuild/linux-riscv64": "0.17.15",
|
"@esbuild/linux-riscv64": "0.17.19",
|
||||||
"@esbuild/linux-s390x": "0.17.15",
|
"@esbuild/linux-s390x": "0.17.19",
|
||||||
"@esbuild/linux-x64": "0.17.15",
|
"@esbuild/linux-x64": "0.17.19",
|
||||||
"@esbuild/netbsd-x64": "0.17.15",
|
"@esbuild/netbsd-x64": "0.17.19",
|
||||||
"@esbuild/openbsd-x64": "0.17.15",
|
"@esbuild/openbsd-x64": "0.17.19",
|
||||||
"@esbuild/sunos-x64": "0.17.15",
|
"@esbuild/sunos-x64": "0.17.19",
|
||||||
"@esbuild/win32-arm64": "0.17.15",
|
"@esbuild/win32-arm64": "0.17.19",
|
||||||
"@esbuild/win32-ia32": "0.17.15",
|
"@esbuild/win32-ia32": "0.17.19",
|
||||||
"@esbuild/win32-x64": "0.17.15"
|
"@esbuild/win32-x64": "0.17.19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/estree-walker": {
|
"node_modules/estree-walker": {
|
||||||
@ -926,12 +935,6 @@
|
|||||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/function-bind": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/glob-parent": {
|
"node_modules/glob-parent": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
@ -950,18 +953,6 @@
|
|||||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/has": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"function-bind": "^1.1.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/has-flag": {
|
"node_modules/has-flag": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
@ -1001,18 +992,6 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-core-module": {
|
|
||||||
"version": "2.11.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
|
|
||||||
"integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"has": "^1.0.3"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/is-extglob": {
|
"node_modules/is-extglob": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
@ -1044,15 +1023,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jake": {
|
"node_modules/jake": {
|
||||||
"version": "10.8.5",
|
"version": "10.8.7",
|
||||||
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
|
||||||
"integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==",
|
"integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "^3.2.3",
|
"async": "^3.2.3",
|
||||||
"chalk": "^4.0.2",
|
"chalk": "^4.0.2",
|
||||||
"filelist": "^1.0.1",
|
"filelist": "^1.0.4",
|
||||||
"minimatch": "^3.0.4"
|
"minimatch": "^3.1.2"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"jake": "bin/cli.js"
|
"jake": "bin/cli.js"
|
||||||
@ -1122,9 +1101,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/modern-normalize": {
|
"node_modules/modern-normalize": {
|
||||||
"version": "1.1.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-2.0.0.tgz",
|
||||||
"integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA==",
|
"integrity": "sha512-CxBoEVKh5U4DH3XuNbc5ONLF6dQBc8dSc7pdZ1957FGbIO5JBqGqqchhET9dTexri8/pk9xBL6+5ceOtCIp1QA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
},
|
},
|
||||||
@ -1202,12 +1181,6 @@
|
|||||||
"tslib": "^2.0.3"
|
"tslib": "^2.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-parse": {
|
|
||||||
"version": "1.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
|
||||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/pathe": {
|
"node_modules/pathe": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/pathe/-/pathe-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/pathe/-/pathe-0.2.0.tgz",
|
||||||
@ -1233,9 +1206,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.21",
|
"version": "8.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
|
||||||
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
|
"integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1245,10 +1218,14 @@
|
|||||||
{
|
{
|
||||||
"type": "tidelift",
|
"type": "tidelift",
|
||||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.4",
|
"nanoid": "^3.3.6",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
@ -1285,23 +1262,6 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/resolve": {
|
|
||||||
"version": "1.22.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
|
||||||
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"is-core-module": "^2.9.0",
|
|
||||||
"path-parse": "^1.0.7",
|
|
||||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"resolve": "bin/resolve"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/reusify": {
|
"node_modules/reusify": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||||
@ -1313,9 +1273,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "3.20.2",
|
"version": "3.25.1",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz",
|
||||||
"integrity": "sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg==",
|
"integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
@ -1391,26 +1351,14 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/supports-preserve-symlinks-flag": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.16.8",
|
"version": "5.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.16.8.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.18.0.tgz",
|
||||||
"integrity": "sha512-QI5g1E/ef7d+PsDifb+a6nnVgC4F22Bg6T0xrBrz6iloVB4PUkkunp6V8nzoOOZJIzjWVdAGqCdlKlhLq/TbIA==",
|
"integrity": "sha512-pdL757Ig5a0I+owA42l6tIuEycRuM7FPY4n62h44mRLRfnOxJkkOHd6i89dOpwZlpF6JXBwaAHF6yWzFrt+QyA==",
|
||||||
"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"
|
||||||
},
|
},
|
||||||
@ -1440,9 +1388,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
|
||||||
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
|
"integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/universalify": {
|
"node_modules/universalify": {
|
||||||
@ -1455,15 +1403,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "4.2.1",
|
"version": "4.3.9",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
|
||||||
"integrity": "sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==",
|
"integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.17.5",
|
"esbuild": "^0.17.5",
|
||||||
"postcss": "^8.4.21",
|
"postcss": "^8.4.23",
|
||||||
"resolve": "^1.22.1",
|
"rollup": "^3.21.0"
|
||||||
"rollup": "^3.18.0"
|
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
|
@ -10,12 +10,12 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsonc-parser": "3.2.0",
|
"jsonc-parser": "3.2.0",
|
||||||
"modern-normalize": "1.1.0"
|
"modern-normalize": "2.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "18.15.11",
|
"@types/node": "20.3.1",
|
||||||
"date-and-time": "2.4.3",
|
"date-and-time": "3.0.1",
|
||||||
"vite": "4.2.1",
|
"vite": "4.3.9",
|
||||||
"vite-plugin-html": "3.2.0"
|
"vite-plugin-html": "3.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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",
|
||||||
|
@ -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",
|
||||||
|
@ -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)
|
||||||
|
10863
package-lock.json
generated
83
package.json
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "divlo",
|
"name": "theoludwig",
|
||||||
"version": "2.5.6",
|
"version": "2.11.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",
|
||||||
@ -14,17 +14,15 @@
|
|||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"build": "npm run resume:build && next build",
|
"build": "npm run resume:build && next build",
|
||||||
"export": "next export",
|
|
||||||
"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 \"**/*.{js,jsx,ts,tsx}\" --ignore-path \".gitignore\"",
|
"lint:eslint": "eslint . --ignore-path .gitignore",
|
||||||
"lint:prettier": "prettier \".\" --check --ignore-path \".gitignore\"",
|
"lint:prettier": "prettier . --check --ignore-path .gitignore",
|
||||||
"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:lighthouse": "lhci autorun",
|
"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",
|
||||||
@ -32,70 +30,71 @@
|
|||||||
"postinstall": "husky install"
|
"postinstall": "husky install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/montserrat": "4.5.14",
|
"@fontsource/montserrat": "5.0.3",
|
||||||
"@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.2.8",
|
||||||
"clsx": "1.2.1",
|
"clsx": "1.2.1",
|
||||||
"date-and-time": "2.4.3",
|
"date-and-time": "3.0.1",
|
||||||
"gray-matter": "4.0.3",
|
"gray-matter": "4.0.3",
|
||||||
"html-react-parser": "3.0.15",
|
"html-react-parser": "4.0.0",
|
||||||
"next": "13.2.4",
|
"katex": "0.16.7",
|
||||||
|
"next": "13.4.6",
|
||||||
"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.4",
|
"next-translate": "2.0.6",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"read-pkg": "7.1.0",
|
"read-pkg": "8.0.0",
|
||||||
|
"rehype-katex": "6.0.3",
|
||||||
"rehype-raw": "6.1.1",
|
"rehype-raw": "6.1.1",
|
||||||
"rehype-slug": "5.1.0",
|
"rehype-slug": "5.1.0",
|
||||||
"remark-gfm": "3.0.1",
|
"remark-gfm": "3.0.1",
|
||||||
"sharp": "0.32.0",
|
"remark-math": "5.1.1",
|
||||||
"shiki": "0.14.1",
|
"sharp": "0.32.1",
|
||||||
|
"shiki": "0.14.2",
|
||||||
"unified": "10.1.2",
|
"unified": "10.1.2",
|
||||||
"unist-util-visit": "4.1.2",
|
"unist-util-visit": "4.1.2",
|
||||||
"universal-cookie": "4.0.4"
|
"universal-cookie": "4.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "17.5.1",
|
"@commitlint/cli": "17.6.5",
|
||||||
"@commitlint/config-conventional": "17.4.4",
|
"@commitlint/config-conventional": "17.6.5",
|
||||||
"@lhci/cli": "0.11.0",
|
"@saithodev/semantic-release-backmerge": "3.2.0",
|
||||||
"@saithodev/semantic-release-backmerge": "3.1.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.0",
|
"@tsconfig/strictest": "2.0.1",
|
||||||
"@types/node": "18.15.11",
|
"@types/node": "20.3.1",
|
||||||
"@types/react": "18.0.32",
|
"@types/react": "18.2.12",
|
||||||
"@types/unist": "2.0.6",
|
"@types/unist": "2.0.6",
|
||||||
"@typescript-eslint/eslint-plugin": "5.57.0",
|
"@typescript-eslint/eslint-plugin": "5.59.11",
|
||||||
"autoprefixer": "10.4.14",
|
"autoprefixer": "10.4.14",
|
||||||
"cypress": "12.9.0",
|
"cypress": "12.14.0",
|
||||||
"editorconfig-checker": "5.0.1",
|
"editorconfig-checker": "5.0.1",
|
||||||
"eslint": "8.37.0",
|
"eslint": "8.42.0",
|
||||||
"eslint-config-conventions": "8.0.0",
|
"eslint-config-conventions": "9.0.0",
|
||||||
"eslint-config-next": "13.2.4",
|
"eslint-config-next": "13.4.6",
|
||||||
"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": "4.2.1",
|
||||||
"eslint-plugin-promise": "6.1.1",
|
"eslint-plugin-promise": "6.1.1",
|
||||||
"eslint-plugin-unicorn": "46.0.0",
|
"eslint-plugin-unicorn": "47.0.0",
|
||||||
"html-w3c-validator": "1.2.2",
|
"html-w3c-validator": "1.3.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.0",
|
"lint-staged": "13.2.2",
|
||||||
"markdownlint-cli2": "0.6.0",
|
"markdownlint-cli2": "0.8.1",
|
||||||
"markdownlint-rule-relative-links": "1.1.2",
|
"markdownlint-rule-relative-links": "1.2.0",
|
||||||
"next-translate-plugin": "2.0.4",
|
"next-translate-plugin": "2.0.5",
|
||||||
"postcss": "8.4.21",
|
"postcss": "8.4.24",
|
||||||
"prettier": "2.8.7",
|
"prettier": "2.8.8",
|
||||||
"prettier-plugin-tailwindcss": "0.2.6",
|
"prettier-plugin-tailwindcss": "0.3.0",
|
||||||
"semantic-release": "21.0.1",
|
"semantic-release": "21.0.5",
|
||||||
"start-server-and-test": "2.0.0",
|
"start-server-and-test": "2.0.0",
|
||||||
"tailwindcss": "3.3.1",
|
"tailwindcss": "3.3.2",
|
||||||
"typescript": "5.0.3",
|
"typescript": "5.0.4",
|
||||||
"vercel": "28.18.3"
|
"vercel": "30.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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')}
|
||||||
|
@ -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')}
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
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'
|
||||||
|
|
||||||
|
import 'katex/dist/katex.min.css'
|
||||||
|
|
||||||
import { Head } from 'components/Head'
|
import { Head } from 'components/Head'
|
||||||
import { Header } from 'components/Header'
|
import { Header } from 'components/Header'
|
||||||
import type { FooterProps } from 'components/Footer'
|
import type { FooterProps } from 'components/Footer'
|
||||||
@ -14,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
|
||||||
|
|
||||||
@ -22,56 +48,69 @@ 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) => {
|
||||||
|
if (props.href?.startsWith('#') ?? false) {
|
||||||
|
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} />
|
||||||
|
@ -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'>
|
||||||
|
@ -31,7 +31,7 @@ For example the [Linux kernel](https://www.kernel.org/), is one of the biggest o
|
|||||||
|
|
||||||
With a project of this magnitude, we can't let everyone do what they want and however they want, **we must set rules and conventions** to get everyone to agree, this allows to add features faster and will reduce possible bugs as **developers** will not struggle as much to understand the code.
|
With a project of this magnitude, we can't let everyone do what they want and however they want, **we must set rules and conventions** to get everyone to agree, this allows to add features faster and will reduce possible bugs as **developers** will not struggle as much to understand the code.
|
||||||
|
|
||||||
## Definition : Design Patterns
|
## Definition: Design Patterns
|
||||||
|
|
||||||
These **rules** and **conventions** are so called **Design Patterns**.
|
These **rules** and **conventions** are so called **Design Patterns**.
|
||||||
|
|
||||||
@ -77,8 +77,8 @@ setTimeout(restart, 86400000)
|
|||||||
##### Example (good way)
|
##### Example (good way)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000
|
const MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000
|
||||||
setTimeout(restart, MILLISECONDS_IN_A_DAY)
|
setTimeout(restart, MILLISECONDS_IN_ONE_DAY)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -131,7 +131,9 @@ const printCar = (car: Car): void => {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### Boolean names (Prefix: is, has, can)
|
#### Boolean names
|
||||||
|
|
||||||
|
The name of a boolean variable should be a question, and the answer should be true or false. We can use prefixes like `is`, `has`, `can` to make it more explicit and we should avoid negation.
|
||||||
|
|
||||||
##### Example (bad way)
|
##### Example (bad way)
|
||||||
|
|
||||||
@ -171,7 +173,10 @@ We have to keep it as simple as possible, not to implement features that are not
|
|||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
|
||||||
const createFile = async (name: string, isTemporary: boolean = false) => {
|
const createFile = async (
|
||||||
|
name: string,
|
||||||
|
isTemporary: boolean = false
|
||||||
|
): Promise<void> => {
|
||||||
if (isTemporary) {
|
if (isTemporary) {
|
||||||
return await fs.promises.writeFile(path.join('temporary', name), '')
|
return await fs.promises.writeFile(path.join('temporary', name), '')
|
||||||
}
|
}
|
||||||
@ -187,11 +192,11 @@ const createFile = async (name: string, isTemporary: boolean = false) => {
|
|||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
|
||||||
const createFile = async (name: string) => {
|
const createFile = async (name: string): Promise<void> => {
|
||||||
await fs.promises.writeFile(name, '')
|
await fs.promises.writeFile(name, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
const createTemporaryFile = async (name: string) => {
|
const createTemporaryFile = async (name: string): Promise<void> => {
|
||||||
await createFile(path.join('temporary', name))
|
await createFile(path.join('temporary', name))
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -210,7 +215,7 @@ The End To End (e2e) and Unit tests should document what is the behavior intende
|
|||||||
|
|
||||||
### Avoid comments
|
### Avoid comments
|
||||||
|
|
||||||
One of the most important rule of "Clean Code" : If you need to add **comments**, it's because your code is **not clean**.
|
One of the most important rule of "Clean Code": If you need to add **comments**, it's because your code is **not clean**.
|
||||||
|
|
||||||
I know that might be counter intuitive at first, as most developers will advice you to add comments to your code, to document what it does.
|
I know that might be counter intuitive at first, as most developers will advice you to add comments to your code, to document what it does.
|
||||||
|
|
||||||
|
@ -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>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
343
posts/programming-challenges.md
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
---
|
||||||
|
title: '🧠 Programming Challenges'
|
||||||
|
description: 'What are Programming Challenges and Competitive Programming and an introduction to Time/Space Complexity with Big O Notation.'
|
||||||
|
isPublished: true
|
||||||
|
publishedOn: '2023-05-21T10:20:18.837Z'
|
||||||
|
---
|
||||||
|
|
||||||
|
Hello! 👋
|
||||||
|
|
||||||
|
As **performance** and **reliability** is more and more important in software development, it is important to know how to write **efficient code**, and also learn to **not rely on every possible dependency of the world**, when it is not worth it.
|
||||||
|
|
||||||
|
The more dependencies we add to our projects, the greater the complexity and maintenance overhead becomes. Each additional dependency requires understanding its functionality, <abbr title="Application Programming Interface">API</abbr>, and potential conflicts with other dependencies. This complexity makes the codebase harder to maintain, and it also poses significant security risks.
|
||||||
|
|
||||||
|
We don't want to "reinvent the wheel" and rewrite everything from scratch for each project. In fact, you are **always depending on something** when you are writing your software. At the very least, you are dependent on the programming language you are using. Even if you are doing very low-level stuff, you are still depending on something: hardware.
|
||||||
|
|
||||||
|
However, it is important to draw a line between what dependencies are worth the cost and which are not.
|
||||||
|
|
||||||
|
Most likely adding a [JavaScript npm package `is-odd`](https://www.npmjs.com/package/is-odd) to check if a number is odd or even for example, is not worth it. Writing it ourselves is easier and allows a better maintenance in the long term.
|
||||||
|
|
||||||
|
Learning **how to solve problems** and how to write efficient code is very important and also a very broad and complicated topic, so this blog post will only be an **introduction to the subject**, and will not go in depth.
|
||||||
|
|
||||||
|
**Note:** Sources used to write this blog post are available at the [end of this post](#sources).
|
||||||
|
|
||||||
|
## What is Competitive Programming?
|
||||||
|
|
||||||
|
**Competitive programming** consists of solving correctly and efficiently **well-defined problems** by writing **computer programs** under specified **constraints**. Typically a solution to a problem is a combination of well-known techniques and new insights.
|
||||||
|
|
||||||
|
There are many famous competitions: [Google Code Jam](https://codingcompetitions.withgoogle.com/codejam), [Facebook Hacker Cup](https://www.facebook.com/codingcompetitions/hacker-cup), [International Olympiad in Informatics](https://ioinformatics.org/), [International Collegiate Programming Contest](https://icpc.global/), [LeetCode](https://leetcode.com/), [CodinGame](https://www.codingame.com/), etc.
|
||||||
|
|
||||||
|
The most common programming languages used for Competitive Programming are: **C++**, **Python** and **Java**. However the design of the algorithms and data structures are applicable to **any programming language**.
|
||||||
|
|
||||||
|
All examples solutions on this blog post will be done in **Python**.
|
||||||
|
|
||||||
|
## Topics to explore/learn with Competitive Programming
|
||||||
|
|
||||||
|
- Time/Space complexity and Big O Notation
|
||||||
|
|
||||||
|
- Sorting: Sorting algorithms and Binary search
|
||||||
|
|
||||||
|
- Data structures: Arrays (1D, 2D: Matrix, 3D, Multidimensional), Dictionaries, Linked lists, Stack, Queue, Trees, Graphs, Heaps, etc.
|
||||||
|
|
||||||
|
- Complete search: Generating Subsets, Permutations, Combinations, etc.
|
||||||
|
|
||||||
|
- Greedy algorithms: Coin problem, Scheduling, Minimizing sums, etc.
|
||||||
|
|
||||||
|
- Dynamic programming: Fibonacci, Coin problem, Knapsack, etc.
|
||||||
|
|
||||||
|
- Bit manipulation: Bit representation, Bit operations, etc.
|
||||||
|
|
||||||
|
- Shortest path: Dijkstra, Bellman-Ford, Floyd-Warshall, etc.
|
||||||
|
|
||||||
|
- String: Trie structure, String hashing, Z-algorithm, etc.
|
||||||
|
|
||||||
|
You can see there are lot of concepts to learn and explore, and it is not an exhaustive list. On this blog post, we will only see the first topic: **Time/Space complexity and Big O Notation**.
|
||||||
|
|
||||||
|
## Time/Space complexity and Big O Notation
|
||||||
|
|
||||||
|
### Definition
|
||||||
|
|
||||||
|
An Algorithm is a finite sequence of well-defined instructions, that have to be given to the computer to perform a specific task. In this context, the variation can occur the way how the instructions are defined. There can be **any number of ways**, a specific set of instructions can be defined **to perform the same task**. Also, with options available to choose any one of the available programming languages, the instructions can take any form of syntax along with the performance boundaries of the chosen programming language. We also indicated the algorithm to be performed in a computer, which leads to the next variation, in terms of the operating system, processor, hardware, etc. that are used, which can also influence the way an algorithm can be performed.
|
||||||
|
|
||||||
|
Different factors can influence the outcome of an algorithm being executed, it is wise to understand how efficiently such programs are used to perform a task. To gauge this, we require to evaluate:
|
||||||
|
|
||||||
|
- The **Space complexity** of an algorithm **quantifies** the amount of **space or memory taken** by an algorithm to run based on the size of the input.
|
||||||
|
- The **Time complexity** of an algorithm **quantifies** the amount of **time taken** by an algorithm to run based on the size of the input.
|
||||||
|
|
||||||
|
We more often talk about the **time complexity** than space complexity of an algorithm, because we can reuse memory unlike time and memory is cheap nowadays.
|
||||||
|
|
||||||
|
**Big O Notation** describes the complexity of an algorithm in terms of **how quickly it grows relative to the input size $n$ (e.g: length of the string, size of the array etc.)** by defining the $N$ number of operations that are done on it.
|
||||||
|
Example of Big O notation: $O(n^2)$.
|
||||||
|
|
||||||
|
### Time complexity
|
||||||
|
|
||||||
|
Time complexity **measures** the **time taken** **to execute each statement** of code in an algorithm. It is not going to examine the total execution time of an algorithm. Rather, it is going to give information about the variation (increase or decrease) in execution time when the number of operations (increase or decrease) in an algorithm.
|
||||||
|
|
||||||
|
There are many rules to calculate the time complexity of an algorithm.
|
||||||
|
|
||||||
|
#### Loops
|
||||||
|
|
||||||
|
A common reason why an algorithm is slow is that it contains many loops that go through the input. The more nested loops the algorithm contains, the slower it will run.
|
||||||
|
|
||||||
|
If there are $k$ nested loops, the time complexity of the algorithm will be $O(n^k)$.
|
||||||
|
|
||||||
|
##### Example $O(n)$
|
||||||
|
|
||||||
|
```python
|
||||||
|
for iteration in range(n):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# or with a while loop
|
||||||
|
iteration = 0
|
||||||
|
while iteration < n:
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Example $O(n^2)$
|
||||||
|
|
||||||
|
```python
|
||||||
|
for iteration in range(n):
|
||||||
|
for iteration2 in range(n):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Example $O(n^3)$
|
||||||
|
|
||||||
|
```python
|
||||||
|
for iteration in range(n):
|
||||||
|
for iteration2 in range(n):
|
||||||
|
for iteration3 in range(n):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
etc.
|
||||||
|
|
||||||
|
#### Order of magnitude
|
||||||
|
|
||||||
|
A time complexity does not tell us the exact number of times the code inside a loop is executed, but it only shows the **order of magnitude**.
|
||||||
|
|
||||||
|
In the following examples, the time complexity of the algorithms is $O(n)$ but the number of operations is different.
|
||||||
|
|
||||||
|
##### Example 1
|
||||||
|
|
||||||
|
```python
|
||||||
|
for iteration in range(0, n * 3, 1):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
Number of operations: $3n$
|
||||||
|
|
||||||
|
##### Example 2
|
||||||
|
|
||||||
|
```python
|
||||||
|
for iteration in range(0, n + 5, 1):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
Number of operations: $n + 5$
|
||||||
|
|
||||||
|
##### Example 3
|
||||||
|
|
||||||
|
```python
|
||||||
|
for iteration in range(0, n, 2):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
Number of operations: ${n \over 2}$
|
||||||
|
|
||||||
|
#### Phases
|
||||||
|
|
||||||
|
If the algorithms consists of consecutive phases, the total time complexity is the largest time complexity of a single phase because it is usually the bottleneck of the code.
|
||||||
|
|
||||||
|
The following code consists of 3 phases, with time complexities $O(n)$, $O(n^2)$ and $O(n)$. Thus the total time complexity is $O(n^2)$.
|
||||||
|
|
||||||
|
```python
|
||||||
|
for iteration in range(n):
|
||||||
|
pass
|
||||||
|
|
||||||
|
for iteration in range(n):
|
||||||
|
for iteration2 in range(n):
|
||||||
|
pass
|
||||||
|
|
||||||
|
for iteration in range(n):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Several variables
|
||||||
|
|
||||||
|
Sometimes the time complexity depends on several factors. In this case, the time complexity formula contains several variables: $O(nm)$.
|
||||||
|
|
||||||
|
```python
|
||||||
|
for iteration in range(n):
|
||||||
|
for iteration2 in range(m):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Recursion
|
||||||
|
|
||||||
|
The time complexity of a recursive function depends on the number of times it is called and the time complexity of a single call. The total time complexity is the product of these values.
|
||||||
|
|
||||||
|
##### Example 1
|
||||||
|
|
||||||
|
The call `recursive(n)` causes $n$ calls and the time complexity of each call is $O(1)$. Thus the total time complexity is $O(n)$.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def recursive(n: int):
|
||||||
|
if n != 1:
|
||||||
|
recursive(n - 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Example 2
|
||||||
|
|
||||||
|
```python
|
||||||
|
def recursive(n: int):
|
||||||
|
if n != 1:
|
||||||
|
recursive(n - 1)
|
||||||
|
recursive(n - 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, `recursive(n)` causes 2 other calls except for $n = 1$.
|
||||||
|
|
||||||
|
The following table shows the function calls produced by this single call:
|
||||||
|
|
||||||
|
| function call | number of calls |
|
||||||
|
| ------------- | --------------- |
|
||||||
|
| $g(n)$ | $1$ |
|
||||||
|
| $g(n - 1)$ | $2$ |
|
||||||
|
| $g(n - 2)$ | $4$ |
|
||||||
|
| ... | ... |
|
||||||
|
| $g(1)$ | $2^{n - 1}$ |
|
||||||
|
|
||||||
|
Based on this, the time complexity is:
|
||||||
|
|
||||||
|
$$
|
||||||
|
1 + 2 + 4 + ... + 2^{n - 1} = 2^n - 1 = O(2^n)
|
||||||
|
$$
|
||||||
|
|
||||||
|
#### Complexity Classes (from fastest to slowest)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Here is a list of classes of functions that are commonly encountered when analyzing the running time of an algorithm.
|
||||||
|
|
||||||
|
- $O(1)$: **Constant** (does not depend on the input size). A typical constant-time algorithm is a direct formula that calculates the answer.
|
||||||
|
|
||||||
|
- $O(\log_2(n))$: **Logarithmic** algorithm often halves the input size at each step. $\log_2(n)$ equals the number of times $n$ must be divided by 2 to get 1.
|
||||||
|
|
||||||
|
- $O(\sqrt{n})$: **Square root** algorithm is slower than $O(\log_2(n))$ but faster than $O(n)$.
|
||||||
|
|
||||||
|
- $O(n)$: **Linear** algorithm goes through the input a constant number of times. This is often the best possible time complexity, because it is usually necessary to access each input element at least once before reporting the answer.
|
||||||
|
|
||||||
|
- $O(n \log_2(n))$: **Log linear** often indicates that the algorithm sorts the input, because the time complexity of efficient sorting algorithms is $O(n \log_2(n))$. Another possibility is that the algorithm uses a data structure where each operation takes $O(\log_2(n))$ time.
|
||||||
|
|
||||||
|
- $O(n^2)$: **Quadratic** algorithm often contains 2 nested loops. It is possible to go trough all pairs of the input elements in $O(n^2)$ time.
|
||||||
|
|
||||||
|
- $O(n^3)$: **Cubic** algorithm often contains 3 nested loops. It is possible to go trough all triplets of the input elements in $O(n^3)$ time.
|
||||||
|
|
||||||
|
- $O(2^n)$: **Exponential** often indicates that the algorithm iterates through all subsets of the input elements. For example, the subsets of $\{1, 2, 3\}$ are $S = \{\{\empty\}, \{1\}, \{2\}, \{3\}, \{1, 2\}, \{1, 3\}, \{2, 3\}, \{1, 2, 3\} \}$.
|
||||||
|
|
||||||
|
- $O(n!)$: **Factorial** often indicates that the algorithm iterates through all permutations of the input elements. For example, the permutations of $\{1, 2, 3\}$ are $P = \{\{1, 2, 3\}, \{1, 3, 2\}, \{2, 1, 3\}, \{2, 3, 1\}, \{3, 1, 2\}, \{3, 2, 1\} \}$.
|
||||||
|
|
||||||
|
### Estimating efficiency
|
||||||
|
|
||||||
|
By checking the time complexity of an algorithm, it is possible to check before implementing the algorithm,that it is efficient enough for the problem.
|
||||||
|
|
||||||
|
Example: assume that the time limit for a problem is 1 second and the input size is $n = 10^5$. If the time complexity is $O(n^2)$, the algorithm will perform about $(10^5)^2 = 10^{10}$ operations.
|
||||||
|
|
||||||
|
Given that a modern computer can perform some hundred of millions of operations per second. This should take at least 10 seconds, so the algorithm seems to be too slow for solving the problem.
|
||||||
|
|
||||||
|
## Practical problem: Maximum subarray sum
|
||||||
|
|
||||||
|
There are often several possible algorithms for solving a problem such that their time complexities are different. This section discusses a classic problem that can be solved using several different algorithmic techniques, including brute force, divide and conquer, dynamic programming, and reduction to shortest paths, each technique with different time complexity.
|
||||||
|
|
||||||
|
**Maximum subarray sum**: Given an array of $n$ integers, find the contiguous subarray with the largest sum.
|
||||||
|
|
||||||
|
Contiguous subarray is any sub series of elements in a given array that are contiguous ie their indices are continuous. The problem is interesting when there may be negative values in the array, because if the array only contains positive values, the maximum subarray sum is basically the sum of the array (the subarray being the complete array).
|
||||||
|
|
||||||
|
### Example 1
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
```txt
|
||||||
|
[1, 2, 3, 4, 5, 6]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
```txt
|
||||||
|
21
|
||||||
|
```
|
||||||
|
|
||||||
|
**Explanation:** The subarray with the largest sum is the array itself (as there is no negative values) `[1, 2, 3, 4, 5, 6]` which has a sum of `21`.
|
||||||
|
|
||||||
|
### Example 2
|
||||||
|
|
||||||
|
#### Input
|
||||||
|
|
||||||
|
```txt
|
||||||
|
[-1, 2, 4, -3, 5, 2, -5, 2]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Output
|
||||||
|
|
||||||
|
```txt
|
||||||
|
10
|
||||||
|
```
|
||||||
|
|
||||||
|
**Explanation:** The subarray with the largest sum is `[2, 4, -3, 5, 2]` which has a sum of `10`.
|
||||||
|
|
||||||
|
### Worst solution: Brute force
|
||||||
|
|
||||||
|
```python
|
||||||
|
def maximum_subarray_sum_cubic(array: list[int]) -> int:
|
||||||
|
"""
|
||||||
|
Time complexity: O((array_length)^3)
|
||||||
|
|
||||||
|
We go through all possible subarrays, calculate the sum in each subarray and maintain the maximum sum.
|
||||||
|
"""
|
||||||
|
if len(array) == 0:
|
||||||
|
return 0
|
||||||
|
best_sum = array[0]
|
||||||
|
length = len(array)
|
||||||
|
for i in range(length):
|
||||||
|
for j in range(i, length):
|
||||||
|
sum = 0
|
||||||
|
for k in range(i, j + 1):
|
||||||
|
sum += array[k]
|
||||||
|
if sum > best_sum:
|
||||||
|
best_sum = sum
|
||||||
|
return best_sum
|
||||||
|
```
|
||||||
|
|
||||||
|
### Better solution: Linear time
|
||||||
|
|
||||||
|
```python
|
||||||
|
def maximum_subarray_sum_linear(array: list[int]) -> int:
|
||||||
|
"""
|
||||||
|
Time complexity: O(array_length)
|
||||||
|
|
||||||
|
We loop through the array and for each array position, we calculate the maximum sum of a subarray that ends at that position. After this, the answer for the problem is the maximum of those sums.
|
||||||
|
"""
|
||||||
|
if len(array) == 0:
|
||||||
|
return 0
|
||||||
|
best_sum = array[0]
|
||||||
|
length = len(array)
|
||||||
|
sum = 0
|
||||||
|
for i in range(length):
|
||||||
|
sum = max(array[i], sum + array[i])
|
||||||
|
best_sum = max(best_sum, sum)
|
||||||
|
return best_sum
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
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/theoludwig/programming-challenges).
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
|
||||||
|
- [Wikipedia - Competitive programming](https://en.wikipedia.org/wiki/Competitive_programming)
|
||||||
|
- [Frontend Masters - The Last Algorithms Course You'll Need](https://frontendmasters.com/courses/algorithms/)
|
||||||
|
- [Big-O Cheat Sheet](https://www.bigocheatsheet.com/)
|
||||||
|
- [programming challenges](https://github.com/theoludwig/programming-challenges)
|
@ -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.divlo.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.divlo.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.divlo.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,11 +23,11 @@ The idea is that a user can create an account to authenticate with an email addr
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
[**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.divlo.fr/) is a website that works on any recent browser, accessible on [thream.divlo.fr](https://thream.divlo.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.
|
||||||
|
|
||||||
@ -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.divlo.fr**](https://thream.divlo.fr/).
|
||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 26 KiB |
BIN
public/images/skills/ArchLinux.png
Normal file
After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
@ -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"
|
|
||||||
}
|
|
76
resume.jsonc
@ -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": [
|
||||||
{
|
{
|
||||||
@ -60,14 +60,14 @@
|
|||||||
],
|
],
|
||||||
"work": [
|
"work": [
|
||||||
{
|
{
|
||||||
"description": "interests",
|
"summary": "Développement d'un outil GED (Gestion Électronique de Documents) en React.js, Laravel et GraphQL.",
|
||||||
"summary": "Développement site web en React.js et Strapi.<br /> Classé n°1 en France sur le Défi de l'entreprise <a href=\"https://www.toolpad.fr/\">ToolPad</a>.",
|
"website": "https://numerize.com/",
|
||||||
"website": "https://www.nuitdelinfo.com/",
|
"name": "Numerize",
|
||||||
"name": "La Nuit de l'info 2021",
|
"location": "4 Rue Sophie Germain, 67720 Hœrdt",
|
||||||
"position": "Participation en équipe de 5 personnes",
|
"position": "Stagiaire Développeur Web",
|
||||||
"startDate": "2021-12-02",
|
"startDate": "2023-04-11",
|
||||||
"endDate": "2021-12-03",
|
"endDate": "2023-06-23",
|
||||||
"duration": "1 semaine"
|
"duration": "3 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.",
|
||||||
@ -79,17 +79,6 @@
|
|||||||
"endDate": "2021-07-30",
|
"endDate": "2021-07-30",
|
||||||
"duration": "1 mois"
|
"duration": "1 mois"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"description": "interests",
|
|
||||||
"summary": "Hackathon développement d'une landing page et web scraping.",
|
|
||||||
"website": "https://www.wildcodeschool.fr/",
|
|
||||||
"name": "Wild Code School",
|
|
||||||
"location": "32 Rue du Bass. d'Austerlitz, 67100 Strasbourg",
|
|
||||||
"position": "Initiation métier développeur web",
|
|
||||||
"startDate": "2019-06-24",
|
|
||||||
"endDate": "2019-06-28",
|
|
||||||
"duration": "1 semaine"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"summary": "Développement d'un site web pour trouver un restaurant à la pause repas.",
|
"summary": "Développement d'un site web pour trouver un restaurant à la pause repas.",
|
||||||
"website": "https://www.itpartners.fr/",
|
"website": "https://www.itpartners.fr/",
|
||||||
@ -101,15 +90,36 @@
|
|||||||
"duration": "1 semaine"
|
"duration": "1 semaine"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"summary": "Apprentissage du métier \"Chargé de communication\" et des logiciels de graphisme tels que \"Adobe Photoshop\".",
|
"description": "interests",
|
||||||
"website": "https://www.es.fr/",
|
"summary": "Développement site web en React.js et Strapi.<br /> Classé n°1 en France sur le Défi de l'entreprise <a href=\"https://www.toolpad.fr/\">ToolPad</a>.",
|
||||||
"name": "ÉS (Électricité de Strasbourg)",
|
"website": "https://www.nuitdelinfo.com/",
|
||||||
"location": "26 Bd du Président-Wilson, 67000 Strasbourg",
|
"name": "La Nuit de l'info 2021",
|
||||||
"position": "Stage de découverte (3ème)",
|
"position": "Participation en équipe de 5 personnes",
|
||||||
"startDate": "2018-02-19",
|
"startDate": "2021-12-02",
|
||||||
"endDate": "2018-02-23",
|
"endDate": "2021-12-03",
|
||||||
|
"duration": "1 semaine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "interests",
|
||||||
|
"summary": "Hackathon développement d'une landing page et web scraping.",
|
||||||
|
"website": "https://www.wildcodeschool.fr/",
|
||||||
|
"name": "Wild Code School",
|
||||||
|
"location": "32 Rue du Bass. d'Austerlitz, 67100 Strasbourg",
|
||||||
|
"position": "Initiation métier développeur web",
|
||||||
|
"startDate": "2019-06-24",
|
||||||
|
"endDate": "2019-06-28",
|
||||||
"duration": "1 semaine"
|
"duration": "1 semaine"
|
||||||
}
|
}
|
||||||
|
// {
|
||||||
|
// "summary": "Apprentissage du métier \"Chargé de communication\" et des logiciels de graphisme tels que \"Adobe Photoshop\".",
|
||||||
|
// "website": "https://www.es.fr/",
|
||||||
|
// "name": "ÉS (Électricité de Strasbourg)",
|
||||||
|
// "location": "26 Bd du Président-Wilson, 67000 Strasbourg",
|
||||||
|
// "position": "Stage de découverte (3ème)",
|
||||||
|
// "startDate": "2018-02-19",
|
||||||
|
// "endDate": "2018-02-23",
|
||||||
|
// "duration": "1 semaine"
|
||||||
|
// }
|
||||||
],
|
],
|
||||||
"interests": [
|
"interests": [
|
||||||
{
|
{
|
||||||
@ -126,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"
|
||||||
|
@ -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: break-word !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;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import rehypeRaw from 'rehype-raw'
|
|||||||
import { serialize } from 'next-mdx-remote/serialize'
|
import { serialize } from 'next-mdx-remote/serialize'
|
||||||
import remarkGfm from 'remark-gfm'
|
import remarkGfm from 'remark-gfm'
|
||||||
import rehypeSlug from 'rehype-slug'
|
import rehypeSlug from 'rehype-slug'
|
||||||
|
import remarkMath from 'remark-math'
|
||||||
|
import rehypeKatex from 'rehype-katex'
|
||||||
import matter from 'gray-matter'
|
import matter from 'gray-matter'
|
||||||
import { getHighlighter } from 'shiki'
|
import { getHighlighter } from 'shiki'
|
||||||
|
|
||||||
@ -45,7 +47,10 @@ export const getPosts = async (): Promise<PostMetadata[]> => {
|
|||||||
const blogPostContent = await fs.promises.readFile(blogPostPath, {
|
const blogPostContent = await fs.promises.readFile(blogPostPath, {
|
||||||
encoding: 'utf8'
|
encoding: 'utf8'
|
||||||
})
|
})
|
||||||
const { data, content } = matter(blogPostContent) as any
|
const { data, content } = matter(blogPostContent) as unknown as {
|
||||||
|
data: FrontMatter
|
||||||
|
content: string
|
||||||
|
}
|
||||||
const date = new Date(data.publishedOn)
|
const date = new Date(data.publishedOn)
|
||||||
return {
|
return {
|
||||||
slug,
|
slug,
|
||||||
@ -81,12 +86,14 @@ export const getPostBySlug = async (
|
|||||||
const source = await serialize(post.content, {
|
const source = await serialize(post.content, {
|
||||||
mdxOptions: {
|
mdxOptions: {
|
||||||
remarkPlugins: [
|
remarkPlugins: [
|
||||||
remarkGfm as any,
|
remarkGfm,
|
||||||
[remarkSyntaxHighlightingPlugin, { highlighter }]
|
[remarkSyntaxHighlightingPlugin, { highlighter }],
|
||||||
|
remarkMath
|
||||||
],
|
],
|
||||||
rehypePlugins: [
|
rehypePlugins: [
|
||||||
rehypeSlug as any,
|
rehypeSlug,
|
||||||
[rehypeRaw, { passThrough: nodeTypes }]
|
[rehypeRaw, { passThrough: nodeTypes }],
|
||||||
|
rehypeKatex
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -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
|
||||||
|