mirror of
https://github.com/theoludwig/theoludwig.git
synced 2025-05-29 22:37:44 +02:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
b25451e631 | |||
042a861f58 | |||
d76db36dbc | |||
99d9dcf334 | |||
ece5ded1b4 | |||
1514600998 | |||
5f5b328895 | |||
c88887a322 | |||
014044573a | |||
df009c3f7b | |||
5c85ca2ef1 |
@ -1,12 +1,5 @@
|
|||||||
.vscode
|
.*
|
||||||
.git
|
!.npmrc
|
||||||
.env
|
|
||||||
build
|
build
|
||||||
.next
|
|
||||||
coverage
|
coverage
|
||||||
node_modules
|
node_modules
|
||||||
tmp
|
|
||||||
temp
|
|
||||||
.DS_Store
|
|
||||||
.lighthouseci
|
|
||||||
.vercel
|
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"prettier/prettier": "error",
|
"prettier/prettier": "error",
|
||||||
"unicorn/prefer-node-protocol": "error",
|
|
||||||
"@next/next/no-img-element": "off"
|
"@next/next/no-img-element": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
.github/workflows/analyze.yml
vendored
2
.github/workflows/analyze.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
|||||||
language: ['javascript']
|
language: ['javascript']
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.1.0'
|
- uses: 'actions/checkout@v3.3.0'
|
||||||
|
|
||||||
- name: 'Initialize CodeQL'
|
- name: 'Initialize CodeQL'
|
||||||
uses: 'github/codeql-action/init@v2'
|
uses: 'github/codeql-action/init@v2'
|
||||||
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -10,10 +10,10 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.1.0'
|
- uses: 'actions/checkout@v3.3.0'
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
- name: 'Use Node.js'
|
||||||
uses: 'actions/setup-node@v3.5.1'
|
uses: 'actions/setup-node@v3.6.0'
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
13
.github/workflows/lint.yml
vendored
13
.github/workflows/lint.yml
vendored
@ -10,10 +10,10 @@ jobs:
|
|||||||
lint:
|
lint:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.1.0'
|
- uses: 'actions/checkout@v3.3.0'
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
- name: 'Use Node.js'
|
||||||
uses: 'actions/setup-node@v3.5.1'
|
uses: 'actions/setup-node@v3.6.0'
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
@ -30,8 +30,8 @@ jobs:
|
|||||||
- name: 'lint:markdown'
|
- name: 'lint:markdown'
|
||||||
run: 'npm run lint:markdown'
|
run: 'npm run lint:markdown'
|
||||||
|
|
||||||
- name: 'lint:typescript'
|
- name: 'lint:eslint'
|
||||||
run: 'npm run lint:typescript'
|
run: 'npm run lint:eslint'
|
||||||
|
|
||||||
- name: 'lint:prettier'
|
- name: 'lint:prettier'
|
||||||
run: 'npm run lint:prettier'
|
run: 'npm run lint:prettier'
|
||||||
@ -40,8 +40,3 @@ jobs:
|
|||||||
uses: 'dotenv-linter/action-dotenv-linter@v2'
|
uses: 'dotenv-linter/action-dotenv-linter@v2'
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.github_token }}
|
github_token: ${{ secrets.github_token }}
|
||||||
|
|
||||||
- name: 'lint:docker'
|
|
||||||
uses: 'hadolint/hadolint-action@v1.6.0'
|
|
||||||
with:
|
|
||||||
dockerfile: './Dockerfile'
|
|
||||||
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
|||||||
release:
|
release:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.1.0'
|
- uses: 'actions/checkout@v3.3.0'
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
@ -21,7 +21,7 @@ jobs:
|
|||||||
git_commit_gpgsign: true
|
git_commit_gpgsign: true
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
- name: 'Use Node.js'
|
||||||
uses: 'actions/setup-node@v3.5.1'
|
uses: 'actions/setup-node@v3.6.0'
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
12
.github/workflows/test.yml
vendored
12
.github/workflows/test.yml
vendored
@ -10,10 +10,10 @@ jobs:
|
|||||||
test-unit:
|
test-unit:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.1.0'
|
- uses: 'actions/checkout@v3.3.0'
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
- name: 'Use Node.js'
|
||||||
uses: 'actions/setup-node@v3.5.1'
|
uses: 'actions/setup-node@v3.6.0'
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
@ -27,10 +27,10 @@ jobs:
|
|||||||
test-lighthouse:
|
test-lighthouse:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.1.0'
|
- uses: 'actions/checkout@v3.3.0'
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
- name: 'Use Node.js'
|
||||||
uses: 'actions/setup-node@v3.5.1'
|
uses: 'actions/setup-node@v3.6.0'
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
@ -52,10 +52,10 @@ jobs:
|
|||||||
test-e2e:
|
test-e2e:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
steps:
|
steps:
|
||||||
- uses: 'actions/checkout@v3.1.0'
|
- uses: 'actions/checkout@v3.3.0'
|
||||||
|
|
||||||
- name: 'Use Node.js'
|
- name: 'Use Node.js'
|
||||||
uses: 'actions/setup-node@v3.5.1'
|
uses: 'actions/setup-node@v3.6.0'
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
@ -1,11 +1,5 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
|
||||||
"default": true,
|
|
||||||
"MD013": false,
|
|
||||||
"MD024": false,
|
|
||||||
"MD033": false,
|
|
||||||
"MD041": false
|
|
||||||
},
|
|
||||||
"globs": ["**/*.{md,mdx}"],
|
"globs": ["**/*.{md,mdx}"],
|
||||||
"ignores": ["**/node_modules"]
|
"ignores": ["**/node_modules"],
|
||||||
|
"customRules": ["markdownlint-rule-relative-links"]
|
||||||
}
|
}
|
||||||
|
8
.markdownlint.json
Normal file
8
.markdownlint.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"default": true,
|
||||||
|
"relative-links": true,
|
||||||
|
"extends": "markdownlint/style/prettier",
|
||||||
|
"MD024": false,
|
||||||
|
"MD033": false,
|
||||||
|
"MD041": false
|
||||||
|
}
|
32
Dockerfile
32
Dockerfile
@ -1,21 +1,27 @@
|
|||||||
FROM node:18.11.0 AS dependencies
|
FROM node:18.13.0 AS builder-dependencies
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/application
|
||||||
COPY ./package*.json ./
|
COPY ./package*.json ./
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
FROM node:18.11.0 AS builder
|
FROM node:18.13.0 AS runner-dependencies
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/application
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
COPY ./package*.json ./
|
||||||
|
RUN npm install --omit=dev --ignore-scripts
|
||||||
|
|
||||||
|
FROM node:18.13.0 AS builder
|
||||||
|
WORKDIR /usr/src/application
|
||||||
|
COPY --from=builder-dependencies /usr/src/application/node_modules ./node_modules
|
||||||
COPY ./ ./
|
COPY ./ ./
|
||||||
COPY --from=dependencies /usr/src/app/node_modules ./node_modules
|
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
FROM node:18.11.0 AS runner
|
FROM gcr.io/distroless/nodejs18-debian11:latest AS runner
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/application
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
COPY --from=builder /usr/src/app/.next/standalone ./
|
COPY --from=builder /usr/src/application/.next/standalone ./
|
||||||
COPY --from=builder /usr/src/app/.next/static ./.next/static
|
COPY --from=builder /usr/src/application/.next/static ./.next/static
|
||||||
COPY --from=builder /usr/src/app/public ./public
|
COPY --from=builder /usr/src/application/public ./public
|
||||||
COPY --from=builder /usr/src/app/locales ./locales
|
COPY --from=builder /usr/src/application/locales ./locales
|
||||||
COPY --from=builder /usr/src/app/next.config.js ./next.config.js
|
COPY --from=builder /usr/src/application/next.config.js ./next.config.js
|
||||||
CMD ["node", "server.js"]
|
CMD ["./server.js"]
|
||||||
|
20
README.md
20
README.md
@ -1,7 +1,7 @@
|
|||||||
<h1 align="center"><a href="https://divlo.fr/">Divlo</a></h1>
|
<h1 align="center"><a href="https://divlo.fr/">Divlo</a></h1>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<strong>Developer Full Stack • Passionate about High-Tech</strong>
|
<strong>Developer Full Stack • Open-Source enthusiast</strong>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
@ -25,21 +25,11 @@
|
|||||||
"pronouns": "He/Him",
|
"pronouns": "He/Him",
|
||||||
"birthDate": "31/03/2003",
|
"birthDate": "31/03/2003",
|
||||||
"nationality": "Alsace, France",
|
"nationality": "Alsace, France",
|
||||||
"interests": [
|
"interests": ["Open-Source enthusiast", "Passionate about High-Tech"],
|
||||||
"Developer Full Stack",
|
|
||||||
"Passionate about High-Tech",
|
|
||||||
"Open-Source enthusiast"
|
|
||||||
],
|
|
||||||
"skills": {
|
"skills": {
|
||||||
"programmingLanguages": [
|
"programmingLanguages": ["JavaScript/TypeScript", "Python", "C/C++", "PHP"],
|
||||||
"JavaScript",
|
"frontEnd": ["HTML", "CSS", "Tailwind CSS", "React.js/Next.js"],
|
||||||
"TypeScript",
|
"backEnd": ["Laravel", "Node.js", "Fastify", "PostgreSQL"],
|
||||||
"Python",
|
|
||||||
"C/C++",
|
|
||||||
"PHP"
|
|
||||||
],
|
|
||||||
"frontEnd": ["HTML", "CSS", "Tailwind CSS", "React.js (+ Next.js)"],
|
|
||||||
"backEnd": ["Laravel", "Node.js", "Fastify", "Prisma", "PostgreSQL"],
|
|
||||||
"tools": ["GNU/Linux", "Ubuntu", "Visual Studio Code", "Git", "Docker"]
|
"tools": ["GNU/Linux", "Ubuntu", "Visual Studio Code", "Git", "Docker"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ export const Skills: React.FC = () => {
|
|||||||
<SkillComponent skill='Laravel' />
|
<SkillComponent skill='Laravel' />
|
||||||
<SkillComponent skill='Node.js' />
|
<SkillComponent skill='Node.js' />
|
||||||
<SkillComponent skill='Fastify' />
|
<SkillComponent skill='Fastify' />
|
||||||
<SkillComponent skill='Prisma' />
|
|
||||||
<SkillComponent skill='PostgreSQL' />
|
<SkillComponent skill='PostgreSQL' />
|
||||||
</SkillsSection>
|
</SkillsSection>
|
||||||
|
|
||||||
|
@ -3,10 +3,10 @@ import fs from 'node:fs'
|
|||||||
|
|
||||||
import { build } from 'vite'
|
import { build } from 'vite'
|
||||||
|
|
||||||
const jsonResumeThemeCustom = new URL('../', import.meta.url)
|
const jsonResumeThemeCustom = new URL('./', import.meta.url)
|
||||||
const jsonResumeThemeCustomDist = new URL('./dist', jsonResumeThemeCustom)
|
const jsonResumeThemeCustomDist = new URL('./dist', jsonResumeThemeCustom)
|
||||||
const publicResumeOutputURL = new URL(
|
const publicResumeOutputURL = new URL(
|
||||||
'../../public/curriculum-vitae',
|
'../public/curriculum-vitae',
|
||||||
import.meta.url
|
import.meta.url
|
||||||
)
|
)
|
||||||
|
|
@ -6,6 +6,7 @@
|
|||||||
<title><%= locals.basics.name %></title>
|
<title><%= locals.basics.name %></title>
|
||||||
<link rel="icon" type="image/png" href="<%= locals.basics.image %>" />
|
<link rel="icon" type="image/png" href="<%= locals.basics.image %>" />
|
||||||
<link rel="stylesheet" href="./styles/global.css" />
|
<link rel="stylesheet" href="./styles/global.css" />
|
||||||
|
<script defer type="module" src="./scripts/main.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
@ -26,12 +27,15 @@
|
|||||||
<strong><%= locals.basics.name %></strong>
|
<strong><%= locals.basics.name %></strong>
|
||||||
</h3>
|
</h3>
|
||||||
<h5 class="text-muted"><%= locals.basics.label %></h5>
|
<h5 class="text-muted"><%= locals.basics.label %></h5>
|
||||||
|
<h5 class="text-muted">
|
||||||
|
<%= locals.basics.age %> (<span id="year-old"></span> ans)
|
||||||
|
</h5>
|
||||||
|
<h5 class="text-muted">
|
||||||
|
<%= locals.basics.location.address %>
|
||||||
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="contact-details clearfix">
|
<div class="contact-details clearfix">
|
||||||
<div class="detail">
|
|
||||||
<span class="info"><%= locals.basics.phone %></span>
|
|
||||||
</div>
|
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
<span class="info">
|
<span class="info">
|
||||||
<a
|
<a
|
||||||
@ -70,61 +74,109 @@
|
|||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<div class="detail" id="work-experience">
|
<section class="section-separated">
|
||||||
<div class="icon">
|
<div class="detail" id="education">
|
||||||
<img src="./images/building-columns.svg" alt="work" />
|
<div class="icon">
|
||||||
|
<img src="./images/graduation-cap.svg" alt="graduation" />
|
||||||
|
</div>
|
||||||
|
<div class="info">
|
||||||
|
<h4 class="title text-uppercase">Formations</h4>
|
||||||
|
<div class="content">
|
||||||
|
<ul class="list-unstyled clear-margin">
|
||||||
|
<% locals.education.forEach((degree) => { %>
|
||||||
|
<li class="card card-nested">
|
||||||
|
<div class="content">
|
||||||
|
<p class="clear-margin relative">
|
||||||
|
<strong><%= degree.studyType %></strong>
|
||||||
|
</p>
|
||||||
|
<p class="clear-margin relative">
|
||||||
|
<strong><%= degree.score %></strong>
|
||||||
|
</p>
|
||||||
|
<p class="text-muted clear-margin">
|
||||||
|
<%= degree.institution %>
|
||||||
|
</p>
|
||||||
|
<p class="text-muted clear-margin">
|
||||||
|
<small>
|
||||||
|
<%= degree.startDate %> <%= degree.endDate !=
|
||||||
|
null ? " - " + degree.endDate : "" %>
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
|
<% if (degree.courses != null) { %>
|
||||||
|
<ul class="education-courses">
|
||||||
|
<% degree.courses.forEach((course) => { %>
|
||||||
|
<li><%= course %></li>
|
||||||
|
<% }) %>
|
||||||
|
</ul>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<% }) %>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
|
||||||
<h4 class="title text-uppercase">Expériences</h4>
|
<div class="detail" id="skills">
|
||||||
<ul class="list-unstyled clear-margin">
|
<div class="icon">
|
||||||
<% locals.work.forEach((experience) => { %>
|
<img src="./images/toolbox.svg" alt="toolbox" />
|
||||||
<li class="card card-nested clearfix">
|
</div>
|
||||||
<div class="content">
|
<div class="info">
|
||||||
<p class="clear-margin relative">
|
<h4 class="title text-uppercase">Compétences</h4>
|
||||||
<a href="<%= experience.website %>">
|
<div class="content">
|
||||||
<strong><%= experience.name %></strong>
|
<ul class="list-unstyled clear-margin">
|
||||||
</a>
|
<% locals.skills.forEach((skill) => { %>
|
||||||
</p>
|
<li class="card card-nested card-skills">
|
||||||
<p class="clear-margin relative">
|
<div class="skill-info">
|
||||||
<strong><%- experience.position %></strong>
|
<strong><%= skill.name %></strong>
|
||||||
</p>
|
<div class="space-top labels">
|
||||||
<p class="text-muted">
|
<% skill.keywords.forEach((keyword) => { %>
|
||||||
<small>
|
<p class="label label-keyword"><%= keyword %></p>
|
||||||
<span class="space-right">
|
<% }) %>
|
||||||
<%= date.format(new Date(experience.startDate),
|
</div>
|
||||||
'DD/MM/YYYY') %> - <%= date.format(new
|
</div>
|
||||||
Date(experience.endDate), 'DD/MM/YYYY') %>
|
</li>
|
||||||
</span>
|
<% }) %>
|
||||||
</small>
|
</ul>
|
||||||
</p>
|
</div>
|
||||||
<div class="experience-description">
|
</div>
|
||||||
<p><%- experience.summary %></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<% }) %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<div class="detail" id="skills">
|
<section class="section-separated">
|
||||||
<div class="icon">
|
<div class="detail" id="work-experience">
|
||||||
<img src="./images/toolbox.svg" alt="toolbox" />
|
<div class="icon">
|
||||||
</div>
|
<img src="./images/building-columns.svg" alt="work" />
|
||||||
<div class="info">
|
</div>
|
||||||
<h4 class="title text-uppercase">Compétences</h4>
|
<div class="info">
|
||||||
<div class="content">
|
<h4 class="title text-uppercase">Expériences</h4>
|
||||||
<ul class="list-unstyled clear-margin">
|
<ul class="list-unstyled clear-margin">
|
||||||
<% locals.skills.forEach((skill) => { %>
|
<% locals.work.filter((experience) =>
|
||||||
<li class="card card-nested card-skills">
|
experience.description == null).forEach((experience) => {
|
||||||
<div class="skill-info">
|
%>
|
||||||
<strong><%= skill.name %></strong>
|
<li class="card card-nested clearfix">
|
||||||
<div class="space-top labels">
|
<div class="content">
|
||||||
<% skill.keywords.forEach((keyword) => { %>
|
<p class="clear-margin relative">
|
||||||
<p class="label label-keyword"><%= keyword %></p>
|
<a href="<%= experience.website %>">
|
||||||
<% }) %>
|
<strong><%= experience.name %></strong>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p class="clear-margin relative">
|
||||||
|
<strong><%- experience.position %></strong>
|
||||||
|
</p>
|
||||||
|
<p class="text-muted">
|
||||||
|
<small>
|
||||||
|
<span class="space-right">
|
||||||
|
<%= date.format(new Date(experience.startDate),
|
||||||
|
'DD/MM/YYYY') %> - <%= date.format(new
|
||||||
|
Date(experience.endDate), 'DD/MM/YYYY') %> (<%=
|
||||||
|
experience.duration %>)
|
||||||
|
</span>
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
|
<div class="experience-description">
|
||||||
|
<p><%- experience.summary %></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@ -132,63 +184,57 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr />
|
<div class="detail" id="interests">
|
||||||
|
<div class="icon">
|
||||||
|
<img src="./images/heart.svg" alt="heart" />
|
||||||
|
</div>
|
||||||
|
<div class="info">
|
||||||
|
<h4 class="title text-uppercase">Intérets</h4>
|
||||||
|
<div class="content">
|
||||||
|
<ul class="list-unstyled clear-margin">
|
||||||
|
<% locals.interests.forEach((interest) => { %>
|
||||||
|
<li class="card card-nested">
|
||||||
|
<p><strong><%= interest.name %></strong></p>
|
||||||
|
</li>
|
||||||
|
<% }) %>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<div class="detail" id="education">
|
<ul class="list-unstyled clear-margin">
|
||||||
<div class="icon">
|
<% locals.work.filter((experience) =>
|
||||||
<img src="./images/graduation-cap.svg" alt="graduation" />
|
experience.description != null).forEach((experience) =>
|
||||||
</div>
|
{ %>
|
||||||
<div class="info">
|
<li class="card card-nested clearfix">
|
||||||
<h4 class="title text-uppercase">Éducation</h4>
|
<div class="content">
|
||||||
<div class="content">
|
<p class="clear-margin relative">
|
||||||
<ul class="list-unstyled clear-margin">
|
<a href="<%= experience.website %>">
|
||||||
<% locals.education.forEach((degree) => { %>
|
<strong><%= experience.name %></strong>
|
||||||
<li class="card card-nested">
|
</a>
|
||||||
<div class="content">
|
</p>
|
||||||
<p class="clear-margin relative">
|
<p class="clear-margin relative">
|
||||||
<strong><%= degree.studyType %></strong>
|
<strong><%- experience.position %></strong>
|
||||||
</p>
|
</p>
|
||||||
<p class="clear-margin relative">
|
<p class="text-muted">
|
||||||
<strong><%= degree.score %></strong>
|
<small>
|
||||||
</p>
|
<span class="space-right">
|
||||||
<p class="text-muted clear-margin">
|
<%= date.format(new
|
||||||
<%= degree.institution %>
|
Date(experience.startDate), 'DD/MM/YYYY') %> -
|
||||||
</p>
|
<%= date.format(new Date(experience.endDate),
|
||||||
<p class="text-muted clear-margin">
|
'DD/MM/YYYY') %> (<%= experience.duration %>)
|
||||||
<small>
|
</span>
|
||||||
<%= degree.startDate %> <%= degree.endDate != null
|
</small>
|
||||||
? " - " + degree.endDate : "" %>
|
</p>
|
||||||
</small>
|
<div class="experience-description">
|
||||||
</p>
|
<p><%- experience.summary %></p>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</div>
|
||||||
<% }) %>
|
</li>
|
||||||
</ul>
|
<% }) %>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<div class="detail" id="interests">
|
|
||||||
<div class="icon">
|
|
||||||
<img src="./images/heart.svg" alt="heart" />
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h4 class="title text-uppercase">Intérets</h4>
|
|
||||||
<div class="content">
|
|
||||||
<ul class="list-unstyled clear-margin">
|
|
||||||
<% locals.interests.forEach((interest) => { %>
|
|
||||||
<li class="card card-nested">
|
|
||||||
<p><strong><%= interest.name %></strong></p>
|
|
||||||
</li>
|
|
||||||
<% }) %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
1763
jsonresume-theme-custom/package-lock.json
generated
1763
jsonresume-theme-custom/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -9,12 +9,13 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"jsonc-parser": "3.2.0",
|
||||||
"modern-normalize": "1.1.0"
|
"modern-normalize": "1.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "18.11.7",
|
"@types/node": "18.11.18",
|
||||||
"date-and-time": "2.4.1",
|
"date-and-time": "2.4.1",
|
||||||
"vite": "3.2.0",
|
"vite": "4.0.4",
|
||||||
"vite-plugin-html": "3.2.0"
|
"vite-plugin-html": "3.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
jsonresume-theme-custom/scripts/main.js
Normal file
5
jsonresume-theme-custom/scripts/main.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { DIVLO_BIRTHDAY, getAge } from '../../utils/getAge.ts'
|
||||||
|
|
||||||
|
const yearOld = document.getElementById('year-old')
|
||||||
|
|
||||||
|
yearOld.textContent = getAge(DIVLO_BIRTHDAY).toString()
|
@ -209,7 +209,6 @@ h5 {
|
|||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
color: #fff;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
@ -217,8 +216,6 @@ h5 {
|
|||||||
}
|
}
|
||||||
.label-keyword {
|
.label-keyword {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: #7eb0db;
|
|
||||||
color: white;
|
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border: 1px solid #357ebd;
|
border: 1px solid #357ebd;
|
||||||
@ -227,3 +224,6 @@ h5 {
|
|||||||
.label-keyword p {
|
.label-keyword p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
.section-separated {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
|
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
|
import { parse as JSONCParser } from 'jsonc-parser'
|
||||||
import { createHtmlPlugin } from 'vite-plugin-html'
|
import { createHtmlPlugin } from 'vite-plugin-html'
|
||||||
import date from 'date-and-time'
|
import date from 'date-and-time'
|
||||||
|
|
||||||
const jsonResumeURL = new URL('../resume.json', import.meta.url)
|
const jsonResumeURL = new URL('../resume.jsonc', import.meta.url)
|
||||||
const dataResumeStringJSON = await fs.promises.readFile(jsonResumeURL, {
|
const dataResumeStringJSON = await fs.promises.readFile(jsonResumeURL, {
|
||||||
encoding: 'utf-8'
|
encoding: 'utf-8'
|
||||||
})
|
})
|
||||||
const resume = JSON.parse(dataResumeStringJSON)
|
const resume = JSONCParser(dataResumeStringJSON)
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
/**
|
||||||
|
* Documentation: <https://vitejs.dev/config/>
|
||||||
|
*/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
build: {
|
build: {
|
||||||
assetsDir: './'
|
assetsDir: './'
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"about": {
|
"about": {
|
||||||
"i-am": "I am",
|
"i-am": "I am",
|
||||||
"description": "Developer Full Stack • Passionate about High-Tech",
|
"description": "Developer Full Stack • Open-Source enthusiast",
|
||||||
"full-name": "Full name",
|
"full-name": "Full name",
|
||||||
"birth-date": "Birth date",
|
"birth-date": "Birth date",
|
||||||
"years-old": "years old",
|
"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\" (second year)."
|
"description-bottom": "I am a student in computer science following the French training \"BUT Informatique\" and I am also a self-taught."
|
||||||
},
|
},
|
||||||
"interests": {
|
"interests": {
|
||||||
"title": "Interests",
|
"title": "Interests",
|
||||||
@ -16,12 +16,12 @@
|
|||||||
"description": "Computer programming is my main hobby, I love it! <br/> Mostly web development for the moment but I'm programming in others programming language too."
|
"description": "Computer programming is my main hobby, I love it! <br/> Mostly web development for the moment but I'm programming in others programming language too."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Passionate about High-Tech",
|
"title": "Open-Source enthusiast",
|
||||||
"description": "I always wondered how the future would be. Every day I want to wake up and think that the future will be great and better than the past. Technologies improve gradually over time, which is very useful in many areas."
|
"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>."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Open-Source enthusiast",
|
"title": "Passionate about High-Tech",
|
||||||
"description": "For me, everyone should work, solve problems, build things and think together. Long live open source, whenever you can share your work, do it! <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": "I always wondered how the future would be. Every day I want to wake up and think that the future will be great and better than the past. Technologies improve gradually over time, which is very useful in many areas."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"about": {
|
"about": {
|
||||||
"i-am": "Je suis",
|
"i-am": "Je suis",
|
||||||
"description": "Développeur Full Stack • Passionné de High-Tech",
|
"description": "Développeur Full Stack • Enthousiaste de l'Open-Source",
|
||||||
"full-name": "Prénom NOM",
|
"full-name": "Prénom NOM",
|
||||||
"birth-date": "Date de naissance",
|
"birth-date": "Date de naissance",
|
||||||
"years-old": "ans",
|
"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\" (deuxième année)."
|
"description-bottom": "Je suis étudiant à l'université suivant la formation \"BUT Informatique\" et me forme en autodidacte dans l'informatique en suivant des formations en ligne."
|
||||||
},
|
},
|
||||||
"interests": {
|
"interests": {
|
||||||
"title": "Intérêts",
|
"title": "Intérêts",
|
||||||
@ -16,12 +16,12 @@
|
|||||||
"description": "La programmation informatique est mon loisir principal, j'adore! <br/> Principalement du développement Web pour le moment, mais je programme aussi dans d'autres langages de programmation."
|
"description": "La programmation informatique est mon loisir principal, j'adore! <br/> Principalement du développement Web pour le moment, mais je programme aussi dans d'autres langages de programmation."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Passionné de High-Tech",
|
"title": "Enthousiaste de l'Open-Source",
|
||||||
"description": "Je me suis toujours demandé comment l'avenir serait. Chaque jour, je veux me réveiller et penser que l'avenir sera formidable et meilleur que le passé. Les technolgies s'améliorent progressivement avec le temps, ce qui est très utile dans de nombreux domaines."
|
"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>."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Enthousiaste de l'Open-Source",
|
"title": "Passionné de High-Tech",
|
||||||
"description": "Pour moi, tout le monde devrait travailler, résoudre des problèmes, construire des choses et réfléchir ensemble. Longue vie à l'open-source, chaque fois que vous pouvez partagez votre travail, faites-le! <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": "Je me suis toujours demandé comment l'avenir serait. Chaque jour, je veux me réveiller et penser que l'avenir sera formidable et meilleur que le passé. Les technolgies s'améliorent progressivement avec le temps, ce qui est très utile dans de nombreux domaines."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
21256
package-lock.json
generated
21256
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
78
package.json
78
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "divlo",
|
"name": "divlo",
|
||||||
"version": "2.5.0",
|
"version": "2.5.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -18,7 +18,7 @@
|
|||||||
"lint:commit": "commitlint",
|
"lint:commit": "commitlint",
|
||||||
"lint:editorconfig": "editorconfig-checker",
|
"lint:editorconfig": "editorconfig-checker",
|
||||||
"lint:markdown": "markdownlint-cli2",
|
"lint:markdown": "markdownlint-cli2",
|
||||||
"lint:typescript": "eslint \"**/*.{js,jsx,ts,tsx}\" --ignore-path \".gitignore\"",
|
"lint:eslint": "eslint \"**/*.{js,jsx,ts,tsx}\" --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",
|
||||||
@ -26,24 +26,24 @@
|
|||||||
"test:lighthouse": "lhci autorun",
|
"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/scripts/build.js",
|
"resume:build": "node ./jsonresume-theme-custom/build.js",
|
||||||
"release": "semantic-release",
|
"release": "semantic-release",
|
||||||
"deploy": "vercel",
|
"deploy": "vercel",
|
||||||
"postinstall": "husky install"
|
"postinstall": "husky install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/montserrat": "4.5.13",
|
"@fontsource/montserrat": "4.5.13",
|
||||||
"@fortawesome/fontawesome-svg-core": "6.2.0",
|
"@fortawesome/fontawesome-svg-core": "6.2.1",
|
||||||
"@fortawesome/free-brands-svg-icons": "6.2.0",
|
"@fortawesome/free-brands-svg-icons": "6.2.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "6.2.0",
|
"@fortawesome/free-solid-svg-icons": "6.2.1",
|
||||||
"@fortawesome/react-fontawesome": "0.2.0",
|
"@fortawesome/react-fontawesome": "0.2.0",
|
||||||
"@giscus/react": "2.2.0",
|
"@giscus/react": "2.2.6",
|
||||||
"clsx": "1.2.1",
|
"clsx": "1.2.1",
|
||||||
"date-and-time": "2.4.1",
|
"date-and-time": "2.4.1",
|
||||||
"gray-matter": "4.0.3",
|
"gray-matter": "4.0.3",
|
||||||
"html-react-parser": "3.0.4",
|
"html-react-parser": "3.0.7",
|
||||||
"next": "13.0.0",
|
"next": "13.1.1",
|
||||||
"next-mdx-remote": "4.1.0",
|
"next-mdx-remote": "4.2.1",
|
||||||
"next-pwa": "5.6.0",
|
"next-pwa": "5.6.0",
|
||||||
"next-themes": "0.2.1",
|
"next-themes": "0.2.1",
|
||||||
"next-translate": "1.6.0",
|
"next-translate": "1.6.0",
|
||||||
@ -51,48 +51,50 @@
|
|||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"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.1.0",
|
||||||
"remark-gfm": "3.0.1",
|
"remark-gfm": "3.0.1",
|
||||||
"sharp": "0.31.1",
|
"sharp": "0.31.3",
|
||||||
"shiki": "0.11.1",
|
"shiki": "0.12.1",
|
||||||
"unified": "10.1.2",
|
"unified": "10.1.2",
|
||||||
"unist-util-visit": "4.1.1",
|
"unist-util-visit": "4.1.1",
|
||||||
"universal-cookie": "4.0.4"
|
"universal-cookie": "4.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "17.1.2",
|
"@commitlint/cli": "17.4.1",
|
||||||
"@commitlint/config-conventional": "17.1.0",
|
"@commitlint/config-conventional": "17.4.0",
|
||||||
"@lhci/cli": "0.9.0",
|
"@lhci/cli": "0.10.0",
|
||||||
"@saithodev/semantic-release-backmerge": "2.1.2",
|
"@saithodev/semantic-release-backmerge": "2.1.2",
|
||||||
"@semantic-release/git": "10.0.1",
|
"@semantic-release/git": "10.0.1",
|
||||||
"@tailwindcss/typography": "0.5.7",
|
"@tailwindcss/typography": "0.5.9",
|
||||||
"@types/node": "18.11.7",
|
"@tsconfig/strictest": "1.0.2",
|
||||||
"@types/react": "18.0.24",
|
"@types/node": "18.11.18",
|
||||||
|
"@types/react": "18.0.26",
|
||||||
"@types/unist": "2.0.6",
|
"@types/unist": "2.0.6",
|
||||||
"@typescript-eslint/eslint-plugin": "5.41.0",
|
"@typescript-eslint/eslint-plugin": "5.48.1",
|
||||||
"autoprefixer": "10.4.12",
|
"autoprefixer": "10.4.13",
|
||||||
"cypress": "10.11.0",
|
"cypress": "12.3.0",
|
||||||
"editorconfig-checker": "4.0.2",
|
"editorconfig-checker": "4.0.2",
|
||||||
"eslint": "8.26.0",
|
"eslint": "8.31.0",
|
||||||
"eslint-config-conventions": "5.0.0",
|
"eslint-config-conventions": "6.0.0",
|
||||||
"eslint-config-next": "13.0.0",
|
"eslint-config-next": "13.1.1",
|
||||||
"eslint-config-prettier": "8.5.0",
|
"eslint-config-prettier": "8.6.0",
|
||||||
"eslint-plugin-import": "2.26.0",
|
"eslint-plugin-import": "2.26.0",
|
||||||
"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": "44.0.2",
|
"eslint-plugin-unicorn": "45.0.2",
|
||||||
"html-w3c-validator": "1.2.1",
|
"html-w3c-validator": "1.2.2",
|
||||||
"husky": "8.0.1",
|
"husky": "8.0.3",
|
||||||
"jsonresume-theme-custom": "file:./jsonresume-theme-custom",
|
"jsonresume-theme-custom": "file:./jsonresume-theme-custom",
|
||||||
"lint-staged": "13.0.3",
|
"lint-staged": "13.1.0",
|
||||||
"markdownlint-cli2": "0.5.1",
|
"markdownlint-cli2": "0.6.0",
|
||||||
"postcss": "8.4.18",
|
"markdownlint-rule-relative-links": "1.1.1",
|
||||||
"prettier": "2.7.1",
|
"postcss": "8.4.21",
|
||||||
"prettier-plugin-tailwindcss": "0.1.13",
|
"prettier": "2.8.2",
|
||||||
|
"prettier-plugin-tailwindcss": "0.2.1",
|
||||||
"semantic-release": "19.0.5",
|
"semantic-release": "19.0.5",
|
||||||
"start-server-and-test": "1.14.0",
|
"start-server-and-test": "1.15.2",
|
||||||
"tailwindcss": "3.2.1",
|
"tailwindcss": "3.2.4",
|
||||||
"typescript": "4.8.4",
|
"typescript": "4.9.4",
|
||||||
"vercel": "28.4.12"
|
"vercel": "28.11.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,11 @@ const BlogPostPage: NextPage<BlogPostPageProps> = (props) => {
|
|||||||
const { src, alt, ...props } = properties
|
const { src, alt, ...props } = properties
|
||||||
let source = src
|
let source = src
|
||||||
source = src?.replace('../public/', '/')
|
source = src?.replace('../public/', '/')
|
||||||
return <img src={source} alt={alt} {...props} />
|
return (
|
||||||
|
<span className='flex flex-col items-center justify-center'>
|
||||||
|
<img src={source} alt={alt} {...props} />
|
||||||
|
</span>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
a: (props) => {
|
a: (props) => {
|
||||||
if (props.href?.startsWith('#') ?? false) {
|
if (props.href?.startsWith('#') ?? false) {
|
||||||
@ -78,7 +82,7 @@ const BlogPostPage: NextPage<BlogPostPageProps> = (props) => {
|
|||||||
export const getStaticProps: GetStaticProps<BlogPostPageProps> = async (
|
export const getStaticProps: GetStaticProps<BlogPostPageProps> = async (
|
||||||
context
|
context
|
||||||
) => {
|
) => {
|
||||||
const slug = context?.params?.slug
|
const slug = context?.params?.['slug']
|
||||||
const { getPostBySlug } = await import('utils/blog')
|
const { getPostBySlug } = await import('utils/blog')
|
||||||
const post = await getPostBySlug(slug)
|
const post = await getPostBySlug(slug)
|
||||||
if (post == null || (post != null && !post.frontmatter.isPublished)) {
|
if (post == null || (post != null && !post.frontmatter.isPublished)) {
|
||||||
|
@ -35,18 +35,11 @@ In this section, I will explain what technologies I used to make this blog, and
|
|||||||
|
|
||||||
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/Divlo/Divlo), so you can see the code and contribute to it.
|
||||||
|
|
||||||
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)
|
|
||||||
- Views counter
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
- [Next.js](https://nextjs.org/)
|
- [Next.js](https://nextjs.org/)
|
||||||
|
|
||||||
It allows to have a server-side rendered website, that means that it is faster and easier to have a good SEO (Search Engine Optimization) than a SPA (Single Page Application).
|
It allows to have a server-side rendered website, that means that it is faster and easier to have a good <abbr title="Search Engine Optimization">SEO</abbr> than a <abbr title="Single Page Application">SPA</abbr>.
|
||||||
|
|
||||||
- [MDX](https://mdxjs.com/)
|
- [MDX](https://mdxjs.com/)
|
||||||
|
|
||||||
|
@ -53,12 +53,7 @@ Since the project is mainly developed during free time (mainly on weekends), the
|
|||||||
|
|
||||||
- The **client** part, called **frontend**, what **the user sees on the screen**, such as forms, buttons and all the **graphic elements** with which the user can interact from a browser.
|
- The **client** part, called **frontend**, what **the user sees on the screen**, such as forms, buttons and all the **graphic elements** with which the user can interact from a browser.
|
||||||
|
|
||||||
<p className='flex flex-col items-center justify-center'>
|

|
||||||
<img
|
|
||||||
alt='HTTP Communication Schema'
|
|
||||||
src='../public/images/posts/thream-v1-0-0/http-communication.png'
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
This design allows the separation between the client and the server, as long as they both structure their communication according to the <abbr title="Representational state transfer">REST</abbr> architectural guidelines, using the <abbr title="Hypertext Transfer Protocol">HTTP</abbr> protocol, they will be able to communicate with each other, which makes it possible to work independently on the backend and on the frontend using different technologies and skills, really useful in teamwork.
|
This design allows the separation between the client and the server, as long as they both structure their communication according to the <abbr title="Representational state transfer">REST</abbr> architectural guidelines, using the <abbr title="Hypertext Transfer Protocol">HTTP</abbr> protocol, they will be able to communicate with each other, which makes it possible to work independently on the backend and on the frontend using different technologies and skills, really useful in teamwork.
|
||||||
|
|
||||||
|
118
resume.json
118
resume.json
@ -1,118 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json",
|
|
||||||
"meta": {
|
|
||||||
"theme": "custom"
|
|
||||||
},
|
|
||||||
"basics": {
|
|
||||||
"name": "Théo LUDWIG",
|
|
||||||
"label": "Développeur Full Stack • Passionné de High-Tech",
|
|
||||||
"image": "https://divlo.fr/images/logo_orange.png",
|
|
||||||
"email": "contact@divlo.fr",
|
|
||||||
"location": {},
|
|
||||||
"url": "https://divlo.fr",
|
|
||||||
"summary": "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\" (deuxième année). <br/> Je mets en pratique tout ce que j'apprends et réalise de nombreux projets."
|
|
||||||
},
|
|
||||||
"education": [
|
|
||||||
{
|
|
||||||
"startDate": "2022",
|
|
||||||
"studyType": "Diplôme du Bachelor Universitaire de Technologie (BUT) Informatique",
|
|
||||||
"institution": "IUT Robert Schuman à Illkirch-Graffenstaden",
|
|
||||||
"score": "En cours"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"startDate": "2019",
|
|
||||||
"endDate": "2021",
|
|
||||||
"studyType": "Diplôme du Baccalauréat Général (Mathématiques et Numériques Sciences Informatiques)",
|
|
||||||
"institution": "Lycée Heinrich Nessel à Haguenau",
|
|
||||||
"score": "Mention Assez Bien"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"startDate": "2014",
|
|
||||||
"endDate": "2018",
|
|
||||||
"studyType": "Diplôme national du brevet",
|
|
||||||
"institution": "Collège Gustave Doré à Hochfelden",
|
|
||||||
"score": "Mention Bien"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"work": [
|
|
||||||
{
|
|
||||||
"summary": "Développement site web en React.js et Strapi afin de répondre <a href=\"https://www.nuitdelinfo.com/nuitinfo/_media/infos:la_nuit_de_l_info_2021_-_sujet.pdf\">au sujet de la Nuit de l'Info 2021</a>.<br /> TOP 1 France: Défi de l'entreprise <a href=\"https://www.nuitdelinfo.com/inscription/defis/300\">ToolPad</a>.",
|
|
||||||
"website": "https://www.nuitdelinfo.com/",
|
|
||||||
"name": "La Nuit de l'info 2021",
|
|
||||||
"position": "Participation avec l'équipe <a href=\"https://www.nuitdelinfo.com/inscription/equipes/46\">Who are We</a>",
|
|
||||||
"startDate": "2021-12-02",
|
|
||||||
"endDate": "2021-12-03"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "Agent administratif en vue de faire face au sucroît temporaire d'activités liés à la numérisation des plans des postes sources <br /> actuellement sous format papier calque suite à la libération des locaux des archives.",
|
|
||||||
"website": "https://www.es.fr/",
|
|
||||||
"name": "ÉS (Électricité de Strasbourg)",
|
|
||||||
"location": "5 Rue André Marie Ampère, 67450 Mundolsheim",
|
|
||||||
"position": "Emploi d'été en qualité d'agent administratif",
|
|
||||||
"startDate": "2021-07-07",
|
|
||||||
"endDate": "2021-07-30"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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": "Stage initiation métier développeur web",
|
|
||||||
"startDate": "2019-06-24",
|
|
||||||
"endDate": "2019-06-28"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"summary": "Développement d'un site web pour trouver un restaurant à la pause repas.",
|
|
||||||
"website": "https://www.itpartners.fr/",
|
|
||||||
"name": "Tribe | IT Partners",
|
|
||||||
"location": "16 Rue du Parc, 67205 Oberhausbergen",
|
|
||||||
"position": "Stage initiation métier développeur web",
|
|
||||||
"startDate": "2019-06-17",
|
|
||||||
"endDate": "2019-06-21"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"interests": [
|
|
||||||
{
|
|
||||||
"name": "Développeur Full Stack"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Passionné de High-Tech"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Enthousiaste de l'Open-Source"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"skills": [
|
|
||||||
{
|
|
||||||
"keywords": ["JavaScript", "TypeScript", "Python", "C/C++", "PHP"],
|
|
||||||
"name": "Langages de programmation"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keywords": ["HTML", "CSS", "Tailwind CSS", "React.js (+ Next.js)"],
|
|
||||||
"name": "Front-end"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keywords": ["Laravel", "Node.js", "Fastify", "PostgreSQL"],
|
|
||||||
"name": "Back-end"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keywords": [
|
|
||||||
"GNU/Linux",
|
|
||||||
"Ubuntu",
|
|
||||||
"Visual Studio Code",
|
|
||||||
"git",
|
|
||||||
"Docker"
|
|
||||||
],
|
|
||||||
"name": "Logiciels et outils"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
150
resume.jsonc
Normal file
150
resume.jsonc
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json",
|
||||||
|
"meta": {
|
||||||
|
"theme": "custom"
|
||||||
|
},
|
||||||
|
"basics": {
|
||||||
|
"name": "Théo LUDWIG",
|
||||||
|
"label": "Développeur Full Stack • Étudiant",
|
||||||
|
"image": "https://divlo.fr/images/logo_orange.png",
|
||||||
|
"email": "contact@divlo.fr",
|
||||||
|
"age": "31/03/2003",
|
||||||
|
"location": {
|
||||||
|
"address": "Alsace, France"
|
||||||
|
},
|
||||||
|
"url": "https://divlo.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>)."
|
||||||
|
},
|
||||||
|
"education": [
|
||||||
|
{
|
||||||
|
"startDate": "2022",
|
||||||
|
"endDate": "2023",
|
||||||
|
"studyType": "Bachelor Universitaire de Technologie (BUT) Informatique",
|
||||||
|
"institution": "IUT Robert Schuman à Illkirch-Graffenstaden",
|
||||||
|
"score": "2ème année",
|
||||||
|
"courses": [
|
||||||
|
"Développement Web avec le framework Laravel en PHP",
|
||||||
|
"Patrons et Principes de conceptions (Code maintenable et réutilisable) en UML",
|
||||||
|
"Programmation systèmes en C (Multi-Thread, Serveur/Client UDP/TCP)",
|
||||||
|
"Sécurisation des accès à la base de données et PL/SQL",
|
||||||
|
"Projet développement d'une application web en React.js en équipe de 3 personnes pendant 3 mois"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"startDate": "2021",
|
||||||
|
"endDate": "2022",
|
||||||
|
"studyType": "Bachelor Universitaire de Technologie (BUT) Informatique",
|
||||||
|
"institution": "IUT Robert Schuman à Illkirch-Graffenstaden",
|
||||||
|
"score": "1ère année",
|
||||||
|
"courses": [
|
||||||
|
"Développement Orientée Objet en Java",
|
||||||
|
"Programmation systèmes en C (Allocation mémoire, Pointeurs, Structures)",
|
||||||
|
"Développement d'application Windows Forms (.NET Framework) en C#",
|
||||||
|
"Base de données relationnelles et langage SQL"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"startDate": "2019",
|
||||||
|
"endDate": "2021",
|
||||||
|
"studyType": "Baccalauréat Général (Mathématiques et Numériques Sciences Informatiques)",
|
||||||
|
"institution": "Lycée Heinrich Nessel à Haguenau",
|
||||||
|
"score": "Mention Assez Bien"
|
||||||
|
}
|
||||||
|
// {
|
||||||
|
// "startDate": "2014",
|
||||||
|
// "endDate": "2018",
|
||||||
|
// "studyType": "Diplôme national du brevet",
|
||||||
|
// "institution": "Collège Gustave Doré à Hochfelden",
|
||||||
|
// "score": "Mention Bien"
|
||||||
|
// }
|
||||||
|
],
|
||||||
|
"work": [
|
||||||
|
{
|
||||||
|
"description": "interests",
|
||||||
|
"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://www.nuitdelinfo.com/",
|
||||||
|
"name": "La Nuit de l'info 2021",
|
||||||
|
"position": "Participation en équipe de 5 personnes",
|
||||||
|
"startDate": "2021-12-02",
|
||||||
|
"endDate": "2021-12-03",
|
||||||
|
"duration": "1 semaine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"summary": "Agent administratif - Numérisation et archivage des plans électriques initialement sous format papier calque.",
|
||||||
|
"website": "https://www.es.fr/",
|
||||||
|
"name": "ÉS (Électricité de Strasbourg)",
|
||||||
|
"location": "5 Rue André Marie Ampère, 67450 Mundolsheim",
|
||||||
|
"position": "Emploi d'été en qualité d'agent administratif",
|
||||||
|
"startDate": "2021-07-07",
|
||||||
|
"endDate": "2021-07-30",
|
||||||
|
"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.",
|
||||||
|
"website": "https://www.itpartners.fr/",
|
||||||
|
"name": "Tribe | IT Partners",
|
||||||
|
"location": "16 Rue du Parc, 67205 Oberhausbergen",
|
||||||
|
"position": "Stage initiation métier développeur web",
|
||||||
|
"startDate": "2019-06-17",
|
||||||
|
"endDate": "2019-06-21",
|
||||||
|
"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": [
|
||||||
|
{
|
||||||
|
"name": "Enthousiaste de l'Open-Source"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Passionné de High-Tech"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"skills": [
|
||||||
|
{
|
||||||
|
"keywords": ["JavaScript/TypeScript", "Python", "C/C++", "PHP"],
|
||||||
|
"name": "Langages de programmation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": ["HTML", "CSS", "Tailwind CSS", "React.js/Next.js"],
|
||||||
|
"name": "Front-end"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": ["Laravel", "Node.js", "Fastify", "PostgreSQL"],
|
||||||
|
"name": "Back-end"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"GNU/Linux",
|
||||||
|
"Ubuntu",
|
||||||
|
"Visual Studio Code",
|
||||||
|
"Git",
|
||||||
|
"Docker"
|
||||||
|
],
|
||||||
|
"name": "Logiciels et outils"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": ["Permis B", "Anglais"],
|
||||||
|
"name": "Autres"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,24 +1,21 @@
|
|||||||
{
|
{
|
||||||
|
"extends": "@tsconfig/strictest/tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"checkJs": true,
|
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"strict": true,
|
|
||||||
"types": ["cypress"],
|
"types": ["cypress"],
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"esModuleInterop": true,
|
"lib": ["dom", "dom.iterable", "ESNext"],
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"incremental": true
|
"incremental": true,
|
||||||
|
"exactOptionalPropertyTypes": false
|
||||||
},
|
},
|
||||||
"exclude": ["dist", ".next", "out", "next.config.js"],
|
"exclude": ["dist", ".next", "out", "next.config.js"],
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||||
|
@ -38,6 +38,9 @@ export const getPosts = async (): Promise<PostMetadata[]> => {
|
|||||||
const postsWithTime = await Promise.all(
|
const postsWithTime = await Promise.all(
|
||||||
posts.map(async (postFilename) => {
|
posts.map(async (postFilename) => {
|
||||||
const [slug, extension] = postFilename.split('.')
|
const [slug, extension] = postFilename.split('.')
|
||||||
|
if (slug == null || extension == null) {
|
||||||
|
throw new Error('Invalid postFilename.')
|
||||||
|
}
|
||||||
const blogPostPath = path.join(POSTS_PATH, `${slug}.${extension}`)
|
const blogPostPath = path.join(POSTS_PATH, `${slug}.${extension}`)
|
||||||
const blogPostContent = await fs.promises.readFile(blogPostPath, {
|
const blogPostContent = await fs.promises.readFile(blogPostPath, {
|
||||||
encoding: 'utf8'
|
encoding: 'utf8'
|
||||||
|
Reference in New Issue
Block a user