Initial commit: SiteLoft.nl website
Full-service digital agency website built with Astro 5, Tailwind CSS v4, and TypeScript. Includes 10 pages: homepage, diensten (development, hosting, growth), pakketten, over ons, blog met eerste GEO-artikel, en contact. Features: dark theme design system, glassmorphism UI, structured data/schema markup voor SEO en GEO, content collections voor blog, responsive design, sitemap generation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
137
src/components/Header.astro
Normal file
137
src/components/Header.astro
Normal file
@@ -0,0 +1,137 @@
|
||||
---
|
||||
const currentPath = Astro.url.pathname;
|
||||
|
||||
const navLinks = [
|
||||
{ href: '/diensten', label: 'Diensten' },
|
||||
{ href: '/pakketten', label: 'Pakketten' },
|
||||
{ href: '/over', label: 'Over Ons' },
|
||||
{ href: '/blog', label: 'Blog' },
|
||||
];
|
||||
|
||||
function isActive(href: string): boolean {
|
||||
if (href === '/') return currentPath === '/';
|
||||
return currentPath.startsWith(href);
|
||||
}
|
||||
---
|
||||
|
||||
<header id="header" class="fixed top-0 left-0 right-0 z-50 transition-all duration-300">
|
||||
<nav class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex h-20 items-center justify-between">
|
||||
<!-- Logo -->
|
||||
<a href="/" class="flex items-center gap-2.5 group">
|
||||
<div class="relative flex h-9 w-9 items-center justify-center rounded-lg bg-gradient-to-br from-accent-400 to-accent-600 transition-transform group-hover:scale-105">
|
||||
<span class="text-lg font-bold text-slate-950">S</span>
|
||||
</div>
|
||||
<span class="text-xl font-bold text-slate-50 tracking-tight">
|
||||
Site<span class="text-accent-400">Loft</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<!-- Desktop Navigation -->
|
||||
<div class="hidden md:flex items-center gap-1">
|
||||
{navLinks.map((link) => (
|
||||
<a
|
||||
href={link.href}
|
||||
class:list={[
|
||||
'relative px-4 py-2 text-sm font-medium rounded-lg transition-colors',
|
||||
isActive(link.href)
|
||||
? 'text-accent-400'
|
||||
: 'text-slate-400 hover:text-slate-100',
|
||||
]}
|
||||
>
|
||||
{link.label}
|
||||
{isActive(link.href) && (
|
||||
<span class="absolute bottom-0 left-1/2 -translate-x-1/2 h-0.5 w-5 rounded-full bg-accent-400" />
|
||||
)}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<!-- CTA Button -->
|
||||
<div class="hidden md:flex items-center gap-3">
|
||||
<a
|
||||
href="/contact"
|
||||
class="inline-flex items-center gap-2 rounded-lg bg-accent-500 px-5 py-2.5 text-sm font-semibold text-slate-950 transition-all hover:bg-accent-400 hover:shadow-lg hover:shadow-accent-500/25"
|
||||
>
|
||||
Start je project
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Mobile menu button -->
|
||||
<button
|
||||
id="mobile-menu-btn"
|
||||
class="md:hidden flex items-center justify-center w-10 h-10 rounded-lg text-slate-400 hover:text-slate-100 hover:bg-slate-800/50 transition-colors"
|
||||
aria-label="Menu openen"
|
||||
>
|
||||
<svg id="menu-icon" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16" />
|
||||
</svg>
|
||||
<svg id="close-icon" class="h-6 w-6 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Mobile menu -->
|
||||
<div id="mobile-menu" class="hidden md:hidden">
|
||||
<div class="mx-4 mt-2 rounded-2xl glass p-4 space-y-1">
|
||||
{navLinks.map((link) => (
|
||||
<a
|
||||
href={link.href}
|
||||
class:list={[
|
||||
'block rounded-lg px-4 py-3 text-sm font-medium transition-colors',
|
||||
isActive(link.href)
|
||||
? 'text-accent-400 bg-accent-500/10'
|
||||
: 'text-slate-300 hover:text-slate-100 hover:bg-slate-800/50',
|
||||
]}
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
))}
|
||||
<div class="pt-2">
|
||||
<a
|
||||
href="/contact"
|
||||
class="block w-full rounded-lg bg-accent-500 px-4 py-3 text-center text-sm font-semibold text-slate-950 transition-colors hover:bg-accent-400"
|
||||
>
|
||||
Start je project
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<script>
|
||||
// Header scroll effect
|
||||
const header = document.getElementById('header');
|
||||
let lastScroll = 0;
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
const currentScroll = window.scrollY;
|
||||
|
||||
if (currentScroll > 50) {
|
||||
header?.classList.add('glass', 'shadow-lg', 'shadow-slate-950/50');
|
||||
} else {
|
||||
header?.classList.remove('glass', 'shadow-lg', 'shadow-slate-950/50');
|
||||
}
|
||||
|
||||
lastScroll = currentScroll;
|
||||
});
|
||||
|
||||
// Mobile menu toggle
|
||||
const mobileMenuBtn = document.getElementById('mobile-menu-btn');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
const menuIcon = document.getElementById('menu-icon');
|
||||
const closeIcon = document.getElementById('close-icon');
|
||||
|
||||
mobileMenuBtn?.addEventListener('click', () => {
|
||||
const isOpen = !mobileMenu?.classList.contains('hidden');
|
||||
mobileMenu?.classList.toggle('hidden');
|
||||
menuIcon?.classList.toggle('hidden');
|
||||
closeIcon?.classList.toggle('hidden');
|
||||
mobileMenuBtn.setAttribute('aria-label', isOpen ? 'Menu openen' : 'Menu sluiten');
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user