Skip to content

Commit 063660d

Browse files
committed
Modernize Look & Feel
1 parent be0ab14 commit 063660d

13 files changed

Lines changed: 1090 additions & 869 deletions

File tree

src/components/footer.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,43 @@ use stylist::yew::styled_component;
55
#[styled_component]
66
pub fn Footer() -> Html {
77
html! {
8-
<footer class="mt-auto flex flex-nowrap min-w-full h-3 z-40">
9-
{
10-
(1..7).into_iter().map(|color| {
11-
html! {
12-
<div class={format!("min-h-full w-1/6 bg-rainbow-{}", color)} />
13-
}
14-
}).collect::<Html>()
15-
}
8+
<footer class="mt-auto">
9+
// Copyright notice
10+
<div class={css!(r#"
11+
background: #0F172A;
12+
padding: 2rem 1rem;
13+
text-align: center;
14+
border-top: 1px solid rgba(203, 213, 225, 0.1);
15+
"#)}>
16+
<p class={css!(r#"
17+
color: rgba(203, 213, 225, 0.6);
18+
font-size: 0.875rem;
19+
line-height: 1.5;
20+
"#)}>
21+
{"© 2025 Til Mohr"}
22+
{" · "}
23+
<a href="https://github.com/CodingTil/personal-site" class={css!(r#"
24+
color: rgba(203, 213, 225, 0.6);
25+
transition: color 0.2s ease;
26+
&:hover {
27+
color: #60A5FA;
28+
}
29+
"#)}>
30+
{"Source Code"}
31+
</a>
32+
</p>
33+
</div>
34+
35+
// Rainbow bar
36+
<div class="flex flex-nowrap min-w-full h-3">
37+
{
38+
(1..7).into_iter().map(|color| {
39+
html! {
40+
<div class={format!("min-h-full w-1/6 bg-rainbow-{}", color)} />
41+
}
42+
}).collect::<Html>()
43+
}
44+
</div>
1645
</footer>
1746
}
1847
}

src/components/header.rs

Lines changed: 194 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use gloo::timers::callback::Timeout;
2+
use web_sys::window;
13
use yew::prelude::*;
24
use yew_router::prelude::*;
35

@@ -6,9 +8,21 @@ use stylist::yew::styled_component;
68
use crate::localization::{use_localization, Localization};
79
use crate::router::Route;
810

11+
fn scroll_to_section(section_id: &str) {
12+
if let Some(window) = window() {
13+
if let Some(document) = window.document() {
14+
if let Some(element) = document.get_element_by_id(section_id) {
15+
element.scroll_into_view();
16+
}
17+
}
18+
}
19+
}
20+
921
#[styled_component]
1022
pub fn Header() -> Html {
1123
let localization = use_localization();
24+
let navigator = use_navigator().unwrap();
25+
let location = use_location().unwrap();
1226

1327
let current_locale = localization.get().clone();
1428

@@ -21,54 +35,198 @@ pub fn Header() -> Html {
2135

2236
let switch_locale = Callback::from(move |_| localization.set(other_locale.clone()));
2337

24-
let header_css = css!(
25-
r#"
26-
backdrop-filter: blur(12px) saturate(180%);
27-
-webkit-backdrop-filter: blur(12px) saturate(180%);
28-
background-color: rgba(15, 23, 42, 0.85);
29-
border-bottom: 1px solid rgba(203, 213, 225, 0.1);
30-
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
31-
"#
32-
);
38+
// Get translations for navigation items
39+
let (projects_text, experience_text, education_text, contact_text) = match current_locale {
40+
Localization::EN => ("Projects", "Experience", "Education", "Contact"),
41+
Localization::DE => ("Projekte", "Erfahrung", "Bildung", "Kontakt"),
42+
};
43+
44+
// Check if we're on the home page
45+
let is_home = location.path() == "/";
46+
47+
// Create navigation callbacks for sections
48+
let nav_to_section = {
49+
let navigator = navigator.clone();
50+
Callback::from(move |section: String| {
51+
let section_clone = section.clone();
52+
if is_home {
53+
// Already on home, just scroll
54+
scroll_to_section(&section);
55+
} else {
56+
// Navigate to home first
57+
navigator.push(&Route::Home);
58+
// Wait a bit for the DOM to update, then scroll
59+
Timeout::new(100, move || {
60+
scroll_to_section(&section_clone);
61+
})
62+
.forget();
63+
}
64+
})
65+
};
66+
67+
let on_projects_click = {
68+
let nav = nav_to_section.clone();
69+
Callback::from(move |e: MouseEvent| {
70+
e.prevent_default();
71+
nav.emit("projects".to_string());
72+
})
73+
};
74+
75+
let on_experience_click = {
76+
let nav = nav_to_section.clone();
77+
Callback::from(move |e: MouseEvent| {
78+
e.prevent_default();
79+
nav.emit("experience".to_string());
80+
})
81+
};
82+
83+
let on_education_click = {
84+
let nav = nav_to_section.clone();
85+
Callback::from(move |e: MouseEvent| {
86+
e.prevent_default();
87+
nav.emit("education".to_string());
88+
})
89+
};
90+
91+
let on_contact_click = {
92+
let nav = nav_to_section.clone();
93+
Callback::from(move |e: MouseEvent| {
94+
e.prevent_default();
95+
nav.emit("contact".to_string());
96+
})
97+
};
3398

3499
html! {
35-
<div class={classes!("h-20", "sticky", "top-0", "z-50", "w-full", header_css)}>
36-
<nav class="container mx-auto pt-5 pb-3 max-w-7xl px-4 xl:px-0 flex justify-between items-center">
100+
<div class={css!(r#"
101+
position: fixed;
102+
top: 0;
103+
left: 0;
104+
right: 0;
105+
z-index: 1000;
106+
backdrop-filter: blur(12px) saturate(180%);
107+
-webkit-backdrop-filter: blur(12px) saturate(180%);
108+
background-color: rgba(15, 23, 42, 0.8);
109+
"#)}>
110+
<nav class={css!(r#"
111+
max-width: 80rem;
112+
margin: 0 auto;
113+
padding: 1.25rem 2rem;
114+
display: flex;
115+
justify-content: space-between;
116+
align-items: center;
117+
@media (max-width: 768px) {
118+
padding: 1rem 1.5rem;
119+
}
120+
"#)}>
37121
<Link<Route> to={Route::Home} classes={css!(r#"
38122
display: flex;
39123
align-items: center;
40124
gap: 0.75rem;
125+
color: #F1F5F9;
126+
font-weight: 700;
127+
font-size: 1.125rem;
41128
transition: all 0.2s ease;
129+
font-family: 'Space Grotesk', sans-serif;
130+
&:hover {
131+
color: #60A5FA;
132+
}
42133
"#)}>
43-
<div class={css!(r#"
44-
transition: all 0.2s ease;
45-
&:hover {
46-
transform: scale(1.1);
47-
}
48-
"#)}>
49-
<i class="fa-solid fa-trademark text-3xl text-rainbow-1" style="filter:drop-shadow(2px 2px 4px rgba(96, 165, 250, 0.3))"></i>
50-
</div>
51-
<span class="text-foreground-primary text-lg font-semibold">{"Home"}</span>
134+
<span>{"TM"}</span>
52135
</Link<Route>>
53-
<button onclick={switch_locale} class={css!(r#"
136+
137+
<div class={css!(r#"
54138
display: flex;
139+
gap: 2rem;
55140
align-items: center;
56-
gap: 0.75rem;
57-
padding: 0.5rem 1rem;
58-
border-radius: 0.5rem;
59-
background-color: rgba(51, 65, 85, 0.5);
60-
transition: all 0.2s ease;
61-
border: 1px solid rgba(203, 213, 225, 0.1);
62-
&:hover {
63-
background-color: rgba(71, 85, 105, 0.6);
64-
transform: translateY(-2px);
65-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
66-
}
67141
"#)}>
68-
<span class="sr-only">{"Switch language to "}</span>
69-
<span class="text-foreground-primary text-lg font-semibold">{other_locale_str}</span>
70-
<i class="fa-solid fa-language text-2xl text-rainbow-1"></i>
71-
</button>
142+
<a href="#projects" onclick={on_projects_click} class={css!(r#"
143+
color: rgba(203, 213, 225, 0.8);
144+
font-weight: 500;
145+
transition: color 0.2s ease;
146+
display: flex;
147+
align-items: center;
148+
line-height: 1;
149+
cursor: pointer;
150+
&:hover {
151+
color: #F1F5F9;
152+
}
153+
@media (max-width: 640px) {
154+
display: none;
155+
}
156+
"#)}>
157+
{projects_text}
158+
</a>
159+
<a href="#experience" onclick={on_experience_click} class={css!(r#"
160+
color: rgba(203, 213, 225, 0.8);
161+
font-weight: 500;
162+
transition: color 0.2s ease;
163+
display: flex;
164+
align-items: center;
165+
line-height: 1;
166+
cursor: pointer;
167+
&:hover {
168+
color: #F1F5F9;
169+
}
170+
@media (max-width: 640px) {
171+
display: none;
172+
}
173+
"#)}>
174+
{experience_text}
175+
</a>
176+
<a href="#education" onclick={on_education_click} class={css!(r#"
177+
color: rgba(203, 213, 225, 0.8);
178+
font-weight: 500;
179+
transition: color 0.2s ease;
180+
display: flex;
181+
align-items: center;
182+
line-height: 1;
183+
cursor: pointer;
184+
&:hover {
185+
color: #F1F5F9;
186+
}
187+
@media (max-width: 640px) {
188+
display: none;
189+
}
190+
"#)}>
191+
{education_text}
192+
</a>
193+
<a href="#contact" onclick={on_contact_click} class={css!(r#"
194+
color: rgba(203, 213, 225, 0.8);
195+
font-weight: 500;
196+
transition: color 0.2s ease;
197+
display: flex;
198+
align-items: center;
199+
line-height: 1;
200+
cursor: pointer;
201+
&:hover {
202+
color: #F1F5F9;
203+
}
204+
@media (max-width: 640px) {
205+
display: none;
206+
}
207+
"#)}>
208+
{contact_text}
209+
</a>
210+
211+
<button onclick={switch_locale} class={css!(r#"
212+
padding: 0.5rem 1rem;
213+
border-radius: 0.5rem;
214+
background-color: rgba(51, 65, 85, 0.5);
215+
color: #F1F5F9;
216+
font-weight: 500;
217+
border: 1px solid rgba(203, 213, 225, 0.1);
218+
transition: all 0.2s ease;
219+
display: flex;
220+
align-items: center;
221+
line-height: 1;
222+
&:hover {
223+
background-color: rgba(71, 85, 105, 0.7);
224+
border-color: rgba(96, 165, 250, 0.3);
225+
}
226+
"#)}>
227+
{other_locale_str}
228+
</button>
229+
</div>
72230
</nav>
73231
</div>
74232
}

0 commit comments

Comments
 (0)