2026-05-12 01:04:17 -05:00
|
|
|
import { useState, useEffect } from 'react'
|
2026-05-13 22:07:35 -05:00
|
|
|
import { Sheet, SheetTrigger, SheetContent, SheetTitle } from '@/components/ui/Sheet'
|
|
|
|
|
import * as VisuallyHidden from '@radix-ui/react-visually-hidden'
|
2026-05-17 14:33:41 -05:00
|
|
|
import { Link, useLocation } from 'react-router-dom'
|
2026-05-12 01:04:17 -05:00
|
|
|
|
|
|
|
|
const Header = () => {
|
|
|
|
|
const [isScrolled, setIsScrolled] = useState(false)
|
2026-05-13 22:07:35 -05:00
|
|
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
2026-05-17 14:33:41 -05:00
|
|
|
const location = useLocation()
|
2026-05-12 01:04:17 -05:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const handleScroll = () => {
|
|
|
|
|
setIsScrolled(window.scrollY > 10)
|
|
|
|
|
}
|
|
|
|
|
window.addEventListener('scroll', handleScroll)
|
|
|
|
|
return () => window.removeEventListener('scroll', handleScroll)
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
const navLinks = [
|
|
|
|
|
{ name: 'Home', href: '/' },
|
|
|
|
|
{ name: 'Services', href: '/services' },
|
|
|
|
|
{ name: 'Industries', href: '/industries' },
|
|
|
|
|
{ name: 'About', href: '/about' },
|
|
|
|
|
{ name: 'Contact', href: '/contact' },
|
|
|
|
|
{ name: 'Support', href: '/support' },
|
|
|
|
|
]
|
|
|
|
|
|
2026-05-13 22:07:35 -05:00
|
|
|
const serviceLinks = [
|
|
|
|
|
{ name: 'Unified Communications', href: '/services/unified-communications' },
|
|
|
|
|
{ name: 'Contact Center', href: '/services/contact-center' },
|
|
|
|
|
{ name: 'Managed Support', href: '/services/managed-support' },
|
|
|
|
|
{ name: 'Consulting & Training', href: '/services/consulting-training' },
|
|
|
|
|
{ name: 'Infrastructure Cabling', href: '/services/infrastructure-cabling' },
|
|
|
|
|
{ name: 'Wireless Access', href: '/services/wireless-access' },
|
|
|
|
|
{ name: 'Local Networking', href: '/services/local-networking' },
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const industryLinks = [
|
|
|
|
|
{ name: 'Healthcare', href: '/industries/healthcare' },
|
|
|
|
|
{ name: 'Retail', href: '/industries/retail' },
|
|
|
|
|
{ name: 'Manufacturing', href: '/industries/manufacturing' },
|
|
|
|
|
{ name: 'Education & Finance', href: '/industries/education-finance' },
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const closeMobileMenu = () => setMobileMenuOpen(false)
|
2026-05-12 01:04:17 -05:00
|
|
|
|
2026-05-17 14:33:41 -05:00
|
|
|
const isActive = (href) => location.pathname === href
|
|
|
|
|
|
2026-05-13 22:07:35 -05:00
|
|
|
return (
|
|
|
|
|
<header className={`sticky top-0 z-40 w-full transition-all duration-300 ${isScrolled ? 'bg-primary-navy shadow-md' : 'bg-primary-navy/95'}`}>
|
|
|
|
|
<div className="container mx-auto px-4">
|
2026-05-25 19:44:10 -05:00
|
|
|
<div className="flex h-16 md:h-18 items-center justify-between">
|
2026-05-13 22:07:35 -05:00
|
|
|
{/* Logo */}
|
|
|
|
|
<div className="flex items-center gap-3">
|
2026-05-17 22:47:03 -05:00
|
|
|
<Link to="/" className="flex items-center gap-3" aria-label="Queue North Technologies Home">
|
2026-05-18 09:44:44 -05:00
|
|
|
<img
|
|
|
|
|
src="/logo.png"
|
|
|
|
|
alt="Queue North Technologies"
|
2026-05-25 19:44:10 -05:00
|
|
|
className="brand-logo-on-dark h-11 md:h-14 w-auto flex-shrink-0"
|
2026-05-17 14:33:41 -05:00
|
|
|
/>
|
2026-05-25 19:44:10 -05:00
|
|
|
<span className="font-bold text-xl lg:text-2xl text-white hidden sm:block tracking-tight">Queue North Technologies</span>
|
2026-05-17 14:33:41 -05:00
|
|
|
</Link>
|
2026-05-13 22:07:35 -05:00
|
|
|
</div>
|
2026-05-12 01:04:17 -05:00
|
|
|
|
2026-05-13 22:07:35 -05:00
|
|
|
{/* Desktop Nav */}
|
2026-05-17 22:47:03 -05:00
|
|
|
<nav className="hidden md:flex items-center gap-6" aria-label="Main navigation">
|
2026-05-13 22:07:35 -05:00
|
|
|
{navLinks.map((link) => (
|
2026-05-17 21:44:48 -05:00
|
|
|
<div key={link.name} className="relative group">
|
|
|
|
|
<Link
|
|
|
|
|
to={link.href}
|
|
|
|
|
className={`text-sm font-medium transition-colors ${isActive(link.href) ? 'text-white underline underline-offset-4' : 'text-white/70 hover:text-white'}`}
|
|
|
|
|
>
|
|
|
|
|
{link.name}
|
|
|
|
|
</Link>
|
|
|
|
|
{/* Services Dropdown */}
|
|
|
|
|
{link.name === 'Services' && (
|
2026-05-18 13:12:18 -05:00
|
|
|
<div className="absolute top-full left-0 w-64 bg-white rounded-md shadow-xl border border-gray-200 hidden group-hover:block pt-2">
|
2026-05-17 21:44:48 -05:00
|
|
|
<div className="p-2">
|
|
|
|
|
{serviceLinks.map((service) => (
|
|
|
|
|
<Link
|
|
|
|
|
key={service.name}
|
|
|
|
|
to={service.href}
|
|
|
|
|
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-md transition-colors"
|
|
|
|
|
>
|
|
|
|
|
{service.name}
|
|
|
|
|
</Link>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{/* Industries Dropdown */}
|
|
|
|
|
{link.name === 'Industries' && (
|
2026-05-18 13:12:18 -05:00
|
|
|
<div className="absolute top-full left-0 w-64 bg-white rounded-md shadow-xl border border-gray-200 hidden group-hover:block pt-2">
|
2026-05-17 21:44:48 -05:00
|
|
|
<div className="p-2">
|
|
|
|
|
{industryLinks.map((industry) => (
|
|
|
|
|
<Link
|
|
|
|
|
key={industry.name}
|
|
|
|
|
to={industry.href}
|
|
|
|
|
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 rounded-md transition-colors"
|
|
|
|
|
>
|
|
|
|
|
{industry.name}
|
|
|
|
|
</Link>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2026-05-13 22:07:35 -05:00
|
|
|
))}
|
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
|
|
{/* CTA Button */}
|
|
|
|
|
<div className="hidden md:block">
|
2026-05-17 22:47:03 -05:00
|
|
|
<Link to="/contact" className="inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 bg-primary-cyan text-primary-navy hover:bg-cyan-600 transition-colors" aria-label="Request a consultation">
|
2026-05-13 22:07:35 -05:00
|
|
|
Request Consultation
|
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Mobile Menu */}
|
|
|
|
|
<div className="md:hidden">
|
|
|
|
|
<Sheet open={mobileMenuOpen} onOpenChange={setMobileMenuOpen}>
|
|
|
|
|
<SheetTrigger asChild>
|
2026-05-17 22:47:03 -05:00
|
|
|
<button className="p-2 text-white hover:text-primary-cyan transition-colors focus:outline-none focus:ring-2 focus:ring-primary-cyan rounded-md" aria-label="Open navigation menu">
|
2026-05-13 22:07:35 -05:00
|
|
|
<span className="sr-only">Open menu</span>
|
|
|
|
|
<svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16" />
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
</SheetTrigger>
|
|
|
|
|
<SheetContent side="right" className="w-[300px] sm:w-[350px] bg-primary-navy text-white">
|
|
|
|
|
<VisuallyHidden.Root asChild>
|
|
|
|
|
<SheetTitle>Navigation Menu</SheetTitle>
|
|
|
|
|
</VisuallyHidden.Root>
|
|
|
|
|
|
2026-05-18 12:11:56 -05:00
|
|
|
{/* Logo */}
|
|
|
|
|
<div className="flex items-center gap-3 pb-4 border-b border-white/10">
|
|
|
|
|
<Link to="/" onClick={closeMobileMenu} className="flex items-center gap-3" aria-label="Queue North Technologies Home">
|
2026-05-25 19:44:10 -05:00
|
|
|
<img src="/logo.png" alt="Queue North Technologies" className="brand-logo-on-dark h-11 w-auto" />
|
|
|
|
|
<span className="font-bold text-xl tracking-tight">Queue North Technologies</span>
|
2026-05-18 12:11:56 -05:00
|
|
|
</Link>
|
|
|
|
|
</div>
|
2026-05-13 22:07:35 -05:00
|
|
|
|
2026-05-18 12:11:56 -05:00
|
|
|
{/* Scrollable nav */}
|
|
|
|
|
<nav className="flex-1 min-h-0 overflow-y-auto" aria-label="Mobile navigation">
|
|
|
|
|
{/* Main links — Services and Industries handled as sections below */}
|
|
|
|
|
<ul className="space-y-1 mb-6">
|
|
|
|
|
{navLinks
|
|
|
|
|
.filter(link => link.name !== 'Services' && link.name !== 'Industries')
|
|
|
|
|
.map((link) => (
|
|
|
|
|
<li key={link.name}>
|
|
|
|
|
<Link
|
|
|
|
|
to={link.href}
|
|
|
|
|
onClick={closeMobileMenu}
|
|
|
|
|
className={`flex items-center py-3 px-2 rounded-md text-base font-medium transition-colors ${isActive(link.href) ? 'text-white bg-white/10' : 'text-white/70 hover:text-white hover:bg-white/5'}`}
|
|
|
|
|
>
|
|
|
|
|
{link.name}
|
|
|
|
|
</Link>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
{/* Services section */}
|
|
|
|
|
<div className="mb-6">
|
|
|
|
|
<Link
|
|
|
|
|
to="/services"
|
|
|
|
|
onClick={closeMobileMenu}
|
|
|
|
|
className={`block py-2 px-2 text-xs font-semibold uppercase tracking-wider mb-1 transition-colors ${isActive('/services') ? 'text-primary-cyan' : 'text-primary-cyan/80 hover:text-primary-cyan'}`}
|
|
|
|
|
>
|
|
|
|
|
Services
|
|
|
|
|
</Link>
|
|
|
|
|
<ul className="space-y-1">
|
|
|
|
|
{serviceLinks.map((service) => (
|
|
|
|
|
<li key={service.name}>
|
|
|
|
|
<Link
|
|
|
|
|
to={service.href}
|
|
|
|
|
onClick={closeMobileMenu}
|
|
|
|
|
className={`flex items-center py-3 px-4 rounded-md text-sm transition-colors ${isActive(service.href) ? 'text-white font-semibold bg-white/10' : 'text-white/70 hover:text-white hover:bg-white/5'}`}
|
|
|
|
|
aria-label={service.name}
|
|
|
|
|
>
|
|
|
|
|
{service.name}
|
|
|
|
|
</Link>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
2026-05-12 01:04:17 -05:00
|
|
|
|
2026-05-18 12:11:56 -05:00
|
|
|
{/* Industries section */}
|
|
|
|
|
<div>
|
|
|
|
|
<Link
|
|
|
|
|
to="/industries"
|
|
|
|
|
onClick={closeMobileMenu}
|
|
|
|
|
className={`block py-2 px-2 text-xs font-semibold uppercase tracking-wider mb-1 transition-colors ${isActive('/industries') ? 'text-primary-cyan' : 'text-primary-cyan/80 hover:text-primary-cyan'}`}
|
|
|
|
|
>
|
|
|
|
|
Industries
|
2026-05-13 22:07:35 -05:00
|
|
|
</Link>
|
2026-05-18 12:11:56 -05:00
|
|
|
<ul className="space-y-1">
|
|
|
|
|
{industryLinks.map((industry) => (
|
|
|
|
|
<li key={industry.name}>
|
|
|
|
|
<Link
|
|
|
|
|
to={industry.href}
|
|
|
|
|
onClick={closeMobileMenu}
|
|
|
|
|
className={`flex items-center py-3 px-4 rounded-md text-sm transition-colors ${isActive(industry.href) ? 'text-white font-semibold bg-white/10' : 'text-white/70 hover:text-white hover:bg-white/5'}`}
|
|
|
|
|
aria-label={industry.name}
|
|
|
|
|
>
|
|
|
|
|
{industry.name}
|
|
|
|
|
</Link>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
2026-05-13 22:07:35 -05:00
|
|
|
</div>
|
2026-05-18 12:11:56 -05:00
|
|
|
</nav>
|
|
|
|
|
|
|
|
|
|
{/* CTA */}
|
|
|
|
|
<div className="pt-4 border-t border-white/10">
|
|
|
|
|
<Link
|
|
|
|
|
to="/contact"
|
|
|
|
|
onClick={closeMobileMenu}
|
|
|
|
|
className="inline-flex items-center justify-center gap-2 w-full rounded-md text-sm font-semibold h-11 px-4 bg-primary-cyan text-primary-navy hover:bg-white transition-colors duration-200"
|
|
|
|
|
aria-label="Get a free quote"
|
|
|
|
|
>
|
|
|
|
|
Get a Free Quote
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
|
|
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
|
|
|
|
</svg>
|
|
|
|
|
</Link>
|
2026-05-13 22:07:35 -05:00
|
|
|
</div>
|
|
|
|
|
</SheetContent>
|
|
|
|
|
</Sheet>
|
2026-05-12 01:04:17 -05:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-05-13 22:07:35 -05:00
|
|
|
</div>
|
|
|
|
|
</header>
|
2026-05-12 01:04:17 -05:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-17 14:33:41 -05:00
|
|
|
export default Header
|