3 Commits
0.1.13 ... dev

Author SHA1 Message Date
Tuan-Dat Tran
fef5d771ba feat(dioxus): bump
Signed-off-by: Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>
2025-11-04 01:00:50 +01:00
Tuan-Dat Tran
1284dd9dd6 chore: recompile
Signed-off-by: Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>
2025-11-03 23:09:31 +01:00
Tuan-Dat Tran
538c99166f chore(deps): update rust dependencies
Signed-off-by: Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>
2025-08-15 08:18:54 +02:00
19 changed files with 2226 additions and 1725 deletions

View File

@@ -1,18 +0,0 @@
name: Build Docker Image
on:
push:
branches:
- main
- dev
- cicd
jobs:
build:
name: Build
runs-on: [ubuntu-latest, aya01]
steps:
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with:
tags: tudattr/athome:latest

3579
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.1" version = "0.2.0"
authors = ["Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>"] authors = ["Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>"]
edition = "2021" edition = "2021"
@@ -8,27 +8,17 @@ edition = "2021"
[dependencies] [dependencies]
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
dioxus = { version = "0.6", features = ["fullstack", "router"] } dioxus = { version = "0.7.0", features = ["fullstack", "router"] }
# Debug # Debug
tracing = "0.1.40" tracing = "0.1.40"
dioxus-logger = "0.6.0" dioxus-logger = "0.7.0"
dioxus-i18n = "0.4.0" dioxus-i18n = { git = "https://github.com/Kannen/dioxus-i18n/", branch = "main"}
tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] }
[features] [features]
default = [] default = ["web"]
web = ["dioxus/web"] web = ["dioxus/web"]
desktop = ["dioxus/desktop"] desktop = ["dioxus/desktop"]
mobile = ["dioxus/mobile"]
server = ["dioxus/server"] server = ["dioxus/server"]
[profile]
[profile.wasm-dev]
inherits = "dev"
opt-level = 1
[profile.server-dev]
inherits = "dev"
[profile.android-dev]
inherits = "dev"

View File

@@ -19,7 +19,10 @@ ENV PATH="/.cargo/bin:$PATH"
# Create the final bundle folder. Bundle always executes in release mode with optimizations enabled # Create the final bundle folder. Bundle always executes in release mode with optimizations enabled
RUN dx bundle --platform web RUN dx bundle --platform web
FROM chef AS runtime FROM debian:bookworm-slim AS runtime
# Install ca-certificates for HTTPS requests if the server makes any outgoing calls
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/dx/athome/release/web/ /usr/local/app COPY --from=builder /app/target/dx/athome/release/web/ /usr/local/app
# set our port and make sure to listen for all connections # set our port and make sure to listen for all connections

View File

@@ -723,18 +723,10 @@ 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;
} }
@@ -747,14 +739,6 @@ 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;
} }
@@ -771,10 +755,6 @@ video {
justify-content: space-between; justify-content: space-between;
} }
.justify-stretch {
justify-content: stretch;
}
.gap-2 { .gap-2 {
gap: 0.5rem; gap: 0.5rem;
} }
@@ -801,10 +781,6 @@ 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;
} }
@@ -1071,10 +1047,6 @@ video {
text-transform: uppercase; text-transform: uppercase;
} }
.italic {
font-style: italic;
}
.leading-none { .leading-none {
line-height: 1; line-height: 1;
} }

View File

