use dioxus::prelude::*; use dioxus_i18n::t; use crate::components::{H4, HR}; #[component] pub fn CV() -> Element { rsx! { div { class: "flex flex-col", div { class: "flex flex-col sm:flex-row justify-center items-center sm:space-x-8 space-y-8 sm:space-y-0", img { class: "rounded-full w-24 h-24", alt: "headshot", src: asset!("./assets/pictures/headshot.webp") } Introduction {}, Socials {} }, HR {} div { class: "flex flex-col justify-between sm:flex-row", WorkExperience {}, Miscellaneous {}, }, HR {}, } } } fn Introduction() -> Element { rsx! { div { class: "flex", P { { t!("cv_introduction_0") } }, }, } } fn WorkExperience() -> Element { rsx! { div { class: "ms-8 max-w-3/4", H4 { { t!("cv_workexperience_title") } }, ol { class:"relative border-s border-gray-700", CVEntry {time: t!("cv_workexperience_dd_devops_time"), title: t!("cv_workexperience_dd_devops_title"), technologies: vec!["Kubenertes".to_string(), "ArgoCD".to_string(), "Ansible".to_string(), "Azure".to_string(), "Docker".to_string(), "ELK".to_string()], description: t!("cv_workexperience_dd_devops_description") }, CVEntry {time: t!("cv_workexperience_ra_ude_time"), title: t!("cv_workexperience_ra_ude_title"), technologies: vec!["Rust".to_string(), "Python".to_string(), "P4".to_string(), "Linux".to_string(), "Docker".to_string(), "Kubernetes".to_string()], description: t!("cv_workexperience_ra_ude_description") }, CVEntry {time: t!("cv_workexperience_mentoring_ude_time"), title: t!("cv_workexperience_mentoring_ude_title"), technologies: vec!["Powerpoint".to_string()], description: t!("cv_workexperience_mentoring_ude_description") }, CVEntry {time: t!("cv_workexperience_se2_gefeba_time"), title: t!("cv_workexperience_se2_gefeba_title"), technologies: vec!["C#".to_string(), "Angular".to_string(), "bootstrap".to_string(), "Entity Framework".to_string()], description: t!("cv_workexperience_se2_gefeba_description") }, CVEntry {time: t!("cv_workexperience_student_fse_time"), title: t!("cv_workexperience_student_fse_title"), technologies: vec!["Linux".to_string(), "Networking".to_string(), "LaTeX".to_string()], description: t!("cv_workexperience_student_fse_description") }, CVEntry {time: t!("cv_workexperience_se1_gefeba_time"), title: t!("cv_workexperience_se1_gefeba_title"), technologies: vec!["C#".to_string(), "HTML".to_string(), "Javascript".to_string(), "CSS".to_string()], description: t!("cv_workexperience_se1_gefeba_description") }, } }, } } fn Miscellaneous() -> Element { rsx! { div { class: "", Education {}, Skills {}, Languages {}, Interests {}, } } } fn Education() -> Element { rsx! { div { H4 { { t!("cv_education_title") } }, Entry { title: t!("cv_education_bachelor_title"), time { class:"mb-1 text-sm font-normal leading-none text-gray-500", { t!("cv_education_bachelor_time") } }, }, } } } fn Skills() -> Element { rsx! { div { H4 { { t!("cv_skills_title") }}, Entry { title: t!("cv_skills_devops_title"), P { { t!("cv_skills_devops_ansible") } }, P { { t!("cv_skills_devops_kubernetes") } }, P { { t!("cv_skills_devops_gitops") } }, } Entry { title: t!("cv_skills_software_engineering_title"), P { { t!("cv_skills_software_engineering_rust") } }, P { { t!("cv_skills_software_engineering_python") } }, P { { t!("cv_skills_software_engineering_csharp") } }, } } } } fn Languages() -> Element { rsx! { div { H4 { { t!("cv_languages_title") } }, Entry { P { {t!("cv_languages_german") } }, P { {t!("cv_languages_english") } }, P { {t!("cv_languages_vietnamese") } }, P { {t!("cv_languages_japanese") } }, } } } } fn Interests() -> Element { rsx! { div { H4 { { t!("cv_interests_title") } }, Entry { P { { t!("cv_interests_coffee") } }, P { { t!("cv_interests_tech_it") } }, P { { t!("cv_interests_guitar") } }, P { { t!("cv_interests_mechanical_keyboards") } }, } } } } #[derive(PartialEq, Props, Clone)] struct EntryProps { #[props(default = "mb-4".to_string())] class: String, #[props(default = "".to_string())] title: String, children: Element, } fn Entry(props: EntryProps) -> Element { rsx! { div { class: "{props.class}", h6 { class: "font-semibold text-white", "{props.title}"} {props.children}, } } } #[derive(PartialEq, Props, Clone)] struct CVEntryProps { #[props(default = "mb-10 ms-4".to_string())] class: String, time: String, title: String, technologies: Vec, #[props(default = "".to_string())] description: String, children: Element, } fn CVEntry(props: CVEntryProps) -> Element { rsx! { li { class: "max-w-xl", class: "{props.class}", div { class:"absolute w-3 h-3 rounded-full mt-1.5 -start-1.5 border border-gray-900 bg-gray-700"}, time { class:"mb-1 text-sm font-normal leading-none text-gray-500", "{props.time}"}, h6 { class: "text-lg font-semibold text-white", "{props.title}"} ul { class: "flex flex-wrap gap-2", for (index, value) in props.technologies.iter().enumerate() { li { key: "{index}", RandomBadge { text: "{value}"} } } } p { class:"text-base font-normal text-gray-400", "{props.description}"}, {props.children} } } } #[component] fn RandomBadge(text: String) -> Element { let badge_color = random_badge_color(text.len()); rsx! { span { class:"text-xs font-medium me-2 px-2.5 py-0.5 rounded {badge_color}", "{text}" } } } fn random_badge_color(seed: usize) -> String { let colors = [ "bg-blue-900 text-blue-300", "bg-gray-700 text-gray-300", "bg-red-900 text-red-300", "bg-green-900 text-green-300", "bg-yellow-900 text-yellow-300", "bg-indigo-900 text-indigo-300", "bg-purple-900 text-purple-300", "bg-pink-900 text-pink-300", ]; colors[seed % colors.len()].to_string() } fn Socials() -> Element { rsx! { div { class: "ms-8 max-w-3/4", H4 { { t!("cv_socials_title") } }, div { class: "flex justify-center items-center space-x-4", P { Link { to:"https://www.linkedin.com/in/tudattr/", class:"hover:underline", new_tab: true, img { class: "h-8", src:asset!("./assets/pictures/LI-Bug.svg.original.svg"), alt:"LinkedIn Logo" } }}, } } } } #[component] fn P(children: Element) -> Element { rsx! { p { class: "text-base font-normal text-gray-400", {children}, } } }