mirror of
https://github.com/theoludwig/theoludwig.git
synced 2025-05-29 22:37:44 +02:00
Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
b25451e631 | |||
042a861f58 | |||
d76db36dbc | |||
99d9dcf334 | |||
ece5ded1b4 | |||
1514600998 |
@ -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.12.1 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.12.1 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.12.1 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"]
|
||||||
|
18
README.md
18
README.md
@ -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",
|
|
||||||
"Open-Source enthusiast",
|
|
||||||
"Passionate about High-Tech"
|
|
||||||
],
|
|
||||||
"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
|
||||||
@ -71,40 +75,44 @@
|
|||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<section class="section-separated">
|
<section class="section-separated">
|
||||||
<div class="detail" id="work-experience">
|
<div class="detail" id="education">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<img src="./images/building-columns.svg" alt="work" />
|
<img src="./images/graduation-cap.svg" alt="graduation" />
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<h4 class="title text-uppercase">Expériences</h4>
|
<h4 class="title text-uppercase">Formations</h4>
|
||||||
<ul class="list-unstyled clear-margin">
|
<div class="content">
|
||||||
<% locals.work.forEach((experience) => { %>
|
<ul class="list-unstyled clear-margin">
|
||||||
<li class="card card-nested clearfix">
|
<% locals.education.forEach((degree) => { %>
|
||||||
<div class="content">
|
<li class="card card-nested">
|
||||||
<p class="clear-margin relative">
|
<div class="content">
|
||||||
<a href="<%= experience.website %>">
|
<p class="clear-margin relative">
|
||||||
<strong><%= experience.name %></strong>
|
<strong><%= degree.studyType %></strong>
|
||||||
</a>
|
</p>
|
||||||
</p>
|
<p class="clear-margin relative">
|
||||||
<p class="clear-margin relative">
|
<strong><%= degree.score %></strong>
|
||||||
<strong><%- experience.position %></strong>
|
</p>
|
||||||
</p>
|
<p class="text-muted clear-margin">
|
||||||
<p class="text-muted">
|
<%= degree.institution %>
|
||||||
<small>
|
</p>
|
||||||
<span class="space-right">
|
<p class="text-muted clear-margin">
|
||||||
<%= date.format(new Date(experience.startDate),
|
<small>
|
||||||
'DD/MM/YYYY') %> - <%= date.format(new
|
<%= degree.startDate %> <%= degree.endDate !=
|
||||||
Date(experience.endDate), 'DD/MM/YYYY') %>
|
null ? " - " + degree.endDate : "" %>
|
||||||
</span>
|
</small>
|
||||||
</small>
|
</p>
|
||||||
</p>
|
<% if (degree.courses != null) { %>
|
||||||
<div class="experience-description">
|
<ul class="education-courses">
|
||||||
<p><%- experience.summary %></p>
|
<% degree.courses.forEach((course) => { %>
|
||||||
|
<li><%= course %></li>
|
||||||
|
<% }) %>
|
||||||
|
</ul>
|
||||||
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</li>
|
||||||
</li>
|
<% }) %>
|
||||||
<% }) %>
|
</ul>
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -137,37 +145,43 @@
|
|||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<section class="section-separated">
|
<section class="section-separated">
|
||||||
<div class="detail" id="education">
|
<div class="detail" id="work-experience">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<img src="./images/graduation-cap.svg" alt="graduation" />
|
<img src="./images/building-columns.svg" alt="work" />
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<h4 class="title text-uppercase">Éducation</h4>
|
<h4 class="title text-uppercase">Expériences</h4>
|
||||||
<div class="content">
|
<ul class="list-unstyled clear-margin">
|
||||||
<ul class="list-unstyled clear-margin">
|
<% locals.work.filter((experience) =>
|
||||||
<% locals.education.forEach((degree) => { %>
|
experience.description == null).forEach((experience) => {
|
||||||
<li class="card card-nested">
|
%>
|
||||||
<div class="content">
|
<li class="card card-nested clearfix">
|
||||||
<p class="clear-margin relative">
|
<div class="content">
|
||||||
<strong><%= degree.studyType %></strong>
|
<p class="clear-margin relative">
|
||||||
</p>
|
<a href="<%= experience.website %>">
|
||||||
<p class="clear-margin relative">
|
<strong><%= experience.name %></strong>
|
||||||
<strong><%= degree.score %></strong>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p class="text-muted clear-margin">
|
<p class="clear-margin relative">
|
||||||
<%= degree.institution %>
|
<strong><%- experience.position %></strong>
|
||||||
</p>
|
</p>
|
||||||
<p class="text-muted clear-margin">
|
<p class="text-muted">
|
||||||
<small>
|
<small>
|
||||||
<%= degree.startDate %> <%= degree.endDate !=
|
<span class="space-right">
|
||||||
null ? " - " + degree.endDate : "" %>
|
<%= date.format(new Date(experience.startDate),
|
||||||
</small>
|
'DD/MM/YYYY') %> - <%= date.format(new
|
||||||
</p>
|
Date(experience.endDate), 'DD/MM/YYYY') %> (<%=
|
||||||
|
experience.duration %>)
|
||||||
|
</span>
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
|
<div class="experience-description">
|
||||||
|
<p><%- experience.summary %></p>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</div>
|
||||||
<% }) %>
|
</li>
|
||||||
</ul>
|
<% }) %>
|
||||||
</div>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -185,6 +199,38 @@
|
|||||||
</li>
|
</li>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<ul class="list-unstyled clear-margin">
|
||||||
|
<% locals.work.filter((experience) =>
|
||||||
|
experience.description != null).forEach((experience) =>
|
||||||
|
{ %>
|
||||||
|
<li class="card card-nested clearfix">
|
||||||
|
<div class="content">
|
||||||
|
<p class="clear-margin relative">
|
||||||
|
<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>
|
||||||
|
</li>
|
||||||
|
<% }) %>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
1753
jsonresume-theme-custom/package-lock.json
generated
1753
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.9",
|
"@types/node": "18.11.18",
|
||||||
"date-and-time": "2.4.1",
|
"date-and-time": "2.4.1",
|
||||||
"vite": "3.2.4",
|
"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()
|
@ -226,5 +226,4 @@ h5 {
|
|||||||
}
|
}
|
||||||
.section-separated {
|
.section-separated {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: space-evenly;
|
|
||||||
}
|
}
|
||||||
|
@ -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: './'
|
||||||
|
19497
package-lock.json
generated
19497
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
64
package.json
64
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "divlo",
|
"name": "divlo",
|
||||||
"version": "2.5.2",
|
"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,7 +26,7 @@
|
|||||||
"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"
|
||||||
@ -37,13 +37,13 @@
|
|||||||
"@fortawesome/free-brands-svg-icons": "6.2.1",
|
"@fortawesome/free-brands-svg-icons": "6.2.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "6.2.1",
|
"@fortawesome/free-solid-svg-icons": "6.2.1",
|
||||||
"@fortawesome/react-fontawesome": "0.2.0",
|
"@fortawesome/react-fontawesome": "0.2.0",
|
||||||
"@giscus/react": "2.2.3",
|
"@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.4",
|
"next": "13.1.1",
|
||||||
"next-mdx-remote": "4.2.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",
|
||||||
@ -53,46 +53,48 @@
|
|||||||
"rehype-raw": "6.1.1",
|
"rehype-raw": "6.1.1",
|
||||||
"rehype-slug": "5.1.0",
|
"rehype-slug": "5.1.0",
|
||||||
"remark-gfm": "3.0.1",
|
"remark-gfm": "3.0.1",
|
||||||
"sharp": "0.31.2",
|
"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.2.0",
|
"@commitlint/cli": "17.4.1",
|
||||||
"@commitlint/config-conventional": "17.2.0",
|
"@commitlint/config-conventional": "17.4.0",
|
||||||
"@lhci/cli": "0.10.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.8",
|
"@tailwindcss/typography": "0.5.9",
|
||||||
"@types/node": "18.11.9",
|
"@tsconfig/strictest": "1.0.2",
|
||||||
"@types/react": "18.0.25",
|
"@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.43.0",
|
"@typescript-eslint/eslint-plugin": "5.48.1",
|
||||||
"autoprefixer": "10.4.13",
|
"autoprefixer": "10.4.13",
|
||||||
"cypress": "11.1.0",
|
"cypress": "12.3.0",
|
||||||
"editorconfig-checker": "4.0.2",
|
"editorconfig-checker": "4.0.2",
|
||||||
"eslint": "8.28.0",
|
"eslint": "8.31.0",
|
||||||
"eslint-config-conventions": "5.0.0",
|
"eslint-config-conventions": "6.0.0",
|
||||||
"eslint-config-next": "13.0.4",
|
"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.2",
|
"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.19",
|
"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.4",
|
"tailwindcss": "3.2.4",
|
||||||
"typescript": "4.9.3",
|
"typescript": "4.9.4",
|
||||||
"vercel": "28.5.5"
|
"vercel": "28.11.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,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)) {
|
||||||
|
@ -5,43 +5,69 @@
|
|||||||
},
|
},
|
||||||
"basics": {
|
"basics": {
|
||||||
"name": "Théo LUDWIG",
|
"name": "Théo LUDWIG",
|
||||||
"label": "Développeur Full Stack • Enthousiaste de l'Open-Source",
|
"label": "Développeur Full Stack • Étudiant",
|
||||||
"image": "https://divlo.fr/images/logo_orange.png",
|
"image": "https://divlo.fr/images/logo_orange.png",
|
||||||
"email": "contact@divlo.fr",
|
"email": "contact@divlo.fr",
|
||||||
"location": {},
|
"age": "31/03/2003",
|
||||||
|
"location": {
|
||||||
|
"address": "Alsace, France"
|
||||||
|
},
|
||||||
"url": "https://divlo.fr",
|
"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 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": [
|
"education": [
|
||||||
{
|
{
|
||||||
"startDate": "2022",
|
"startDate": "2022",
|
||||||
"studyType": "Diplôme du Bachelor Universitaire de Technologie (BUT) Informatique",
|
"endDate": "2023",
|
||||||
|
"studyType": "Bachelor Universitaire de Technologie (BUT) Informatique",
|
||||||
"institution": "IUT Robert Schuman à Illkirch-Graffenstaden",
|
"institution": "IUT Robert Schuman à Illkirch-Graffenstaden",
|
||||||
"score": "2ème année"
|
"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",
|
"startDate": "2019",
|
||||||
"endDate": "2021",
|
"endDate": "2021",
|
||||||
"studyType": "Diplôme du Baccalauréat Général (Mathématiques et Numériques Sciences Informatiques)",
|
"studyType": "Baccalauréat Général (Mathématiques et Numériques Sciences Informatiques)",
|
||||||
"institution": "Lycée Heinrich Nessel à Haguenau",
|
"institution": "Lycée Heinrich Nessel à Haguenau",
|
||||||
"score": "Mention Assez Bien"
|
"score": "Mention Assez Bien"
|
||||||
},
|
|
||||||
{
|
|
||||||
"startDate": "2014",
|
|
||||||
"endDate": "2018",
|
|
||||||
"studyType": "Diplôme national du brevet",
|
|
||||||
"institution": "Collège Gustave Doré à Hochfelden",
|
|
||||||
"score": "Mention Bien"
|
|
||||||
}
|
}
|
||||||
|
// {
|
||||||
|
// "startDate": "2014",
|
||||||
|
// "endDate": "2018",
|
||||||
|
// "studyType": "Diplôme national du brevet",
|
||||||
|
// "institution": "Collège Gustave Doré à Hochfelden",
|
||||||
|
// "score": "Mention Bien"
|
||||||
|
// }
|
||||||
],
|
],
|
||||||
"work": [
|
"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 /> Classé n°1 en France sur le Défi de l'entreprise <a href=\"https://www.nuitdelinfo.com/inscription/defis/300\">ToolPad</a>.",
|
"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/",
|
"website": "https://www.nuitdelinfo.com/",
|
||||||
"name": "La Nuit de l'info 2021",
|
"name": "La Nuit de l'info 2021",
|
||||||
"position": "Participation en équipe de 5 personnes",
|
"position": "Participation en équipe de 5 personnes",
|
||||||
"startDate": "2021-12-02",
|
"startDate": "2021-12-02",
|
||||||
"endDate": "2021-12-03"
|
"endDate": "2021-12-03",
|
||||||
|
"duration": "1 semaine"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"summary": "Agent administratif - Numérisation et archivage des plans électriques initialement sous format papier calque.",
|
"summary": "Agent administratif - Numérisation et archivage des plans électriques initialement sous format papier calque.",
|
||||||
@ -50,16 +76,19 @@
|
|||||||
"location": "5 Rue André Marie Ampère, 67450 Mundolsheim",
|
"location": "5 Rue André Marie Ampère, 67450 Mundolsheim",
|
||||||
"position": "Emploi d'été en qualité d'agent administratif",
|
"position": "Emploi d'été en qualité d'agent administratif",
|
||||||
"startDate": "2021-07-07",
|
"startDate": "2021-07-07",
|
||||||
"endDate": "2021-07-30"
|
"endDate": "2021-07-30",
|
||||||
|
"duration": "1 mois"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"description": "interests",
|
||||||
"summary": "Hackathon développement d'une landing page et web scraping.",
|
"summary": "Hackathon développement d'une landing page et web scraping.",
|
||||||
"website": "https://www.wildcodeschool.fr/",
|
"website": "https://www.wildcodeschool.fr/",
|
||||||
"name": "Wild Code School",
|
"name": "Wild Code School",
|
||||||
"location": "32 Rue du Bass. d'Austerlitz, 67100 Strasbourg",
|
"location": "32 Rue du Bass. d'Austerlitz, 67100 Strasbourg",
|
||||||
"position": "Stage initiation métier développeur web",
|
"position": "Initiation métier développeur web",
|
||||||
"startDate": "2019-06-24",
|
"startDate": "2019-06-24",
|
||||||
"endDate": "2019-06-28"
|
"endDate": "2019-06-28",
|
||||||
|
"duration": "1 semaine"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"summary": "Développement d'un site web pour trouver un restaurant à la pause repas.",
|
"summary": "Développement d'un site web pour trouver un restaurant à la pause repas.",
|
||||||
@ -68,7 +97,8 @@
|
|||||||
"location": "16 Rue du Parc, 67205 Oberhausbergen",
|
"location": "16 Rue du Parc, 67205 Oberhausbergen",
|
||||||
"position": "Stage initiation métier développeur web",
|
"position": "Stage initiation métier développeur web",
|
||||||
"startDate": "2019-06-17",
|
"startDate": "2019-06-17",
|
||||||
"endDate": "2019-06-21"
|
"endDate": "2019-06-21",
|
||||||
|
"duration": "1 semaine"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"summary": "Apprentissage du métier \"Chargé de communication\" et des logiciels de graphisme tels que \"Adobe Photoshop\".",
|
"summary": "Apprentissage du métier \"Chargé de communication\" et des logiciels de graphisme tels que \"Adobe Photoshop\".",
|
||||||
@ -77,13 +107,11 @@
|
|||||||
"location": "26 Bd du Président-Wilson, 67000 Strasbourg",
|
"location": "26 Bd du Président-Wilson, 67000 Strasbourg",
|
||||||
"position": "Stage de découverte (3ème)",
|
"position": "Stage de découverte (3ème)",
|
||||||
"startDate": "2018-02-19",
|
"startDate": "2018-02-19",
|
||||||
"endDate": "2018-02-23"
|
"endDate": "2018-02-23",
|
||||||
|
"duration": "1 semaine"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"interests": [
|
"interests": [
|
||||||
{
|
|
||||||
"name": "Développeur Full Stack"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Enthousiaste de l'Open-Source"
|
"name": "Enthousiaste de l'Open-Source"
|
||||||
},
|
},
|
||||||
@ -93,11 +121,11 @@
|
|||||||
],
|
],
|
||||||
"skills": [
|
"skills": [
|
||||||
{
|
{
|
||||||
"keywords": ["JavaScript", "TypeScript", "Python", "C/C++", "PHP"],
|
"keywords": ["JavaScript/TypeScript", "Python", "C/C++", "PHP"],
|
||||||
"name": "Langages de programmation"
|
"name": "Langages de programmation"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"keywords": ["HTML", "CSS", "Tailwind CSS", "React.js (+ Next.js)"],
|
"keywords": ["HTML", "CSS", "Tailwind CSS", "React.js/Next.js"],
|
||||||
"name": "Front-end"
|
"name": "Front-end"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -109,10 +137,14 @@
|
|||||||
"GNU/Linux",
|
"GNU/Linux",
|
||||||
"Ubuntu",
|
"Ubuntu",
|
||||||
"Visual Studio Code",
|
"Visual Studio Code",
|
||||||
"git",
|
"Git",
|
||||||
"Docker"
|
"Docker"
|
||||||
],
|
],
|
||||||
"name": "Logiciels et outils"
|
"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