@@ -1,7 +1,6 @@
headers_home = Home headers_home = Home
headers_cv = Lebenslauf headers_cv = Lebenslauf
headers_publications_projects = Artikel/Projekte headers_publications_projects = Artikel/Projekte
headers_consulting = Consulting
headers_about = Impressum headers_about = Impressum
headers_language_buttons_english = 🇬🇧 Englisch headers_language_buttons_english = 🇬🇧 Englisch
headers_language_buttons_german = 🇩🇪 Deutsch headers_language_buttons_german = 🇩🇪 Deutsch
@@ -16,7 +15,7 @@ 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 modernen 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.
@@ -62,20 +61,19 @@ 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 = Als DevOps Engineer bei DextraData cv_workexperience_dd_devops_description = Als DevOps Engineer war ich
bin ich für die Cloud-basierte Infrastruktur hinter den vielfältigen verantwortlich für das Design, die Implementierung und die Wartung
SaaS-Produkten des Unternehmens verantwortlich. Ich arbeite eng mit skalierbarer Infrastrukturlösungen in verschiedenen SaaS-Produktumgebungen.
Software-Entwicklern, Customer Success Managern und Customer Success Engineers Dies umfasste die Standardisierung und Optimierung von CI/CD-Pipelines sowie
zusammen, um betriebliche Exzellenz und unterbrechungsfreie Servicebereitstellung den Aufbau robuster Monitoring-Frameworks zur Gewährleistung hoher
für unsere Kunden zu gewährleisten, wobei ihre spezifischen Anforderungen im Verfügbarkeit und Performance. Meine Arbeit konzentrierte sich auf einen
Vordergrund stehen. Ich verwalte Kubernetes-Cluster-Deployments, überwache "Shift-Left"-Ansatz, der Entwicklungsteams durch Self-Service-Funktionen und
kontinuierlich Deployment-Gesundheitsmetriken und implementiere optimierte operative Workflows befähigte, sowie auf die Verbesserung der
Infrastructure-as-Code-Lösungen. Systemzuverlässigkeit und -sicherheit.
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
cv_education_bachelor_time = 2015 - jetzt cv_education_bachelor_time = 2015 - jetzt
cv_education_bachelor_description = ""
cv_skills_title = Fähigkeiten cv_skills_title = Fähigkeiten
cv_skills_devops_title = DevOps cv_skills_devops_title = DevOps
cv_skills_devops_ansible = Ansible cv_skills_devops_ansible = Ansible
@@ -111,7 +109,6 @@ publications_projects_publications_rpm_description = In diesem Artikel stellen
publications_projects_publications_iot_fuzzers_title = Overview of IoT Fuzzing Techniques publications_projects_publications_iot_fuzzers_title = Overview of IoT Fuzzing Techniques
publications_projects_publications_iot_fuzzers_authors = Tuan-Dat Tran publications_projects_publications_iot_fuzzers_authors = Tuan-Dat Tran
publications_projects_publications_iot_fuzzers_conference = Seminar publications_projects_publications_iot_fuzzers_conference = Seminar
publications_projects_publications_iot_fuzzers_url = https://git.tudattr.dev/AISE/seminar/src/branch/main/paper.pdf
publications_projects_publications_iot_fuzzers_description = In dieser Arbeit publications_projects_publications_iot_fuzzers_description = In dieser Arbeit
vergleichen wir Methoden, die speziell von IoT Fuzzern genutzt werden um die vergleichen wir Methoden, die speziell von IoT Fuzzern genutzt werden um die
von IoT Geräten stammenden Herausforderungen und Einschränkungen zu umgehen. von IoT Geräten stammenden Herausforderungen und Einschränkungen zu umgehen.
@@ -119,13 +116,11 @@ publications_projects_projects_title = Projekte
publications_projects_projects_bpba_title = Unbenannter Ethereum Smart Contract Fuzzer publications_projects_projects_bpba_title = Unbenannter Ethereum Smart Contract Fuzzer
publications_projects_projects_bpba_authors = Tuan-Dat Tran publications_projects_projects_bpba_authors = Tuan-Dat Tran
publications_projects_projects_bpba_kind = Bachelorprojekt/Bachelorarbeit publications_projects_projects_bpba_kind = Bachelorprojekt/Bachelorarbeit
publications_projects_projects_bpba_url = https://git.ude-syssec.de/uni-due-syssec/students/2022_tuan-dat_tran_libAFLEVMFuzzer/ethfuzz/
publications_projects_projects_bpba_description = In diesem aktuell laufendem publications_projects_projects_bpba_description = In diesem aktuell laufendem
Projekt entwickle ich einen Ethereum Smart Contract Fuzzer. Mehr Infos folgen... Projekt entwickle ich einen Ethereum Smart Contract Fuzzer. Mehr Infos folgen...
publications_projects_projects_dotfiles_title = .dotfiles publications_projects_projects_dotfiles_title = .dotfiles
publications_projects_projects_dotfiles_authors = Tuan-Dat Tran publications_projects_projects_dotfiles_authors = Tuan-Dat Tran
publications_projects_projects_dotfiles_kind = Personal publications_projects_projects_dotfiles_kind = Personal
publications_projects_projects_dotfiles_url = https://git.tudattr.dev/tudattr/dotfiles
publications_projects_projects_dotfiles_description = dotfiles ist ein publications_projects_projects_dotfiles_description = dotfiles ist ein
umgangssprachlicher Begriff, der normalerweise für Konfigurationsdateien in umgangssprachlicher Begriff, der normalerweise für Konfigurationsdateien in
Linux-basierten Systemen verwendet wird. Meine Dotfiles enthalten Linux-basierten Systemen verwendet wird. Meine Dotfiles enthalten
@@ -137,7 +132,6 @@ publications_projects_projects_dotfiles_description = dotfiles ist ein
publications_projects_projects_homelab_title = Homelab publications_projects_projects_homelab_title = Homelab
publications_projects_projects_homelab_authors = Tuan-Dat Tran publications_projects_projects_homelab_authors = Tuan-Dat Tran
publications_projects_projects_homelab_kind = Personal publications_projects_projects_homelab_kind = Personal
publications_projects_projects_homelab_url = https://git.tudattr.dev/tudattr/ansible
publications_projects_projects_homelab_description = Ansible ist ein publications_projects_projects_homelab_description = Ansible ist ein
Automatisierungs-Werkzeug, die eine automatische Maschinenbereitstellung, Automatisierungs-Werkzeug, die eine automatische Maschinenbereitstellung,
Konfigurationsverwaltung und Anwendungsbereitstellung ermöglicht. Ich Konfigurationsverwaltung und Anwendungsbereitstellung ermöglicht. Ich
@@ -146,15 +140,14 @@ publications_projects_projects_homelab_description = Ansible ist ein
publications_projects_projects_athome_title = Diese Website publications_projects_projects_athome_title = Diese Website
publications_projects_projects_athome_authors = Tuan-Dat Tran publications_projects_projects_athome_authors = Tuan-Dat Tran
publications_projects_projects_athome_kind = Personal publications_projects_projects_athome_kind = Personal
publications_projects_projects_athome_url = /#
publications_projects_projects_athome_description = Diese Website ist eine mit publications_projects_projects_athome_description = Diese Website ist eine mit
dem auf Rust basiertem Dioxus Framwork und TailwindCSS gebaute Full Stack dem auf Rust basiertem Dioxus Framwork und TailwindCSS gebaute Full Stack
WASM Website, die sowohl zum Auffrischen von Web Themen, sowie als Rust WASM Website, die sowohl zum Auffrischen von Web Themen, sowie als Rust
Hobbyprojekt dient. Hobbyprojekt dient.
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 = © 2025
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
link_opens_new_tab = (öffnet in neuem Tab)

