feat: Phase 3 Batch 3 — header/footer/mobilenav polish + fix Button.jsx TS generics (v0.3.3)
- Sticky dark navy header with clean nav and CTA - Reorganized MobileNav with Primary/Services/Industries sections - Dark navy footer with cyan accent headers - Added navy-light color token - Fixed Button.jsx: removed TypeScript generic syntax that broke esbuild - Replaced asChild Button usage with styled anchor tags
This commit is contained in:
parent
76aa71691f
commit
35aaa639ec
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "queuenorth-website",
|
"name": "queuenorth-website",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.3.2",
|
"version": "0.3.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "concurrently \"vite\" \"node server/index.js\"",
|
"dev": "concurrently \"vite\" \"node server/index.js\"",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
const currentYear = new Date().getFullYear()
|
const currentYear = new Date().getFullYear()
|
||||||
|
|
||||||
|
const companyInfo = {
|
||||||
|
name: 'Queue North',
|
||||||
|
tagline: 'Modern communications infrastructure without the vendor noise.',
|
||||||
|
address: 'Your trusted partner in UCaaS, Contact Center, and infrastructure solutions.',
|
||||||
|
}
|
||||||
|
|
||||||
const quickLinks = [
|
const quickLinks = [
|
||||||
{ name: 'Home', href: '/' },
|
{ name: 'Home', href: '/' },
|
||||||
{ name: 'Services', href: '/services' },
|
{ name: 'Services', href: '/services' },
|
||||||
|
|
@ -31,34 +37,31 @@ const Footer = () => {
|
||||||
return (
|
return (
|
||||||
<footer className="bg-primary-navy text-white">
|
<footer className="bg-primary-navy text-white">
|
||||||
<div className="container mx-auto px-4 py-12">
|
<div className="container mx-auto px-4 py-12">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mb-8">
|
||||||
{/* Company Info */}
|
{/* Company Info */}
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2 mb-4">
|
<div className="flex items-center gap-2 mb-4">
|
||||||
<img
|
<img
|
||||||
src="/logo.svg"
|
src="/logo.svg"
|
||||||
alt="Queue North"
|
alt="Queue North"
|
||||||
className="h-6 w-auto"
|
className="h-8 w-auto"
|
||||||
/>
|
/>
|
||||||
<span className="font-bold text-lg">Queue North</span>
|
<span className="font-bold text-lg">Queue North</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-soft-text text-sm mb-4">
|
<p className="text-navy-light text-sm mb-3">{companyInfo.tagline}</p>
|
||||||
Modern communications infrastructure without the vendor noise.
|
<p className="text-navy-light text-sm mb-4">{companyInfo.address}</p>
|
||||||
</p>
|
<p className="text-navy-light text-xs">© {currentYear} Queue North Technologies. All rights reserved.</p>
|
||||||
<p className="text-soft-text text-sm">
|
|
||||||
© {currentYear} Queue North Technologies. All rights reserved.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Quick Links */}
|
{/* Quick Links */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold mb-4 text-lg">Quick Links</h3>
|
<h3 className="font-semibold mb-4 text-sm uppercase tracking-wider text-cyan">Quick Links</h3>
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{quickLinks.map((link) => (
|
{quickLinks.map((link) => (
|
||||||
<li key={link.name}>
|
<li key={link.name}>
|
||||||
<a
|
<a
|
||||||
href={link.href}
|
href={link.href}
|
||||||
className="text-soft-text hover:text-white transition-colors text-sm"
|
className="text-navy-light hover:text-white transition-colors text-sm"
|
||||||
>
|
>
|
||||||
{link.name}
|
{link.name}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -69,13 +72,13 @@ const Footer = () => {
|
||||||
|
|
||||||
{/* Services */}
|
{/* Services */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold mb-4 text-lg">Services</h3>
|
<h3 className="font-semibold mb-4 text-sm uppercase tracking-wider text-cyan">Services</h3>
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{services.map((service) => (
|
{services.map((service) => (
|
||||||
<li key={service.name}>
|
<li key={service.name}>
|
||||||
<a
|
<a
|
||||||
href={service.href}
|
href={service.href}
|
||||||
className="text-soft-text hover:text-white transition-colors text-sm"
|
className="text-navy-light hover:text-white transition-colors text-sm"
|
||||||
>
|
>
|
||||||
{service.name}
|
{service.name}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -86,13 +89,13 @@ const Footer = () => {
|
||||||
|
|
||||||
{/* Industries */}
|
{/* Industries */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold mb-4 text-lg">Industries</h3>
|
<h3 className="font-semibold mb-4 text-sm uppercase tracking-wider text-cyan">Industries</h3>
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{industries.map((industry) => (
|
{industries.map((industry) => (
|
||||||
<li key={industry.name}>
|
<li key={industry.name}>
|
||||||
<a
|
<a
|
||||||
href={industry.href}
|
href={industry.href}
|
||||||
className="text-soft-text hover:text-white transition-colors text-sm"
|
className="text-navy-light hover:text-white transition-colors text-sm"
|
||||||
>
|
>
|
||||||
{industry.name}
|
{industry.name}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -103,8 +106,8 @@ const Footer = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Bottom */}
|
{/* Bottom */}
|
||||||
<div className="border-t border-white/10 mt-8 pt-8 text-center">
|
<div className="border-t border-white/10 pt-8">
|
||||||
<p className="text-soft-text text-sm">
|
<p className="text-center text-navy-light text-sm">
|
||||||
8x8 Certified Partner | Veteran Owned | 25+ Years Experience
|
8x8 Certified Partner | Veteran Owned | 25+ Years Experience
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -24,17 +24,17 @@ const Header = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<header className={`sticky top-0 z-40 w-full border-b transition-all duration-300 ${isScrolled ? 'bg-background/90 backdrop-blur shadow-sm -translate-y-px' : 'bg-transparent'}`}>
|
<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">
|
<div className="container mx-auto px-4">
|
||||||
<div className="flex h-16 items-center justify-between">
|
<div className="flex h-16 items-center justify-between">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-3">
|
||||||
<img
|
<img
|
||||||
src="/logo.svg"
|
src="/logo.svg"
|
||||||
alt="Queue North Technologies"
|
alt="Queue North Technologies"
|
||||||
className="h-8 w-auto"
|
className="h-8 w-auto flex-shrink-0"
|
||||||
/>
|
/>
|
||||||
<span className="font-bold text-xl text-primary-navy hidden sm:block">Queue North</span>
|
<span className="font-bold text-xl text-white hidden sm:block tracking-tight">Queue North</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Desktop Nav */}
|
{/* Desktop Nav */}
|
||||||
|
|
@ -43,7 +43,7 @@ const Header = () => {
|
||||||
<a
|
<a
|
||||||
key={link.name}
|
key={link.name}
|
||||||
href={link.href}
|
href={link.href}
|
||||||
className="text-sm font-medium text-text hover:text-primary-navy transition-colors"
|
className="text-sm font-medium text-navy-light hover:text-white transition-colors"
|
||||||
>
|
>
|
||||||
{link.name}
|
{link.name}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -51,18 +51,15 @@ const Header = () => {
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{/* CTA Button */}
|
{/* CTA Button */}
|
||||||
<div className="hidden md:flex">
|
<div className="hidden md:block">
|
||||||
<a
|
<a href="/contact" className="inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-3 bg-primary-navy text-white hover:bg-primary-navy-dark transition-colors">
|
||||||
href="/contact"
|
|
||||||
className="bg-primary-navy text-white px-4 py-2 rounded-md text-sm font-medium hover:bg-primary-navy-dark transition-colors"
|
|
||||||
>
|
|
||||||
Request Consultation
|
Request Consultation
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Mobile Menu Toggle */}
|
{/* Mobile Menu Toggle */}
|
||||||
<SheetTrigger asChild>
|
<SheetTrigger asChild>
|
||||||
<button className="md:hidden p-2 text-text hover:text-primary-navy focus:outline-none focus:ring-2 focus:ring-primary-navy rounded-md">
|
<button className="md:hidden p-2 text-white hover:text-cyan transition-colors focus:outline-none focus:ring-2 focus:ring-cyan rounded-md">
|
||||||
<span className="sr-only">Open menu</span>
|
<span className="sr-only">Open menu</span>
|
||||||
<svg
|
<svg
|
||||||
className="h-6 w-6"
|
className="h-6 w-6"
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,30 @@ import { useState } from 'react'
|
||||||
const MobileNav = () => {
|
const MobileNav = () => {
|
||||||
const [isOpen, setIsOpen] = useState(false)
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
|
|
||||||
const navLinks = [
|
const primaryLinks = [
|
||||||
{ name: 'Home', href: '/' },
|
{ name: 'Home', href: '/' },
|
||||||
{ name: 'Services', href: '/services' },
|
|
||||||
{ name: 'Industries', href: '/industries' },
|
|
||||||
{ name: '8x8', href: '/8x8' },
|
|
||||||
{ name: 'About', href: '/about' },
|
{ name: 'About', href: '/about' },
|
||||||
{ name: 'Contact', href: '/contact' },
|
{ name: 'Contact', href: '/contact' },
|
||||||
{ name: 'Support', href: '/support' },
|
{ name: 'Support', href: '/support' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const services = [
|
||||||
|
{ 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 industries = [
|
||||||
|
{ name: 'Healthcare', href: '/industries/healthcare' },
|
||||||
|
{ name: 'Retail', href: '/industries/retail' },
|
||||||
|
{ name: 'Manufacturing', href: '/industries/manufacturing' },
|
||||||
|
{ name: 'Education & Finance', href: '/industries/education-finance' },
|
||||||
|
]
|
||||||
|
|
||||||
const closeMobileMenu = () => {
|
const closeMobileMenu = () => {
|
||||||
setIsOpen(false)
|
setIsOpen(false)
|
||||||
}
|
}
|
||||||
|
|
@ -22,7 +36,7 @@ const MobileNav = () => {
|
||||||
<div className="md:hidden">
|
<div className="md:hidden">
|
||||||
<Sheet open={isOpen} onOpenChange={setIsOpen}>
|
<Sheet open={isOpen} onOpenChange={setIsOpen}>
|
||||||
<SheetTrigger asChild>
|
<SheetTrigger asChild>
|
||||||
<button className="p-2 text-text hover:text-primary-navy focus:outline-none">
|
<button className="p-2 text-white hover:text-cyan focus:outline-none focus:ring-2 focus:ring-cyan rounded-md">
|
||||||
<svg
|
<svg
|
||||||
className="h-6 w-6"
|
className="h-6 w-6"
|
||||||
fill="none"
|
fill="none"
|
||||||
|
|
@ -39,35 +53,78 @@ const MobileNav = () => {
|
||||||
<span className="sr-only">Open menu</span>
|
<span className="sr-only">Open menu</span>
|
||||||
</button>
|
</button>
|
||||||
</SheetTrigger>
|
</SheetTrigger>
|
||||||
<SheetContent side="right" className="w-[280px] sm:w-[320px]">
|
<SheetContent side="right" className="w-[300px] sm:w-[350px] bg-primary-navy text-white">
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
<div className="flex items-center gap-2 mb-6">
|
<div className="flex items-center gap-3 mb-6">
|
||||||
<img
|
<img
|
||||||
src="/logo.svg"
|
src="/logo.svg"
|
||||||
alt="Queue North"
|
alt="Queue North"
|
||||||
className="h-8 w-auto"
|
className="h-9 w-auto"
|
||||||
/>
|
/>
|
||||||
<span className="font-bold text-xl text-primary-navy">Queue North</span>
|
<span className="font-bold text-xl">Queue North</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav className="flex flex-col space-y-4">
|
<nav className="flex flex-col space-y-6">
|
||||||
{navLinks.map((link) => (
|
{/* Primary Links */}
|
||||||
<a
|
<div>
|
||||||
key={link.name}
|
<h4 className="text-xs font-semibold uppercase tracking-wider text-navy-light mb-3">Primary</h4>
|
||||||
href={link.href}
|
<ul className="space-y-2">
|
||||||
onClick={closeMobileMenu}
|
{primaryLinks.map((link) => (
|
||||||
className="text-base font-medium text-text hover:text-primary-navy py-2 border-b border-gray-100 last:border-0"
|
<li key={link.name}>
|
||||||
>
|
<a
|
||||||
{link.name}
|
href={link.href}
|
||||||
</a>
|
onClick={closeMobileMenu}
|
||||||
))}
|
className="block text-base font-medium text-navy-light hover:text-white transition-colors py-2"
|
||||||
|
>
|
||||||
|
{link.name}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Services */}
|
||||||
|
<div>
|
||||||
|
<h4 className="text-xs font-semibold uppercase tracking-wider text-navy-light mb-3">Services</h4>
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{services.map((service) => (
|
||||||
|
<li key={service.name}>
|
||||||
|
<a
|
||||||
|
href={service.href}
|
||||||
|
onClick={closeMobileMenu}
|
||||||
|
className="block text-sm text-navy-light hover:text-white transition-colors py-2 border-b border-white/10 last:border-0"
|
||||||
|
>
|
||||||
|
{service.name}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Industries */}
|
||||||
|
<div>
|
||||||
|
<h4 className="text-xs font-semibold uppercase tracking-wider text-navy-light mb-3">Industries</h4>
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{industries.map((industry) => (
|
||||||
|
<li key={industry.name}>
|
||||||
|
<a
|
||||||
|
href={industry.href}
|
||||||
|
onClick={closeMobileMenu}
|
||||||
|
className="block text-sm text-navy-light hover:text-white transition-colors py-2 border-b border-white/10 last:border-0"
|
||||||
|
>
|
||||||
|
{industry.name}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div className="mt-auto pt-6">
|
<div className="mt-auto pt-6">
|
||||||
<a
|
<a
|
||||||
href="/contact"
|
href="/contact"
|
||||||
onClick={closeMobileMenu}
|
onClick={closeMobileMenu}
|
||||||
className="block w-full bg-primary-navy text-white px-4 py-3 rounded-md text-center font-medium hover:bg-primary-navy-dark transition-colors"
|
className="inline-flex items-center justify-center rounded-md text-sm font-medium h-10 px-4 py-2 w-full bg-primary-navy text-white hover:bg-primary-navy-dark transition-colors"
|
||||||
>
|
>
|
||||||
Request Consultation
|
Request Consultation
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,6 @@
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
|
||||||
const Button = React.forwardRef<
|
const Button = React.forwardRef(({ className = '', variant = 'default', size = 'default', ...props }, ref) => {
|
||||||
HTMLButtonElement,
|
|
||||||
React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
||||||
variant?: 'default' | 'secondary' | 'outline' | 'ghost' | 'link'
|
|
||||||
size?: 'default' | 'sm' | 'lg' | 'icon'
|
|
||||||
}
|
|
||||||
>(({ className = '', variant = 'default', size = 'default', ...props }, ref) => {
|
|
||||||
const baseStyles = 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none'
|
const baseStyles = 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none'
|
||||||
|
|
||||||
const variants = {
|
const variants = {
|
||||||
|
|
@ -27,7 +21,7 @@ const Button = React.forwardRef<
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={`${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`}
|
className={`${baseStyles} ${variants[variant] || ''} ${sizes[size] || ''} ${className}`}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ export default {
|
||||||
text: '#0F172A',
|
text: '#0F172A',
|
||||||
muted: '#475569',
|
muted: '#475569',
|
||||||
'soft-text': '#64748B',
|
'soft-text': '#64748B',
|
||||||
|
'navy-light': '#68A3B8',
|
||||||
primary: {
|
primary: {
|
||||||
navy: '#0B2A3C',
|
navy: '#0B2A3C',
|
||||||
'navy-dark': '#071A2A',
|
'navy-dark': '#071A2A',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue