4 Commits

Author SHA1 Message Date
Tuan-Dat Tran
a387293f94 feat(ftl): Updated description for dd
Signed-off-by: Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>
2025-03-12 22:15:35 +01:00
Tuan-Dat Tran
64aa115ef4 feat(cargo): update
Signed-off-by: Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>
2025-02-11 19:48:58 +01:00
Tuan-Dat Tran
8f00360ff8 feat(version): bumped to version 0.5.1
Signed-off-by: Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>
2025-02-11 19:24:55 +01:00
Tuan-Dat Tran
16e04980b5 feat(dark-mode): removed dark mode, made it default
Signed-off-by: Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>
2025-02-11 19:24:10 +01:00
12 changed files with 597 additions and 585 deletions

739
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "athome" name = "athome"
version = "0.4.0" version = "0.4.1"
authors = ["Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>"] authors = ["Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>"]
edition = "2021" edition = "2021"

View File

@@ -723,10 +723,18 @@ video {
max-width: 36rem; max-width: 36rem;
} }
.flex-auto {
flex: 1 1 auto;
}
.flex-grow { .flex-grow {
flex-grow: 1; flex-grow: 1;
} }
.grow {
flex-grow: 1;
}
.cursor-pointer { .cursor-pointer {
cursor: pointer; cursor: pointer;
} }
@@ -739,6 +747,14 @@ video {
flex-wrap: wrap; flex-wrap: wrap;
} }
.content-center {
align-content: center;
}
.items-start {
align-items: flex-start;
}
.items-center { .items-center {
align-items: center; align-items: center;
} }
@@ -755,6 +771,10 @@ video {
justify-content: space-between; justify-content: space-between;
} }
.justify-stretch {
justify-content: stretch;
}
.gap-2 { .gap-2 {
gap: 0.5rem; gap: 0.5rem;
} }
@@ -781,6 +801,10 @@ video {
margin-bottom: calc(2rem * var(--tw-space-y-reverse)); margin-bottom: calc(2rem * var(--tw-space-y-reverse));
} }
.self-stretch {
align-self: stretch;
}
.rounded { .rounded {
border-radius: 0.25rem; border-radius: 0.25rem;
} }
@@ -823,69 +847,69 @@ video {
border-inline-start-width: 1px; border-inline-start-width: 1px;
} }
.border-gray-200 { .border-gray-600 {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(229 231 235 / var(--tw-border-opacity)); border-color: rgb(75 85 99 / var(--tw-border-opacity));
} }
.border-white { .border-gray-700 {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(255 255 255 / var(--tw-border-opacity)); border-color: rgb(55 65 81 / var(--tw-border-opacity));
} }
.bg-blue-100 { .border-gray-900 {
--tw-bg-opacity: 1; --tw-border-opacity: 1;
background-color: rgb(219 234 254 / var(--tw-bg-opacity)); border-color: rgb(17 24 39 / var(--tw-border-opacity));
} }
.bg-gray-100 { .bg-blue-900 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity)); background-color: rgb(30 58 138 / var(--tw-bg-opacity));
} }
.bg-gray-200 { .bg-gray-700 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(229 231 235 / var(--tw-bg-opacity)); background-color: rgb(55 65 81 / var(--tw-bg-opacity));
} }
.bg-gray-50 { .bg-gray-800 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(249 250 251 / var(--tw-bg-opacity)); background-color: rgb(31 41 55 / var(--tw-bg-opacity));
} }
.bg-green-100 { .bg-gray-900 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(220 252 231 / var(--tw-bg-opacity)); background-color: rgb(17 24 39 / var(--tw-bg-opacity));
} }
.bg-indigo-100 { .bg-green-900 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(224 231 255 / var(--tw-bg-opacity)); background-color: rgb(20 83 45 / var(--tw-bg-opacity));
} }
.bg-pink-100 { .bg-indigo-900 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(252 231 243 / var(--tw-bg-opacity)); background-color: rgb(49 46 129 / var(--tw-bg-opacity));
} }
.bg-purple-100 { .bg-pink-900 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(243 232 255 / var(--tw-bg-opacity)); background-color: rgb(131 24 67 / var(--tw-bg-opacity));
} }
.bg-red-100 { .bg-purple-900 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(254 226 226 / var(--tw-bg-opacity)); background-color: rgb(88 28 135 / var(--tw-bg-opacity));
} }
.bg-white { .bg-red-900 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity)); background-color: rgb(127 29 29 / var(--tw-bg-opacity));
} }
.bg-yellow-100 { .bg-yellow-900 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(254 249 195 / var(--tw-bg-opacity)); background-color: rgb(113 63 18 / var(--tw-bg-opacity));
} }
.bg-gradient-to-br { .bg-gradient-to-br {
@@ -1063,14 +1087,24 @@ video {
letter-spacing: 0.1em; letter-spacing: 0.1em;
} }
.text-blue-800 { .text-blue-300 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(30 64 175 / var(--tw-text-opacity)); color: rgb(147 197 253 / var(--tw-text-opacity));
} }
.text-cyan-600 { .text-blue-500 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(8 145 178 / var(--tw-text-opacity)); color: rgb(59 130 246 / var(--tw-text-opacity));
}
.text-cyan-400 {
--tw-text-opacity: 1;
color: rgb(34 211 238 / var(--tw-text-opacity));
}
.text-gray-300 {
--tw-text-opacity: 1;
color: rgb(209 213 219 / var(--tw-text-opacity));
} }
.text-gray-400 { .text-gray-400 {
@@ -1083,44 +1117,34 @@ video {
color: rgb(107 114 128 / var(--tw-text-opacity)); color: rgb(107 114 128 / var(--tw-text-opacity));
} }
.text-gray-700 {
--tw-text-opacity: 1;
color: rgb(55 65 81 / var(--tw-text-opacity));
}
.text-gray-800 {
--tw-text-opacity: 1;
color: rgb(31 41 55 / var(--tw-text-opacity));
}
.text-gray-900 { .text-gray-900 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(17 24 39 / var(--tw-text-opacity)); color: rgb(17 24 39 / var(--tw-text-opacity));
} }
.text-green-800 { .text-green-300 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(22 101 52 / var(--tw-text-opacity)); color: rgb(134 239 172 / var(--tw-text-opacity));
} }
.text-indigo-800 { .text-indigo-300 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(55 48 163 / var(--tw-text-opacity)); color: rgb(165 180 252 / var(--tw-text-opacity));
} }
.text-pink-800 { .text-pink-300 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(157 23 77 / var(--tw-text-opacity)); color: rgb(249 168 212 / var(--tw-text-opacity));
} }
.text-purple-800 { .text-purple-300 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(107 33 168 / var(--tw-text-opacity)); color: rgb(216 180 254 / var(--tw-text-opacity));
} }
.text-red-800 { .text-red-300 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(153 27 27 / var(--tw-text-opacity)); color: rgb(252 165 165 / var(--tw-text-opacity));
} }
.text-transparent { .text-transparent {
@@ -1132,9 +1156,9 @@ video {
color: rgb(255 255 255 / var(--tw-text-opacity)); color: rgb(255 255 255 / var(--tw-text-opacity));
} }
.text-yellow-800 { .text-yellow-300 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(133 77 14 / var(--tw-text-opacity)); color: rgb(253 224 71 / var(--tw-text-opacity));
} }
.shadow { .shadow {
@@ -1174,20 +1198,17 @@ video {
transition-duration: 300ms; transition-duration: 300ms;
} }
.hover\:bg-gray-100:hover { @custom-variant dark (&:where(.dark, .dark *));
.hover\:bg-gray-700:hover {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity)); background-color: rgb(55 65 81 / var(--tw-bg-opacity));
} }
.hover\:bg-gradient-to-br:hover { .hover\:bg-gradient-to-br:hover {
background-image: linear-gradient(to bottom right, var(--tw-gradient-stops)); background-image: linear-gradient(to bottom right, var(--tw-gradient-stops));
} }
.hover\:text-blue-700:hover {
--tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity));
}
.hover\:text-white:hover { .hover\:text-white:hover {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity)); color: rgb(255 255 255 / var(--tw-text-opacity));
@@ -1206,9 +1227,9 @@ video {
z-index: 10; z-index: 10;
} }
.focus\:text-blue-700:focus { .focus\:text-white:focus {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity)); color: rgb(255 255 255 / var(--tw-text-opacity));
} }
.focus\:outline-none:focus { .focus\:outline-none:focus {
@@ -1228,14 +1249,14 @@ video {
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
} }
.focus\:ring-blue-700:focus { .focus\:ring-blue-500:focus {
--tw-ring-opacity: 1; --tw-ring-opacity: 1;
--tw-ring-color: rgb(29 78 216 / var(--tw-ring-opacity)); --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity));
} }
.focus\:ring-cyan-300:focus { .focus\:ring-cyan-800:focus {
--tw-ring-opacity: 1; --tw-ring-opacity: 1;
--tw-ring-color: rgb(103 232 249 / var(--tw-ring-opacity)); --tw-ring-color: rgb(21 94 117 / var(--tw-ring-opacity));
} }
.group:hover .group-hover\:from-green-400 { .group:hover .group-hover\:from-green-400 {
@@ -1287,11 +1308,6 @@ video {
font-size: 3rem; font-size: 3rem;
line-height: 1; line-height: 1;
} }
.md\:text-blue-700 {
--tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity));
}
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
@@ -1301,163 +1317,3 @@ video {
} }
} }
@media (prefers-color-scheme: dark) {
.dark\:border-gray-600 {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
}
.dark\:border-gray-700 {
--tw-border-opacity: 1;
border-color: rgb(55 65 81 / var(--tw-border-opacity));
}
.dark\:border-gray-900 {
--tw-border-opacity: 1;
border-color: rgb(17 24 39 / var(--tw-border-opacity));
}
.dark\:bg-blue-900 {
--tw-bg-opacity: 1;
background-color: rgb(30 58 138 / var(--tw-bg-opacity));
}
.dark\:bg-gray-700 {
--tw-bg-opacity: 1;
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
}
.dark\:bg-gray-800 {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}
.dark\:bg-gray-900 {
--tw-bg-opacity: 1;
background-color: rgb(17 24 39 / var(--tw-bg-opacity));
}
.dark\:bg-green-900 {
--tw-bg-opacity: 1;
background-color: rgb(20 83 45 / var(--tw-bg-opacity));
}
.dark\:bg-indigo-900 {
--tw-bg-opacity: 1;
background-color: rgb(49 46 129 / var(--tw-bg-opacity));
}
.dark\:bg-pink-900 {
--tw-bg-opacity: 1;
background-color: rgb(131 24 67 / var(--tw-bg-opacity));
}
.dark\:bg-purple-900 {
--tw-bg-opacity: 1;
background-color: rgb(88 28 135 / var(--tw-bg-opacity));
}
.dark\:bg-red-900 {
--tw-bg-opacity: 1;
background-color: rgb(127 29 29 / var(--tw-bg-opacity));
}
.dark\:bg-yellow-900 {
--tw-bg-opacity: 1;
background-color: rgb(113 63 18 / var(--tw-bg-opacity));
}
.dark\:text-blue-300 {
--tw-text-opacity: 1;
color: rgb(147 197 253 / var(--tw-text-opacity));
}
.dark\:text-cyan-400 {
--tw-text-opacity: 1;
color: rgb(34 211 238 / var(--tw-text-opacity));
}
.dark\:text-gray-300 {
--tw-text-opacity: 1;
color: rgb(209 213 219 / var(--tw-text-opacity));
}
.dark\:text-gray-400 {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
}
.dark\:text-gray-500 {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.dark\:text-green-300 {
--tw-text-opacity: 1;
color: rgb(134 239 172 / var(--tw-text-opacity));
}
.dark\:text-indigo-300 {
--tw-text-opacity: 1;
color: rgb(165 180 252 / var(--tw-text-opacity));
}
.dark\:text-pink-300 {
--tw-text-opacity: 1;
color: rgb(249 168 212 / var(--tw-text-opacity));
}
.dark\:text-purple-300 {
--tw-text-opacity: 1;
color: rgb(216 180 254 / var(--tw-text-opacity));
}
.dark\:text-red-300 {
--tw-text-opacity: 1;
color: rgb(252 165 165 / var(--tw-text-opacity));
}
.dark\:text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:text-yellow-300 {
--tw-text-opacity: 1;
color: rgb(253 224 71 / var(--tw-text-opacity));
}
.dark\:hover\:bg-gray-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
}
.dark\:hover\:text-white:hover {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:focus\:text-white:focus {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:focus\:ring-blue-500:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity));
}
.dark\:focus\:ring-cyan-800:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(21 94 117 / var(--tw-ring-opacity));
}
}
@media (min-width: 768px) {
@media (prefers-color-scheme: dark) {
.md\:dark\:text-blue-500 {
--tw-text-opacity: 1;
color: rgb(59 130 246 / var(--tw-text-opacity));
}
}
}