View File

@@ -1,7 +1,6 @@
headers_home = Home headers_home = Home
headers_cv = Résumé headers_cv = Résumé
headers_publications_projects = Publications/Projects headers_publications_projects = Publications/Projects
headers_consulting = Consulting
headers_about = About headers_about = About
headers_language_buttons_english = 🇬🇧 English headers_language_buttons_english = 🇬🇧 English
headers_language_buttons_german = 🇩🇪 German headers_language_buttons_german = 🇩🇪 German
@@ -14,6 +13,7 @@ home_card_text =
home_card_contact_button = Get in touch. home_card_contact_button = Get in touch.
cv_introduction_title = DevOps Engineer | Homelab Enthusiast cv_introduction_title = DevOps Engineer | Homelab Enthusiast
cv_introduction_0 = cv_introduction_0 =
A results-driven DevOps Engineer with a career in technology spanning over 8 years. My journey began with foundational part-time roles in software development (C#, Python) and academic research during my university studies. Now, I apply this deep technical understanding to my full-time DevOps role, where I specialize in building and maintaining scalable, high-availability SaaS infrastructure using Kubernetes, Azure, ArgoCD, and Ansible.
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,
Ansible, Azure, and modern cloud technologies. Hands-on research experience Ansible, Azure, and modern cloud technologies. Hands-on research experience
@@ -58,19 +58,18 @@ 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, I was
I am responsible for the cloud-based infrastructure hosting our companies responsible for designing, implementing, and maintaining scalable
diverse portfolio of SaaS products, collaborating with Software Developers, infrastructure solutions across multiple SaaS product environments. This
Customer Success Managers, and Customer Success Engineers to ensure involved standardizing and optimizing CI/CD pipelines and establishing
operational excellence and uninterrupted service delivery for our customers robust monitoring frameworks to ensure high availability and performance.
with their specific requirements at the forefront. I manage My work focused on a "shift-left" approach, empowering development teams
Kubernetes cluster deployments, continuously monitor deployment health metrics, with self-service capabilities and streamlined operational workflows as
and implement Infrastructure as Code solutions. well as enhancement of system reliability and security.
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
cv_education_bachelor_time = 2015 - now cv_education_bachelor_time = 2015 - now
cv_education_bachelor_description = ""
cv_skills_title = Skills cv_skills_title = Skills
cv_skills_devops_title = DevOps cv_skills_devops_title = DevOps
cv_skills_devops_ansible = Ansible cv_skills_devops_ansible = Ansible
@@ -106,7 +105,6 @@ publications_projects_publications_rpm_description = In this paper, we present
publications_projects_publications_iot_fuzzers_title = Overview of IoT Fuzzing Techniques publications_projects_publications_iot_fuzzers_title = Overview of IoT Fuzzing Techniques
publications_projects_publications_iot_fuzzers_authors = Tuan-Dat Tran publications_projects_publications_iot_fuzzers_authors = Tuan-Dat Tran
publications_projects_publications_iot_fuzzers_conference = Seminar publications_projects_publications_iot_fuzzers_conference = Seminar
publications_projects_publications_iot_fuzzers_url = https://git.tudattr.dev/AISE/seminar/src/branch/main/paper.pdf
publications_projects_publications_iot_fuzzers_description = In this paper, we publications_projects_publications_iot_fuzzers_description = In this paper, we
are comparing techniques used by IoT fuzzers to circumvent the challenges are comparing techniques used by IoT fuzzers to circumvent the challenges
presented by IoT devices and the constraints of the solutions proposed by the presented by IoT devices and the constraints of the solutions proposed by the
@@ -115,12 +113,10 @@ publications_projects_projects_title = Projects
publications_projects_projects_bpba_title = Undisclosed Ethereum Smart Contract Fuzzer publications_projects_projects_bpba_title = Undisclosed Ethereum Smart Contract Fuzzer
publications_projects_projects_bpba_authors = Tuan-Dat Tran publications_projects_projects_bpba_authors = Tuan-Dat Tran
publications_projects_projects_bpba_kind = Bachelor Project/Bachelor Thesis publications_projects_projects_bpba_kind = Bachelor Project/Bachelor Thesis
publications_projects_projects_bpba_url = https://git.ude-syssec.de/uni-due-syssec/students/2022_tuan-dat_tran_libAFLEVMFuzzer/ethfuzz/
publications_projects_projects_bpba_description = In this ongoing project I am building an Ethereum Smart Contract Fuzzer. More info will follow. publications_projects_projects_bpba_description = In this ongoing project I am building an Ethereum Smart Contract Fuzzer. More info will follow.
publications_projects_projects_dotfiles_title = .dotfiles publications_projects_projects_dotfiles_title = .dotfiles
publications_projects_projects_dotfiles_authors = Tuan-Dat Tran publications_projects_projects_dotfiles_authors = Tuan-Dat Tran
publications_projects_projects_dotfiles_kind = Personal publications_projects_projects_dotfiles_kind = Personal
publications_projects_projects_dotfiles_url = https://git.tudattr.dev/tudattr/dotfiles
publications_projects_projects_dotfiles_description = dotfiles is a slang term publications_projects_projects_dotfiles_description = dotfiles is a slang term
usually used for configuration files in Linux based systems. My dotfiles usually used for configuration files in Linux based systems. My dotfiles
contain configurations for tools I frequently use as well as a documentation contain configurations for tools I frequently use as well as a documentation
@@ -130,7 +126,6 @@ publications_projects_projects_dotfiles_description = dotfiles is a slang term
publications_projects_projects_homelab_title = Homelab publications_projects_projects_homelab_title = Homelab
publications_projects_projects_homelab_authors = Tuan-Dat Tran publications_projects_projects_homelab_authors = Tuan-Dat Tran
publications_projects_projects_homelab_kind = Personal publications_projects_projects_homelab_kind = Personal
publications_projects_projects_homelab_url = https://git.tudattr.dev/tudattr/ansible
publications_projects_projects_homelab_description = Ansible is a automation publications_projects_projects_homelab_description = Ansible is a automation
tool which allows for automatic provisioning, configuration management and tool which allows for automatic provisioning, configuration management and
application deployment. I use ansible to set up my homelab, which serves as a application deployment. I use ansible to set up my homelab, which serves as a
@@ -138,15 +133,14 @@ publications_projects_projects_homelab_description = Ansible is a automation
publications_projects_projects_athome_title = This Website publications_projects_projects_athome_title = This Website
publications_projects_projects_athome_authors = Tuan-Dat Tran publications_projects_projects_athome_authors = Tuan-Dat Tran
publications_projects_projects_athome_kind = Personal publications_projects_projects_athome_kind = Personal
publications_projects_projects_athome_url = /#
publications_projects_projects_athome_description = This website is a publications_projects_projects_athome_description = This website is a
full-stack WASM site built using the Rust-based Dioxus framework and full-stack WASM site built using the Rust-based Dioxus framework and
TailwindCSS. It serves both as a way to refresh web development topics and as TailwindCSS. It serves both as a way to refresh web development topics and as
a Rust hobby project. a Rust hobby project.
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 = © 2025
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
link_opens_new_tab = (opens in a new tab)

24
package-lock.json generated
View File

@@ -4,6 +4,9 @@
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"dependencies": {
"caniuse-lite": "^1.0.30001753"
},
"devDependencies": { "devDependencies": {
"tailwindcss": "^3.4.3" "tailwindcss": "^3.4.3"
} }
@@ -227,6 +230,26 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/caniuse-lite": {
"version": "1.0.30001753",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001753.tgz",
"integrity": "sha512-Bj5H35MD/ebaOV4iDLqPEtiliTN29qkGtEHCwawWn4cYm+bPJM2NsaP30vtZcnERClMzp52J4+aw2UNbK4o+zw==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "CC-BY-4.0"
},
"node_modules/chokidar": { "node_modules/chokidar": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -782,6 +805,7 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.7", "nanoid": "^3.3.7",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",

View File

@@ -1,5 +1,8 @@
{ {
"devDependencies": { "devDependencies": {
"tailwindcss": "^3.4.3" "tailwindcss": "^3.4.3"
},
"dependencies": {
"caniuse-lite": "^1.0.30001753"
} }
} }

View File

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

61
scripts/check_i18n.py Normal file
View File

@@ -0,0 +1,61 @@
import os
import re
def check_i18n_keys(project_root):
src_dir = os.path.join(project_root, "src")
languages_dir = os.path.join(project_root, "languages")
rust_key_regex = re.compile(r't!\("([a-zA-Z0-9_.]+)"\)')
ftl_key_regex = re.compile(r"^([a-zA-Z0-9_.-]+)\s*=")
used_keys = set()
defined_keys = set()
# Extract keys from Rust files
for root, _, files in os.walk(src_dir):
for file in files:
if file.endswith(".rs"):
file_path = os.path.join(root, file)
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
for match in rust_key_regex.finditer(content):
used_keys.add(match.group(1))
# Extract keys from FTL files
for root, _, files in os.walk(languages_dir):
for file in files:
if file.endswith(".ftl"):
file_path = os.path.join(root, file)
with open(file_path, "r", encoding="utf-8") as f:
for line in f:
match = ftl_key_regex.match(line)
if match:
defined_keys.add(match.group(1))
print("--- i18n Key Check Report ---")
missing_keys = used_keys - defined_keys
if not missing_keys:
print("✅ No missing translation keys found in FTL files.")
else:
print(
"❌ Missing translation keys (used in code but not defined in FTL files):"
)
for key in sorted(list(missing_keys)):
print(f" - {key}")
unused_keys = defined_keys - used_keys
if not unused_keys:
print("✅ No unused translation keys found in FTL files.")
else:
print("⚠️ Unused translation keys (defined in FTL files but not used in code):")
for key in sorted(list(unused_keys)):
print(f" - {key}")
print("-----------------------------")
if __name__ == "__main__":
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
check_i18n_keys(project_root)

View File

@@ -280,3 +280,35 @@ fn random_badge_color(seed: usize) -> String {
colors[seed % colors.len()].to_string() colors[seed % colors.len()].to_string()
} }
#[derive(PartialEq, Props, Clone)]
pub struct AccessibleLinkProps {
to: String,
#[props(default = "".to_string())]
class: String,
#[props(default = false)]
new_tab: bool,
children: Element,
}
#[component]
pub fn AccessibleLink(props: AccessibleLinkProps) -> Element {
let mut aria_label = String::new();
let mut rel = String::new();
if props.new_tab {
aria_label = t!("link_opens_new_tab").to_string();
rel = "noopener noreferrer".to_string();
}
rsx! {
Link {
to: "{props.to}",
class: "{props.class}",
new_tab: props.new_tab,
rel: "{rel}",
aria_label: "{aria_label}",
{props.children}
}
}
}

