1 Commits

Author SHA1 Message Date
Tuan-Dat Tran
8f1989ebc9 chore(version): Update for 2026
Signed-off-by: Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>
2026-01-18 13:47:55 +01:00
10 changed files with 161 additions and 154 deletions

6
Cargo.lock generated
View File

@@ -1190,15 +1190,13 @@ dependencies = [
[[package]] [[package]]
name = "dioxus-i18n" name = "dioxus-i18n"
version = "0.4.2" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97da8c5cbb956baaa8faffeb7ffba342dc8f2dc02f16aeaf9d94708bcf2b221" checksum = "eaa2df724b94e2a93229609951a0570a4b8807215c588e78f88a8532bdde319f"
dependencies = [ dependencies = [
"dioxus-lib", "dioxus-lib",
"fluent", "fluent",
"thiserror 2.0.12",
"unic-langid", "unic-langid",
"walkdir",
] ]
[[package]] [[package]]

View File

@@ -13,7 +13,7 @@ dioxus = { version = "0.6", features = ["fullstack", "router"] }
# Debug # Debug
tracing = "0.1.40" tracing = "0.1.40"
dioxus-logger = "0.6.0" dioxus-logger = "0.6.0"
dioxus-i18n = "0.4.0" dioxus-i18n = "0.3.0"
[features] [features]
default = [] default = []

View File

@@ -24,4 +24,4 @@ title = "Tuan-Dat Tran"
reload_html = true reload_html = true
# which files or dirs will be watcher monitoring # which files or dirs will be watcher monitoring
watch_path = ["src", "assets", "languages"] watch_path = ["src", "assets"]

View File

@@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "1.86.0" channel = "1.85.0"
components = ["rustfmt", "clippy", "rust-analyzer"] components = ["rustfmt", "clippy", "rust-analyzer"]

View File

@@ -242,41 +242,3 @@ pub fn Urling(prop: UrlingProp) -> Element {
} }
} }
} }
#[component]
pub fn BadgeList(list: Vec<String>) -> 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()
}

View File

