astro_avtourist/frontend/src/components/layout/header/Navbar.astro

241 lines
7.2 KiB
Text
Raw Normal View History

2026-03-31 22:53:39 +05:00
---
export interface Props {
links?: Array<{ name: string; url: string }>;
class?: string;
2026-03-31 22:53:39 +05:00
}
const defaultLinks = [
{ name: 'Главная', url: '/' },
2026-03-31 22:53:39 +05:00
{ name: 'Услуги', url: '/services' },
{ name: 'Кейсы', url: '/cases' },
{ name: 'Блог', url: '/blog' },
{ name: 'Отзывы', url: '/reviews' },
{ name: 'Контакты', url: '/contacts' },
];
const {
links = defaultLinks,
class: className = '',
2026-03-31 22:53:39 +05:00
}: Props = Astro.props;
// Определяем текущую страницу
const currentPath = Astro.url.pathname;
const isHomePage = currentPath === '/' || currentPath === '';
// Фильтруем ссылки: убираем "Главная" если мы на главной странице
const filteredLinks = isHomePage
? links.filter(link => link.url !== '/')
: links;
2026-03-31 22:53:39 +05:00
---
<nav class={className}>
<ul class="nav-list">
{filteredLinks.map((link, index) => {
const isActive = currentPath === link.url ||
(link.url !== '/' && currentPath.startsWith(link.url));
return (
<li class="nav-item" style={{ '--item-index': index } as any}>
<a
href={link.url}
class={`nav-link ${isActive ? 'active' : ''}`}
data-text={link.name}
>
<span class="nav-link-text">{link.name}</span>
<span class="nav-indicator"></span>
</a>
</li>
)})}
2026-03-31 22:53:39 +05:00
</ul>
</nav>
<style>
.nav-list {
display: flex;
gap: 0.5rem;
2026-03-31 22:53:39 +05:00
list-style: none;
margin: 0;
padding: 0;
position: relative;
}
.nav-item {
position: relative;
perspective: 500px;
/* Убираем анимацию появления */
2026-03-31 22:53:39 +05:00
}
.nav-link {
position: relative;
display: flex;
align-items: center;
padding: 0.6rem 1.2rem;
/* Цвет текста как в логотипе (logo-name) */
color: #1e3050;
2026-03-31 22:53:39 +05:00
text-decoration: none;
font-weight: 600;
font-size: 0.95rem;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border-radius: 10px;
overflow: hidden;
letter-spacing: 0.3px;
cursor: pointer;
}
/* Текст с анимацией */
.nav-link-text {
position: relative;
display: inline-block;
transition: transform 0.2s cubic-bezier(0.34, 1.2, 0.64, 1);
}
/* Индикатор под пунктом */
.nav-indicator {
position: absolute;
bottom: -4px;
left: 50%;
width: 0;
height: 3px;
background: linear-gradient(90deg, #eac26e, #d4af37, #eac26e);
border-radius: 3px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
transform: translateX(-50%);
opacity: 0;
2026-03-31 22:53:39 +05:00
}
/* Hover эффекты */
2026-03-31 22:53:39 +05:00
.nav-link:hover {
/* При наведении цвет становится насыщеннее */
color: #0a1a2e;
background: rgba(30, 48, 80, 0.05);
transform: translateY(-2px);
}
.nav-link:hover .nav-link-text {
transform: scale(1.05);
}
.nav-item:hover .nav-indicator {
width: 70%;
opacity: 1;
animation: indicatorPulse 0.6s ease-out;
}
/* Активное состояние - улучшенная видимость */
.nav-link.active {
/* Используем темно-синий цвет вместо золотого для лучшей читаемости */
2026-03-31 22:53:39 +05:00
color: #1e3050;
background: linear-gradient(135deg, rgba(234, 194, 110, 0.25), rgba(234, 194, 110, 0.12));
position: relative;
font-weight: 700;
/* Добавляем небольшую тень для выделения */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.nav-link.active .nav-indicator {
width: 80%;
opacity: 1;
background: linear-gradient(90deg, #eac26e, #f0d68a, #eac26e);
height: 3px;
bottom: -4px;
}
/* Дополнительный эффект для активного пункта - полужирный */
.nav-link.active .nav-link-text {
font-weight: 700;
2026-03-31 22:53:39 +05:00
}
/* Ripple эффект при клике */
.nav-link::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: radial-gradient(circle, rgba(234, 194, 110, 0.3), transparent);
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
pointer-events: none;
}
.nav-link:active::before {
width: 200px;
height: 200px;
opacity: 0;
}
/* Анимация индикатора */
@keyframes indicatorPulse {
0% {
width: 0;
opacity: 0;
}
50% {
width: 85%;
opacity: 0.8;
}
100% {
width: 70%;
opacity: 1;
}
}
/* Дополнительный эффект свечения при наведении */
.nav-link::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(234, 194, 110, 0.1), transparent);
transition: left 0.5s ease;
pointer-events: none;
}
.nav-link:hover::after {
left: 100%;
}
/* Адаптив */
2026-03-31 22:53:39 +05:00
@media (max-width: 992px) {
.nav-list {
display: none;
}
}
</style>
<script>
// Добавляем дополнительные эффекты для активной ссылки
document.addEventListener('DOMContentLoaded', () => {
// Находим все активные ссылки
const activeLinks = document.querySelectorAll('.nav-link.active');
activeLinks.forEach(link => {
// Добавляем дополнительный класс для стилизации
link.classList.add('active-animated');
// Создаем эффект пульсации для активного индикатора
const indicator = link.querySelector('.nav-indicator');
if (indicator) {
(indicator as HTMLElement).style.animation = 'indicatorPulse 1s ease-out infinite';
}
});
// Добавляем поддержку touch-устройств
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
link.addEventListener('touchstart', function(this: HTMLElement) {
// Убираем эффект наведения на touch-устройствах
this.classList.add('touch-active');
// Убираем класс через таймаут
setTimeout(() => {
this.classList.remove('touch-active');
}, 300);
});
});
});
</script>