Skip to content

Commit ed94453

Browse files
authored
Merge pull request #29 from jonaspm:dev
feat: implement responsive navigation component and integrate into layout
2 parents b674653 + 5c85a6c commit ed94453

File tree

4 files changed

+84
-25
lines changed

4 files changed

+84
-25
lines changed

src/components/Navigation.astro

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
const navItems = ['Home', 'Bio', 'Skills', 'Projects', 'Contact'];
3+
---
4+
5+
<header class="fixed top-0 left-0 right-0 z-20 bg-grayblue-800 bg-opacity-90">
6+
<nav class="container mx-auto px-6 py-3">
7+
<!-- Mobile menu button -->
8+
<div class="flex items-center justify-between md:hidden">
9+
<a href="#home" class="text-grayblue-100 font-medium text-lg">Jonas <span class="text-blue-300">PM</span></a>
10+
<button id="mobile-menu-button" class="text-grayblue-300 hover:text-blue-300 transition-colors focus:outline-none">
11+
<span class="material-symbols-rounded transition-transform duration-300" id="menu-icon">menu</span>
12+
</button>
13+
</div>
14+
15+
<!-- Desktop navigation -->
16+
<ul class="hidden md:flex justify-center gap-6">
17+
{navItems.map((item) => (
18+
<li>
19+
<a href={`#${item.toLowerCase()}`} class="text-sm font-light uppercase tracking-wider transition-colors text-grayblue-300 hover:text-blue-300">
20+
{item}
21+
</a>
22+
</li>
23+
))}
24+
</ul>
25+
26+
<!-- Mobile navigation menu -->
27+
<ul id="mobile-menu" class="max-h-0 overflow-hidden md:hidden flex-col flex gap-4 transition-all duration-300 ease-in-out">
28+
{navItems.map((item) => (
29+
<li class="text-center">
30+
<a href={`#${item.toLowerCase()}`} class="block text-sm font-light uppercase tracking-wider transition-colors text-grayblue-300 hover:text-blue-300">
31+
{item}
32+
</a>
33+
</li>
34+
))}
35+
</ul>
36+
</nav>
37+
</header>
38+
39+
<script>
40+
// Mobile menu toggle functionality
41+
const mobileMenuButton = document.getElementById('mobile-menu-button');
42+
const mobileMenu = document.getElementById('mobile-menu');
43+
const menuIcon = document.getElementById('menu-icon');
44+
45+
if (mobileMenuButton && mobileMenu && menuIcon) {
46+
mobileMenuButton.addEventListener('click', () => {
47+
// Toggle menu visibility with animation
48+
if (mobileMenu.classList.contains('max-h-0')) {
49+
mobileMenu.classList.remove('max-h-0');
50+
mobileMenu.classList.add('max-h-96', 'py-2'); // Set a large enough height to accommodate content
51+
menuIcon.textContent = 'close';
52+
menuIcon.classList.add('rotate-180');
53+
} else {
54+
mobileMenu.classList.add('max-h-0');
55+
mobileMenu.classList.remove('max-h-96', 'py-2');
56+
menuIcon.textContent = 'menu';
57+
menuIcon.classList.remove('rotate-180');
58+
}
59+
});
60+
61+
// Close mobile menu when clicking on a link
62+
const mobileMenuLinks = mobileMenu.querySelectorAll('a');
63+
mobileMenuLinks.forEach(link => {
64+
link.addEventListener('click', () => {
65+
mobileMenu.classList.add('max-h-0');
66+
mobileMenu.classList.remove('max-h-96', 'py-2');
67+
menuIcon.textContent = 'menu';
68+
menuIcon.classList.remove('rotate-180');
69+
});
70+
});
71+
}
72+
</script>

src/layouts/Layout.astro

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
const { title } = Astro.props
33
import '@/styles/global.css'
4+
import Navigation from '@/components/Navigation.astro'
45
---
56

