mirror of
https://github.com/theoludwig/theoludwig.git
synced 2025-05-29 22:37:44 +02:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
6abc881e94 | |||
a67d6665ea | |||
1152039663 | |||
919ebd5f3e | |||
94212f9b5c | |||
bf9347f685 | |||
896b6051e8 | |||
b5f3552c07 | |||
5fbae8601f | |||
48d35776a9 |
@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"prettier/prettier": "error",
|
"prettier/prettier": "error",
|
||||||
"unicorn/prefer-node-protocol": "off"
|
"unicorn/prefer-node-protocol": "off",
|
||||||
|
"@typescript-eslint/no-misused-promises": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
188
.github/workflows/Divlo.yml
vendored
188
.github/workflows/Divlo.yml
vendored
@ -1,188 +0,0 @@
|
|||||||
name: 'Divlo'
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [master, develop]
|
|
||||||
pull_request:
|
|
||||||
branches: [master, develop]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: ['javascript']
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v2.4.0'
|
|
||||||
|
|
||||||
- name: 'Initialize CodeQL'
|
|
||||||
uses: 'github/codeql-action/init@v1'
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
|
|
||||||
- name: 'Perform CodeQL Analysis'
|
|
||||||
uses: 'github/codeql-action/analyze@v1'
|
|
||||||
|
|
||||||
build:
|
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v2.4.0'
|
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
|
||||||
uses: 'actions/setup-node@v2.5.1'
|
|
||||||
with:
|
|
||||||
node-version: '16.x'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: 'Install'
|
|
||||||
run: 'npm install'
|
|
||||||
|
|
||||||
- name: 'Build'
|
|
||||||
run: 'npm run build'
|
|
||||||
|
|
||||||
lint:
|
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v2.4.0'
|
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
|
||||||
uses: 'actions/setup-node@v2.5.1'
|
|
||||||
with:
|
|
||||||
node-version: '16.x'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: 'Install'
|
|
||||||
run: 'npm install'
|
|
||||||
|
|
||||||
- name: 'lint:commit'
|
|
||||||
run: 'npm run lint:commit -- --to "${{ github.sha }}"'
|
|
||||||
|
|
||||||
- name: 'lint:editorconfig'
|
|
||||||
run: 'npm run lint:editorconfig'
|
|
||||||
|
|
||||||
- name: 'lint:markdown'
|
|
||||||
run: 'npm run lint:markdown'
|
|
||||||
|
|
||||||
- name: 'lint:typescript'
|
|
||||||
run: 'npm run lint:typescript'
|
|
||||||
|
|
||||||
- name: 'lint:prettier'
|
|
||||||
run: 'npm run lint:prettier'
|
|
||||||
|
|
||||||
- name: 'resume:validate'
|
|
||||||
run: 'npm run resume:validate'
|
|
||||||
|
|
||||||
- name: 'lint:dotenv'
|
|
||||||
uses: 'dotenv-linter/action-dotenv-linter@v2'
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.github_token }}
|
|
||||||
|
|
||||||
- name: 'lint:docker'
|
|
||||||
uses: 'hadolint/hadolint-action@v1.6.0'
|
|
||||||
with:
|
|
||||||
dockerfile: './Dockerfile'
|
|
||||||
|
|
||||||
test-unit:
|
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v2.4.0'
|
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
|
||||||
uses: 'actions/setup-node@v2.5.1'
|
|
||||||
with:
|
|
||||||
node-version: '16.x'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: 'Install'
|
|
||||||
run: 'npm install'
|
|
||||||
|
|
||||||
- name: 'Unit Test'
|
|
||||||
run: 'npm run test:unit'
|
|
||||||
|
|
||||||
test-lighthouse:
|
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v2.4.0'
|
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
|
||||||
uses: 'actions/setup-node@v2.5.1'
|
|
||||||
with:
|
|
||||||
node-version: '16.x'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: 'Install'
|
|
||||||
run: 'npm install'
|
|
||||||
|
|
||||||
- name: 'Build'
|
|
||||||
run: 'npm run build'
|
|
||||||
|
|
||||||
- name: 'html-w3c-validator'
|
|
||||||
run: 'npm run test:html-w3c-validator'
|
|
||||||
|
|
||||||
- name: 'Lighthouse'
|
|
||||||
run: 'npm run test:lighthouse'
|
|
||||||
env:
|
|
||||||
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
|
|
||||||
|
|
||||||
test-e2e:
|
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v2.4.0'
|
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
|
||||||
uses: 'actions/setup-node@v2.5.1'
|
|
||||||
with:
|
|
||||||
node-version: '16.x'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: 'Install'
|
|
||||||
run: 'npm install'
|
|
||||||
|
|
||||||
- name: 'Build'
|
|
||||||
run: 'npm run build'
|
|
||||||
|
|
||||||
- name: 'End To End (e2e) Test'
|
|
||||||
run: 'npm run test:e2e'
|
|
||||||
|
|
||||||
release:
|
|
||||||
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
|
||||||
needs: [analyze, build, lint, test-unit, test-lighthouse, test-e2e]
|
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
steps:
|
|
||||||
- uses: 'actions/checkout@v2.4.0'
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: 'Import GPG key'
|
|
||||||
uses: 'crazy-max/ghaction-import-gpg@v4'
|
|
||||||
with:
|
|
||||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
|
||||||
git_user_signingkey: true
|
|
||||||
git_commit_gpgsign: true
|
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
|
||||||
uses: 'actions/setup-node@v2.5.1'
|
|
||||||
with:
|
|
||||||
node-version: '16.x'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: 'Install'
|
|
||||||
run: 'npm install'
|
|
||||||
|
|
||||||
- name: 'Release'
|
|
||||||
run: 'npm run release'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
GIT_COMMITTER_NAME: ${{ secrets.GIT_NAME }}
|
|
||||||
GIT_COMMITTER_EMAIL: ${{ secrets.GIT_EMAIL }}
|
|
||||||
|
|
||||||
- name: 'Deploy to Vercel'
|
|
||||||
run: 'npm run deploy -- --token="${VERCEL_TOKEN}" --prod'
|
|
||||||
env:
|
|
||||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
|
||||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
|
||||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
|
27
.github/workflows/analyze.yml
vendored
Normal file
27
.github/workflows/analyze.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
name: 'Analyze'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [develop]
|
||||||
|
pull_request:
|
||||||
|
branches: [master, develop]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
runs-on: 'ubuntu-latest'
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: ['javascript']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: 'actions/checkout@v3.0.0'
|
||||||
|
|
||||||
|
- name: 'Initialize CodeQL'
|
||||||
|
uses: 'github/codeql-action/init@v1'
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
|
- name: 'Perform CodeQL Analysis'
|
||||||
|
uses: 'github/codeql-action/analyze@v1'
|
25
.github/workflows/build.yml
vendored
Normal file
25
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
name: 'Build'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [develop]
|
||||||
|
pull_request:
|
||||||
|
branches: [master, develop]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- uses: 'actions/checkout@v3.0.0'
|
||||||
|
|
||||||
|
- name: 'Use Node.js'
|
||||||
|
uses: 'actions/setup-node@v3.0.0'
|
||||||
|
with:
|
||||||
|
node-version: '16.x'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: 'Install'
|
||||||
|
run: 'npm install'
|
||||||
|
|
||||||
|
- name: 'Build'
|
||||||
|
run: 'npm run build'
|
47
.github/workflows/lint.yml
vendored
Normal file
47
.github/workflows/lint.yml
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
name: 'Lint'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [develop]
|
||||||
|
pull_request:
|
||||||
|
branches: [master, develop]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- uses: 'actions/checkout@v3.0.0'
|
||||||
|
|
||||||
|
- name: 'Use Node.js'
|
||||||
|
uses: 'actions/setup-node@v3.0.0'
|
||||||
|
with:
|
||||||
|
node-version: '16.x'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: 'Install'
|
||||||
|
run: 'npm install'
|
||||||
|
|
||||||
|
- name: 'lint:commit'
|
||||||
|
run: 'npm run lint:commit -- --to "${{ github.sha }}"'
|
||||||
|
|
||||||
|
- name: 'lint:editorconfig'
|
||||||
|
run: 'npm run lint:editorconfig'
|
||||||
|
|
||||||
|
- name: 'lint:markdown'
|
||||||
|
run: 'npm run lint:markdown'
|
||||||
|
|
||||||
|
- name: 'lint:typescript'
|
||||||
|
run: 'npm run lint:typescript'
|
||||||
|
|
||||||
|
- name: 'lint:prettier'
|
||||||
|
run: 'npm run lint:prettier'
|
||||||
|
|
||||||
|
- name: 'lint:dotenv'
|
||||||
|
uses: 'dotenv-linter/action-dotenv-linter@v2'
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.github_token }}
|
||||||
|
|
||||||
|
- name: 'lint:docker'
|
||||||
|
uses: 'hadolint/hadolint-action@v1.6.0'
|
||||||
|
with:
|
||||||
|
dockerfile: './Dockerfile'
|
44
.github/workflows/release.yml
vendored
Normal file
44
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
name: 'Release'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- uses: 'actions/checkout@v3.0.0'
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: 'Import GPG key'
|
||||||
|
uses: 'crazy-max/ghaction-import-gpg@v4'
|
||||||
|
with:
|
||||||
|
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
git_user_signingkey: true
|
||||||
|
git_commit_gpgsign: true
|
||||||
|
|
||||||
|
- name: 'Use Node.js'
|
||||||
|
uses: 'actions/setup-node@v3.0.0'
|
||||||
|
with:
|
||||||
|
node-version: '16.x'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: 'Install'
|
||||||
|
run: 'npm install'
|
||||||
|
|
||||||
|
- name: 'Release'
|
||||||
|
run: 'npm run release'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
GIT_COMMITTER_NAME: ${{ secrets.GIT_NAME }}
|
||||||
|
GIT_COMMITTER_EMAIL: ${{ secrets.GIT_EMAIL }}
|
||||||
|
|
||||||
|
- name: 'Deploy to Vercel'
|
||||||
|
run: 'npm run deploy -- --token="${VERCEL_TOKEN}" --prod'
|
||||||
|
env:
|
||||||
|
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||||
|
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||||
|
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
70
.github/workflows/test.yml
vendored
Normal file
70
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
name: 'Test'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [develop]
|
||||||
|
pull_request:
|
||||||
|
branches: [master, develop]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-unit:
|
||||||
|
runs-on: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- uses: 'actions/checkout@v3.0.0'
|
||||||
|
|
||||||
|
- name: 'Use Node.js'
|
||||||
|
uses: 'actions/setup-node@v3.0.0'
|
||||||
|
with:
|
||||||
|
node-version: '16.x'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: 'Install'
|
||||||
|
run: 'npm install'
|
||||||
|
|
||||||
|
- name: 'Unit Test'
|
||||||
|
run: 'npm run test:unit'
|
||||||
|
|
||||||
|
test-lighthouse:
|
||||||
|
runs-on: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- uses: 'actions/checkout@v3.0.0'
|
||||||
|
|
||||||
|
- name: 'Use Node.js'
|
||||||
|
uses: 'actions/setup-node@v3.0.0'
|
||||||
|
with:
|
||||||
|
node-version: '16.x'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: 'Install'
|
||||||
|
run: 'npm install'
|
||||||
|
|
||||||
|
- name: 'Build'
|
||||||
|
run: 'npm run build'
|
||||||
|
|
||||||
|
- name: 'html-w3c-validator'
|
||||||
|
run: 'npm run test:html-w3c-validator'
|
||||||
|
|
||||||
|
- name: 'Lighthouse'
|
||||||
|
run: 'npm run test:lighthouse'
|
||||||
|
env:
|
||||||
|
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
|
||||||
|
|
||||||
|
test-e2e:
|
||||||
|
runs-on: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- uses: 'actions/checkout@v3.0.0'
|
||||||
|
|
||||||
|
- name: 'Use Node.js'
|
||||||
|
uses: 'actions/setup-node@v3.0.0'
|
||||||
|
with:
|
||||||
|
node-version: '16.x'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: 'Install'
|
||||||
|
run: 'npm install'
|
||||||
|
|
||||||
|
- name: 'Build'
|
||||||
|
run: 'npm run build'
|
||||||
|
|
||||||
|
- name: 'End To End (e2e) Test'
|
||||||
|
run: 'npm run test:e2e'
|
@ -3,5 +3,6 @@
|
|||||||
"http://localhost:3000/",
|
"http://localhost:3000/",
|
||||||
"http://localhost:3000/blog",
|
"http://localhost:3000/blog",
|
||||||
"http://localhost:3000/blog/hello-world"
|
"http://localhost:3000/blog/hello-world"
|
||||||
]
|
],
|
||||||
|
"files": ["./public/curriculum-vitae.html"]
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
[
|
[
|
||||||
"@saithodev/semantic-release-backmerge",
|
"@saithodev/semantic-release-backmerge",
|
||||||
{
|
{
|
||||||
|
"branches": [{ "from": "master", "to": "develop" }],
|
||||||
"backmergeStrategy": "merge"
|
"backmergeStrategy": "merge"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/Divlo/Divlo/actions/workflows/Divlo.yml"><img src="https://github.com/Divlo/Divlo/actions/workflows/Divlo.yml/badge.svg?branch=master" alt="Divlo's CI" /></a>
|
|
||||||
<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/Divlo"><img alt="GitHub" src="https://img.shields.io/badge/-GitHub-5A5A5A?style=flat&labelColor=5A5A5A&logo=github&logoColor=white"/></a>
|
||||||
<a href="https://gitlab.com/Divlo"><img alt="GitLab" src="https://img.shields.io/badge/-GitLab-303030?style=flat&labelColor=303030&logo=gitlab&logoColor=white"/></a>
|
<a href="https://gitlab.com/Divlo"><img alt="GitLab" src="https://img.shields.io/badge/-GitLab-303030?style=flat&labelColor=303030&logo=gitlab&logoColor=white"/></a>
|
||||||
<a href="https://www.npmjs.com/~divlo"><img alt="npm" src="https://img.shields.io/badge/-npm-c4302b?style=flat&labelColor=c4302b&logo=npm&logoColor=white"/></a>
|
<a href="https://www.npmjs.com/~divlo"><img alt="npm" src="https://img.shields.io/badge/-npm-c4302b?style=flat&labelColor=c4302b&logo=npm&logoColor=white"/></a>
|
||||||
|
@ -10,7 +10,7 @@ interface HeadProps {
|
|||||||
export const Head: React.FC<HeadProps> = (props) => {
|
export const Head: React.FC<HeadProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
title = 'Divlo',
|
title = 'Divlo',
|
||||||
image = '/images/icons/icon-96x96.png',
|
image = 'https://divlo.fr/images/icons/icon-96x96.png',
|
||||||
description,
|
description,
|
||||||
url = 'https://divlo.fr/'
|
url = 'https://divlo.fr/'
|
||||||
} = props
|
} = props
|
||||||
@ -39,7 +39,7 @@ export const Head: React.FC<HeadProps> = (props) => {
|
|||||||
<meta name='twitter:card' content='summary' />
|
<meta name='twitter:card' content='summary' />
|
||||||
<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:src' content={image} />
|
<meta name='twitter:image' content={image} />
|
||||||
|
|
||||||
{/* Google Verification */}
|
{/* Google Verification */}
|
||||||
<meta
|
<meta
|
||||||
|
@ -12,7 +12,7 @@ export const InterestItem: React.FC<InterestItemProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<li className='interest-item my-2 mx-2 h-8 w-8' title={title}>
|
<li className='interest-item my-2 mx-2 h-8 w-8' title={title}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
className='block h-full w-full cursor-pointer text-yellow dark:text-yellow-dark'
|
className='block h-full w-full text-yellow dark:text-yellow-dark'
|
||||||
icon={fontAwesomeIcon}
|
icon={fontAwesomeIcon}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
@ -11,7 +11,7 @@ export const ProfileDescriptionBottom: React.FC = () => {
|
|||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<a
|
<a
|
||||||
href='/curriculum-vitae.html'
|
href='/curriculum-vitae'
|
||||||
className='text-yellow hover:underline dark:text-yellow-dark'
|
className='text-yellow hover:underline dark:text-yellow-dark'
|
||||||
>
|
>
|
||||||
Curriculum vitæ
|
Curriculum vitæ
|
||||||
|
@ -1,14 +1,30 @@
|
|||||||
import useTranslation from 'next-translate/useTranslation'
|
import useTranslation from 'next-translate/useTranslation'
|
||||||
|
|
||||||
|
import {
|
||||||
|
DIVLO_BIRTHDAY_DAY,
|
||||||
|
DIVLO_BIRTHDAY_MONTH,
|
||||||
|
DIVLO_BIRTHDAY_YEAR
|
||||||
|
} from 'utils/getAge'
|
||||||
|
|
||||||
import { ProfileItem } from './ProfileItem'
|
import { ProfileItem } from './ProfileItem'
|
||||||
|
|
||||||
export const ProfileList: React.FC = () => {
|
export interface ProfileListProps {
|
||||||
|
age: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProfileList: React.FC<ProfileListProps> = (props) => {
|
||||||
|
const { age } = props
|
||||||
const { t } = useTranslation('home')
|
const { t } = useTranslation('home')
|
||||||
|
|
||||||
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.full-name')} value='Théo LUDWIG' />
|
||||||
<ProfileItem title={t('home:about.birth-date')} value='31/03/2003' />
|
<ProfileItem
|
||||||
|
title={t('home:about.birth-date')}
|
||||||
|
value={`${DIVLO_BIRTHDAY_DAY}/${DIVLO_BIRTHDAY_MONTH}/${DIVLO_BIRTHDAY_YEAR} (${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'
|
||||||
|
@ -3,13 +3,19 @@ import { ProfileInformation } from './ProfileInfo'
|
|||||||
import { ProfileList } from './ProfileList'
|
import { ProfileList } from './ProfileList'
|
||||||
import { ProfileLogo } from './ProfileLogo'
|
import { ProfileLogo } from './ProfileLogo'
|
||||||
|
|
||||||
export const Profile: React.FC = () => {
|
export interface ProfileProps {
|
||||||
|
age: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Profile: React.FC<ProfileProps> = (props) => {
|
||||||
|
const { age } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col items-center justify-center px-10 pt-2 md:flex-row md:pt-10'>
|
<div className='flex flex-col items-center justify-center px-10 pt-2 md:flex-row md:pt-10'>
|
||||||
<ProfileLogo />
|
<ProfileLogo />
|
||||||
<div>
|
<div>
|
||||||
<ProfileInformation />
|
<ProfileInformation />
|
||||||
<ProfileList />
|
<ProfileList age={age} />
|
||||||
<ProfileDescriptionBottom />
|
<ProfileDescriptionBottom />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
const path = require('path')
|
import fs from 'fs'
|
||||||
const fs = require('fs')
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
const ejs = require('ejs')
|
import ejs from 'ejs'
|
||||||
const date = require('date-and-time')
|
import date from 'date-and-time'
|
||||||
const { Parcel } = require('@parcel/core')
|
import { Parcel } from '@parcel/core'
|
||||||
|
|
||||||
const render = async (resume) => {
|
export const render = async (resume) => {
|
||||||
const themeIndexPath = path.join(__dirname, 'theme', 'index.ejs')
|
const themeIndexURL = new URL('./theme/index.ejs', import.meta.url)
|
||||||
const themeBuildPath = path.join(__dirname, 'theme', 'index.html')
|
const themeBuildURL = new URL('./theme/index.html', import.meta.url)
|
||||||
const indexHTMLPath = path.join(__dirname, 'dist', 'index.html')
|
const indexHTMLURL = new URL('./dist/index.html', import.meta.url)
|
||||||
const html = await ejs.renderFile(themeIndexPath, {
|
const themeBuildPath = fileURLToPath(themeBuildURL)
|
||||||
|
const html = await ejs.renderFile(fileURLToPath(themeIndexURL), {
|
||||||
date,
|
date,
|
||||||
locals: {
|
locals: {
|
||||||
...resume
|
...resume
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
await fs.promises.writeFile(themeBuildURL, html, { encoding: 'utf-8' })
|
||||||
await fs.promises.writeFile(themeBuildPath, html, { encoding: 'utf-8' })
|
|
||||||
const bundler = new Parcel({
|
const bundler = new Parcel({
|
||||||
entries: themeBuildPath,
|
entries: themeBuildPath,
|
||||||
source: themeBuildPath,
|
source: themeBuildPath,
|
||||||
@ -24,9 +24,5 @@ const render = async (resume) => {
|
|||||||
defaultConfig: '@parcel/config-default'
|
defaultConfig: '@parcel/config-default'
|
||||||
})
|
})
|
||||||
await bundler.run()
|
await bundler.run()
|
||||||
return await fs.promises.readFile(indexHTMLPath, { encoding: 'utf-8' })
|
return await fs.promises.readFile(indexHTMLURL, { encoding: 'utf-8' })
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
render
|
|
||||||
}
|
}
|
||||||
|
3099
jsonresume-theme-custom/package-lock.json
generated
3099
jsonresume-theme-custom/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,17 +2,18 @@
|
|||||||
"name": "jsonresume-theme-custom",
|
"name": "jsonresume-theme-custom",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
"scripts": {},
|
"scripts": {},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"date-and-time": "2.1.2",
|
"date-and-time": "2.3.0",
|
||||||
"ejs": "3.1.6",
|
"ejs": "3.1.6",
|
||||||
"modern-normalize": "1.1.0"
|
"modern-normalize": "1.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@parcel/config-default": "2.3.2",
|
"@parcel/config-default": "2.4.0",
|
||||||
"@parcel/core": "2.3.2",
|
"@parcel/core": "2.4.0",
|
||||||
"@parcel/optimizer-data-url": "^2.3.2",
|
"@parcel/optimizer-data-url": "2.4.0",
|
||||||
"@parcel/transformer-inline-string": "^2.3.2",
|
"@parcel/transformer-inline-string": "2.4.0",
|
||||||
"parcel": "2.3.2"
|
"parcel": "2.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
jsonresume-theme-custom/scripts/build.js
Normal file
18
jsonresume-theme-custom/scripts/build.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import fs from 'fs'
|
||||||
|
|
||||||
|
import { render } from '../index.js'
|
||||||
|
|
||||||
|
const jsonResumeURL = new URL('../../resume.json', import.meta.url)
|
||||||
|
const publicResumeURL = new URL(
|
||||||
|
'../../public/curriculum-vitae.html',
|
||||||
|
import.meta.url
|
||||||
|
)
|
||||||
|
|
||||||
|
const dataResumeStringJSON = await fs.promises.readFile(jsonResumeURL, {
|
||||||
|
encoding: 'utf-8'
|
||||||
|
})
|
||||||
|
const dataResumeJSON = JSON.parse(dataResumeStringJSON)
|
||||||
|
const dataResumeIndexHTML = await render(dataResumeJSON)
|
||||||
|
await fs.promises.writeFile(publicResumeURL, dataResumeIndexHTML, {
|
||||||
|
encoding: 'utf-8'
|
||||||
|
})
|
@ -87,7 +87,7 @@
|
|||||||
<li class="card card-nested clearfix">
|
<li class="card card-nested clearfix">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p class="clear-margin relative">
|
<p class="clear-margin relative">
|
||||||
<a href="<%= experience.url %>">
|
<a href="<%= experience.website %>">
|
||||||
<strong><%= experience.name %></strong>
|
<strong><%= experience.name %></strong>
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"description": "Developer Full Stack Junior • Passionate about High-Tech",
|
"description": "Developer Full Stack Junior • Passionate about High-Tech",
|
||||||
"full-name": "Full name",
|
"full-name": "Full name",
|
||||||
"birth-date": "Birth date",
|
"birth-date": "Birth date",
|
||||||
|
"years-old": "years old",
|
||||||
"nationality": "Nationality",
|
"nationality": "Nationality",
|
||||||
"description-bottom": "I am self-taught in Computer Science by following online trainings and I am also a student at the university following the French training \"BUT Informatique\" (first year)."
|
"description-bottom": "I am self-taught in Computer Science by following online trainings and I am also a student at the university following the French training \"BUT Informatique\" (first year)."
|
||||||
},
|
},
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"description": "Développeur Full Stack Junior • Passionné de High-Tech",
|
"description": "Développeur Full Stack Junior • Passionné de High-Tech",
|
||||||
"full-name": "Prénom NOM",
|
"full-name": "Prénom NOM",
|
||||||
"birth-date": "Date de naissance",
|
"birth-date": "Date de naissance",
|
||||||
|
"years-old": "ans",
|
||||||
"nationality": "Nationalité",
|
"nationality": "Nationalité",
|
||||||
"description-bottom": "Je me forme en autodidacte dans l'informatique en suivant des formations en ligne et je suis aussi un étudiant à l'université suivant la formation \"BUT Informatique\" (première année)."
|
"description-bottom": "Je me forme en autodidacte dans l'informatique en suivant des formations en ligne et je suis aussi un étudiant à l'université suivant la formation \"BUT Informatique\" (première année)."
|
||||||
},
|
},
|
||||||
|
13816
package-lock.json
generated
13816
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
72
package.json
72
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "divlo",
|
"name": "divlo",
|
||||||
"version": "2.0.0",
|
"version": "2.2.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -13,7 +13,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"build": "npm run resume:export && next build",
|
"build": "npm run resume:build && next build",
|
||||||
"export": "next export",
|
"export": "next export",
|
||||||
"lint:commit": "commitlint",
|
"lint:commit": "commitlint",
|
||||||
"lint:editorconfig": "editorconfig-checker",
|
"lint:editorconfig": "editorconfig-checker",
|
||||||
@ -26,81 +26,77 @@
|
|||||||
"test:lighthouse": "lhci autorun",
|
"test:lighthouse": "lhci autorun",
|
||||||
"test:e2e": "start-server-and-test \"start\" \"http://localhost:3000\" \"cypress run\"",
|
"test:e2e": "start-server-and-test \"start\" \"http://localhost:3000\" \"cypress run\"",
|
||||||
"test:e2e:dev": "start-server-and-test \"dev\" \"http://localhost:3000\" \"cypress open\"",
|
"test:e2e:dev": "start-server-and-test \"dev\" \"http://localhost:3000\" \"cypress open\"",
|
||||||
"resume:validate": "resume validate",
|
"resume:build": "node ./jsonresume-theme-custom/scripts/build.js",
|
||||||
"resume:serve": "resume serve --theme \"custom\"",
|
|
||||||
"resume:export": "resume export \"./public/curriculum-vitae.html\" --format \"html\" --theme \"custom\"",
|
|
||||||
"release": "semantic-release",
|
"release": "semantic-release",
|
||||||
"deploy": "vercel",
|
"deploy": "vercel",
|
||||||
"postinstall": "husky install"
|
"postinstall": "husky install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/montserrat": "4.5.5",
|
"@fontsource/montserrat": "4.5.7",
|
||||||
"@fortawesome/fontawesome-svg-core": "1.3.0",
|
"@fortawesome/fontawesome-svg-core": "6.1.1",
|
||||||
"@fortawesome/free-brands-svg-icons": "6.0.0",
|
"@fortawesome/free-brands-svg-icons": "6.1.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "6.0.0",
|
"@fortawesome/free-solid-svg-icons": "6.1.1",
|
||||||
"@fortawesome/react-fontawesome": "0.1.17",
|
"@fortawesome/react-fontawesome": "0.1.18",
|
||||||
"classnames": "2.3.1",
|
"classnames": "2.3.1",
|
||||||
"date-and-time": "2.1.2",
|
"date-and-time": "2.3.0",
|
||||||
"gray-matter": "4.0.3",
|
"gray-matter": "4.0.3",
|
||||||
"html-react-parser": "1.4.8",
|
"html-react-parser": "1.4.9",
|
||||||
"next": "12.1.0",
|
"next": "12.1.0",
|
||||||
"next-mdx-remote": "4.0.0",
|
"next-mdx-remote": "4.0.0",
|
||||||
"next-pwa": "5.4.4",
|
"next-pwa": "5.4.6",
|
||||||
"next-themes": "0.1.1",
|
"next-themes": "0.1.1",
|
||||||
"next-translate": "1.3.4",
|
"next-translate": "1.3.5",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
"read-pkg": "7.1.0",
|
"read-pkg": "7.1.0",
|
||||||
"rehype-raw": "6.1.1",
|
"rehype-raw": "6.1.1",
|
||||||
"rehype-slug": "5.0.1",
|
"rehype-slug": "5.0.1",
|
||||||
"remark-gfm": "3.0.1",
|
"remark-gfm": "3.0.1",
|
||||||
"sharp": "0.30.1",
|
"sharp": "0.30.3",
|
||||||
"shiki": "0.10.1",
|
"shiki": "0.10.1",
|
||||||
"unified": "10.1.1",
|
"unified": "10.1.2",
|
||||||
"unist-util-visit": "4.1.0",
|
"unist-util-visit": "4.1.0",
|
||||||
"universal-cookie": "4.0.4"
|
"universal-cookie": "4.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "16.2.1",
|
"@commitlint/cli": "16.2.3",
|
||||||
"@commitlint/config-conventional": "16.2.1",
|
"@commitlint/config-conventional": "16.2.1",
|
||||||
"@lhci/cli": "0.9.0",
|
"@lhci/cli": "0.9.0",
|
||||||
"@saithodev/semantic-release-backmerge": "2.1.1",
|
"@saithodev/semantic-release-backmerge": "2.1.2",
|
||||||
"@semantic-release/git": "10.0.1",
|
"@semantic-release/git": "10.0.1",
|
||||||
"@tailwindcss/typography": "0.5.2",
|
"@tailwindcss/typography": "0.5.2",
|
||||||
"@testing-library/jest-dom": "5.16.2",
|
"@testing-library/jest-dom": "5.16.2",
|
||||||
"@testing-library/react": "12.1.3",
|
"@testing-library/react": "12.1.4",
|
||||||
"@types/date-and-time": "0.13.0",
|
"@types/jest": "27.4.1",
|
||||||
"@types/jest": "27.4.0",
|
"@types/node": "17.0.23",
|
||||||
"@types/node": "17.0.19",
|
"@types/react": "17.0.42",
|
||||||
"@types/react": "17.0.39",
|
|
||||||
"@types/unist": "2.0.6",
|
"@types/unist": "2.0.6",
|
||||||
"@typescript-eslint/eslint-plugin": "5.12.1",
|
"@typescript-eslint/eslint-plugin": "5.16.0",
|
||||||
"autoprefixer": "10.4.2",
|
"autoprefixer": "10.4.4",
|
||||||
"cypress": "9.5.0",
|
"cypress": "9.5.2",
|
||||||
"editorconfig-checker": "4.0.2",
|
"editorconfig-checker": "4.0.2",
|
||||||
"eslint": "8.9.0",
|
"eslint": "8.11.0",
|
||||||
"eslint-config-conventions": "1.1.0",
|
"eslint-config-conventions": "1.1.2",
|
||||||
"eslint-config-next": "12.1.0",
|
"eslint-config-next": "12.1.0",
|
||||||
"eslint-config-prettier": "8.4.0",
|
"eslint-config-prettier": "8.5.0",
|
||||||
"eslint-plugin-import": "2.25.4",
|
"eslint-plugin-import": "2.25.4",
|
||||||
"eslint-plugin-prettier": "4.0.0",
|
"eslint-plugin-prettier": "4.0.0",
|
||||||
"eslint-plugin-promise": "6.0.0",
|
"eslint-plugin-promise": "6.0.0",
|
||||||
"eslint-plugin-unicorn": "41.0.0",
|
"eslint-plugin-unicorn": "41.0.1",
|
||||||
"html-w3c-validator": "1.0.0",
|
"html-w3c-validator": "1.1.0",
|
||||||
"husky": "7.0.4",
|
"husky": "7.0.4",
|
||||||
"jest": "27.5.1",
|
"jest": "27.5.1",
|
||||||
"jsonresume-theme-custom": "file:./jsonresume-theme-custom",
|
"jsonresume-theme-custom": "file:./jsonresume-theme-custom",
|
||||||
"lint-staged": "12.3.4",
|
"lint-staged": "12.3.7",
|
||||||
"markdownlint-cli": "0.31.1",
|
"markdownlint-cli": "0.31.1",
|
||||||
"next-secure-headers": "2.2.0",
|
"next-secure-headers": "2.2.0",
|
||||||
"postcss": "8.4.6",
|
"postcss": "8.4.12",
|
||||||
"prettier": "2.5.1",
|
"prettier": "2.6.0",
|
||||||
"prettier-plugin-tailwindcss": "0.1.7",
|
"prettier-plugin-tailwindcss": "0.1.8",
|
||||||
"resume-cli": "3.0.6",
|
|
||||||
"semantic-release": "19.0.2",
|
"semantic-release": "19.0.2",
|
||||||
"start-server-and-test": "1.14.0",
|
"start-server-and-test": "1.14.0",
|
||||||
"tailwindcss": "3.0.23",
|
"tailwindcss": "3.0.23",
|
||||||
"typescript": "4.4.4",
|
"typescript": "4.6.2",
|
||||||
"vercel": "24.0.0"
|
"vercel": "24.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import { Head } from 'components/Head'
|
|||||||
import { Header } from 'components/Header'
|
import { Header } from 'components/Header'
|
||||||
import { Footer, FooterProps } from 'components/Footer'
|
import { Footer, FooterProps } from 'components/Footer'
|
||||||
import { getDefaultDescription } from 'utils/getDefaultDescription'
|
import { getDefaultDescription } from 'utils/getDefaultDescription'
|
||||||
|
import { DIVLO_BIRTHDAY, getAge } from 'utils/getAge'
|
||||||
|
|
||||||
interface Error404Props extends FooterProps {
|
interface Error404Props extends FooterProps {
|
||||||
description: string
|
description: string
|
||||||
@ -31,7 +32,8 @@ const Error404: NextPage<Error404Props> = (props) => {
|
|||||||
export const getStaticProps: GetStaticProps<FooterProps> = async () => {
|
export const getStaticProps: GetStaticProps<FooterProps> = async () => {
|
||||||
const { readPackage } = await import('read-pkg')
|
const { readPackage } = await import('read-pkg')
|
||||||
const { version } = await readPackage()
|
const { version } = await readPackage()
|
||||||
const description = getDefaultDescription()
|
const age = getAge(DIVLO_BIRTHDAY)
|
||||||
|
const description = getDefaultDescription(age)
|
||||||
return { props: { version, description } }
|
return { props: { version, description } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import { Head } from 'components/Head'
|
|||||||
import { Header } from 'components/Header'
|
import { Header } from 'components/Header'
|
||||||
import { Footer, FooterProps } from 'components/Footer'
|
import { Footer, FooterProps } from 'components/Footer'
|
||||||
import { getDefaultDescription } from 'utils/getDefaultDescription'
|
import { getDefaultDescription } from 'utils/getDefaultDescription'
|
||||||
|
import { DIVLO_BIRTHDAY, getAge } from 'utils/getAge'
|
||||||
|
|
||||||
interface Error500Props extends FooterProps {
|
interface Error500Props extends FooterProps {
|
||||||
description: string
|
description: string
|
||||||
@ -31,7 +32,8 @@ const Error500: NextPage<Error500Props> = (props) => {
|
|||||||
export const getStaticProps: GetStaticProps<FooterProps> = async () => {
|
export const getStaticProps: GetStaticProps<FooterProps> = async () => {
|
||||||
const { readPackage } = await import('read-pkg')
|
const { readPackage } = await import('read-pkg')
|
||||||
const { version } = await readPackage()
|
const { version } = await readPackage()
|
||||||
const description = getDefaultDescription()
|
const age = getAge(DIVLO_BIRTHDAY)
|
||||||
|
const description = getDefaultDescription(age)
|
||||||
return { props: { version, description } }
|
return { props: { version, description } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,14 +13,16 @@ import { OpenSource } from 'components/OpenSource'
|
|||||||
import { Header } from 'components/Header'
|
import { Header } from 'components/Header'
|
||||||
import { Footer, FooterProps } from 'components/Footer'
|
import { Footer, FooterProps } from 'components/Footer'
|
||||||
import { getDefaultDescription } from 'utils/getDefaultDescription'
|
import { getDefaultDescription } from 'utils/getDefaultDescription'
|
||||||
|
import { DIVLO_BIRTHDAY, getAge } from 'utils/getAge'
|
||||||
|
|
||||||
interface HomeProps extends FooterProps {
|
interface HomeProps extends FooterProps {
|
||||||
description: string
|
description: string
|
||||||
|
age: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const Home: NextPage<HomeProps> = (props) => {
|
const Home: NextPage<HomeProps> = (props) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { version, description } = props
|
const { version, description, age } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -29,7 +31,7 @@ const Home: NextPage<HomeProps> = (props) => {
|
|||||||
<Header showLanguage />
|
<Header showLanguage />
|
||||||
<main className='flex flex-col md:mx-auto md:max-w-4xl lg:max-w-7xl'>
|
<main className='flex flex-col md:mx-auto md:max-w-4xl lg:max-w-7xl'>
|
||||||
<Section isMain id='about'>
|
<Section isMain id='about'>
|
||||||
<Profile />
|
<Profile age={age} />
|
||||||
<SocialMediaList />
|
<SocialMediaList />
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
@ -74,11 +76,12 @@ const Home: NextPage<HomeProps> = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getStaticProps: GetStaticProps<FooterProps> = async () => {
|
export const getStaticProps: GetStaticProps<HomeProps> = async () => {
|
||||||
const { readPackage } = await import('read-pkg')
|
const { readPackage } = await import('read-pkg')
|
||||||
const { version } = await readPackage()
|
const { version } = await readPackage()
|
||||||
const description = getDefaultDescription()
|
const age = getAge(DIVLO_BIRTHDAY)
|
||||||
return { props: { version, description } }
|
const description = getDefaultDescription(age)
|
||||||
|
return { props: { version, description, age } }
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Home
|
export default Home
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: '🧼 Clean Code'
|
title: '🧼 Clean Code'
|
||||||
description: 'What is "Clean Code", what are "Design Patterns", and why is it so important today ? Tips and tricks to make your code more readable and maintainable in the long term.'
|
description: 'What is "Clean Code", what are "Design Patterns", and why is it so important today? Tips and tricks to make your code more readable and maintainable in the long term.'
|
||||||
isPublished: true
|
isPublished: true
|
||||||
publishedOn: '2022-02-23T08:00:18.758Z'
|
publishedOn: '2022-02-23T08:00:18.758Z'
|
||||||
---
|
---
|
||||||
@ -29,7 +29,7 @@ Code like that works great, but it is not enough, even if the code will be read
|
|||||||
|
|
||||||
For example the [Linux kernel](https://www.kernel.org/), is one of the biggest open source project with many contributors worldwide. Last data shows that it is about **20 millions** lines of code.
|
For example the [Linux kernel](https://www.kernel.org/), is one of the biggest open source project with many contributors worldwide. Last data shows that it is about **20 millions** lines of code.
|
||||||
|
|
||||||
With a project of this magnitude, we can't let everyone do what they wants and however they wants, **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
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ function getUser(): User
|
|||||||
##### Example (bad way)
|
##### Example (bad way)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// What does 86400000 mean ?
|
// What does 86400000 mean?
|
||||||
setTimeout(restart, 86400000)
|
setTimeout(restart, 86400000)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ I decided to keep things simple, here are the 2 main features missing on my blog
|
|||||||
- Comments (you can interact with me on my Twitter account)
|
- Comments (you can interact with me on my Twitter account)
|
||||||
- Views counter
|
- Views counter
|
||||||
|
|
||||||
That not mean that theses features will never be implemented, but to avoid the need of a database now, I dropped out theses features.
|
That not mean that these features will never be implemented, but to avoid the need of a database now, I dropped out these features.
|
||||||
|
|
||||||
### Technologies
|
### Technologies
|
||||||
|
|
||||||
|
@ -1,44 +1,66 @@
|
|||||||
---
|
---
|
||||||
title: '❌ Mistakes I made as a junior developer'
|
title: '❌ Mistakes I made as a junior developer'
|
||||||
description: 'Here are mistakes I made when I started, to prevent you from making the same mistakes.'
|
description: 'Here are mistakes I made when I started, to prevent you from making the same mistakes.'
|
||||||
isPublished: false
|
isPublished: true
|
||||||
publishedOn: '2021-12-06T22:06:33.818Z'
|
publishedOn: '2022-03-14T07:42:52.989Z'
|
||||||
---
|
---
|
||||||
|
|
||||||
Hello! 👋
|
Hello! 👋
|
||||||
|
|
||||||
I will explain some of my mistakes I made as a junior developer, so you can avoid doing them.
|
I will explain some of the mistakes I made as a junior developer, so you can avoid doing them.
|
||||||
|
|
||||||
## 1. Skipped learning how to do automated tests
|
## 1. Skipped learning how to do automated tests
|
||||||
|
|
||||||
Probably one of the most common error junior developers do.
|
Probably one of the most common errors junior developers does.
|
||||||
|
|
||||||
When you begin in programming, you learn a programming language, so you learn variables, conditions, loops, functions, etc.
|
When you begin in programming, you learn a programming language, so you learn variables, conditions, loops, functions, etc.
|
||||||
|
|
||||||
With these concepts, you might start a new project, thinking that you will be able to do everything.
|
With these concepts, you might start a new project, but as the project grows, you will end up using functions at multiple places in code, so if you change the behavior of a function, it will affect the whole project.
|
||||||
|
|
||||||
But as the project grows, you will end up using functions at multiple places in code, so if you change the behavior of a function, it will affect the whole project.
|
And because the code grows, you might do some refactoring to make it more maintainable, but because we are humans, we make mistakes, you could accidentally break the entire project even with a tiny change you thought was safe to do.
|
||||||
|
|
||||||
And because the code grows, you might do some refactoring, but because we are humans, we make mistakes, you could accidentally break the whole project even with a tiny change you thought was safe to do.
|
If you had automated tests, you would have a way to know if you made a mistake even before deploying to production.
|
||||||
|
|
||||||
If you would have automated tests, you would have a way to know if you made a mistake even before deploying to production.
|
|
||||||
|
|
||||||
Depending on the programming language you are using, and what is the project you are working on, writing tests will be different.
|
Depending on the programming language you are using, and what is the project you are working on, writing tests will be different.
|
||||||
|
|
||||||
Be aware that there are 3 main testing strategy:
|
Be aware that there are 3 main testing strategies:
|
||||||
|
|
||||||
- [Unit testing](https://en.wikipedia.org/wiki/Unit_testing)
|
- [Unit testing](https://en.wikipedia.org/wiki/Unit_testing)
|
||||||
- [Integration testing](https://en.wikipedia.org/wiki/Integration_testing)
|
- [Integration testing](https://en.wikipedia.org/wiki/Integration_testing)
|
||||||
- [End-to-end testing](https://en.wikipedia.org/wiki/End-to-end_testing)
|
- [End-to-end testing](https://en.wikipedia.org/wiki/End-to-end_testing)
|
||||||
|
|
||||||
After you learnt the basic of programming, learn how to write automated tests, it will save you a lot of time and debugging.
|
After you learned the basics of programming, learn how to write automated tests, it will save you a lot of time and debugging.
|
||||||
|
|
||||||
|
I would even say that you should get used-to writing tests, it should be an automatism, you should not even have to think about it to do it.
|
||||||
|
|
||||||
## 2. Thinking too big, with too much abstraction
|
## 2. Thinking too big, with too much abstraction
|
||||||
|
|
||||||
Abstraction is great, but it can be harder to understand what is going on if actally don't need this abstraction.
|
Abstraction is great, but it can be harder to understand what is going on if actually don't need this abstraction.
|
||||||
|
|
||||||
Find the right balance, between abstraction and implementation, start simple, and then gradually improve and add more features.
|
Find the right balance, between abstraction and simple implementation, start simple, and then gradually improve and add more features.
|
||||||
|
|
||||||
When you start a new project, you should focus on the core of the project, not on the details, to release as soon as possible, a working usable version of your project also called a [**Minimum Viable Product** (MVP)](https://en.wikipedia.org/wiki/Minimum_viable_product).
|
When you start a new project, you should focus on the core of the project, not on the details, to release as soon as possible, a working usable version of your project also called a [**Minimum Viable Product** (MVP)](https://en.wikipedia.org/wiki/Minimum_viable_product), it is better than a half-functioning, over-engineered project.
|
||||||
|
|
||||||
## 3. Focusing on the thing that don't add value to a project
|
I made this mistake while developing [Thream](https://thream.divlo.fr), your **open source** platform to stay close with your friends and communities, **talk**, chat, **collaborate**, share and **have fun**.
|
||||||
|
|
||||||
|
Basically, I thought it was cool, to do a "big" v1.0.0 release with a lot of features, but in fact, it was not, because I could not even show what I was developing (to the end-users, not technical people) as I was making multiple features at the same time and also mainly focused on the **REST API** side and not at all the **website (frontend)**.
|
||||||
|
|
||||||
|
What I recommend you to do is to start with a **v1.0.0** release as soon as possible with the minimum required features needed for your project idea, and then gradually add new features and release new versions.
|
||||||
|
|
||||||
|
In my example for [Thream](https://thream.divlo.fr), I could release a v1.0.0 without these features:
|
||||||
|
|
||||||
|
- English/French translation (could be only English)
|
||||||
|
- Light/Dark theme (could be only Dark)
|
||||||
|
- OAuth2 Authentication (could be only simple email/password authentication)
|
||||||
|
- User public profile
|
||||||
|
- Channels (maybe could be only one channel per guild to start with)
|
||||||
|
|
||||||
|
And probably more, what was really required with [Thream](https://thream.divlo.fr), is that users could authenticate, create a community of friends, and then they could communicate with each other with messages in real-time, really that was enough.
|
||||||
|
|
||||||
|
And then with this basis, I could release, v1.1.0, v1.2.0 etc. with more features, and release new versions more often to show the progress of the project, it is also more motivating to have users testing our project and to **get feedback sooner**.
|
||||||
|
|
||||||
|
**Start simple, improve later.**
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
The real key to success is to **be passionate**, **keep learning** on your own, and **look at mistakes as learning experiences**.
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
export const DIVLO_BIRTHDAY = new Date('2003-03-31')
|
export const DIVLO_BIRTHDAY_DAY = '31'
|
||||||
|
export const DIVLO_BIRTHDAY_MONTH = '03'
|
||||||
|
export const DIVLO_BIRTHDAY_YEAR = '2003'
|
||||||
|
export const DIVLO_BIRTHDAY = new Date(
|
||||||
|
`${DIVLO_BIRTHDAY_YEAR}-${DIVLO_BIRTHDAY_MONTH}-${DIVLO_BIRTHDAY_DAY}`
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the age of a person based on their birth date
|
* Calculates the age of a person based on their birth date
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import { DIVLO_BIRTHDAY, getAge } from './getAge'
|
export const getDefaultDescription = (age: number): string => {
|
||||||
|
|
||||||
export const getDefaultDescription = (): string => {
|
|
||||||
const age = getAge(DIVLO_BIRTHDAY)
|
|
||||||
return `I'm Divlo, I'm ${age} years old, I'm from France - Developer Full Stack Junior • Passionate about High-Tech`
|
return `I'm Divlo, I'm ${age} years old, I'm from France - Developer Full Stack Junior • Passionate about High-Tech`
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"$schema": "https://openapi.vercel.sh/vercel.json",
|
||||||
"github": {
|
"github": {
|
||||||
"enabled": false
|
"enabled": false
|
||||||
}
|
},
|
||||||
|
"cleanUrls": true
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user