View File

@@ -13,7 +13,7 @@ pub fn CV() -> Element {
img { img {
class: "rounded-full w-24 h-24", class: "rounded-full w-24 h-24",
alt: "headshot", alt: "headshot",
src: asset!("./assets/pictures/headshot.webp") src: asset!("/assets/pictures/headshot.webp")
} }
Introduction {}, Introduction {},
Socials {} Socials {}
@@ -39,11 +39,11 @@ fn Introduction() -> Element {
P { P {
{ t!("cv_introduction_tools") }, { t!("cv_introduction_tools") },
" ", " ",
Link { new_tab: true, to: "https://www.lazyvim.org/", "NeoVim (LazyVim)" }, AccessibleLink { new_tab: true, to: "https://www.lazyvim.org/", "NeoVim" },
", ", ", ",
Link { new_tab: true, to: "https://zellij.dev/", "Zellij" }, AccessibleLink { new_tab: true, to: "https://zellij.dev/", "Zellij" },
", ", ", ",
Link { new_tab: true, to: "https://k9scli.io/", "k9s" } AccessibleLink { new_tab: true, to: "https://k9scli.io/", "k9s" }
}, },
}, },
} }
@@ -57,7 +57,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!["Kubernetes".to_string(), "ArgoCD".to_string(), "Ansible".to_string(), "Azure".to_string(), "Elastic Stack".to_string(), "Helm".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"),
@@ -210,7 +210,7 @@ fn Socials() -> Element {
H4 { { t!("cv_socials_title") } }, H4 { { t!("cv_socials_title") } },
div { div {
class: "flex justify-center items-center space-x-4", 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" } }}, P { AccessibleLink { 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" } }},
} }
} }
} }

