1
1
mirror of https://github.com/theoludwig/theoludwig.git synced 2024-12-08 00:44:30 +01:00

feat: components structure Curriculum Vitae

This commit is contained in:
Théo LUDWIG 2024-07-31 22:27:51 +02:00
parent b4611e4a7f
commit a596d1c443
Signed by: theoludwig
GPG Key ID: ADFE5A563D718F3B
20 changed files with 891 additions and 38 deletions

View File

@ -1,4 +1,5 @@
import type { LocaleProps } from "@repo/i18n/config" import type { LocaleProps } from "@repo/i18n/config"
import { CurriculumVitae } from "@repo/ui/CurriculumVitae"
import { unstable_setRequestLocale } from "next-intl/server" import { unstable_setRequestLocale } from "next-intl/server"
interface CurriculumVitaeProps extends LocaleProps {} interface CurriculumVitaeProps extends LocaleProps {}
@ -9,11 +10,7 @@ const CurriculumVitaePage: React.FC<CurriculumVitaeProps> = (props) => {
// Enable static rendering // Enable static rendering
unstable_setRequestLocale(params.locale) unstable_setRequestLocale(params.locale)
return ( return <CurriculumVitae />
<main>
<h1>CurriculumVitae</h1>
</main>
)
} }
export default CurriculumVitaePage export default CurriculumVitaePage

View File

@ -160,3 +160,227 @@ code .line:last-child {
white-space: normal !important; white-space: normal !important;
width: 100% !important; width: 100% !important;
} }
.container-fluid {
padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;
}
.curriculum-vitae {
background: #f0f0f0;
color: #333;
line-height: 1.42857143;
font-size: 14px;
hr {
margin-top: 15px;
margin-bottom: 15px;
border: 0;
border-top: 1px solid #eee;
}
p {
margin: 0;
}
strong {
font-weight: 600;
}
a {
color: #337ab7;
text-decoration: none;
}
a:focus,
a:hover {
color: #23527c;
text-decoration: underline;
}
.link-disguise {
color: inherit;
}
.link-disguise:hover {
color: inherit;
}
.h1,
.h2,
.h3,
h1,
h2,
h3 {
margin-top: 20px;
margin-bottom: 10px;
}
.h4,
.h5,
.h6,
h4,
h5,
h6 {
margin-top: 10px;
margin-bottom: 10px;
}
.h1,
.h2,
.h3,
.h4,
.h5,
.h6,
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: inherit;
font-weight: 500;
line-height: 1.1;
color: inherit;
}
.h3,
h3 {
font-size: 24px;
}
.h4,
h4 {
font-size: 18px;
}
.h5,
h5 {
font-size: 14px;
}
.row {
margin-right: -15px;
margin-left: -15px;
}
.clear-margin {
margin: 0;
}
.relative {
position: relative;
}
.center-block {
display: block;
margin-right: auto;
margin-left: auto;
}
.text-muted {
color: #777;
}
.text-uppercase {
text-transform: uppercase;
}
.list-unstyled {
padding-left: 0;
list-style: none;
}
.main {
padding: 5px;
}
.title {
font-weight: 600;
}
.profile-card-wrapper {
position: relative;
}
.card-wrapper {
float: none !important;
padding: 5px;
}
.profile-card-wrapper .profile-card {
padding: 10px;
}
.card {
background: white;
border-radius: 3px;
padding: 10px 0;
}
.profile-pic {
padding: 10px 0;
}
.profile-pic img {
width: 100px;
height: 100px;
border-radius: 50%;
vertical-align: middle;
border: 0;
}
.contact-details {
display: flex;
justify-content: center;
}
.contact-details .detail {
position: relative;
min-height: 1px;
padding: 10px;
}
.social-links {
line-height: 2.5;
}
.experience-description {
margin-top: 10px;
}
.background-details .detail {
display: table;
}
.background-details .detail .icon,
.background-details .detail .info {
display: table-cell;
}
.background-details .detail .icon {
color: #707070;
}
.background-details .detail .icon {
min-width: 45px;
max-width: 45px;
text-align: center;
}
.icon img {
width: 20px;
height: 20px;
}
.background-details .detail .mobile-title {
display: none;
}
.card-nested {
min-height: 0;
}
.card-skills {
position: relative;
}
.labels {
line-height: 2;
}
.space-top {
margin-top: 10px;
}
.label {
display: inline;
padding: 0.2em 0.6em 0.3em;
font-size: 75%;
font-weight: 600;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: 0.25em;
}
.label-keyword {
display: inline-block;
font-size: 0.9em;
padding: 5px;
border: 1px solid #357ebd;
margin-right: 5px;
}
.label-keyword p {
margin: 0;
}
.section-separated {
display: flex;
}
}