@@ -1,7 +1,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_i18n::t; use dioxus_i18n::t;
use crate::components::*; use crate::components::{H4, HR};
#[component] #[component]
pub fn CV() -> Element { pub fn CV() -> Element {
@@ -33,18 +33,8 @@ pub fn CV() -> Element {
fn Introduction() -> Element { fn Introduction() -> Element {
rsx! { rsx! {
div { div {
class: "flex-col", class: "flex",
h6 { class: "text-lg font-semibold text-white", { t!("cv_introduction_title") } },
P { { t!("cv_introduction_0") } }, P { { t!("cv_introduction_0") } },
P {
{ t!("cv_introduction_tools") },
" ",
Link { new_tab: true, to: "https://www.lazyvim.org/", "NeoVim (LazyVim)" },
", ",
Link { new_tab: true, to: "https://zellij.dev/", "Zellij" },
", ",
Link { new_tab: true, to: "https://k9scli.io/", "k9s" }
},
}, },
} }
} }
@@ -57,7 +47,7 @@ fn WorkExperience() -> Element {
ol { ol {
class:"relative border-s border-gray-700", class:"relative border-s border-gray-700",
CVEntry {time: t!("cv_workexperience_dd_devops_time"), title: t!("cv_workexperience_dd_devops_title"), CVEntry {time: t!("cv_workexperience_dd_devops_time"), title: t!("cv_workexperience_dd_devops_title"),
technologies: vec!["Kubernetes".to_string(), "ArgoCD".to_string(), "Ansible".to_string(), "Azure".to_string(), "ELK".to_string(), "Helm".to_string()], 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") description: t!("cv_workexperience_dd_devops_description")
}, },
CVEntry {time: t!("cv_workexperience_ra_ude_time"), title: t!("cv_workexperience_ra_ude_title"), CVEntry {time: t!("cv_workexperience_ra_ude_time"), title: t!("cv_workexperience_ra_ude_title"),
@@ -196,13 +186,44 @@ 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"}, 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}"}, 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}"} h6 { class: "text-lg font-semibold text-white", "{props.title}"}
BadgeList{ list: props.technologies } 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}"}, p { class:"text-base font-normal text-gray-400", "{props.description}"},
{props.children} {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 { fn Socials() -> Element {
rsx! { rsx! {
div { div {

View File

@@ -12,15 +12,13 @@ home_card_text =
Willkommen auf meiner kleinen Webseite im World Wide Web. Willkommen auf meiner kleinen Webseite im World Wide Web.
Mein Name ist Tuan und ich bin Linux-Bastler, IT-Security Enthusiast und IT-Automatisierer aus Leidenschaft. Mein Name ist Tuan und ich bin Linux-Bastler, IT-Security Enthusiast und IT-Automatisierer aus Leidenschaft.
home_card_contact_button = Get in touch. home_card_contact_button = Get in touch.
cv_introduction_title = DevOps Engineer | Homelab Enthusiast
cv_introduction_0 = cv_introduction_0 =
DevOps Engineer und Softwareentwickler mit starkem akademischen Hintergrund DevOps-Engineer und Softwareentwickler mit starkem akademischen Hintergrund
in Netzwerktechnologien und Softwareentwicklung. Spezialisiert auf Kubernetes, in Netzwerktechnologien und Softwareentwicklung. Spezialisiert auf Kubernetes,
Ansible, Azure und moderne Cloud-Technologien. Praxisnahe Ansible, Azure und moderne Cloud-Technologien. Praxisnahe
Forschungserfahrung in Software-Defined Networking, 5G und Maschinellem Lernen. Forschungserfahrung in Software-Defined Networking, 5G und Maschinellem Lernen.
Leidenschaft für effiziente IT-Infrastrukturen, Automatisierung und Leidenschaft für effiziente IT-Infrastrukturen, Automatisierung und
innovative Softwarelösungen. innovative Softwarelösungen.
cv_introduction_tools = Lieblingstools:
cv_workexperience_title = Berufserfahrung cv_workexperience_title = Berufserfahrung
cv_workexperience_se1_gefeba_title = Software Entwickler @ gefeba Engineering GmbH cv_workexperience_se1_gefeba_title = Software Entwickler @ gefeba Engineering GmbH
cv_workexperience_se1_gefeba_time = 2013 - 2015 cv_workexperience_se1_gefeba_time = 2013 - 2015
@@ -63,14 +61,15 @@ cv_workexperience_ra_ude_description = Während meiner Tätigkeit bei der
cv_workexperience_dd_devops_title = DevOps Engineer @ DextraData cv_workexperience_dd_devops_title = DevOps Engineer @ DextraData
cv_workexperience_dd_devops_time = 2025 - Jetzt cv_workexperience_dd_devops_time = 2025 - Jetzt
cv_workexperience_dd_devops_description = Als DevOps Engineer bei DextraData cv_workexperience_dd_devops_description = Als DevOps Engineer bei DextraData
bin ich für die Cloud-basierte Infrastruktur hinter den vielfältigen bin ich Teil eines horizontal strukturierten DevOps-Teams und verantwortlich
SaaS-Produkten des Unternehmens verantwortlich. Ich arbeite eng mit für die Verwaltung und Optimierung sowohl cloudbasierter als auch On-Premise-
Software-Entwicklern, Customer Success Managern und Customer Success Engineers Infrastrukturen, die unsere Single-Tenant-SaaS-Lösungen hosten. Meine Aufgabe
zusammen, um betriebliche Exzellenz und unterbrechungsfreie Servicebereitstellung besteht nicht nur darin, diese Umgebungen zu warten und zu verbessern, sondern
für unsere Kunden zu gewährleisten, wobei ihre spezifischen Anforderungen im auch Automatisierung und Effizienz durch moderne DevOps-Praktiken
Vordergrund stehen. Ich verwalte Kubernetes-Cluster-Deployments, überwache voranzutreiben. Ich war maßgeblich an der Umstellung unserer Kubernetes-
kontinuierlich Deployment-Gesundheitsmetriken und implementiere basierten Deployments von manuellen Prozessen auf einen stärker
Infrastructure-as-Code-Lösungen. automatisierten und skalierbaren Ansatz beteiligt, indem ich Infrastructure as
Code mit Azure Resource Manager und Ansible eingesetzt habe.
cv_socials_title = Profile cv_socials_title = Profile
cv_education_title = Bildungsweg cv_education_title = Bildungsweg
cv_education_bachelor_title = BSc Angewandte Informatik - Systems Engineering cv_education_bachelor_title = BSc Angewandte Informatik - Systems Engineering
@@ -154,7 +153,7 @@ publications_projects_projects_athome_description = Diese Website ist eine mit
impressum_off = Impressum anzeigen impressum_off = Impressum anzeigen
impressum_on = Impressum impressum_on = Impressum
component_under_construction = Diese Seite befindet sich gerade im Aufbau component_under_construction = Diese Seite befindet sich gerade im Aufbau
footer_year = © 2025 footer_year = "© 2026 "
footer_name = Tuan-Dat Tran footer_name = Tuan-Dat Tran
footer_rights = . All Rights Reserved. footer_rights = . All Rights Reserved.
footer_contact = Kontakt footer_contact = Kontakt

View File

@@ -12,7 +12,6 @@ home_card_text =
Welcome to my little place on the internet Welcome to my little place on the internet
My name is Tuan and I'm passionate about Linux, system security, automation, performance tweaking and all things tech. My name is Tuan and I'm passionate about Linux, system security, automation, performance tweaking and all things tech.
home_card_contact_button = Get in touch. home_card_contact_button = Get in touch.
cv_introduction_title = DevOps Engineer | Homelab Enthusiast
cv_introduction_0 = cv_introduction_0 =
DevOps Engineer and Software Developer with a strong academic background in DevOps Engineer and Software Developer with a strong academic background in
networking technologies and software development. Specialized in Kubernetes, networking technologies and software development. Specialized in Kubernetes,
@@ -20,7 +19,6 @@ cv_introduction_0 =
in Software-Defined Networking, 5G, and Machine Learning. Passionate about in Software-Defined Networking, 5G, and Machine Learning. Passionate about
efficient IT infrastructures, automation, and innovative software efficient IT infrastructures, automation, and innovative software
solutions. solutions.
cv_introduction_tools = Favorite Tools:
cv_workexperience_title = Work Experience cv_workexperience_title = Work Experience
cv_workexperience_se1_gefeba_title = Software Engineer @ gefeba Engineering GmbH cv_workexperience_se1_gefeba_title = Software Engineer @ gefeba Engineering GmbH
cv_workexperience_se1_gefeba_time = 2013 - 2015 cv_workexperience_se1_gefeba_time = 2013 - 2015
@@ -58,14 +56,15 @@ cv_workexperience_ra_ude_description = While working at the Network
infractructure, inventory system and online presence. infractructure, inventory system and online presence.
cv_workexperience_dd_devops_title = DevOps Engineer @ DextraData cv_workexperience_dd_devops_title = DevOps Engineer @ DextraData
cv_workexperience_dd_devops_time = 2025 - now cv_workexperience_dd_devops_time = 2025 - now
cv_workexperience_dd_devops_description = At DextraData as a DevOps Engineer, cv_workexperience_dd_devops_description = As a DevOps Engineer at DextraData,
I am responsible for the cloud-based infrastructure hosting our companies I am part of a horizontally structured DevOps team, responsible for managing
diverse portfolio of SaaS products, collaborating with Software Developers, and optimizing both cloud and on-premise infrastructure that hosts our
Customer Success Managers, and Customer Success Engineers to ensure single-tenant SaaS solutions. My role involves not only maintaining and
operational excellence and uninterrupted service delivery for our customers improving these environments but also driving automation and efficiency
with their specific requirements at the forefront. I manage through modern DevOps practices. I have been actively involved in
Kubernetes cluster deployments, continuously monitor deployment health metrics, transitioning our Kubernetes-based deployments from manual processes to a
and implement Infrastructure as Code solutions. more automated and scalable approach by leveraging Infrastructure as Code
with Azure Resource Manager and Ansible.
cv_socials_title = Socials cv_socials_title = Socials
cv_education_title = Education cv_education_title = Education
cv_education_bachelor_title = BSc Systems Engineering cv_education_bachelor_title = BSc Systems Engineering
@@ -146,7 +145,7 @@ publications_projects_projects_athome_description = This website is a
impressum_off = Show Impressum impressum_off = Show Impressum
impressum_on = Impressum impressum_on = Impressum
component_under_construction = This page is currently under construction component_under_construction = This page is currently under construction
footer_year = © 2025 footer_year = "© 2026 "
footer_name = Tuan-Dat Tran footer_name = Tuan-Dat Tran
footer_rights = . All Rights Reserved. footer_rights = . All Rights Reserved.
footer_contact = Contact footer_contact = Contact

View File

@@ -50,11 +50,11 @@ fn App() -> Element {
I18nConfig::new(langid!("en-GB")) I18nConfig::new(langid!("en-GB"))
.with_locale(Locale::new_static( .with_locale(Locale::new_static(
langid!("en-GB"), langid!("en-GB"),
include_str!("../languages/en-GB.ftl"), include_str!("./languages/en-GB.ftl"),
)) ))
.with_locale(Locale::new_static( .with_locale(Locale::new_static(
langid!("de-DE"), langid!("de-DE"),
include_str!("../languages/de-DE.ftl"), include_str!("./languages/de-DE.ftl"),
)) ))
}); });

View File

@@ -1,7 +1,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_i18n::t; use dioxus_i18n::t;
use crate::components::{BadgeList, Bolding, H1, HR}; use crate::components::{Bolding, H1, HR};
#[component] #[component]
pub fn PublicationsProjects() -> Element { pub fn PublicationsProjects() -> Element {
@@ -21,13 +21,108 @@ 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)] #[derive(Clone, PartialEq, Props)]
struct ProjectProp { struct ProjectProp {
#[props(default = "".to_string())] #[props(default = "".to_string())]
url: String, url: String,
authors: String, authors: String,
title: String, title: String,
technologies: Vec<String>,
kind: String, kind: String,
#[props(default = "".to_string())] #[props(default = "".to_string())]
description: String, description: String,
@@ -45,7 +140,6 @@ fn Project(prop: ProjectProp) -> Element {
class:"mb-2 text-2xl font-bold tracking-tight text-white", class:"mb-2 text-2xl font-bold tracking-tight text-white",
"{prop.title}", "{prop.title}",
}, },
p {}
p { class: "text-lg text-white", "{prop.kind}" }, p { class: "text-lg text-white", "{prop.kind}" },
p { p {
class:"font-normal text-gray-400", class:"font-normal text-gray-400",
@@ -53,8 +147,7 @@ fn Project(prop: ProjectProp) -> Element {
authors: "{prop.authors}", authors: "{prop.authors}",
patterns: pattern, patterns: pattern,
}, },
}, }
BadgeList{list: prop.technologies},
p { p {
class:"font-normal text-gray-400", class:"font-normal text-gray-400",
"{prop.description}", "{prop.description}",
@@ -62,68 +155,3 @@ 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")
}
}
}
}