mirror of
https://github.com/theoludwig/theoludwig.git
synced 2025-05-29 22:37:44 +02:00
feat: components structure Curriculum Vitae
This commit is contained in:
@ -4,6 +4,7 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./CurriculumVitae": "./src/CurriculumVitae/CurriculumVitae.tsx",
|
||||
"./Design/Button": "./src/Design/Button/Button.tsx",
|
||||
"./Design/Link": "./src/Design/Link/Link.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 { 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 { Button } from "./Button"
|
||||
|
@ -1,6 +1,6 @@
|
||||
export interface AboutItemProps {
|
||||
label: string
|
||||
value: string
|
||||
value: React.ReactNode
|
||||
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 { AboutItem } from "./AboutItem"
|
||||
import { AboutItemBirthDate } from "./AboutItemBirthDate"
|
||||
import { BirthDate } from "./BirthDate"
|
||||
|
||||
export interface AboutListProps {}
|
||||
|
||||
@ -13,7 +13,10 @@ export const AboutList: React.FC<AboutListProps> = () => {
|
||||
label={t("home.about.pronouns.label")}
|
||||
value={t("home.about.pronouns.value")}
|
||||
/>
|
||||
<AboutItemBirthDate />
|
||||
<AboutItem
|
||||
label={t("home.about.birth-date.label")}
|
||||
value={<BirthDate />}
|
||||
/>
|
||||
<AboutItem
|
||||
label={t("home.about.nationality.label")}
|
||||
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,
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user