fix: undefined Tailwind classes, SPA navigation, phone/email links (closes #51, #52)

- Replace all undefined shadcn/ui Tailwind classes with correct config values
  (text-muted-foreground→text-muted, text-card-foreground→text-text,
   bg-secondary→bg-section-alt, ring-ring→ring-primary-navy, etc.)
- Replace text-cyan/bg-cyan with text-primary-cyan/bg-primary-cyan
- Convert all internal <a href> to React Router <Link to> for SPA navigation
- Remove self-referencing /contact button on Contact page
- Add tel: links for phone numbers, mailto: links for emails in
  Contact.jsx and Support.jsx hero badges and info sections
- Fix Header.jsx mobile menu button hover:text-cyan→hover:text-primary-cyan (batch 0.6.3)
This commit is contained in:
null 2026-05-17 17:42:03 -05:00
parent b5170caf9d
commit 9cdc299ade
18 changed files with 58 additions and 54 deletions

View File

@ -53,15 +53,15 @@ const Footer = () => {
<p className="text-navy-light text-sm mb-3">{companyInfo.address}</p>
<div className="space-y-2 text-navy-light text-sm mb-3">
<div>
<a href={`mailto:${companyInfo.email}`} className="hover:text-cyan transition-colors">{companyInfo.email}</a>
<a href={`mailto:${companyInfo.email}`} className="hover:text-primary-cyan transition-colors">{companyInfo.email}</a>
</div>
<div>
<a href={`tel:${companyInfo.phone.replace(/\D/g, '')}`} className="hover:text-cyan transition-colors">{companyInfo.phone}</a>
<a href={`tel:${companyInfo.phone.replace(/\D/g, '')}`} className="hover:text-primary-cyan transition-colors">{companyInfo.phone}</a>
</div>
<a href="/contact" className="inline-block text-cyan hover:underline">Contact Form</a>
<a href="/contact" className="inline-block text-primary-cyan hover:underline">Contact Form</a>
</div>
<div className="mt-4">
<a href="/contact" className="inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-4 bg-cyan text-primary-navy hover:bg-cyan/90 transition-colors">
<a href="/contact" className="inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-4 bg-primary-cyan text-primary-navy hover:bg-primary-cyan/90 transition-colors">
Request Consultation
</a>
</div>
@ -70,7 +70,7 @@ const Footer = () => {
{/* Quick Links */}
<div>
<h3 className="font-semibold mb-4 text-sm uppercase tracking-wider text-cyan">Quick Links</h3>
<h3 className="font-semibold mb-4 text-sm uppercase tracking-wider text-primary-cyan">Quick Links</h3>
<ul className="space-y-2">
{quickLinks.map((link) => (
<li key={link.name}>
@ -87,7 +87,7 @@ const Footer = () => {
{/* Services */}
<div>
<h3 className="font-semibold mb-4 text-sm uppercase tracking-wider text-cyan">Services</h3>
<h3 className="font-semibold mb-4 text-sm uppercase tracking-wider text-primary-cyan">Services</h3>
<ul className="space-y-2">
{services.map((service) => (
<li key={service.name}>
@ -104,7 +104,7 @@ const Footer = () => {
{/* Industries */}
<div>
<h3 className="font-semibold mb-4 text-sm uppercase tracking-wider text-cyan">Industries</h3>
<h3 className="font-semibold mb-4 text-sm uppercase tracking-wider text-primary-cyan">Industries</h3>
<ul className="space-y-2">
{industries.map((industry) => (
<li key={industry.name}>

View File

@ -86,7 +86,7 @@ const Header = () => {
<div className="md:hidden">
<Sheet open={mobileMenuOpen} onOpenChange={setMobileMenuOpen}>
<SheetTrigger asChild>
<button className="p-2 text-white hover:text-cyan transition-colors focus:outline-none focus:ring-2 focus:ring-cyan rounded-md">
<button className="p-2 text-white hover:text-primary-cyan transition-colors focus:outline-none focus:ring-2 focus:ring-primary-cyan rounded-md">
<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" />

View File

@ -40,7 +40,7 @@ const MobileNav = () => {
<div className="md:hidden">
<Sheet open={isOpen} onOpenChange={setIsOpen}>
<SheetTrigger asChild>
<button className="p-2 text-white hover:text-cyan focus:outline-none focus:ring-2 focus:ring-cyan rounded-md">
<button className="p-2 text-white hover:text-primary-cyan focus:outline-none focus:ring-2 focus:ring-primary-cyan rounded-md">
<svg
className="h-6 w-6"
fill="none"

View File

@ -2,7 +2,7 @@ import * as React from 'react'
const Badge = React.forwardRef(
({ className = '', variant = 'default', ...props }, ref) => {
const baseStyles = 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2'
const baseStyles = 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-primary-navy focus:ring-offset-2'
const variants = {
default: 'border-transparent bg-primary-navy text-white hover:bg-primary-navy-dark',

View File

@ -1,14 +1,14 @@
import * as React from 'react'
const Button = React.forwardRef(({ 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-primary-navy focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none'
const variants = {
default: 'bg-primary-navy text-white hover:bg-primary-navy-dark',
secondary: 'bg-section-alt text-text hover:bg-opacity-80',
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
ghost: 'hover:bg-secondary hover:text-secondary-foreground',
link: 'text-primary underline-offset-4 hover:underline',
outline: 'border border-border bg-background hover:bg-section-alt hover:text-text',
ghost: 'hover:bg-section-alt hover:text-text',
link: 'text-primary-navy underline-offset-4 hover:underline',
}
const sizes = {

View File

@ -4,7 +4,7 @@ const Card = React.forwardRef(
({ className = '', ...props }, ref) => (
<div
ref={ref}
className={`rounded-xl border border-border bg-card text-card-foreground shadow-sm ${className}`}
className={`rounded-xl border border-border bg-card text-text shadow-sm ${className}`}
{...props}
/>
)
@ -37,7 +37,7 @@ const CardDescription = React.forwardRef(
({ className = '', ...props }, ref) => (
<p
ref={ref}
className={`text-sm text-muted-foreground ${className}`}
className={`text-sm text-muted ${className}`}
{...props}
/>
)

View File

@ -4,7 +4,7 @@ const CardDescription = React.forwardRef(
({ className = '', ...props }, ref) => (
<p
ref={ref}
className={`text-sm text-muted-foreground ${className}`}
className={`text-sm text-muted ${className}`}
{...props}
/>
)

View File

@ -28,7 +28,7 @@ const DialogContent = React.forwardRef(
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-[#F8FAFC] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-primary-navy focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-section-alt">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
@ -67,7 +67,7 @@ const DialogDescription = React.forwardRef(
({ className = '', ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={`text-sm text-muted-foreground ${className}`}
className={`text-sm text-muted ${className}`}
{...props}
/>
))

View File

@ -5,7 +5,7 @@ const Input = React.forwardRef(
return (
<input
type={type}
className={`flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${className}`}
className={`flex h-10 w-full rounded-md border border-border bg-background px-3 py-2 text-sm ring-offset-[#F8FAFC] file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-navy focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${className}`}
ref={ref}
{...props}
/>

View File

@ -4,14 +4,14 @@ const Select = ({ children, className = '', ...props }) => {
return (
<div className={`relative ${className}`}>
<select
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 appearance-none"
className="flex h-10 w-full rounded-md border border-border bg-background px-3 py-2 text-sm ring-offset-[#F8FAFC] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-navy focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 appearance-none"
{...props}
>
{children}
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2">
<svg
className="h-4 w-4 text-muted-foreground"
className="h-4 w-4 text-muted"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"

View File

@ -33,7 +33,7 @@ const SheetContent = React.forwardRef(({ className, children, side = 'right', ..
{...props}
>
{children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-[#F8FAFC] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-primary-navy focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-section-alt">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
@ -61,7 +61,7 @@ SheetFooter.displayName = 'SheetFooter'
const SheetTitle = React.forwardRef(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={`text-lg font-semibold text-foreground ${className}`}
className={`text-lg font-semibold text-text ${className}`}
{...props}
/>
))
@ -70,7 +70,7 @@ SheetTitle.displayName = SheetPrimitive.Title.displayName
const SheetDescription = React.forwardRef(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={`text-sm text-muted-foreground ${className}`}
className={`text-sm text-muted ${className}`}
{...props}
/>
))

View File

@ -4,7 +4,7 @@ const Textarea = React.forwardRef(
({ className = '', ...props }, ref) => {
return (
<textarea
className={`flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${className}`}
className="flex min-h-[80px] w-full rounded-md border border-border bg-background px-3 py-2 text-sm ring-offset-[#F8FAFC] placeholder:text-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-navy focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${className}"
ref={ref}
{...props}
/>
@ -13,4 +13,4 @@ const Textarea = React.forwardRef(
)
Textarea.displayName = 'Textarea'
export { Textarea }
export { Textarea }

View File

@ -114,13 +114,13 @@ const Contact = () => {
<svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 5.13a1 1 0 01-1.31.42a2 2 0 00-2.63-.54l-2.238 5.03a2 2 0 01-2.71.319L2.663 12H4a2 2 0 012 2v2a2 2 0 01-2 2H2a2 2 0 01-2-2V5z" />
</svg>
<p className="text-sm font-medium">(906) 482-6616</p>
<a href="tel:+19064826616" className="text-sm font-medium hover:underline">(906) 482-6616</a>
</div>
<div className="flex items-center gap-2 px-4 py-2 bg-primary-navy/10 rounded-lg text-primary-navy">
<svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
<p className="text-sm font-medium">info@queuenorth.com</p>
<a href="mailto:info@queuenorth.com" className="text-sm font-medium hover:underline">info@queuenorth.com</a>
</div>
</div>
<div className="mb-8">
@ -150,7 +150,7 @@ const Contact = () => {
</div>
<div>
<h3 className="font-semibold text-text mb-2">Phone</h3>
<p className="text-soft-text">(906) 482-6616</p>
<p className="text-soft-text"><a href="tel:+19064826616" className="hover:underline">(906) 482-6616</a></p>
</div>
<div>
<h3 className="font-semibold text-text mb-2">Contact Us</h3>
@ -299,7 +299,7 @@ const Contact = () => {
onChange={handleChange}
required
placeholder="Tell us about your needs..."
className={`w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${errors.message ? 'border-red-500 focus-visible:ring-red-500' : ''}`}
className={`w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-[#F8FAFC] placeholder:text-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-navy focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${errors.message ? 'border-red-500 focus-visible:ring-red-500' : ''}`}
rows={5}
/>
{debouncedErrors.message && (

View File

@ -1,4 +1,5 @@
import { industries } from '@/data/industries'
import { Link } from 'react-router-dom'
const Industries = () => {
return (
@ -51,12 +52,12 @@ const Industries = () => {
</div>
</div>
<a href={`/industries/${industry.id}`} className="inline-flex items-center gap-1 text-primary-navy font-medium hover:underline mt-2">
<Link to={`/industries/${industry.id}`} className="inline-flex items-center gap-1 text-primary-navy font-medium hover:underline mt-2">
Learn more
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7" />
</svg>
</a>
</Link>
</div>
</div>
</div>
@ -73,12 +74,12 @@ const Industries = () => {
<p className="text-xl text-soft-text mb-8 max-w-2xl mx-auto">
We work with businesses across all industries. Contact us to discuss your specific needs.
</p>
<a
href="/contact"
<Link
to="/contact"
className="inline-block bg-primary-navy text-white px-8 py-3 rounded-md font-bold text-lg hover:bg-primary-navy-dark transition-colors"
>
Request Consultation
</a>
</Link>
</div>
</div>
</section>

View File

@ -1,5 +1,6 @@
import { useParams } from 'react-router-dom'
import { industries } from '@/data/industries'
import { Link } from 'react-router-dom'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
const IndustryDetail = () => {
@ -13,9 +14,9 @@ const IndustryDetail = () => {
<div className="text-center">
<h1 className="text-3xl font-bold text-primary-navy mb-4">Industry Not Found</h1>
<p className="text-xl text-soft-text mb-8">The industry you're looking for doesn't exist.</p>
<a href="/industries" className="text-primary-navy hover:underline">
<Link to="/industries" className="text-primary-navy hover:underline">
Back to Industries
</a>
</Link>
</div>
</div>
</section>
@ -92,14 +93,14 @@ const IndustryDetail = () => {
<p className="text-soft-text">{industry.name}</p>
</div>
<div className="pt-4 border-t border-border">
<a href="/contact" 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">
<Link to="/contact" 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">
Request Consultation
</a>
</Link>
</div>
<div className="pt-2">
<a href="/industries" className="text-primary-navy hover:underline">
<Link to="/industries" className="text-primary-navy hover:underline">
Back to Industries
</a>
</Link>
</div>
</CardContent>
</Card>

View File

@ -1,5 +1,6 @@
import { useParams } from 'react-router-dom'
import { services } from '@/data/services'
import { Link } from 'react-router-dom'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
const ServiceDetail = () => {
@ -13,9 +14,9 @@ const ServiceDetail = () => {
<div className="text-center">
<h1 className="text-3xl font-bold text-primary-navy mb-4">Service Not Found</h1>
<p className="text-xl text-soft-text mb-8">The service you're looking for doesn't exist.</p>
<a href="/services" className="text-primary-navy hover:underline">
<Link to="/services" className="text-primary-navy hover:underline">
Back to Services
</a>
</Link>
</div>
</div>
</section>
@ -108,14 +109,14 @@ const ServiceDetail = () => {
<p className="text-soft-text capitalize">{service.id.replace('-', ' ')}</p>
</div>
<div className="pt-4 border-t border-border">
<a href="/contact" 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">
<Link to="/contact" 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">
Request This Service
</a>
</Link>
</div>
<div className="pt-2">
<a href="/services" className="text-primary-navy hover:underline">
<Link to="/services" className="text-primary-navy hover:underline">
Back to Services
</a>
</Link>
</div>
</CardContent>
</Card>

View File

@ -1,5 +1,6 @@
import { services } from '@/data/services'
import { MessageCircle, Users, LifeBuoy, GraduationCap, Link as LinkIcon, Wifi, Network } from 'lucide-react'
import { Link } from 'react-router-dom'
const Services = () => {
return (
@ -51,12 +52,12 @@ const Services = () => {
</div>
))}
</div>
<a href={`/services/${service.id}`} className="inline-flex items-center gap-1 text-primary-navy font-medium hover:underline mt-2">
<Link to={`/services/${service.id}`} className="inline-flex items-center gap-1 text-primary-navy font-medium hover:underline mt-2">
Learn more
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7" />
</svg>
</a>
</Link>
</div>
</div>
</div>
@ -73,12 +74,12 @@ const Services = () => {
<p className="text-xl text-soft-text mb-8 max-w-2xl mx-auto">
Don't see exactly what you're looking for? We can help you find the right solution.
</p>
<a
href="/contact"
<Link
to="/contact"
className="inline-block bg-primary-navy text-white px-8 py-3 rounded-md font-bold text-lg hover:bg-primary-navy-dark transition-colors"
>
Request Consultation
</a>
</Link>
</div>
</div>
</section>

View File

@ -302,7 +302,7 @@ const Support = () => {
onChange={handleChange}
required
placeholder="Please describe your issue in detail..."
className={`w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${errors.issue ? 'border-red-500 focus-visible:ring-red-500' : ''}`}
className={`w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-[#F8FAFC] placeholder:text-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-navy focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${errors.issue ? 'border-red-500 focus-visible:ring-red-500' : ''}`}
rows={5}
/>
{debouncedErrors.issue && (