astro_hts/frontend/src/components/layout/header/Header.astro
2026-03-26 07:34:57 +05:00

131 lines
No EOL
5.1 KiB
Text

---
import Button from '@components/base/Button.astro';
import MobileMenu from './MobileMenu.astro';
const currentPath = Astro.url.pathname;
const cleanPath = currentPath.replace(/\/$/, "") || "/";
const baseLinks = [
{ text: "Услуги", href: "/services" },
{ text: "Автопарк", href: "/cars" },
{ text: "Проекты", href: "/projects" },
{ text: "Контакты", href: "/contacts" },
];
const navLinks = cleanPath !== "/" ? [{ text: "Главная", href: "/" }, ...baseLinks] : baseLinks;
---
<div id="main-header" class="sticky top-0 z-[100] w-full border-b border-[#393328] bg-[#181611]">
<div class="layout-container flex justify-center w-full">
<div class="layout-content-container flex flex-col max-w-[1440px] mx-auto w-full px-4 md:px-10">
<header class="flex items-center justify-between py-4 relative">
<!-- Логотип основного хедера -->
<a href="/" class="flex items-center gap-4 text-white group relative z-10">
<div class="size-10 bg-primary/20 rounded flex items-center justify-center">
<span class="material-symbols-outlined text-primary text-2xl">local_shipping</span>
</div>
<div class="flex flex-col">
<h2 class="text-white text-xl font-bold font-display leading-none tracking-tight uppercase">HIMTRANS</h2>
<span class="text-[10px] text-text-secondary font-display tracking-widest uppercase font-semibold">Service</span>
</div>
</a>
<!-- Desktop Nav -->
<div class="hidden lg:flex flex-1 justify-end gap-8 items-center">
<nav class="flex items-center gap-8">
{navLinks.map((link) => (
<a href={link.href} class="text-white/80 hover:text-primary text-sm font-medium transition-colors font-display uppercase tracking-wide">
{link.text}
</a>
))}
</nav>
<Button href="#contacts" variant="outline" className="h-9 px-5 text-xs border-white/20">
Связаться
</Button>
</div>
<!-- КНОПКА ГАМБУРГЕР -->
<button
id="menu-toggle"
class="lg:hidden flex flex-col gap-[8px] p-2 relative z-[160] focus:outline-none"
aria-label="Menu"
>
<div class="hamburger-line line-1"></div>
<div class="hamburger-line line-2"></div>
<div class="hamburger-line line-3"></div>
</button>
</header>
</div>
</div>
<!-- АНИМАЦИОННАЯ ЛИНИЯ ПРОГРЕССА -->
<div
id="scroll-line"
class="absolute bottom-0 left-0 h-[2px] bg-primary z-20 will-change-[width] shadow-[0_0_10px_rgba(242,166,13,0.7)]"
style="width: 0%"
></div>
<!-- Мобильное меню -->
<MobileMenu links={navLinks} />
</div>
<script>
const menuToggle = document.getElementById('menu-toggle');
const mobileMenu = document.getElementById('mobile-menu');
const overlay = document.getElementById('menu-overlay');
const scrollLine = document.getElementById('scroll-line');
const mobileLinks = document.querySelectorAll('.mobile-link');
// --- ЛОГИКА АНИМАЦИОННОЙ ЛИНИИ ---
function updateScrollProgress() {
if (!scrollLine) return;
// Сколько прокручено
const winScroll = window.scrollY || document.documentElement.scrollTop;
// Общая доступная высота (высота всего документа - высота видимого окна)
const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
// Рассчитываем процент
const scrolled = height > 0 ? (winScroll / height) * 100 : 0;
// Обновляем ширину
scrollLine.style.width = scrolled + "%";
}
// --- ЛОГИКА МЕНЮ ---
function toggleMenu() {
const isActive = menuToggle?.classList.contains('is-active');
if (isActive) {
menuToggle?.classList.remove('is-active');
mobileMenu?.classList.add('-translate-x-full');
overlay?.classList.add('opacity-0', 'pointer-events-none');
document.body.style.overflow = '';
} else {
menuToggle?.classList.add('is-active');
mobileMenu?.classList.remove('-translate-x-full');
overlay?.classList.remove('opacity-0', 'pointer-events-none');
document.body.style.overflow = 'hidden';
}
}
// Слушатели событий
menuToggle?.addEventListener('click', toggleMenu);
overlay?.addEventListener('click', toggleMenu);
mobileLinks.forEach(l => l.addEventListener('click', toggleMenu));
// Оптимизированный слушатель скролла
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
window.requestAnimationFrame(() => {
updateScrollProgress();
ticking = false;
});
ticking = true;
}
});
// Инициализация при загрузке и ресайзе
window.addEventListener('DOMContentLoaded', updateScrollProgress);
window.addEventListener('resize', updateScrollProgress);
</script>