3
rust-toolchain.toml Normal file
View File

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

View File

@@ -14,7 +14,7 @@ pub fn P(props: PProps) -> Element {
div { div {
class: "{props.class}", class: "{props.class}",
p { p {
class: "mb-2 font-normal text-gray-900 dark:text-white", class: "mb-2 font-normal text-white",
{props.children} {props.children}
}, },
} }
@@ -27,7 +27,7 @@ pub fn Title(props: PProps) -> Element {
div { div {
class: "{props.class}", class: "{props.class}",
h1 { h1 {
class: "mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white", class: "mb-2 text-2xl font-bold tracking-tight text-white",
{props.children} {props.children}
} }
} }
@@ -40,7 +40,7 @@ pub fn H1(props: PProps) -> Element {
div { div {
class: "{props.class}", class: "{props.class}",
h1 { h1 {
class: "mb-4 text-3xl font-extrabold text-gray-900 dark:text-white md:text-5xl lg:text-6xl", class: "mb-4 text-3xl font-extrabold text-white md:text-5xl lg:text-6xl",
span { span {
class: "text-transparent bg-clip-text bg-gradient-to-r to-emerald-600 from-sky-400", class: "text-transparent bg-clip-text bg-gradient-to-r to-emerald-600 from-sky-400",
{props.children} {props.children}
@@ -56,7 +56,7 @@ pub fn H4(props: PProps) -> Element {
class: "{props.class}", class: "{props.class}",
class: "mb-4", class: "mb-4",
h3 { h3 {
class: "text-lg uppercase text-cyan-600 dark:text-cyan-400 tracking-widest mb-4 font-bold", class: "text-lg uppercase text-cyan-400 tracking-widest mb-4 font-bold",
{props.children} {props.children}
} }
} }
@@ -69,7 +69,7 @@ pub fn H5(props: PProps) -> Element {
div { div {
class: "{props.class}", class: "{props.class}",
h5 { h5 {
class: "mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white", class: "mb-2 text-2xl font-bold tracking-tight text-white",
{props.children} {props.children}
} }
} }
@@ -89,7 +89,7 @@ pub struct CardProp {
pub fn Card(prop: CardProp) -> Element { pub fn Card(prop: CardProp) -> Element {
rsx! { rsx! {
div { div {
class: "flex flex-col py-10 items-center min-w-fit text-white bg-gradient-to-r from-purple-500 to-blue-500 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-cyan-300 dark:focus:ring-cyan-800 rounded-lg px-5 py-2.5 min-w-fit max-w-8", class: "flex flex-col py-10 items-center min-w-fit text-white bg-gradient-to-r from-purple-500 to-blue-500 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-cyan-800 rounded-lg px-5 py-2.5 min-w-fit max-w-8",
div { div {
class: "pb-4", class: "pb-4",
div { div {
@@ -97,7 +97,7 @@ pub fn Card(prop: CardProp) -> Element {
Picture {src: "{prop.picture}"}, Picture {src: "{prop.picture}"},
} }
} }
Title { "{prop.name}", span { class: "text-grey-600 dark:text-grey-500 text-lg", " {prop.gender}" } }, Title { "{prop.name}", span { class: "text-grey-500 text-lg", " {prop.gender}" } },
{ prop.children } { prop.children }
} }
} }
@@ -123,11 +123,11 @@ fn Picture(prop: PictureProp) -> Element {
pub fn UnderConstruction() -> Element { pub fn UnderConstruction() -> Element {
rsx! { rsx! {
div { div {
class:"rounded justify-between w-full p-4 border-b border-gray-200 bg-gray-50 dark:bg-gray-700 dark:border-gray-600 my-8", class:"rounded justify-between w-full p-4 border-b bg-gray-700 border-gray-600 my-8",
div { div {
class:"items-center mx-auto", class:"items-center mx-auto",
p { p {
class:"items-center text-sm font-normal text-gray-500 dark:text-gray-400", class:"items-center text-sm font-normal text-gray-400",
span { { t!("component_under_construction") } } span { { t!("component_under_construction") } }
} }
} }
@@ -137,7 +137,7 @@ pub fn UnderConstruction() -> Element {
pub fn HR() -> Element { pub fn HR() -> Element {
rsx! { rsx! {
hr { class:"h-px my-8 bg-gray-200 border-0 dark:bg-gray-700"} hr { class:"h-px my-8 border-0 bg-gray-700"}
} }
} }

View File

@@ -45,7 +45,7 @@ fn WorkExperience() -> Element {
class: "ms-8 max-w-3/4", class: "ms-8 max-w-3/4",
H4 { { t!("cv_workexperience_title") } }, H4 { { t!("cv_workexperience_title") } },
ol { ol {
class:"relative border-s border-gray-200 dark: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!["Kubenertes".to_string(), "ArgoCD".to_string(), "Ansible".to_string(), "Azure".to_string(), "Docker".to_string(), "ELK".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")
@@ -93,7 +93,7 @@ fn Education() -> Element {
H4 { { t!("cv_education_title") } }, H4 { { t!("cv_education_title") } },
Entry { Entry {
title: t!("cv_education_bachelor_title"), title: t!("cv_education_bachelor_title"),
time { class:"mb-1 text-sm font-normal leading-none text-gray-400 dark:text-gray-500", { t!("cv_education_bachelor_time") } }, time { class:"mb-1 text-sm font-normal leading-none text-gray-500", { t!("cv_education_bachelor_time") } },
}, },
} }
} }
@@ -160,7 +160,7 @@ fn Entry(props: EntryProps) -> Element {
rsx! { rsx! {
div { div {
class: "{props.class}", class: "{props.class}",
h6 { class: "font-semibold text-gray-900 dark:text-white", "{props.title}"} h6 { class: "font-semibold text-white", "{props.title}"}
{props.children}, {props.children},
} }
} }
@@ -183,16 +183,16 @@ fn CVEntry(props: CVEntryProps) -> Element {
li { li {
class: "max-w-xl", class: "max-w-xl",
class: "{props.class}", 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"}, 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-400 dark: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-gray-900 dark:text-white", "{props.title}"} h6 { class: "text-lg font-semibold text-white", "{props.title}"}
ul { ul {
class: "flex flex-wrap gap-2", class: "flex flex-wrap gap-2",
for (index, value) in props.technologies.iter().enumerate() { for (index, value) in props.technologies.iter().enumerate() {
li { key: "{index}", RandomBadge { text: "{value}"} } li { key: "{index}", RandomBadge { text: "{value}"} }
} }
} }
p { class:"text-base font-normal text-gray-500 dark:text-gray-400", "{props.description}"}, p { class:"text-base font-normal text-gray-400", "{props.description}"},
{props.children} {props.children}
} }
} }
@@ -211,14 +211,14 @@ fn RandomBadge(text: String) -> Element {
fn random_badge_color(seed: usize) -> String { fn random_badge_color(seed: usize) -> String {
let colors = [ let colors = [
"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300", "bg-blue-900 text-blue-300",
"bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300", "bg-gray-700 text-gray-300",
"bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300", "bg-red-900 text-red-300",
"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300", "bg-green-900 text-green-300",
"bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300", "bg-yellow-900 text-yellow-300",
"bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-300", "bg-indigo-900 text-indigo-300",
"bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300", "bg-purple-900 text-purple-300",
"bg-pink-100 text-pink-800 dark:bg-pink-900 dark:text-pink-300", "bg-pink-900 text-pink-300",
]; ];
colors[seed % colors.len()].to_string() colors[seed % colors.len()].to_string()
@@ -241,7 +241,7 @@ fn Socials() -> Element {
fn P(children: Element) -> Element { fn P(children: Element) -> Element {
rsx! { rsx! {
p { p {
class: "text-base font-normal text-gray-500 dark:text-gray-400", class: "text-base font-normal text-gray-400",
{children}, {children},
} }
} }

View File

@@ -60,14 +60,16 @@ cv_workexperience_ra_ude_description = Während meiner Tätigkeit bei der
aufgebaut und verwaltet. aufgebaut und verwaltet.
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 = Bei DextraData, einem führenden cv_workexperience_dd_devops_description = Als DevOps Engineer bei DextraData
SaaS-Anbieter im Bereich Governance, Risk und Compliance (GRC), stelle ich bin ich Teil eines horizontal strukturierten DevOps-Teams und verantwortlich
die Verfügbarkeit und Stabilität von Software-Deployments für unsere Kunden für die Verwaltung und Optimierung sowohl cloudbasierter als auch On-Premise-
sowie für interne Entwicklungsteams über mehrere Produkte hinweg sicher. In Infrastrukturen, die unsere Single-Tenant-SaaS-Lösungen hosten. Meine Aufgabe
Zusammenarbeit mit Customer-Success-Teams und Softwareentwicklern besteht nicht nur darin, diese Umgebungen zu warten und zu verbessern, sondern
gewährleisten wir einen reibungslosen Betrieb unserer Multi-Tenant- und Single auch Automatisierung und Effizienz durch moderne DevOps-Praktiken
-Tenant-Instanzen von der Vorentwicklung bis hin zu den voranzutreiben. Ich war maßgeblich an der Umstellung unserer Kubernetes-
Produktionsumgebungen. 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.
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

View File

@@ -56,13 +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, a leading SaaS cv_workexperience_dd_devops_description = As a DevOps Engineer at DextraData,
provider in the Governance, Risk, and Compliance (GRC) sector, I ensure the I am part of a horizontally structured DevOps team, responsible for managing
availability and health of software deployments for our customers and and optimizing both cloud and on-premise infrastructure that hosts our
internal development teams across multiple products. Collaborating with single-tenant SaaS solutions. My role involves not only maintaining and
Customer Success and Software Engineers alike we ensure smooth operations on improving these environments but also driving automation and efficiency
our multi-tenant as well as single tenant instances from pre-dev to through modern DevOps practices. I have been actively involved in
production environments. 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_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

View File

@@ -6,17 +6,17 @@ pub fn Footer() -> Element {
div { div {
class: "container mx-auto pb-4", class: "container mx-auto pb-4",
footer { footer {
class:"bg-white rounded-lg shadow dark:bg-gray-800", class:"rounded-lg shadow bg-gray-800",
div { div {
class:"w-full mx-auto p-4 flex items-center justify-between", class:"w-full mx-auto p-4 flex items-center justify-between",
span { span {
class:"text-sm text-gray-500 sm:text-center dark:text-gray-400", class:"text-sm sm:text-center text-gray-400",
{ t!("footer_year") }, { t!("footer_year") },
a { href: "#", class: "hover:underline", { t!("footer_name") }}, a { href: "#", class: "hover:underline", { t!("footer_name") }},
{ t!("footer_rights") } { t!("footer_rights") }
} }
ul { ul {
class:"flex flex-wrap items-center mt-3 text-sm font-medium text-gray-500 dark:text-gray-400 sm:mt-0", class:"flex flex-wrap items-center mt-3 text-sm font-medium text-gray-400 sm:mt-0",
li { li {
Link { to:"mailto:tuan-dat.tran@tudattr.dev", class:"hover:underline", { t!("footer_contact") } } Link { to:"mailto:tuan-dat.tran@tudattr.dev", class:"hover:underline", { t!("footer_contact") } }
}, },

View File

@@ -40,11 +40,11 @@ fn LanguageButtonGroup() -> Element {
div { div {
class: "rounded-md shadow-sm justify-end", class: "rounded-md shadow-sm justify-end",
button { button {
class: "px-4 py-2 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-s-lg hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-2 focus:ring-blue-700 focus:text-blue-700 dark:bg-gray-800 dark:border-gray-700 dark:text-white dark:hover:text-white dark:hover:bg-gray-700 dark:focus:ring-blue-500 dark:focus:text-white", class: "px-4 py-2 text-sm font-medium border rounded-s-lg focus:z-10 focus:ring-2 bg-gray-800 border-gray-700 text-white hover:text-white hover:bg-gray-700 focus:ring-blue-500 focus:text-white",
onclick: change_to_english, onclick: change_to_english,
label { { t!("headers_language_buttons_english") } } }, label { { t!("headers_language_buttons_english") } } },
button { button {
class: "px-4 py-2 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-e-lg hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-2 focus:ring-blue-700 focus:text-blue-700 dark:bg-gray-800 dark:border-gray-700 dark:text-white dark:hover:text-white dark:hover:bg-gray-700 dark:focus:ring-blue-500 dark:focus:text-white", class: "px-4 py-2 text-sm font-medium border rounded-e-lg focus:z-10 focus:ring-2 bg-gray-800 border-gray-700 text-white hover:text-white hover:bg-gray-700 focus:ring-blue-500 focus:text-white",
onclick: change_to_german, onclick: change_to_german,
label { { t!("headers_language_buttons_german") } } } label { { t!("headers_language_buttons_german") } } }
} }
@@ -54,6 +54,6 @@ fn LanguageButtonGroup() -> Element {
#[component] #[component]
fn HeaderLink(url: Route, text: String) -> Element { fn HeaderLink(url: Route, text: String) -> Element {
rsx! { rsx! {
Link { to: url, class:"md:bg-transparent md:text-blue-700 md:p-0 dark:text-white md:dark:text-blue-500", {text} } Link { to: url, class:"md:bg-transparent md:p-0 text-blue-500", {text} }
} }
} }

View File

@@ -81,7 +81,7 @@ fn App() -> Element {
" "
} }
div { div {
class: "bg-white dark:bg-gray-900 min-h-screen", class: "bg-gray-900 min-h-screen",
Router::<Route> {}, Router::<Route> {},
} }
} }

View File

@@ -58,23 +58,23 @@ fn Publication(prop: PublicationProp) -> Element {
let pattern = vec!["T.-D. Tran".to_string(), "Tuan-Dat Tran".to_string()]; let pattern = vec!["T.-D. Tran".to_string(), "Tuan-Dat Tran".to_string()];
rsx! { rsx! {
Link { Link {
class:"block max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700", class:"block max-w-sm p-6 border rounded-lg shadow bg-gray-800 border-gray-700 hover:bg-gray-700",
to:"{prop.doi}", to:"{prop.doi}",
new_tab: true, new_tab: true,
h5 { h5 {
class:"mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white", class:"mb-2 text-2xl font-bold tracking-tight text-white",
"{prop.title}", "{prop.title}",
}, },
span { class: "text-lg text-gray-900 dark:text-white", "{prop.conference}" }, span { class: "text-lg text-white", "{prop.conference}" },
p { p {
class:"font-normal text-gray-700 dark:text-gray-400 italic", class:"font-normal text-gray-400 italic",
Bolding { Bolding {
authors: "{prop.authors}", authors: "{prop.authors}",
patterns: pattern, patterns: pattern,
}, },
} }
p { p {
class:"font-normal text-gray-700 dark:text-gray-400", class:"font-normal text-gray-400",
"{prop.description}", "{prop.description}",
} }
} }
@@ -133,23 +133,23 @@ fn Project(prop: ProjectProp) -> Element {
rsx! { rsx! {
Link { Link {
class:"block max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700", class:"block max-w-sm p-6 border rounded-lg shadow bg-gray-800 border-gray-700 hover:bg-gray-700",
to:"{prop.url}", to:"{prop.url}",
new_tab: true, new_tab: true,
h5 { h5 {
class:"mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white", class:"mb-2 text-2xl font-bold tracking-tight text-white",
"{prop.title}", "{prop.title}",
}, },
p { class: "text-lg text-gray-900 dark:text-white", "{prop.kind}" }, p { class: "text-lg text-white", "{prop.kind}" },
p { p {
class:"font-normal text-gray-700 dark:text-gray-400", class:"font-normal text-gray-400",
Bolding { Bolding {
authors: "{prop.authors}", authors: "{prop.authors}",
patterns: pattern, patterns: pattern,
}, },
} }
p { p {
class:"font-normal text-gray-700 dark:text-gray-400", class:"font-normal text-gray-400",
"{prop.description}", "{prop.description}",
} }
} }