View File

@@ -1,4 +1,4 @@
use crate::components::{Card, P}; use crate::components::{AccessibleLink, Card, P};
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_i18n::t; use dioxus_i18n::t;
@@ -10,7 +10,7 @@ pub fn Home() -> Element {
Card { Card {
name: t!("home_card_name"), name: t!("home_card_name"),
gender: t!("home_card_gender"), gender: t!("home_card_gender"),
picture: asset!("./assets/pictures/headshot.webp"), picture: asset!("/assets/pictures/headshot.webp"),
div { div {
class: "py-4", class: "py-4",
div { div {
@@ -20,9 +20,10 @@ pub fn Home() -> Element {
} }
}, },
}, },
Link { AccessibleLink {
to: "mailto:tuan-dat.tran@tudattr.dev", to: "mailto:tuan-dat.tran@tudattr.dev",
class: "text-gray-900 bg-gradient-to-br from-green-400 to-blue-600 group-hover:from-green-400 group-hover:to-blue-600 hover:text-white rounded-full shadow-lg py-4 px-4", class: "text-gray-900 bg-gradient-to-br from-green-400 to-blue-600 group-hover:from-green-400 group-hover:to-blue-600 hover:text-white rounded-full shadow-lg py-4 px-4",
new_tab: true,
{ t!("home_card_contact_button") } { t!("home_card_contact_button") }
} }
}, },