67
<!DOCTYPE html>
@@ -13,18 +14,18 @@ import '@/styles/global.css'
1314
<meta name="author" content="Jonas Perusquia Morales" />
1415
<meta name="keywords" content="Jonas Perusquia Morales, CTO, Chief Technology Officer, Software Engineer, Web Developer, Jonas Perusquia" />
1516
<meta name="generator" content={Astro.generator} />
17+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
1618
<title>{title}</title>
1719
<script type="text/javascript">
1820
(function(c,l,a,r,i,t,y){
1921
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
2022
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
2123
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
2224
})(window, document, "clarity", "script", "l5tvca8qee");
23-
</script>
25+
</script>
2426
</head>
2527
<body class="min-h-screen h-full bg-grayblue-900 text-grayblue-100">
26-
<main>
27-
<slot />
28-
</main>
28+
<Navigation />
29+
<slot />
2930
</body>
3031
</html>

src/pages/index.astro

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,28 +44,10 @@ const projects = [
4444
},
4545
]
4646
47-
const navItems = ['Home', 'Bio', 'Skills', 'Projects', 'Contact']
48-
4947
---
5048

5149
<Layout title="Jonas Perusquia Morales">
52-
53-
<header class="fixed top-0 left-0 right-0 z-20 bg-grayblue-800 bg-opacity-90">
54-
<nav class="container mx-auto px-6 py-3">
55-
<ul class="flex justify-center gap-6">
56-
{navItems.map((item) => (
57-
<li>
58-
<a href={`#${item.toLowerCase()}`} class="text-sm font-light uppercase tracking-wider transition-colors text-grayblue-300 hover:text-blue-300">
59-
{item}
60-
</a>
61-
</li>
62-
))}
63-
</ul>
64-
</nav>
65-
</header>
66-
6750
<main class="max-w-7xl mx-auto px-6 pt-14 xs:pt-20">
68-
6951
<!-- HOME SECTION -->
7052
<section id="home" class="py-14 sm:py-20">
7153
<div class="flex flex-col items-center lg:flex-row lg:justify-between">
@@ -78,7 +60,7 @@ const navItems = ['Home', 'Bio', 'Skills', 'Projects', 'Contact']
7860
<div class="flex gap-4 mt-6 justify-center lg:justify-start">
7961
{
8062
socialNetworks.map(socialNetwork => (
81-
<a href={socialNetwork.url} class="text-grayblue-300 hover:text-blue-300 transition-transform hover:scale-110">
63+
<a aria-label={socialNetwork.name} href={socialNetwork.url} class="text-grayblue-300 hover:text-blue-300 transition-transform hover:scale-110">
8264
<div class="h-6 w-6">
8365
<Fragment set:html={socialNetwork.image} />
8466
</div>
@@ -94,6 +76,7 @@ const navItems = ['Home', 'Bio', 'Skills', 'Projects', 'Contact']
9476
width={320}
9577
height={320}
9678
class="rounded-full object-cover"
79+
loading="eager"
9780
/>
9881
</div>
9982
</div>
@@ -141,7 +124,7 @@ const navItems = ['Home', 'Bio', 'Skills', 'Projects', 'Contact']
141124
</div>
142125
<div class="project-image self-center">
143126
<div class="overflow-hidden aspect-video rounded-lg">
144-
<img class="duration-300 transition-all aspect-video " src={ project.image.src } alt={ project.name }></img>
127+
<img loading="lazy" class="duration-300 transition-all aspect-video " src={ project.image.src } alt={ project.name }></img>
145128
</div>
146129
</div>
147130
</a>
@@ -162,5 +145,4 @@ const navItems = ['Home', 'Bio', 'Skills', 'Projects', 'Contact']
162145
<footer class="bg-grayblue-800 py-6 text-center text-sm text-grayblue-400">
163146
<p>Made with ♥️ from Chihuahua, Mexico.</p>
164147
</footer>
165-
166148
</Layout>

src/styles/global.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,4 +369,8 @@ html {
369369
& img {
370370
@apply scale-110;
371371
}
372+
}
373+
374+
#mobile-menu {
375+
interpolate-size: allow-keywords;
372376
}

0 commit comments

Comments
 (0)