upgrade to different layout
Some checks failed
renovate / renovate (push) Successful in 5m22s
release-image-gitea / release (push) Failing after 7m9s
release-image-harbor / release (push) Failing after 7m9s

This commit is contained in:
2025-06-08 16:02:39 -05:00
parent e1632629a9
commit 3e89e6cb1c
75 changed files with 8314 additions and 2884 deletions

View File

@@ -0,0 +1,205 @@
---
import ThemeToggle from './ThemeToggle.astro';
import directus from "../../lib/directus"
import { readSingleton } from "@directus/sdk";
const global = await directus.request(readSingleton("global"));
const navItems = [
{ text: 'Home', href: '/' },
{ text: 'Blog', href: '/blog' },
{ text: 'Topics', href: '/topics' },
{ text: 'About', href: '/about' },
{ text: 'RSS', href: 'rss.xml' },
];
const pathname = new URL(Astro.request.url).pathname;
const currentPath = pathname.slice(1); // remove the first "/"
---
<header class="py-4 fixed top-0 left-0 right-0 z-40 bg-white dark:bg-zinc-900 border-b border-zinc-100 dark:border-zinc-800">
<div class="max-w-3xl mx-auto px-4 flex items-center justify-between">
<!-- Logo -->
<a href="/" class="font-bold text-xl text-zinc-900 dark:text-white">{global.initals}</a>
<!-- Desktop navigation -->
<nav class="hidden sm:flex items-center space-x-6">
{navItems.map(item => {
const isActive = currentPath === (item.href === '/' ? '' : item.href.slice(1));
return (
<a
href={item.href}
class={`text-sm font-medium ${isActive
? 'text-zinc-900 dark:text-white'
: 'text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white'}`}
>
{item.text}
</a>
)
})}
<ThemeToggle />
</nav>
<!-- Mobile menu button -->
<button id="mobile-menu-button" class="sm:hidden flex items-center" aria-label="Menu">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 text-zinc-900 dark:text-white">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
</svg>
</button>
</div>
</header>
<!-- Mobile menu overlay -->
<div id="mobile-menu" class="fixed inset-0 z-50 bg-white dark:bg-zinc-900 flex flex-col opacity-0 pointer-events-none transition-all duration-300 ease-in-out">
<div class="flex justify-between items-center p-4 border-b border-zinc-100 dark:border-zinc-800">
<a href="/" class="font-bold text-xl text-zinc-900 dark:text-white">JD</a>
<button id="close-menu-button" class="text-zinc-900 dark:text-white p-2 rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors" aria-label="Close menu">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<nav class="flex-1 flex flex-col items-center justify-center space-y-6 text-center">
{navItems.map((item, index) => {
const isActive = currentPath === (item.href === '/' ? '' : item.href.slice(1));
return (
<a
href={item.href}
class={`text-lg font-medium mobile-nav-item opacity-0 translate-y-4 ${isActive
? 'text-zinc-900 dark:text-white'
: 'text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white'}`}
style={`transition-delay: ${index * 0.05}s;`}
>
{item.text}
</a>
)
})}
<div class="pt-4 mobile-nav-item opacity-0 translate-y-4" style="transition-delay: 0.25s;">
<ThemeToggle />
</div>
</nav>
</div>
<!-- Spacer to prevent content from hiding behind fixed header -->
<div class="h-16"></div>
<script>
// Mobile menu toggle with animations
document.addEventListener('DOMContentLoaded', () => {
const mobileMenuButton = document.getElementById('mobile-menu-button');
const closeMenuButton = document.getElementById('close-menu-button');
const mobileMenu = document.getElementById('mobile-menu');
const navItems = document.querySelectorAll('.mobile-nav-item');
// Open menu with animations
mobileMenuButton?.addEventListener('click', () => {
if (!mobileMenu) return;
// Prevent body scrolling
document.body.style.overflow = 'hidden';
// Show menu with fade in
mobileMenu.classList.remove('pointer-events-none');
mobileMenu.classList.add('pointer-events-auto');
// Animate opacity
setTimeout(() => {
mobileMenu.style.opacity = '1';
// Animate each nav item with staggered delay
navItems.forEach(item => {
setTimeout(() => {
item.classList.remove('opacity-0', 'translate-y-4');
}, 150);
});
}, 50);
});
// Close menu with animations
const closeMenu = () => {
if (!mobileMenu) return;
// Fade out nav items first
navItems.forEach(item => {
item.classList.add('opacity-0', 'translate-y-4');
});
// Then fade out the menu
setTimeout(() => {
mobileMenu.style.opacity = '0';
// After animation completes, hide menu and restore scrolling
setTimeout(() => {
mobileMenu.classList.remove('pointer-events-auto');
mobileMenu.classList.add('pointer-events-none');
document.body.style.overflow = '';
}, 300);
}, 100);
};
// Close button event
closeMenuButton?.addEventListener('click', closeMenu);
// Close menu when clicking a link
const mobileLinks = mobileMenu?.querySelectorAll('a');
mobileLinks?.forEach(link => {
link.addEventListener('click', closeMenu);
});
// Close menu on escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && mobileMenu?.classList.contains('pointer-events-auto')) {
closeMenu();
}
});
// Add smooth animation to header on scroll
const header = document.querySelector('header');
let lastScrollY = window.scrollY;
window.addEventListener('scroll', () => {
if (!header) return;
const currentScrollY = window.scrollY;
// Add shadow on scroll
if (currentScrollY > 10) {
header.classList.add('shadow-sm');
} else {
header.classList.remove('shadow-sm');
}
// Update last scroll position
lastScrollY = currentScrollY;
});
});
</script>
<style>
/* Smooth animations for mobile navigation */
.mobile-nav-item {
transition: opacity 0.5s ease, transform 0.5s ease, color 0.3s ease;
}
/* Header transition */
header {
transition: box-shadow 0.3s ease, transform 0.3s ease, background-color 0.3s ease;
}
/* Mobile menu button hover effect */
#mobile-menu-button {
transition: transform 0.2s ease;
}
#mobile-menu-button:hover {
transform: scale(1.05);
}
/* Mobile menu transition */
#mobile-menu {
transition: opacity 0.3s ease;
backdrop-filter: blur(4px);
}
</style>