diff --git a/Cargo.lock b/Cargo.lock index 3bebea8..6a9dcf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1190,13 +1190,15 @@ dependencies = [ [[package]] name = "dioxus-i18n" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa2df724b94e2a93229609951a0570a4b8807215c588e78f88a8532bdde319f" +checksum = "a97da8c5cbb956baaa8faffeb7ffba342dc8f2dc02f16aeaf9d94708bcf2b221" dependencies = [ "dioxus-lib", "fluent", + "thiserror 2.0.12", "unic-langid", + "walkdir", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0730d91..1901b42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ dioxus = { version = "0.6", features = ["fullstack", "router"] } # Debug tracing = "0.1.40" dioxus-logger = "0.6.0" -dioxus-i18n = "0.3.0" +dioxus-i18n = "0.4.0" [features] default = [] diff --git a/src/languages/de-DE.ftl b/languages/de-DE.ftl similarity index 93% rename from src/languages/de-DE.ftl rename to languages/de-DE.ftl index 14e8d75..5522e69 100644 --- a/src/languages/de-DE.ftl +++ b/languages/de-DE.ftl @@ -61,15 +61,14 @@ cv_workexperience_ra_ude_description = Während meiner Tätigkeit bei der cv_workexperience_dd_devops_title = DevOps Engineer @ DextraData cv_workexperience_dd_devops_time = 2025 - Jetzt cv_workexperience_dd_devops_description = Als DevOps Engineer bei DextraData - bin ich Teil eines horizontal strukturierten DevOps-Teams und verantwortlich - für die Verwaltung und Optimierung sowohl cloudbasierter als auch On-Premise- - Infrastrukturen, die unsere Single-Tenant-SaaS-Lösungen hosten. Meine Aufgabe - besteht nicht nur darin, diese Umgebungen zu warten und zu verbessern, sondern - auch Automatisierung und Effizienz durch moderne DevOps-Praktiken - voranzutreiben. Ich war maßgeblich an der Umstellung unserer Kubernetes- - basierten Deployments von manuellen Prozessen auf einen stärker - automatisierten und skalierbaren Ansatz beteiligt, indem ich Infrastructure as - Code mit Azure Resource Manager und Ansible eingesetzt habe. + bin ich für die Cloud-basierte Infrastruktur hinter den vielfältigen + SaaS-Produkten des Unternehmens verantwortlich. Ich arbeite eng mit + Software-Entwicklern, Customer Success Managern und Customer Success Engineers + zusammen, um betriebliche Exzellenz und unterbrechungsfreie Servicebereitstellung + für unsere Kunden zu gewährleisten, wobei ihre spezifischen Anforderungen im + Vordergrund stehen. Ich verwalte Kubernetes-Cluster-Deployments, überwache + kontinuierlich Deployment-Gesundheitsmetriken und implementiere + Infrastructure-as-Code-Lösungen. cv_socials_title = Profile cv_education_title = Bildungsweg cv_education_bachelor_title = BSc Angewandte Informatik - Systems Engineering diff --git a/src/languages/en-GB.ftl b/languages/en-GB.ftl similarity index 92% rename from src/languages/en-GB.ftl rename to languages/en-GB.ftl index 1772a86..194f12c 100644 --- a/src/languages/en-GB.ftl +++ b/languages/en-GB.ftl @@ -56,15 +56,14 @@ cv_workexperience_ra_ude_description = While working at the Network infractructure, inventory system and online presence. cv_workexperience_dd_devops_title = DevOps Engineer @ DextraData cv_workexperience_dd_devops_time = 2025 - now -cv_workexperience_dd_devops_description = As a DevOps Engineer at DextraData, - I am part of a horizontally structured DevOps team, responsible for managing - and optimizing both cloud and on-premise infrastructure that hosts our - single-tenant SaaS solutions. My role involves not only maintaining and - improving these environments but also driving automation and efficiency - through modern DevOps practices. I have been actively involved in - transitioning our Kubernetes-based deployments from manual processes to a - more automated and scalable approach by leveraging Infrastructure as Code - with Azure Resource Manager and Ansible. +cv_workexperience_dd_devops_description = At DextraData as a DevOps Engineer, + I am responsible for the cloud-based infrastructure hosting our companies + diverse portfolio of SaaS products, collaborating with Software Developers, + Customer Success Managers, and Customer Success Engineers to ensure + operational excellence and uninterrupted service delivery for our customers + with their specific requirements at the forefront. I manage + Kubernetes cluster deployments, continuously monitor deployment health metrics, + and implement Infrastructure as Code solutions. cv_socials_title = Socials cv_education_title = Education cv_education_bachelor_title = BSc Systems Engineering diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 787a54a..c33c525 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.85.0" +channel = "1.86.0" components = ["rustfmt", "clippy", "rust-analyzer"] diff --git a/src/components/mod.rs b/src/components/mod.rs index ce6556b..672ebc0 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -242,3 +242,41 @@ pub fn Urling(prop: UrlingProp) -> Element { } } } + +#[component] +pub fn BadgeList(list: Vec) -> Element { + rsx!( + ul { + class: "flex flex-wrap gap-2", + for (index, value) in list.iter().enumerate() { + li { key: "{index}", RandomBadge { text: "{value}"} } + } + } + ) +} + +#[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() +} diff --git a/src/cv.rs b/src/cv.rs index 88c9e4e..a81c027 100644 --- a/src/cv.rs +++ b/src/cv.rs @@ -1,7 +1,7 @@ use dioxus::prelude::*; use dioxus_i18n::t; -use crate::components::{H4, HR}; +use crate::components::*; #[component] pub fn CV() -> Element { @@ -47,7 +47,7 @@ fn WorkExperience() -> Element { 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()], + technologies: vec!["Kubernetes".to_string(), "ArgoCD".to_string(), "Ansible".to_string(), "Azure".to_string(), "ELK".to_string(), "Helm".to_string()], description: t!("cv_workexperience_dd_devops_description") }, CVEntry {time: t!("cv_workexperience_ra_ude_time"), title: t!("cv_workexperience_ra_ude_title"), @@ -186,44 +186,13 @@ fn CVEntry(props: CVEntryProps) -> Element { 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}"} } - } - } + BadgeList{ list: props.technologies } 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 { diff --git a/src/main.rs b/src/main.rs index 6be5f61..39b7805 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,11 +50,11 @@ fn App() -> Element { I18nConfig::new(langid!("en-GB")) .with_locale(Locale::new_static( langid!("en-GB"), - include_str!("./languages/en-GB.ftl"), + include_str!("../languages/en-GB.ftl"), )) .with_locale(Locale::new_static( langid!("de-DE"), - include_str!("./languages/de-DE.ftl"), + include_str!("../languages/de-DE.ftl"), )) }); diff --git a/src/publications.rs b/src/publications.rs index 03fbd68..3dc7574 100644 --- a/src/publications.rs +++ b/src/publications.rs @@ -1,7 +1,7 @@ use dioxus::prelude::*; use dioxus_i18n::t; -use crate::components::{Bolding, H1, HR}; +use crate::components::{BadgeList, Bolding, H1, HR}; #[component] pub fn PublicationsProjects() -> Element { @@ -21,108 +21,13 @@ pub fn PublicationsProjects() -> Element { } } -#[derive(Clone, PartialEq, Props)] -struct PublicationProp { - #[props(default = "".to_string())] - doi: String, - authors: String, - title: String, - conference: String, - #[props(default = "".to_string())] - description: String, -} - -fn Publications() -> Element { - rsx! { - div { - class: "flex gap-4 items-center flex-wrap", - Publication { - title: t!("publications_projects_publications_rpm_title"), - authors: t!("publications_projects_publications_rpm_authors"), - conference: t!("publications_projects_publications_rpm_conference"), - doi: t!("publications_projects_publications_rpm_url"), - description: t!("publications_projects_publications_rpm_description") - }, - - Publication { - title: t!("publications_projects_publications_iot_fuzzers_title"), - authors: t!("publications_projects_publications_iot_fuzzers_authors"), - conference: t!("publications_projects_publications_iot_fuzzers_conference"), - doi: "/#", - description: t!("publications_projects_publications_iot_fuzzers_description") - }, - } - } -} -fn Publication(prop: PublicationProp) -> Element { - let pattern = vec!["T.-D. Tran".to_string(), "Tuan-Dat Tran".to_string()]; - rsx! { - Link { - class:"block max-w-sm p-6 border rounded-lg shadow bg-gray-800 border-gray-700 hover:bg-gray-700", - to:"{prop.doi}", - new_tab: true, - h5 { - class:"mb-2 text-2xl font-bold tracking-tight text-white", - "{prop.title}", - }, - span { class: "text-lg text-white", "{prop.conference}" }, - p { - class:"font-normal text-gray-400 italic", - Bolding { - authors: "{prop.authors}", - patterns: pattern, - }, - } - p { - class:"font-normal text-gray-400", - "{prop.description}", - } - } - } -} - -fn Projects() -> Element { - rsx! { - div { - class: "flex gap-4 items-center flex-wrap", - Project { - title: t!("publications_projects_projects_bpba_title"), - authors: t!("publications_projects_projects_bpba_authors"), - kind: t!("publications_projects_projects_bpba_kind"), - url: "/#", - description: t!("publications_projects_projects_bpba_description") - }, - Project { - title: t!("publications_projects_projects_dotfiles_title"), - authors: t!("publications_projects_projects_dotfiles_authors"), - kind: t!("publications_projects_projects_dotfiles_kind"), - url: "/#", - description: t!("publications_projects_projects_dotfiles_description") - }, - Project { - title: t!("publications_projects_projects_homelab_title"), - authors: t!("publications_projects_projects_homelab_authors"), - kind: t!("publications_projects_projects_homelab_kind"), - url: "/#", - description: t!("publications_projects_projects_homelab_description") - } - Project { - title: t!("publications_projects_projects_athome_title"), - authors: t!("publications_projects_projects_athome_authors"), - kind: t!("publications_projects_projects_athome_kind"), - url: "/#", - description: t!("publications_projects_projects_athome_description") - } - } - } -} - #[derive(Clone, PartialEq, Props)] struct ProjectProp { #[props(default = "".to_string())] url: String, authors: String, title: String, + technologies: Vec, kind: String, #[props(default = "".to_string())] description: String, @@ -140,6 +45,7 @@ fn Project(prop: ProjectProp) -> Element { class:"mb-2 text-2xl font-bold tracking-tight text-white", "{prop.title}", }, + p {} p { class: "text-lg text-white", "{prop.kind}" }, p { class:"font-normal text-gray-400", @@ -147,7 +53,8 @@ fn Project(prop: ProjectProp) -> Element { authors: "{prop.authors}", patterns: pattern, }, - } + }, + BadgeList{list: prop.technologies}, p { class:"font-normal text-gray-400", "{prop.description}", @@ -155,3 +62,68 @@ fn Project(prop: ProjectProp) -> Element { } } } + +fn Publications() -> Element { + rsx! { + div { + class: "flex gap-4 items-center flex-wrap", + Project { + title: t!("publications_projects_publications_rpm_title"), + authors: t!("publications_projects_publications_rpm_authors"), + technologies: vec![], + kind: t!("publications_projects_publications_rpm_conference"), + url: t!("publications_projects_publications_rpm_url"), + description: t!("publications_projects_publications_rpm_description") + }, + + Project { + title: t!("publications_projects_publications_iot_fuzzers_title"), + authors: t!("publications_projects_publications_iot_fuzzers_authors"), + technologies: vec![], + kind: t!("publications_projects_publications_iot_fuzzers_conference"), + url: "/#", + description: t!("publications_projects_publications_iot_fuzzers_description") + }, + } + } +} + +fn Projects() -> Element { + rsx! { + div { + class: "flex gap-4 items-center flex-wrap", + Project { + title: t!("publications_projects_projects_bpba_title"), + authors: t!("publications_projects_projects_bpba_authors"), + technologies: vec![], + kind: t!("publications_projects_projects_bpba_kind"), + url: "/#", + description: t!("publications_projects_projects_bpba_description") + }, + Project { + title: t!("publications_projects_projects_dotfiles_title"), + authors: t!("publications_projects_projects_dotfiles_authors"), + technologies: vec![], + kind: t!("publications_projects_projects_dotfiles_kind"), + url: "/#", + description: t!("publications_projects_projects_dotfiles_description") + }, + Project { + title: t!("publications_projects_projects_homelab_title"), + authors: t!("publications_projects_projects_homelab_authors"), + technologies: vec![], + kind: t!("publications_projects_projects_homelab_kind"), + url: "/#", + description: t!("publications_projects_projects_homelab_description") + } + Project { + title: t!("publications_projects_projects_athome_title"), + authors: t!("publications_projects_projects_athome_authors"), + technologies: vec![], + kind: t!("publications_projects_projects_athome_kind"), + url: "/#", + description: t!("publications_projects_projects_athome_description") + } + } + } +}