212 lines
10 KiB
TypeScript
212 lines
10 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { useNavigate, useLocation } from 'react-router-dom';
|
|
import { motion } from 'framer-motion';
|
|
import Modal from './Modal';
|
|
import './Header.css';
|
|
|
|
const navItems = [
|
|
{ name: 'Home', link: '/' },
|
|
{ name: 'About Us', link: '/about' },
|
|
{ name: 'Services', link: '/services' },
|
|
{ name: 'Pricing', link: '/pricing' },
|
|
{ name: 'Blog', link: '/blog' },
|
|
{ name: 'Contacts', link: '#contact' },
|
|
];
|
|
|
|
const Header: React.FC = () => {
|
|
const [activeTab, setActiveTab] = useState('Home');
|
|
const [hoveredTab, setHoveredTab] = useState<string | null>(null);
|
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
const [isLangOpen, setIsLangOpen] = useState(false);
|
|
const [isLoginOpen, setIsLoginOpen] = useState(false);
|
|
const [currentLang, setCurrentLang] = useState('Eng');
|
|
const [isScrolled, setIsScrolled] = useState(false);
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
|
|
useEffect(() => {
|
|
const onScroll = () => {
|
|
setIsScrolled(window.scrollY > 50);
|
|
if (isMobileMenuOpen) setIsMobileMenuOpen(false);
|
|
};
|
|
window.addEventListener('scroll', onScroll, { passive: true });
|
|
return () => window.removeEventListener('scroll', onScroll);
|
|
}, [isMobileMenuOpen]);
|
|
|
|
// Close mobile menu on route change
|
|
useEffect(() => {
|
|
setIsMobileMenuOpen(false);
|
|
}, [location.pathname]);
|
|
|
|
const handleLangSelect = (lang: string) => {
|
|
setCurrentLang(lang);
|
|
setIsLangOpen(false);
|
|
};
|
|
|
|
const handleNavClick = (e: React.MouseEvent<HTMLAnchorElement>, item: typeof navItems[0]) => {
|
|
if (item.link.startsWith('/')) {
|
|
e.preventDefault();
|
|
navigate(item.link);
|
|
setIsMobileMenuOpen(false);
|
|
return;
|
|
}
|
|
|
|
// Hash links - if not on homepage, navigate there first
|
|
if (location.pathname !== '/') {
|
|
e.preventDefault();
|
|
navigate('/' + item.link);
|
|
setIsMobileMenuOpen(false);
|
|
return;
|
|
}
|
|
|
|
// On homepage, let the default anchor behavior work
|
|
setIsMobileMenuOpen(false);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<header className={`header ${isScrolled ? 'scrolled' : ''} ${isMobileMenuOpen ? 'mobile-open' : ''}`}>
|
|
<div className="container header-content">
|
|
<div className="logo-container">
|
|
<a href="/" onClick={(e) => { e.preventDefault(); navigate('/'); }}>
|
|
<picture>
|
|
<source media="(max-width: 768px)" srcSet="/logo/aimpress-logo-mobile.svg" />
|
|
<img src="/logo/aimpress-logo-desktop.svg" alt="AIMPRESS Logo" className="logo" />
|
|
</picture>
|
|
</a>
|
|
</div>
|
|
|
|
<nav className="desktop-nav">
|
|
<ul className="nav-list" onMouseLeave={() => setHoveredTab(null)}>
|
|
{navItems.map((item) => {
|
|
const isActive = (hoveredTab || activeTab) === item.name;
|
|
return (
|
|
<li
|
|
key={item.name}
|
|
className={`nav-item ${isActive ? 'active' : ''}`}
|
|
onMouseEnter={() => setHoveredTab(item.name)}
|
|
onClick={() => setActiveTab(item.name)}
|
|
>
|
|
<a
|
|
href={item.link}
|
|
className="nav-link"
|
|
onClick={(e) => handleNavClick(e, item)}
|
|
>
|
|
{item.name}
|
|
{isActive && (
|
|
<motion.div
|
|
className="active-pill"
|
|
layoutId="nav-pill"
|
|
transition={{ type: 'spring', stiffness: 500, damping: 30 }}
|
|
/>
|
|
)}
|
|
</a>
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
</nav>
|
|
|
|
<div className="header-actions">
|
|
<div className="auth-lang-group">
|
|
<div className="language-selector-wrapper">
|
|
<div
|
|
className="language-selector"
|
|
onClick={() => setIsLangOpen(!isLangOpen)}
|
|
>
|
|
<img src="/icons/planet.svg" alt="Language" className="lang-icon" />
|
|
<span>{currentLang}</span>
|
|
</div>
|
|
|
|
{isLangOpen && (
|
|
<motion.div
|
|
className="language-dropdown"
|
|
initial={{ opacity: 0, y: 10 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0, y: 10 }}
|
|
>
|
|
<div
|
|
className={`lang-option ${currentLang === 'Eng' ? 'active' : ''}`}
|
|
onClick={() => handleLangSelect('Eng')}
|
|
>
|
|
Eng
|
|
</div>
|
|
<div
|
|
className={`lang-option ${currentLang === 'Ukr' ? 'active' : ''}`}
|
|
onClick={() => handleLangSelect('Ukr')}
|
|
>
|
|
Ukr
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</div>
|
|
<button className="login-btn" onClick={() => setIsLoginOpen(true)}>Log in</button>
|
|
</div>
|
|
|
|
<button className="mobile-menu-toggle" onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}>
|
|
<span className="hamburger-line"></span>
|
|
<span className="hamburger-line"></span>
|
|
<span className="hamburger-line"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile Menu Overlay */}
|
|
{isMobileMenuOpen && (
|
|
<motion.div
|
|
className="mobile-menu-overlay"
|
|
initial={{ opacity: 0, y: -20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0, y: -20 }}
|
|
>
|
|
<ul className="mobile-nav-list">
|
|
{navItems.map((item) => (
|
|
<li
|
|
key={item.name}
|
|
className={`mobile-nav-item ${activeTab === item.name ? 'active' : ''}`}
|
|
>
|
|
<a href={item.link} onClick={(e) => {
|
|
handleNavClick(e, item);
|
|
setActiveTab(item.name);
|
|
}}>
|
|
<span style={{ position: 'relative', zIndex: 1 }}>{item.name}</span>
|
|
{activeTab === item.name && (
|
|
<motion.div
|
|
className="active-pill-mobile"
|
|
layoutId="nav-pill-mobile"
|
|
transition={{ type: 'spring', stiffness: 500, damping: 30 }}
|
|
/>
|
|
)}
|
|
</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</motion.div>
|
|
)}
|
|
</header>
|
|
|
|
{/* Login Modal */}
|
|
<Modal isOpen={isLoginOpen} onClose={() => setIsLoginOpen(false)}>
|
|
<div className="login-form-container">
|
|
<h2 className="login-title">Welcome Back</h2>
|
|
<form className="login-form" onSubmit={(e) => e.preventDefault()}>
|
|
<div className="form-group">
|
|
<label>Email / Login</label>
|
|
<input type="text" placeholder="Enter your email" className="glass-input" />
|
|
</div>
|
|
<div className="form-group">
|
|
<label>Password</label>
|
|
<input type="password" placeholder="Enter your password" className="glass-input" />
|
|
</div>
|
|
<button type="submit" className="submit-btn full-width">Log In</button>
|
|
<p className="login-footer">
|
|
Don't have an account? <a href="#">Sign up</a>
|
|
</p>
|
|
</form>
|
|
</div>
|
|
</Modal>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Header;
|