use dioxus::prelude::*; use dioxus_sdk::{i18n::use_i18, translate}; use crate::components::{H4, HR}; #[component] pub fn CV() -> Element { rsx! { div { class: "flex flex-col ", div { class: "flex justify-between", Introduction {}, Socials {} }, HR {} div { class: "flex justify-between", WorkExperience {}, Miscellaneous {}, }, HR {}, } } } fn Introduction() -> Element { let i18 = use_i18(); rsx! { div { class: "flex", img { class: "rounded-full w-16 h-16 mx-16", src: "/pictures/headshot.webp" } P { { translate!(i18, "cv.introduction_0") } }, P { { translate!(i18, "cv.introduction_1") } } }, } } fn WorkExperience() -> Element { let i18 = use_i18(); rsx! { div { class: "ms-8 max-w-3/4", H4 { { translate!(i18, "cv.workexperience.title") } }, ol { class:"relative border-s border-gray-200 dark:border-gray-700", CVEntry {time: translate!(i18, "cv.workexperience.ra_ude.time"), title: translate!(i18, "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: translate!(i18, "cv.workexperience.ra_ude.description") }, CVEntry {time: translate!(i18, "cv.workexperience.mentoring_ude.time"), title: translate!(i18, "cv.workexperience.mentoring_ude.title"), technologies: vec!["Powerpoint".to_string()], description: translate!(i18, "cv.workexperience.mentoring_ude.description") }, CVEntry {time: translate!(i18, "cv.workexperience.se2_gefeba.time"), title: translate!(i18, "cv.workexperience.se2_gefeba.title"), technologies: vec!["C#".to_string(), "Angular".to_string(), "bootstrap".to_string(), "Entity Framework".to_string()], description: translate!(i18, "cv.workexperience.se2_gefeba.description") }, CVEntry {time: translate!(i18, "cv.workexperience.student_fse.time"), title: translate!(i18, "cv.workexperience.student_fse.title"), technologies: vec!["Linux".to_string(), "Networking".to_string(), "LaTeX".to_string()], description: translate!(i18, "cv.workexperience.student_fse.description") }, CVEntry {time: translate!(i18, "cv.workexperience.se1_gefeba.time"), title: translate!(i18, "cv.workexperience.se1_gefeba.title"), technologies: vec!["C#".to_string(), "HTML".to_string(), "Javascript".to_string(), "CSS".to_string()], description: translate!(i18, "cv.workexperience.se1_gefeba.description") }, } }, } } fn Miscellaneous() -> Element { rsx! { div { class: "", Education {}, Skills {}, Languages {}, Interests {}, } } } fn Education() -> Element { let i18 = use_i18(); rsx! { div { H4 { { translate!(i18, "cv.education.title") } }, Entry { title: translate!(i18, "cv.education.bachelor.title"), time { class:"mb-1 text-sm font-normal leading-none text-gray-400 dark:text-gray-500", { translate!(i18, "cv.education.bachelor.time") } }, }, } } } fn Skills() -> Element { let i18 = use_i18(); rsx! { div { H4 { { translate!(i18, "cv.skills.title") }}, Entry { title: translate!(i18, "cv.skills.devops.title"), P { { translate!(i18, "cv.skills.devops.ansible") } }, P { { translate!(i18, "cv.skills.devops.kubernetes") } }, P { { translate!(i18, "cv.skills.devops.gitops") } }, }Entry { title: translate!(i18, "cv.skills.software_engineering.title"), P { { translate!(i18, "cv.skills.software_engineering.rust") } }, P { { translate!(i18, "cv.skills.software_engineering.python") } }, P { { translate!(i18, "cv.skills.software_engineering.csharp") } }, } } } } fn Languages() -> Element { let i18 = use_i18(); rsx! { div { H4 { { translate!(i18, "cv.languages.title") } }, Entry { P { {translate!(i18, "cv.languages.german") } }, P { {translate!(i18, "cv.languages.english") } }, P { {translate!(i18, "cv.languages.vietnamese") } }, P { {translate!(i18, "cv.languages.japanese") } }, } } } } fn Interests() -> Element { let i18 = use_i18(); rsx! { div { H4 { { translate!(i18, "cv.interests.title") } }, Entry { P { { translate!(i18, "cv.interests.coffee") } }, P { { translate!(i18, "cv.interests.tech_it") } }, P { { translate!(i18, "cv.interests.guitar") } }, P { { translate!(i18, "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-gray-900 dark: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 bg-gray-200 rounded-full mt-1.5 -start-1.5 border border-white dark:border-gray-900 dark:bg-gray-700"}, time { class:"mb-1 text-sm font-normal leading-none text-gray-400 dark:text-gray-500", "{props.time}"}, h6 { class: "text-lg font-semibold text-gray-900 dark:text-white", "{props.title}"} ul { class: "flex", for (index, value) in props.technologies.iter().enumerate() { li { key: "{index}", RandomBadge { text: "{value}"} } } } p { class:"text-base font-normal text-gray-500 dark: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 ", class: "{badge_color}", "{text}" } } } fn random_badge_color(seed: usize) -> String { let colors = [ "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300", "bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300", "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300", "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300", "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300", "bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-300", "bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300", "bg-pink-100 text-pink-800 dark:bg-pink-900 dark:text-pink-300", ]; colors[seed % colors.len()].to_string() } fn Socials() -> Element { let i18 = use_i18(); rsx! { div { class: "ms-8 max-w-3/4", H4 { { translate!(i18, "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:"/pictures/LI-Bug.svg.original.svg", alt:"LinkedIn Logo" } }}, P { Link { to:"https://git.tudattr.dev/tudattr", class:"hover:underline", new_tab: true, img { class: "h-8", src:"/pictures/Gitea_Logo.svg", alt:"Gitea Logo" } }}, } } } } #[component] fn P(children: Element) -> Element { rsx! { p { class: "text-base font-normal text-gray-500 dark:text-gray-400", {children}, } } }