View File

@ -0,0 +1,181 @@
{
"$schema": "https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json",
"basics": {
"name": "Théo LUDWIG",
"label": "Développeur Full Stack • Étudiant",
"image": "https://theoludwig.fr/images/logo_background.png",
"email": "contact@theoludwig.fr",
"age": "31/03/2003",
"location": {
"address": "Alsace, France",
},
"url": "https://theoludwig.fr",
"summary": "Je me demande constamment comment améliorer notre présent, afin de rendre notre futur meilleur, particulièrement grâce aux progrès de l'informatique. <br /> Ma priorité réside dans la création d'expériences utilisateurs (UX) intuitives, répondant aux besoins des utilisateurs de la manière la plus efficace que possible.",
},
"education": [
{
"startDate": "2023",
"endDate": "2024",
"studyType": "Bachelor Universitaire de Technologie (BUT) Informatique",
"institution": "IUT Robert Schuman à Illkirch-Graffenstaden",
"score": "3ème année",
"courses": [
"Développement Web en Node.js et React.js",
"Intégration/Déploiement Continue et Docker",
"Complexité Algorithmique Théorique et Pratique en C++",
// "Projet développement LLM (Large Language Model) et NLP (Natural Language Processing)",
"Base de données NoSQL (Redis, MongoDB, Cassandra)",
],
},
{
"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",
"Qualité de développement et Tests automatisés",
"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",
],
},
{
"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": [
{
"summary": "Développement de WebSurg, une université virtuelle consacrée à la formation médico-chirurgicale, en React.js/Next.js et API Platform avec Symfony.",
"website": "https://ircad.fr/",
"name": "IRCAD",
"location": "1 Place de l'Hôpital, 67000 Strasbourg",
"position": "Alternant Développeur Web Full Stack",
"startDate": "2023-08-28",
"endDate": "2024-09-02",
"duration": "1 an",
},
{
"summary": "Développement d'un outil GED (Gestion Électronique de Documents) en React.js, Laravel et GraphQL.",
"website": "https://numerize.com/",
"name": "Numerize",
"location": "4 Rue Sophie Germain, 67720 Hœrdt",
"position": "Stagiaire Développeur Web Full Stack",
"startDate": "2023-04-11",
"endDate": "2023-07-26",
"duration": "4 mois",
},
// {
// "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"
// },
{
"summary": "Développement d'un site web pour trouver un restaurant à la pause repas.",
"website": "https://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",
},
{
"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://toolpad.fr/\">ToolPad</a>.",
"website": "https://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",
},
{
"description": "interests",
"summary": "Hackathon développement d'une landing page et web scraping.",
"website": "https://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": "Apprentissage du métier \"Chargé de communication\" et des logiciels de graphisme tels que \"Adobe Photoshop\".",
// "website": "https://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": "Frontend",
},
{
"keywords": ["Laravel", "Node.js", "Fastify", "PostgreSQL"],
"name": "Backend",
},
{
"keywords": [
"GNU/Linux",
"Arch Linux",
"Visual Studio Code",
"Git",
"Docker",
],
"name": "Logiciels et outils",
},
{
"keywords": ["Permis B", "Anglais"],
"name": "Autres",
},
],
}

View File

@ -7,6 +7,9 @@
"en-US": "English", "en-US": "English",
"fr-FR": "French" "fr-FR": "French"
}, },
"common": {
"others": "Others"
},
"footer": { "footer": {
"all-rights-reserved": "All rights reserved" "all-rights-reserved": "All rights reserved"
}, },
@ -54,7 +57,8 @@
"programming-languages": "Programming languages", "programming-languages": "Programming languages",
"frontend": "Frontend", "frontend": "Frontend",
"backend": "Backend", "backend": "Backend",
"software-tools": "Software and tools" "software-tools": "Software and tools",
"driving-license": "Permis B"
}, },
"portfolio": { "portfolio": {
"title": "Portfolio", "title": "Portfolio",
@ -71,5 +75,110 @@
"title": "Open-Source", "title": "Open-Source",
"description": "Most famous open source projects I contributed to." "description": "Most famous open source projects I contributed to."
} }
},
"curriculum-vitae": {
"description": "Développeur Full Stack • Étudiant",
"about": {
"title": "À propos",
"description": "Je me demande constamment comment améliorer notre présent, afin de rendre notre futur meilleur, particulièrement grâce aux progrès de l'informatique. <br></br> Ma priorité réside dans la création d'expériences utilisateurs (UX) intuitives, répondant aux besoins des utilisateurs de la manière la plus efficace que possible."
},
"education": {
"title": "Formations",
"iut": {
"study-type": "Bachelor Universitaire de Technologie (BUT) Informatique",
"institution": "IUT Robert Schuman à Illkirch-Graffenstaden",
"years": {
"2023-2024": {
"title": "2023 - 2024",
"description": "3ème année",
"courses": {
"web": "Développement Web en Node.js et React.js",
"ci-cd": "Intégration/Déploiement Continue et Docker",
"complexity-algorithms": "Complexité Algorithmique Théorique et Pratique en C++",
"no-sql": "Base de données NoSQL (Redis, MongoDB, Cassandra)"
}
},
"2022-2023": {
"title": "2022 - 2023",
"description": "2ème année",
"courses": {
"web": "Développement Web avec le framework Laravel en PHP",
"tests": "Qualité de développement et Tests automatisés",
"clean-code": "Patrons et Principes de conceptions (Code maintenable et réutilisable) en UML",
"systems-c": "Programmation systèmes en C (Multi-Thread, Serveur/Client UDP/TCP)",
"sql-security": "Sécurisation des accès à la base de données et PL/SQL"
}
},
"2021-2022": {
"title": "2021 - 2022",
"description": "1ère année",
"courses": {
"java": "Développement Orientée Objet en Java",
"systems-c": "Programmation systèmes en C (Allocation mémoire, Pointeurs, Structures)",
"windows-forms": "Développement d'application Windows Forms (.NET Framework) en C#",
"sql": "Base de données relationnelles et langage SQL"
}
}
}
},
"lycee": {
"study-type": "Baccalauréat Général (Mathématiques et Numériques Sciences Informatiques)",
"institution": "Lycée Heinrich Nessel à Haguenau",
"score": "Mention Assez Bien",
"years": {
"2019-2021": {
"title": "2019 - 2021"
}
}
}
},
"work": {
"title": "Expériences",
"ircad": {
"summary": "Développement de WebSurg, une université virtuelle consacrée à la formation médico-chirurgicale, en React.js/Next.js et API Platform avec Symfony.",
"website": "https://ircad.fr/",
"name": "IRCAD",
"location": "1 Place de l'Hôpital, 67000 Strasbourg",
"position": "Alternant Développeur Web Full Stack",
"startDate": "2023-08-28",
"endDate": "2024-09-02",
"duration": "1 an"
},
"numerize": {
"summary": "Développement d'un outil GED (Gestion Électronique de Documents) en React.js, Laravel et GraphQL.",
"website": "https://numerize.com/",
"name": "Numerize",
"location": "4 Rue Sophie Germain, 67720 Hœrdt",
"position": "Stagiaire Développeur Web Full Stack",
"startDate": "2023-04-11",
"endDate": "2023-07-26",
"duration": "4 mois"
}
},
"interests-work": {
"nuit-info-2021": {
"summary": "Développement site web en React.js et Strapi.<br></br> Classé n°1 en France sur le Défi de l'entreprise <toolpad-link>ToolPad</toolpad-link>.",
"website": "https://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"
},
"wild-code-school": {
"summary": "Hackathon développement d'une landing page et web scraping.",
"website": "https://wildcodeschool.fr/",
"name": "Wild Code School",
"location": "32 Rue du Bassin d'Austerlitz, 67100 Strasbourg",
"position": "Initiation métier Développeur web",
"startDate": "2019-06-24",
"endDate": "2019-06-28",
"duration": "1 semaine"
}
},
"interests": {
"open-source": "Enthousiaste de l'Open-Source",
"high-tech": "Passionné de High-Tech"
}
} }
} }