View File

@@ -1,59 +1,30 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_i18n::t;
use crate::components::{H1, HR, P}; use crate::components::{H1, HR, P};
#[component] #[component]
pub fn Impressum() -> Element { pub fn Impressum() -> Element {
let mut impressum = use_signal(Vec::<String>::new);
let mut contact = use_signal(Vec::<String>::new);
rsx! { rsx! {
div { div {
div { div {
class: "flex flex-col items-center", class: "flex flex-col items-center",
button { H1 { "Impressum" },
onclick: move |_| async move {
if let Ok(data) = get_impressum().await {
impressum.set(data.clone());
}
if let Ok(data) = get_contact().await {
contact.set(data.clone());
}
},
H1 { { t!("impressum_on") } },
},
}, },
HR{},
div { div {
class: "flex flex-col items-center", class: "flex flex-col items-center",
for line in impressum() { P { {"Tuan-Dat Tran"} },
P { {line} } P { {"c/o AutorenServices.de"} },
} P { {"Birkenallee 24"} },
P { {"36037 Fulda"} },
} }
if !impressum.read().is_empty() { HR{} }, HR{},
div { div {
class: "flex flex-col items-center", class: "flex flex-col items-center",
for line in contact() { P { {"tuan-dat.tran(at)tudattr(dot)dev"} },
P { {line} } P { {"+49 17(six) 83(four)683(eight)8"} },
}
} }
} }
} }
} }
#[server(GetServerData)]
async fn get_impressum() -> Result<Vec<String>, ServerFnError> {
Ok(vec![
"Tuan-Dat Tran".to_string(),
"c/o AutorenServices.de".to_string(),
"Birkenallee 24".to_string(),
"36037 Fulda".to_string(),
])
}
async fn get_contact() -> Result<Vec<String>, ServerFnError> {
Ok(vec![
"tuan-dat.tran(at)tudattr(dot)dev".to_string(),
"+49 17(six) 83(four)683(eight)8".to_string(),
])
}

