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

241 lines
No EOL
7.2 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
export interface Props {
links?: Array<{ name: string; url: string }>;
class?: string;
}
const defaultLinks = [
{ name: 'Главная', url: '/' },
{ name: 'Услуги', url: '/services' },
{ name: 'Кейсы', url: '/cases' },
{ name: 'Блог', url: '/blog' },
{ name: 'Отзывы', url: '/reviews' },
{ name: 'Контакты', url: '/contacts' },
];
const {
links = defaultLinks,
class: className = '',
}: Props = Astro.props;
// Определяем текущую страницу
const currentPath = Astro.url.pathname;
const isHomePage = currentPath === '/' || currentPath === '';
// Фильтруем ссылки: убираем "Главная" если мы на главной странице
const filteredLinks = isHomePage
? links.filter(link => link.url !== '/')
: links;
---
<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>
)})}
</ul>
</nav>
<style>
.nav-list {
display: flex;
gap: 0.5rem;
list-style: none;
margin: 0;
padding: 0;
position: relative;
}
.nav-item {
position: relative;
perspective: 500px;
/* Убираем анимацию появления */
}
.nav-link {
position: relative;
display: flex;
align-items: center;
padding: 0.6rem 1.2rem;
/* Цвет текста как в логотипе (logo-name) */
color: #1e3050;
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;
}
/* Hover эффекты */
.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 {
/* Используем темно-синий цвет вместо золотого для лучшей читаемости */
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;
}
/* 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%;
}
/* Адаптив */
@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>