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>
138 lines
4.9 KiB
Plaintext
138 lines
4.9 KiB
Plaintext
---
|
|
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>
|