View File

@ -7,6 +7,9 @@
"en-US": "Anglais", "en-US": "Anglais",
"fr-FR": "Français" "fr-FR": "Français"
}, },
"common": {
"others": "Autres"
},
"footer": { "footer": {
"all-rights-reserved": "Tous droits réservés" "all-rights-reserved": "Tous droits réservés"
}, },
@ -54,7 +57,8 @@
"programming-languages": "Langages de programmation", "programming-languages": "Langages de programmation",
"frontend": "Frontend", "frontend": "Frontend",
"backend": "Backend", "backend": "Backend",
"software-tools": "Logiciels et outils" "software-tools": "Logiciels et outils",
"driving-license": "Permis B"
}, },
"portfolio": { "portfolio": {
"title": "Portfolio", "title": "Portfolio",
@ -71,5 +75,110 @@
"title": "Open-Source", "title": "Open-Source",
"description": "Projets open source les plus célèbres auxquels j'ai contribué." "description": "Projets open source les plus célèbres auxquels j'ai contribué."
} }
},
"curriculum-vitae": {
"description": "Développeur Full Stack • Étudiant",
"about": {
"title": "À propos",
"description": "Je me demande constamment comment améliorer notre présent, afin de rendre notre futur meilleur, particulièrement grâce aux progrès de l'informatique. <br></br> Ma priorité réside dans la création d'expériences utilisateurs (UX) intuitives, répondant aux besoins des utilisateurs de la manière la plus efficace que possible."
},
"education": {
"title": "Formations",
"iut": {
"study-type": "Bachelor Universitaire de Technologie (BUT) Informatique",
"institution": "IUT Robert Schuman à Illkirch-Graffenstaden",
"years": {
"2023-2024": {
"title": "2023 - 2024",
"description": "3ème année",
"courses": {
"web": "Développement Web en Node.js et React.js",
"ci-cd": "Intégration/Déploiement Continue et Docker",
"complexity-algorithms": "Complexité Algorithmique Théorique et Pratique en C++",
"no-sql": "Base de données NoSQL (Redis, MongoDB, Cassandra)"
}
},
"2022-2023": {
"title": "2022 - 2023",
"description": "2ème année",
"courses": {
"web": "Développement Web avec le framework Laravel en PHP",
"tests": "Qualité de développement et Tests automatisés",
"clean-code": "Patrons et Principes de conceptions (Code maintenable et réutilisable) en UML",
"systems-c": "Programmation systèmes en C (Multi-Thread, Serveur/Client UDP/TCP)",
"sql-security": "Sécurisation des accès à la base de données et PL/SQL"
}
},
"2021-2022": {
"title": "2021 - 2022",
"description": "1ère année",
"courses": {
"java": "Développement Orientée Objet en Java",
"systems-c": "Programmation systèmes en C (Allocation mémoire, Pointeurs, Structures)",
"windows-forms": "Développement d'application Windows Forms (.NET Framework) en C#",
"sql": "Base de données relationnelles et langage SQL"
}
}
}
},
"lycee": {
"study-type": "Baccalauréat Général (Mathématiques et Numériques Sciences Informatiques)",
"institution": "Lycée Heinrich Nessel à Haguenau",
"score": "Mention Assez Bien",
"years": {
"2019-2021": {
"title": "2019 - 2021"
}
}
}
},
"work": {
"title": "Expériences",
"ircad": {
"summary": "Développement de WebSurg, une université virtuelle consacrée à la formation médico-chirurgicale, en React.js/Next.js et API Platform avec Symfony.",
"website": "https://ircad.fr/",
"name": "IRCAD",
"location": "1 Place de l'Hôpital, 67000 Strasbourg",
"position": "Alternant Développeur Web Full Stack",
"startDate": "2023-08-28",
"endDate": "2024-09-02",
"duration": "1 an"
},
"numerize": {
"summary": "Développement d'un outil GED (Gestion Électronique de Documents) en React.js, Laravel et GraphQL.",
"website": "https://numerize.com/",
"name": "Numerize",
"location": "4 Rue Sophie Germain, 67720 Hœrdt",
"position": "Stagiaire Développeur Web Full Stack",
"startDate": "2023-04-11",
"endDate": "2023-07-26",
"duration": "4 mois"
}
},
"interests-work": {
"nuit-info-2021": {
"summary": "Développement site web en React.js et Strapi. <br></br> Classé n°1 en France sur le Défi de l'entreprise <toolpad-link>ToolPad</toolpad-link>.",
"website": "https://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"
},
"wild-code-school": {
"summary": "Hackathon développement d'une landing page et web scraping.",
"website": "https://wildcodeschool.fr/",
"name": "Wild Code School",
"location": "32 Rue du Bassin d'Austerlitz, 67100 Strasbourg",
"position": "Initiation métier Développeur web",
"startDate": "2019-06-24",
"endDate": "2019-06-28",
"duration": "1 semaine"
}
},
"interests": {
"open-source": "Enthousiaste de l'Open-Source",
"high-tech": "Passionné de High-Tech"
}
} }
} }