View File

@@ -12,7 +12,9 @@ pub fn Footer() -> Element {
span { span {
class:"text-sm sm:text-center 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 {

View File

@@ -1,5 +1,5 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_i18n::{prelude::i18n, t, unic_langid::langid}; use dioxus_i18n::{prelude::*, t, unic_langid::langid};
use crate::Route; use crate::Route;
@@ -15,7 +15,7 @@ pub fn Header() -> Element {
Link { Link {
to: Route::Home {}, to: Route::Home {},
class: "rounded-md shadow-sm", class: "rounded-md shadow-sm",
img { src:asset!("./assets/pictures/ClackCat_t.webp"), class:"rounded-full h-8", alt:"TuDatTr Logo" }, img { src:asset!("/assets/pictures/ClackCat_t.webp"), class:"rounded-full h-8", alt:"TuDatTr Logo" },
}, },
}, },
li { HeaderLink { url: Route::Home {}, text: t!("headers_home")} }, li { HeaderLink { url: Route::Home {}, text: t!("headers_home")} },

View File

@@ -3,13 +3,11 @@
use components::H1; use components::H1;
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_i18n::prelude::use_init_i18n; use dioxus_i18n::{prelude::*, unic_langid::langid};
use dioxus_i18n::prelude::I18nConfig;
use dioxus_i18n::prelude::Locale;
use dioxus_i18n::unic_langid::langid;
use layout::footer::Footer; use layout::footer::Footer;
use layout::header::Header; use layout::header::Header;
use tracing::Level; use tracing::{Level, info};
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
pub mod components; pub mod components;
mod cv; mod cv;
@@ -35,32 +33,42 @@ pub enum Route {
PublicationsProjects {}, PublicationsProjects {},
#[route("/resume")] #[route("/resume")]
CV {}, CV {},
#[route("/health")]
Health {},
#[end_layout] #[end_layout]
#[route("/:..route")] #[route("/:..route")]
PageNotFound { route: Vec<String> }, PageNotFound { route: Vec<String> },
} }
fn main() { fn main() {
dioxus_logger::init(Level::DEBUG).expect("failed to init logger"); // Configure tracing to output JSON logs
LaunchBuilder::new().launch(App) tracing_subscriber::registry()
.with(EnvFilter::from_default_env().add_directive(Level::INFO.into()))
.with(fmt::layer().json())
.init();
info!("Starting Dioxus application...");
LaunchBuilder::new().launch(App);
}
#[component]
fn Health() -> Element {
rsx! { "OK" }
} }
fn App() -> Element { fn App() -> Element {
use_init_i18n(|| { use_init_i18n(|| {
I18nConfig::new(langid!("en-GB")) I18nConfig::new(langid!("en-GB"))
.with_locale((langid!("de-DE"), include_str!("../languages/de-DE.ftl")))
.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(
langid!("de-DE"),
include_str!("../languages/de-DE.ftl"),
))
}); });
rsx! { rsx! {
document::Link { rel: "stylesheet", href: asset!("./assets/tailwind.css") } document::Link { rel: "stylesheet", href: asset!("/assets/tailwind.css") }
document::Link { rel: "icon", href: asset!("./assets/favicon.ico") } document::Link { rel: "icon", href: asset!("/assets/favicon.ico") }
meta { meta {
name: "description", name: "description",
content: "Visit Tuan-Dat Tran's website for his CV, publications, projects, and consulting services. Connect for collaboration.", content: "Visit Tuan-Dat Tran's website for his CV, publications, projects, and consulting services. Connect for collaboration.",

View File

@@ -81,7 +81,7 @@ fn Publications() -> Element {
authors: t!("publications_projects_publications_iot_fuzzers_authors"), authors: t!("publications_projects_publications_iot_fuzzers_authors"),
technologies: vec![], technologies: vec![],
kind: t!("publications_projects_publications_iot_fuzzers_conference"), kind: t!("publications_projects_publications_iot_fuzzers_conference"),
url: "/#", url: "/publications/#",
description: t!("publications_projects_publications_iot_fuzzers_description") description: t!("publications_projects_publications_iot_fuzzers_description")
}, },
} }
@@ -97,7 +97,7 @@ fn Projects() -> Element {
authors: t!("publications_projects_projects_bpba_authors"), authors: t!("publications_projects_projects_bpba_authors"),
technologies: vec![], technologies: vec![],
kind: t!("publications_projects_projects_bpba_kind"), kind: t!("publications_projects_projects_bpba_kind"),
url: "/#", url: "/publications/#",
description: t!("publications_projects_projects_bpba_description") description: t!("publications_projects_projects_bpba_description")
}, },
Project { Project {
@@ -105,7 +105,7 @@ fn Projects() -> Element {
authors: t!("publications_projects_projects_dotfiles_authors"), authors: t!("publications_projects_projects_dotfiles_authors"),
technologies: vec![], technologies: vec![],
kind: t!("publications_projects_projects_dotfiles_kind"), kind: t!("publications_projects_projects_dotfiles_kind"),
url: "/#", url: "/publications/#",
description: t!("publications_projects_projects_dotfiles_description") description: t!("publications_projects_projects_dotfiles_description")
}, },
Project { Project {
@@ -113,7 +113,7 @@ fn Projects() -> Element {
authors: t!("publications_projects_projects_homelab_authors"), authors: t!("publications_projects_projects_homelab_authors"),
technologies: vec![], technologies: vec![],
kind: t!("publications_projects_projects_homelab_kind"), kind: t!("publications_projects_projects_homelab_kind"),
url: "/#", url: "/publications/#",
description: t!("publications_projects_projects_homelab_description") description: t!("publications_projects_projects_homelab_description")
} }
Project { Project {
@@ -121,7 +121,7 @@ fn Projects() -> Element {
authors: t!("publications_projects_projects_athome_authors"), authors: t!("publications_projects_projects_athome_authors"),
technologies: vec![], technologies: vec![],
kind: t!("publications_projects_projects_athome_kind"), kind: t!("publications_projects_projects_athome_kind"),
url: "/#", url: "/publications/#",
description: t!("publications_projects_projects_athome_description") description: t!("publications_projects_projects_athome_description")
} }
} }