mirror of
https://github.com/theoludwig/theoludwig.git
synced 2024-11-05 04:51:30 +01:00
feat: components structure Curriculum Vitae
This commit is contained in:
parent
b4611e4a7f
commit
a596d1c443
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
@ -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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
|
16
packages/ui/src/CurriculumVitae/CurriculumVitae.stories.tsx
Normal file
16
packages/ui/src/CurriculumVitae/CurriculumVitae.stories.tsx
Normal 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: {},
|
||||||
|
}
|
40
packages/ui/src/CurriculumVitae/CurriculumVitae.tsx
Normal file
40
packages/ui/src/CurriculumVitae/CurriculumVitae.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
19
packages/ui/src/CurriculumVitae/CurriculumVitaeAbout.tsx
Normal file
19
packages/ui/src/CurriculumVitae/CurriculumVitaeAbout.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
21
packages/ui/src/CurriculumVitae/CurriculumVitaeEducation.tsx
Normal file
21
packages/ui/src/CurriculumVitae/CurriculumVitaeEducation.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
21
packages/ui/src/CurriculumVitae/CurriculumVitaeInterests.tsx
Normal file
21
packages/ui/src/CurriculumVitae/CurriculumVitaeInterests.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
55
packages/ui/src/CurriculumVitae/CurriculumVitaeProfile.tsx
Normal file
55
packages/ui/src/CurriculumVitae/CurriculumVitaeProfile.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
23
packages/ui/src/CurriculumVitae/CurriculumVitaeSection.tsx
Normal file
23
packages/ui/src/CurriculumVitae/CurriculumVitaeSection.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
21
packages/ui/src/CurriculumVitae/CurriculumVitaeSkills.tsx
Normal file
21
packages/ui/src/CurriculumVitae/CurriculumVitaeSkills.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
19
packages/ui/src/CurriculumVitae/CurriculumVitaeWork.tsx
Normal file
19
packages/ui/src/CurriculumVitae/CurriculumVitaeWork.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
@ -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"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export interface AboutItemProps {
|
export interface AboutItemProps {
|
||||||
label: string
|
label: string
|
||||||
value: string
|
value: React.ReactNode
|
||||||
link?: string
|
link?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
@ -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")}
|
||||||
|
21
packages/ui/src/Home/About/AboutList/BirthDate.tsx
Normal file
21
packages/ui/src/Home/About/AboutList/BirthDate.tsx
Normal 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,
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user