View File

@ -4,6 +4,7 @@
"private": true, "private": true,
"type": "module", "type": "module",
"exports": { "exports": {
"./CurriculumVitae": "./src/CurriculumVitae/CurriculumVitae.tsx",
"./Design/Button": "./src/Design/Button/Button.tsx", "./Design/Button": "./src/Design/Button/Button.tsx",
"./Design/Link": "./src/Design/Link/Link.tsx", "./Design/Link": "./src/Design/Link/Link.tsx",
"./Design/Spinner": "./src/Design/Spinner/Spinner.tsx", "./Design/Spinner": "./src/Design/Spinner/Spinner.tsx",

View File

@ -0,0 +1,16 @@
import type { Meta, StoryObj } from "@storybook/react"
import { CurriculumVitae as CurriculumVitaeComponent } from "./CurriculumVitae"
const meta = {
title: "Curriculum Vitae/CurriculumVitae",
component: CurriculumVitaeComponent,
} satisfies Meta<typeof CurriculumVitaeComponent>
export default meta
type Story = StoryObj<typeof meta>
export const CurriculumVitae: Story = {
args: {},
}

View File

@ -0,0 +1,40 @@
import { CurriculumVitaeAbout } from "./CurriculumVitaeAbout"
import { CurriculumVitaeEducation } from "./CurriculumVitaeEducation"
import { CurriculumVitaeInterests } from "./CurriculumVitaeInterests"
import { CurriculumVitaeProfile } from "./CurriculumVitaeProfile"
import { CurriculumVitaeSkills } from "./CurriculumVitaeSkills"
import { CurriculumVitaeWork } from "./CurriculumVitaeWork"
export interface CurriculumVitaeProps {}
export const CurriculumVitae: React.FC<CurriculumVitaeProps> = () => {
return (
<main className="curriculum-vitae container-fluid">
<div className="row main clearfix">
<section className="col-md-3 card-wrapper profile-card-wrapper affix">
<CurriculumVitaeProfile />
<div className="card background-card">
<div className="background-details">
<CurriculumVitaeAbout />
<hr />
<section className="section-separated">
<CurriculumVitaeEducation />
<CurriculumVitaeSkills />
</section>
<hr />
<section className="section-separated">
<CurriculumVitaeWork />
<CurriculumVitaeInterests />
</section>
</div>
</div>
</section>
</div>
</main>
)
}

View File

@ -0,0 +1,19 @@
import { useTranslations } from "next-intl"
import { FaUser } from "react-icons/fa"
import { CurriculumVitaeSection } from "./CurriculumVitaeSection"
export interface CurriculumVitaeAboutProps {}
export const CurriculumVitaeAbout: React.FC<CurriculumVitaeAboutProps> = () => {
const t = useTranslations()
return (
<CurriculumVitaeSection
id="about"
title={t("curriculum-vitae.about.title")}
icon={<FaUser size={24} />}
>
<p>{t.rich("curriculum-vitae.about.description")}</p>
</CurriculumVitaeSection>
)
}

View File

@ -0,0 +1,21 @@
import { useTranslations } from "next-intl"
import { FaGraduationCap } from "react-icons/fa"
import { CurriculumVitaeSection } from "./CurriculumVitaeSection"
export interface CurriculumVitaeEducationProps {}
export const CurriculumVitaeEducation: React.FC<
CurriculumVitaeEducationProps
> = () => {
const t = useTranslations()
return (
<CurriculumVitaeSection
id="education"
title={t("curriculum-vitae.education.title")}
icon={<FaGraduationCap size={24} />}
>
<p>Test</p>
</CurriculumVitaeSection>
)
}

View File

@ -0,0 +1,21 @@
import { useTranslations } from "next-intl"
import { FaHeart } from "react-icons/fa"
import { CurriculumVitaeSection } from "./CurriculumVitaeSection"
export interface CurriculumVitaeInterestsProps {}
export const CurriculumVitaeInterests: React.FC<
CurriculumVitaeInterestsProps
> = () => {
const t = useTranslations()
return (
<CurriculumVitaeSection
id="interests"
title={t("home.interests.title")}
icon={<FaHeart size={24} />}
>
<p>Test</p>
</CurriculumVitaeSection>
)
}

View File

@ -0,0 +1,55 @@
import { Link } from "@repo/i18n/navigation"
import { useTranslations } from "next-intl"
import Image from "next/image"
import { BirthDate } from "../Home/About/AboutList/BirthDate"
export interface CurriculumVitaeProfileProps {}
export const CurriculumVitaeProfile: React.FC<
CurriculumVitaeProfileProps
> = () => {
const t = useTranslations()
return (
<div className="card profile-card">
<div className="profile-pic-container">
<div className="profile-pic">
<Image
className="media-object img-circle center-block"
alt={t("meta.title")}
src="/images/logo_background.webp"
width={800}
height={800}
/>
</div>
<div className="name-and-profession text-center">
<h3>
<strong>{t("meta.title")}</strong>
</h3>
<h5 className="text-muted">{t("curriculum-vitae.description")}</h5>
<h5 className="text-muted">
<BirthDate />
</h5>
<h5 className="text-muted">{t("home.about.nationality.value")}</h5>
</div>
</div>
<div className="contact-details clearfix">
<div className="detail">
<span className="info">
<a className="link-disguise" href="mailto:contact@theoludwig.fr">
contact@theoludwig.fr
</a>
</span>
</div>
<div className="detail">
<span className="info">
<Link className="link-disguise" href="/">
https://theoludwig.fr/
</Link>
</span>
</div>
</div>
<hr />
</div>
)
}

View File

@ -0,0 +1,23 @@
export interface CurriculumVitaeSectionProps extends React.PropsWithChildren {
id: string
icon: React.ReactNode
title: string
}
export const CurriculumVitaeSection: React.FC<CurriculumVitaeSectionProps> = (
props,
) => {
const { id, icon, title, children } = props
return (
<section className="detail" id={id}>
<div className="icon">{icon}</div>
<div className="info">
<h4 className="title text-uppercase">{title}</h4>
<div className="content">{children}</div>
</div>
</section>
)
}

View File

@ -0,0 +1,21 @@
import { useTranslations } from "next-intl"
import { FaToolbox } from "react-icons/fa"
import { CurriculumVitaeSection } from "./CurriculumVitaeSection"
export interface CurriculumVitaeSkillsProps {}
export const CurriculumVitaeSkills: React.FC<
CurriculumVitaeSkillsProps
> = () => {
const t = useTranslations()
return (
<CurriculumVitaeSection
id="skills"
title={t("home.skills.title")}
icon={<FaToolbox size={24} />}
>
<p>Test</p>
</CurriculumVitaeSection>
)
}

View File

@ -0,0 +1,19 @@
import { useTranslations } from "next-intl"
import { MdWork } from "react-icons/md"
import { CurriculumVitaeSection } from "./CurriculumVitaeSection"
export interface CurriculumVitaeWorkProps {}
export const CurriculumVitaeWork: React.FC<CurriculumVitaeWorkProps> = () => {
const t = useTranslations()
return (
<CurriculumVitaeSection
id="work-experience"
title={t("curriculum-vitae.work.title")}
icon={<MdWork size={24} />}
>
<p>Test</p>
</CurriculumVitaeSection>
)
}

View File

@ -1,6 +1,6 @@
import type { Meta, StoryObj } from "@storybook/react" import type { Meta, StoryObj } from "@storybook/react"
import { expect, fn, userEvent, within } from "@storybook/test" import { expect, fn, userEvent, within } from "@storybook/test"
import { FaCheck } from "react-icons/fa6" import { FaCheck } from "react-icons/fa"
import type { ButtonLinkProps } from "./Button" import type { ButtonLinkProps } from "./Button"
import { Button } from "./Button" import { Button } from "./Button"

View File

@ -1,6 +1,6 @@
export interface AboutItemProps { export interface AboutItemProps {
label: string label: string
value: string value: React.ReactNode
link?: string link?: string
} }

View File

@ -1,27 +0,0 @@
"use client"
import { BIRTH_DATE } from "@repo/utils/constants"
import { getAge, getISODate } from "@repo/utils/dates"
import { useTranslations } from "next-intl"
import { useMemo } from "react"
import { AboutItem } from "./AboutItem"
export interface AboutItemBirthDateProps {}
export const AboutItemBirthDate: React.FC<AboutItemBirthDateProps> = () => {
const t = useTranslations()
const age = useMemo(() => {
return getAge(BIRTH_DATE)
}, [])
return (
<AboutItem
label={t("home.about.birth-date.label")}
value={t("home.about.birth-date.value", {
age,
birthDate: getISODate(BIRTH_DATE),
})}
/>
)
}

View File

@ -1,6 +1,6 @@
import { useTranslations } from "next-intl" import { useTranslations } from "next-intl"
import { AboutItem } from "./AboutItem" import { AboutItem } from "./AboutItem"
import { AboutItemBirthDate } from "./AboutItemBirthDate" import { BirthDate } from "./BirthDate"
export interface AboutListProps {} export interface AboutListProps {}
@ -13,7 +13,10 @@ export const AboutList: React.FC<AboutListProps> = () => {
label={t("home.about.pronouns.label")} label={t("home.about.pronouns.label")}
value={t("home.about.pronouns.value")} value={t("home.about.pronouns.value")}
/> />
<AboutItemBirthDate /> <AboutItem
label={t("home.about.birth-date.label")}
value={<BirthDate />}
/>
<AboutItem <AboutItem
label={t("home.about.nationality.label")} label={t("home.about.nationality.label")}
value={t("home.about.nationality.value")} value={t("home.about.nationality.value")}

View File

@ -0,0 +1,21 @@
"use client"
import { BIRTH_DATE, BIRTH_DATE_STRING } from "@repo/utils/constants"
import { getAge } from "@repo/utils/dates"
import { useTranslations } from "next-intl"
import { useMemo } from "react"
export interface BirthDateProps {}
export const BirthDate: React.FC<BirthDateProps> = () => {
const t = useTranslations()
const age = useMemo(() => {
return getAge(BIRTH_DATE)
}, [])
return t("home.about.birth-date.value", {
age,
birthDate: BIRTH_DATE_STRING,
})
}