Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Hazielgmz/astro-Portfolio/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Header.astro component provides a sticky navigation bar at the top of the page. It features smooth scroll navigation, active section highlighting using IntersectionObserver, and includes social media links to GitHub and LinkedIn.
Location
src/components/Header.astro
Features
1. Navigation Items
The header displays three main navigation links:
const navItems = [
{
title: "Trayectoria",
label: "Trayectoria",
url: "/#trayectoria",
},
{
title: "Proyectos",
label: "Proyectos",
url: "/#proyectos",
},
{
title: "Herramientas",
label: "Herramientas",
url: "/#herramientas",
},
]
Includes hardcoded links to:
- GitHub profile
- LinkedIn profile
<a href="https://github.com/Hazielgmz" target="_blank">
<span class="sr-only">GitHub</span>
<svg viewBox="0 0 16 16" aria-hidden="true" width="24" height="24">
<!-- GitHub icon SVG -->
</svg>
</a>
<a href="https://www.linkedin.com/in/hazielgmz/" target="_blank">
<span class="sr-only">LinkedIn</span>
<svg viewBox="0 0 24 24" aria-hidden="true" width="24" height="24">
<!-- LinkedIn icon SVG -->
</svg>
</a>
3. Active Section Highlighting
Uses IntersectionObserver API to highlight the current section:
const callback = (entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
navItems.forEach((item) => {
if (item.getAttribute("aria-label") == entry.target.id) {
item.classList.add("text-blue-500")
} else {
item.classList.remove("text-blue-500")
}
})
}
})
}
const observer = new IntersectionObserver(callback, {
root: null,
rootMargin: "0px",
threshold: 0.3,
})
The header background blurs as you scroll down (animation defined in Layout component):
<nav id="header-nav" class="flex px-4 text-medium font-medium rounded-full...">
Code Structure
HTML Structure
<header class="fixed top-0 z-10 flex items-center justify-center w-full mx-auto mt-2">
<nav id="header-nav" class="flex px-4 text-medium font-medium rounded-full text-gray-600 dark:text-gray-200 justify-center items-center">
<div class="social-links">
{navItems.map((link) => (
<a
class="relative block px-2 py-2 transition hover:text-blue-500 dark:hover:text-blue-500"
aria-label={link.label}
href={link.url}
>
{link.title}
</a>
))}
<!-- Social media icons -->
</div>
</nav>
</header>
Styling
nav {
display: ruby;
align-items: right;
justify-content: space-between;
}
nav a {
padding-left: 0.5em;
padding-right: 0.5em;
padding-top: 0.25em;
padding-bottom: 0.25em;
color: inherit;
border-bottom: 4px solid transparent;
text-decoration: none;
}
.social-links,
.social-links a {
display: flex;
}
@media (max-width: 500px) {
.social-links {
text-size-adjust: 90%;
}
}
Usage Example
The Header is typically imported and used in the Layout component:
---
import Header from '../components/Header.astro';
---
<body>
<Header />
<slot />
<Footer />
</body>
Customization Tips
Add New Navigation Items
Update the navItems array:
const navItems = [
{
title: "About",
label: "About",
url: "/#about",
},
{
title: "Skills",
label: "Skills",
url: "/#skills",
},
// Add more items...
]
Replace the GitHub and LinkedIn URLs:
<a href="https://github.com/your-username" target="_blank">
<!-- GitHub icon -->
</a>
<a href="https://www.linkedin.com/in/your-profile/" target="_blank">
<!-- LinkedIn icon -->
</a>
Add More Social Icons
Add additional social media links after the existing ones:
<a href="https://twitter.com/your-handle" target="_blank">
<span class="sr-only">Twitter</span>
<svg viewBox="0 0 24 24" aria-hidden="true" width="24" height="24">
<!-- Twitter icon SVG -->
</svg>
</a>
Adjust IntersectionObserver Threshold
Modify when sections are considered “active”:
const observer = new IntersectionObserver(callback, {
root: null,
rootMargin: "0px",
threshold: 0.5, // Change from 0.3 to trigger at 50% visibility
})
Change Active Link Color
Modify the hover and active state colors:
<a
class="relative block px-2 py-2 transition hover:text-purple-500 dark:hover:text-purple-400"
aria-label={link.label}
href={link.url}
>
And update the JavaScript:
if (item.getAttribute("aria-label") == entry.target.id) {
item.classList.add("text-purple-500") // Change from text-blue-500
} else {
item.classList.remove("text-purple-500")
}
Accessibility Features
- Screen reader text for icon-only links (
sr-only class)
- Proper
aria-label attributes for navigation items
- Semantic
<header> and <nav> elements
- High contrast hover states
- Responsive design for mobile devices
Integration with Astro Page Transitions
The script uses Astro’s astro:page-load event to ensure the IntersectionObserver works correctly with client-side routing:
document.addEventListener("astro:page-load", () => {
// Observer setup...
// Cleanup on page hide
document.onvisibilitychange = () => {
if (document.visibilityState === "hidden") {
observer.disconnect()
} else {
sections.forEach((section) => {
observer.observe(section)
})
}
}
})
Dark Mode Support
The header automatically adapts to dark mode:
- Light mode:
text-gray-600 with hover:text-blue-500
- Dark mode:
dark:text-gray-200 with dark:hover:text-blue-500