Neue services
This commit is contained in:
BIN
src/assets/hero-bg.webp
Normal file
BIN
src/assets/hero-bg.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
BIN
src/assets/process-illustration.webp
Normal file
BIN
src/assets/process-illustration.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
File diff suppressed because it is too large
Load Diff
63
src/index.css
Normal file
63
src/index.css
Normal file
@@ -0,0 +1,63 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
html {
|
||||
height: auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #0a0a0a;
|
||||
color: white;
|
||||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.lenis.lenis-smooth {
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
|
||||
.lenis.lenis-smooth [data-lenis-prevent] {
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
.lenis.lenis-stopped {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.lenis.lenis-scrolling iframe {
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { motion, useInView, useSpring, useTransform, useScroll, useMotionValueEvent } from 'framer-motion';
|
||||
import Contact from '../../components/Contact';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { motion, useInView, useSpring, useTransform, useScroll, useMotionValueEvent } from 'framer-motion';
|
||||
import Contact from '../../components/Contact';
|
||||
import SEO from '../../components/SEO';
|
||||
|
||||
const Counter = ({ value }: { value: number }) => {
|
||||
const ref = useRef(null);
|
||||
@@ -40,13 +41,6 @@ const AboutPage: React.FC = () => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
const stats = [
|
||||
{ label: 'Businesses served', value: '150+' },
|
||||
{ label: 'Uptime achieved', value: '99.9%' },
|
||||
{ label: 'Years of service', value: '15+' },
|
||||
{ label: 'Response time', value: '<2min' },
|
||||
];
|
||||
|
||||
const values = [
|
||||
{
|
||||
title: 'Security-First',
|
||||
@@ -66,14 +60,21 @@ const AboutPage: React.FC = () => {
|
||||
];
|
||||
|
||||
const timeline = [
|
||||
{ year: '2010', title: 'Founded in Corpus Christi', desc: 'Started with a mission to bring enterprise-level IT solutions to local businesses.' },
|
||||
{ year: '2000', title: 'Founded in Corpus Christi', desc: 'Started with a mission to bring enterprise-level IT solutions to local businesses.' },
|
||||
{ year: '2015', title: 'Expanded Service Portfolio', desc: 'Added cloud services and advanced networking to serve growing businesses.' },
|
||||
{ year: '2020', title: 'Remote Work Transformation', desc: 'Helped 100+ businesses transition to secure remote work during the pandemic.' },
|
||||
{ year: '2024', title: 'Leading the Coastal Bend', desc: 'Now serving 150+ businesses with modern, reliable IT infrastructure.' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="pt-20 min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
||||
{ year: '2020', title: 'Remote Work Transformation', desc: 'Helped local businesses strengthen remote access, security, and day-to-day support during a disruptive period.' },
|
||||
{ year: '2024', title: 'Leading the Coastal Bend', desc: 'Now supporting 30+ local businesses with practical, reliable IT infrastructure.' },
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title="About Bay Area IT | Local IT Support in Corpus Christi"
|
||||
description="Learn about Bay Area IT, a local IT partner serving Corpus Christi and the Coastal Bend with practical support, reliable service, and over 25 years of experience."
|
||||
keywords={['about Bay Area IT', 'Corpus Christi IT company', 'local IT support Coastal Bend']}
|
||||
canonicalUrl="https://bayareait.services/about"
|
||||
/>
|
||||
<div className="pt-20 min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
||||
<div className="absolute top-0 left-0 right-0 h-[800px] bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(0,0,0,0.2),rgba(0,0,0,0))] dark:bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(255,255,255,0.25),rgba(255,255,255,0))] pointer-events-none" />
|
||||
|
||||
{/* Hero Section */}
|
||||
@@ -92,7 +93,7 @@ const AboutPage: React.FC = () => {
|
||||
transition={{ delay: 0.1 }}
|
||||
className="text-xl text-gray-600 dark:text-gray-300 max-w-3xl mx-auto leading-relaxed"
|
||||
>
|
||||
Since 2010, we've been helping businesses in Corpus Christi and surrounding communities build reliable, secure technology foundations that drive growth.
|
||||
Since 2000, we've been helping businesses in Corpus Christi and surrounding communities build reliable, secure technology foundations that keep work moving.
|
||||
</motion.p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -104,13 +105,13 @@ const AboutPage: React.FC = () => {
|
||||
<h2 className="font-display text-3xl font-bold mb-8 text-gray-900 dark:text-white">Our Story</h2>
|
||||
<div className="prose dark:prose-invert max-w-none text-lg text-gray-600 dark:text-gray-300 space-y-6">
|
||||
<p>
|
||||
Bay Area Affiliates was founded with a simple belief: local businesses deserve the same level of IT expertise and reliability as large corporations, but with the personal touch that only comes from working with your neighbors.
|
||||
Bay Area IT was founded with a simple belief: local businesses deserve dependable technology support without enterprise complexity, vague communication, or reactive chaos.
|
||||
</p>
|
||||
<p>
|
||||
Over the years, we've watched the Coastal Bend grow and change. We've helped businesses navigate technology challenges, from the transition to cloud computing to the rapid shift to remote work. Through it all, we've maintained our commitment to clear communication, reliable solutions, and exceptional service.
|
||||
</p>
|
||||
<p>
|
||||
Today, we're proud to serve over 150 businesses across the region, from Corpus Christi to the smallest coastal communities. Our team combines deep technical expertise with real-world business understanding to deliver IT solutions that actually work for our clients.
|
||||
Today, we're proud to support 30+ local businesses across the region. Our team combines deep technical experience with real-world business judgment to deliver IT support that is clear, practical, and reliable.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -121,10 +122,10 @@ const AboutPage: React.FC = () => {
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_60%_50%_at_50%_-20%,rgba(255,255,255,0.03),rgba(255,255,255,0))] pointer-events-none"></div>
|
||||
<div className="max-w-7xl mx-auto grid grid-cols-2 md:grid-cols-4 gap-8 text-center relative z-10">
|
||||
{[
|
||||
{ label: 'Businesses served', value: 150, suffix: '+' },
|
||||
{ label: 'Uptime achieved', value: 99.9, suffix: '%' },
|
||||
{ label: 'Years of service', value: 15, suffix: '+' },
|
||||
{ label: 'Response time', value: 2, prefix: '<', suffix: 'min' },
|
||||
{ label: 'Businesses served', value: 30, suffix: '+' },
|
||||
{ label: 'Uptime achieved', value: 99.9, suffix: '%' },
|
||||
{ label: 'Years of service', value: 25, suffix: '+' },
|
||||
{ label: 'Response time', value: 2, prefix: '<', suffix: 'min' },
|
||||
].map((stat, index) => (
|
||||
<div key={index} className="p-4">
|
||||
<div className="text-4xl md:text-5xl font-bold mb-2 flex justify-center items-center gap-1">
|
||||
@@ -238,9 +239,10 @@ const AboutPage: React.FC = () => {
|
||||
</section>
|
||||
|
||||
<Contact />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default AboutPage;
|
||||
|
||||
@@ -1,16 +1,37 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Contact from '../../components/Contact';
|
||||
import { blogPostData } from '../data/seoData';
|
||||
|
||||
const BlogPage: React.FC = () => {
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
import React, { useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Contact from '../../components/Contact';
|
||||
import SEO from '../../components/SEO';
|
||||
import { blogPostData } from '../data/seoData';
|
||||
|
||||
const cardVariants = {
|
||||
hidden: { opacity: 0, y: 20 },
|
||||
visible: (index: number) => ({
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
duration: 0.45,
|
||||
delay: Math.min(index * 0.06, 0.3),
|
||||
ease: 'easeOut',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
const BlogPage: React.FC = () => {
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="pt-20 min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
||||
<>
|
||||
<SEO
|
||||
title="Blog | Bay Area IT Insights for Corpus Christi Businesses"
|
||||
description="Read practical IT guidance for Corpus Christi and Coastal Bend businesses, from managed IT support and costs to business email and local service coverage."
|
||||
keywords={['Corpus Christi IT blog', 'managed IT insights', 'business IT support articles']}
|
||||
canonicalUrl="https://bayareait.services/blog"
|
||||
/>
|
||||
<div className="pt-20 min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
||||
<div className="absolute top-0 left-0 right-0 h-[800px] bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(0,0,0,0.2),rgba(0,0,0,0))] dark:bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(255,255,255,0.25),rgba(255,255,255,0))] pointer-events-none" />
|
||||
<div className="absolute top-[300px] left-1/2 -translate-x-1/2 w-[800px] h-[800px] bg-gray-100/50 dark:bg-white/5 rounded-full blur-[120px] pointer-events-none" />
|
||||
<section className="py-20 px-6 bg-white dark:bg-[#0f0f0f] border-b border-gray-100 dark:border-white/5 relative bg-transparent">
|
||||
@@ -24,23 +45,27 @@ const BlogPage: React.FC = () => {
|
||||
|
||||
<section className="py-16 px-6 bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(0,0,0,0.05),rgba(0,0,0,0))] dark:bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(255,255,255,0.05),rgba(255,255,255,0))]">
|
||||
<div className="max-w-5xl mx-auto space-y-16">
|
||||
{blogPostData.map((post) => (
|
||||
{blogPostData.filter(post => !post.redirect).map((post, index) => (
|
||||
<Link
|
||||
key={post.id}
|
||||
to={`/${post.slug}`}
|
||||
className="block"
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
whileHover={{ y: -5 }}
|
||||
className="group grid md:grid-cols-2 gap-0 bg-white dark:bg-[#161616] rounded-3xl overflow-hidden shadow-lg border border-gray-100 dark:border-white/5 hover:shadow-2xl hover:shadow-blue-900/10 transition-all duration-300"
|
||||
>
|
||||
>
|
||||
<motion.div
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
custom={index}
|
||||
variants={cardVariants}
|
||||
whileHover={{ y: -5 }}
|
||||
className="group grid md:grid-cols-2 gap-0 bg-white dark:bg-[#161616] rounded-3xl overflow-hidden shadow-lg border border-gray-100 dark:border-white/5 hover:shadow-2xl hover:shadow-blue-900/10 transition-all duration-300"
|
||||
>
|
||||
<div className="h-64 md:h-auto overflow-hidden relative">
|
||||
<img
|
||||
src={post.image || '/images/blog/default.png'}
|
||||
alt={post.h1}
|
||||
loading={index === 0 ? 'eager' : 'lazy'}
|
||||
decoding="async"
|
||||
fetchPriority={index === 0 ? 'high' : 'low'}
|
||||
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-105"
|
||||
/>
|
||||
<div className="absolute top-4 left-4">
|
||||
@@ -73,9 +98,10 @@ const BlogPage: React.FC = () => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<Contact />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
<Contact />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlogPage;
|
||||
|
||||
@@ -1,322 +1,236 @@
|
||||
import React, { useEffect, useRef, useLayoutEffect } from 'react';
|
||||
import { motion, useMotionTemplate, useMotionValue } from 'framer-motion';
|
||||
import { Link } from 'react-router-dom';
|
||||
import gsap from 'gsap';
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||
import SEO from '../../components/SEO';
|
||||
import Services from '../../components/Services';
|
||||
import CTA from '../../components/CTA';
|
||||
import AreasWeServe from '../../components/AreasWeServe';
|
||||
import { BlogPostData } from '../data/seoData';
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
interface BlogPostPageProps {
|
||||
data: BlogPostData;
|
||||
}
|
||||
|
||||
const BlogPostPage: React.FC<BlogPostPageProps> = ({ data }) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const parallaxWrapperRef = useRef<HTMLDivElement>(null);
|
||||
const mouseX = useMotionValue(0);
|
||||
const mouseY = useMotionValue(0);
|
||||
|
||||
const handleMouseMove = ({ currentTarget, clientX, clientY }: React.MouseEvent) => {
|
||||
const { left, top } = currentTarget.getBoundingClientRect();
|
||||
mouseX.set(clientX - left);
|
||||
mouseY.set(clientY - top + 75);
|
||||
};
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const ctx = gsap.context(() => {
|
||||
// Parallax Background
|
||||
if (parallaxWrapperRef.current) {
|
||||
gsap.to(parallaxWrapperRef.current, {
|
||||
yPercent: 30,
|
||||
ease: "none",
|
||||
scrollTrigger: {
|
||||
trigger: containerRef.current,
|
||||
start: "top top",
|
||||
end: "bottom top",
|
||||
scrub: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Text Stagger Animation
|
||||
gsap.fromTo(".hero-stagger",
|
||||
{ y: 50, opacity: 0 },
|
||||
{ y: 0, opacity: 1, duration: 1, stagger: 0.2, ease: "power3.out", delay: 0.2 }
|
||||
);
|
||||
}, containerRef);
|
||||
|
||||
return () => ctx.revert();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
const category = data.slug.includes('corpus-christi-blog') ||
|
||||
data.slug.includes('portland-tx') ||
|
||||
data.slug.includes('rockport-tx') ||
|
||||
data.slug.includes('aransas-pass') ||
|
||||
data.slug.includes('kingsville-tx')
|
||||
? 'Local Services'
|
||||
: 'IT Insights';
|
||||
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
keywords={data.keywords}
|
||||
canonicalUrl={window.location.href}
|
||||
/>
|
||||
|
||||
<div className="min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
||||
{/* Hero Section */}
|
||||
<section
|
||||
ref={containerRef}
|
||||
onMouseMove={handleMouseMove}
|
||||
className="relative min-h-screen flex items-center justify-center overflow-hidden pt-20 group"
|
||||
>
|
||||
{/* Parallax Background */}
|
||||
<div className="absolute inset-0 z-0 pointer-events-none">
|
||||
<div ref={parallaxWrapperRef} className="absolute w-full h-[120%] -top-[10%] left-0">
|
||||
{/* Base Layer */}
|
||||
<img
|
||||
alt="Abstract dark technology background"
|
||||
className="w-full h-full object-cover opacity-90 dark:opacity-70 brightness-75 contrast-150"
|
||||
src="/src/assets/hero-bg.png"
|
||||
/>
|
||||
|
||||
{/* Highlight Layer */}
|
||||
<motion.img
|
||||
style={{
|
||||
maskImage: useMotionTemplate`radial-gradient(100px circle at ${mouseX}px ${mouseY}px, black, transparent)`,
|
||||
WebkitMaskImage: useMotionTemplate`radial-gradient(100px circle at ${mouseX}px ${mouseY}px, black, transparent)`,
|
||||
}}
|
||||
alt=""
|
||||
className="absolute inset-0 w-full h-full object-cover mix-blend-screen opacity-100 brightness-150 contrast-150 filter saturate-150"
|
||||
src="/src/assets/hero-bg.png"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-background-light via-transparent to-transparent dark:from-background-dark dark:via-transparent dark:to-transparent"></div>
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-background-light/50 dark:from-background-dark/50 to-transparent"></div>
|
||||
</div>
|
||||
|
||||
{/* Hero Content */}
|
||||
<div className="relative z-10 text-center max-w-4xl px-6">
|
||||
{/* Breadcrumbs */}
|
||||
<nav className="hero-stagger mb-8 text-sm">
|
||||
<ol className="flex items-center gap-2 text-gray-600 dark:text-gray-400 justify-center">
|
||||
<li>
|
||||
<Link to="/" className="hover:text-gray-900 dark:hover:text-white transition-colors">
|
||||
Home
|
||||
</Link>
|
||||
</li>
|
||||
<span className="material-symbols-outlined text-xs">chevron_right</span>
|
||||
<li>
|
||||
<Link to="/blog" className="hover:text-gray-900 dark:hover:text-white transition-colors">
|
||||
Blog
|
||||
</Link>
|
||||
</li>
|
||||
<span className="material-symbols-outlined text-xs">chevron_right</span>
|
||||
<li className="text-gray-900 dark:text-white font-medium">{category}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div className="hero-stagger flex items-center justify-center gap-2 mb-6">
|
||||
<span className="h-px w-8 bg-gray-400 dark:bg-gray-500"></span>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-gray-600 dark:text-gray-400 font-medium">
|
||||
{category}
|
||||
</span>
|
||||
<span className="h-px w-8 bg-gray-400 dark:bg-gray-500"></span>
|
||||
</div>
|
||||
|
||||
<h1 className="hero-stagger font-display text-4xl md:text-6xl lg:text-7xl font-medium tracking-tighter leading-[1.1] mb-8 text-gray-900 dark:text-white">
|
||||
{data.h1}
|
||||
</h1>
|
||||
|
||||
{/* Meta Info */}
|
||||
<div className="hero-stagger flex items-center gap-6 text-gray-600 dark:text-gray-400 mb-8 justify-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="material-symbols-outlined text-sm">schedule</span>
|
||||
<span>5 min read</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="material-symbols-outlined text-sm">calendar_today</span>
|
||||
<span>January 2025</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Featured Image */}
|
||||
{data.image && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: 0.4, duration: 0.8 }}
|
||||
className="hero-stagger rounded-2xl overflow-hidden border border-gray-200 dark:border-white/10 shadow-2xl mb-8 max-w-md mx-auto"
|
||||
>
|
||||
<img
|
||||
src={data.image}
|
||||
alt={data.h1}
|
||||
className="w-full h-auto max-h-64 object-cover"
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
<div className="hero-stagger flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||
<motion.a
|
||||
href="/contact"
|
||||
className="px-8 py-3 bg-white dark:bg-white text-black dark:text-black rounded-full font-medium shadow-xl"
|
||||
whileHover={{ scale: 1.05, backgroundColor: "#3b82f6", color: "#ffffff" }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
Get IT Support
|
||||
</motion.a>
|
||||
<motion.a
|
||||
href="/it-support-corpus-christi"
|
||||
className="px-8 py-3 bg-white/10 dark:bg-white/10 backdrop-blur-sm border-2 border-white/40 dark:border-white/40 text-white dark:text-white rounded-full font-medium shadow-xl"
|
||||
whileHover={{ scale: 1.05, backgroundColor: "rgba(255,255,255,0.2)", borderColor: "#ffffff" }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
View All Services
|
||||
</motion.a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Main Content Section */}
|
||||
<section className="px-6 py-16 relative">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="bg-white/80 dark:bg-white/5 backdrop-blur-xl rounded-3xl p-12 md:p-16 shadow-2xl border border-gray-100 dark:border-white/10"
|
||||
>
|
||||
<div className="prose prose-lg md:prose-xl dark:prose-invert max-w-none prose-headings:font-display prose-h2:text-3xl prose-h2:mb-6 prose-h2:mt-12 prose-h3:text-2xl prose-h3:mt-8 prose-h3:mb-4 prose-p:leading-relaxed prose-li:leading-relaxed prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-a:no-underline hover:prose-a:underline prose-strong:text-gray-900 dark:prose-strong:text-white">
|
||||
<div dangerouslySetInnerHTML={{ __html: data.content }} />
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA Section */}
|
||||
<section className="px-6 py-16">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
className="max-w-4xl mx-auto"
|
||||
>
|
||||
<div className="p-12 bg-gradient-to-br from-blue-50 to-gray-50 dark:from-blue-950/30 dark:to-gray-950/30 rounded-3xl border border-blue-100 dark:border-blue-900/50 shadow-xl text-center">
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-5xl mb-6 block">
|
||||
{category === 'Local Services' ? 'location_on' : 'insights'}
|
||||
</span>
|
||||
<h2 className="font-display text-3xl font-bold mb-4 text-gray-900 dark:text-white">
|
||||
{category === 'Local Services'
|
||||
? 'Ready to Get IT Support in Your Area?'
|
||||
: 'Need Expert IT Support for Your Business?'}
|
||||
</h2>
|
||||
<p className="text-lg text-gray-700 dark:text-gray-300 mb-8 max-w-2xl mx-auto">
|
||||
{category === 'Local Services'
|
||||
? 'Contact us today to learn how we can help your business with reliable IT support and managed services.'
|
||||
: 'Let us handle your IT needs so you can focus on growing your business. Get a free consultation today.'}
|
||||
</p>
|
||||
<Link
|
||||
to="/contact"
|
||||
className="inline-flex items-center gap-3 px-10 py-5 bg-black dark:bg-white text-white dark:text-black rounded-full font-bold text-lg transition-all hover:scale-105 shadow-2xl hover:shadow-3xl"
|
||||
>
|
||||
Get Started
|
||||
<span className="material-symbols-outlined">arrow_forward</span>
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
|
||||
{/* Related Content Grid */}
|
||||
<section className="px-6 py-16">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<motion.h2
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
className="font-display text-4xl font-bold mb-12 text-center text-gray-900 dark:text-white"
|
||||
>
|
||||
Why Choose Bay Area IT?
|
||||
</motion.h2>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.1 }}
|
||||
className="p-8 bg-white dark:bg-white/5 rounded-2xl border border-gray-100 dark:border-white/10 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-5xl mb-4 block">
|
||||
verified_user
|
||||
</span>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
Proven Expertise
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
Years of experience serving businesses across the Coastal Bend with comprehensive IT solutions.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.2 }}
|
||||
className="p-8 bg-white dark:bg-white/5 rounded-2xl border border-gray-100 dark:border-white/10 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-5xl mb-4 block">
|
||||
support_agent
|
||||
</span>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
24/7 Support
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
Round-the-clock monitoring and support to keep your business running smoothly at all times.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="p-8 bg-white dark:bg-white/5 rounded-2xl border border-gray-100 dark:border-white/10 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-5xl mb-4 block">
|
||||
handshake
|
||||
</span>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
Local Partnership
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
A trusted local partner who understands your community and business needs.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Services Section */}
|
||||
<Services preview={true} />
|
||||
|
||||
{/* Areas We Serve & CTA */}
|
||||
<AreasWeServe />
|
||||
<CTA />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlogPostPage;
|
||||
import React, { useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Link } from 'react-router-dom';
|
||||
import SEO from '../../components/SEO';
|
||||
import Services from '../../components/Services';
|
||||
import CTA from '../../components/CTA';
|
||||
import AreasWeServe from '../../components/AreasWeServe';
|
||||
import { BlogPostData } from '../data/seoData';
|
||||
|
||||
interface BlogPostPageProps {
|
||||
data: BlogPostData;
|
||||
}
|
||||
|
||||
const BlogPostPage: React.FC<BlogPostPageProps> = ({ data }) => {
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
const category = data.slug.includes('corpus-christi-blog') ||
|
||||
data.slug.includes('portland-tx') ||
|
||||
data.slug.includes('rockport-tx') ||
|
||||
data.slug.includes('aransas-pass') ||
|
||||
data.slug.includes('kingsville-tx')
|
||||
? 'Local Services'
|
||||
: 'IT Insights';
|
||||
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
keywords={data.keywords}
|
||||
canonicalUrl={`https://bayareait.services/${data.slug}`}
|
||||
/>
|
||||
|
||||
<div className="min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden pt-32 pb-16">
|
||||
{/* Clean Hero Section */}
|
||||
<article className="max-w-4xl mx-auto px-6">
|
||||
<header className="mb-12 text-center">
|
||||
{/* Breadcrumbs */}
|
||||
<nav className="mb-8 text-sm">
|
||||
<ol className="flex items-center gap-2 text-gray-500 dark:text-gray-400 justify-center">
|
||||
<li>
|
||||
<Link to="/" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
Home
|
||||
</Link>
|
||||
</li>
|
||||
<span className="material-symbols-outlined text-xs">chevron_right</span>
|
||||
<li>
|
||||
<Link to="/blog" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||
Blog
|
||||
</Link>
|
||||
</li>
|
||||
<span className="material-symbols-outlined text-xs">chevron_right</span>
|
||||
<li className="text-gray-900 dark:text-white font-medium">{category}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div className="flex items-center justify-center gap-2 mb-6">
|
||||
<span className="h-px w-8 bg-blue-600/30 dark:bg-blue-400/30"></span>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-blue-600 dark:text-blue-400 font-bold">
|
||||
{category}
|
||||
</span>
|
||||
<span className="h-px w-8 bg-blue-600/30 dark:bg-blue-400/30"></span>
|
||||
</div>
|
||||
|
||||
<h1 className="font-display text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight leading-tight mb-6 text-gray-900 dark:text-white">
|
||||
{data.h1}
|
||||
</h1>
|
||||
|
||||
{/* Meta Info */}
|
||||
<div className="flex items-center gap-6 text-gray-500 dark:text-gray-400 mb-10 justify-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="material-symbols-outlined text-sm">schedule</span>
|
||||
<span>5 min read</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="material-symbols-outlined text-sm">location_on</span>
|
||||
<span>Coastal Bend business guide</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Featured Image */}
|
||||
{data.image && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="rounded-3xl overflow-hidden border border-gray-100 dark:border-white/5 shadow-xl md:mb-16 mb-8 max-w-4xl mx-auto"
|
||||
>
|
||||
<img
|
||||
src={data.image}
|
||||
alt={data.h1}
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
fetchPriority="high"
|
||||
className="w-full h-auto max-h-[500px] object-cover"
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
</header>
|
||||
|
||||
{/* Main Content Section */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.2, duration: 0.6 }}
|
||||
className="bg-white dark:bg-[#111] rounded-[2rem] p-8 md:p-12 lg:p-16 shadow-lg border border-gray-100 dark:border-white/5 mb-16"
|
||||
>
|
||||
<div className="prose prose-lg dark:prose-invert max-w-none prose-headings:font-display prose-headings:font-bold prose-h2:text-3xl prose-h2:mb-6 prose-h2:mt-12 prose-h3:text-2xl prose-h3:mt-8 prose-h3:mb-4 prose-p:leading-relaxed prose-li:leading-relaxed prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-a:no-underline hover:prose-a:underline prose-img:rounded-xl prose-img:shadow-md">
|
||||
<div dangerouslySetInnerHTML={{ __html: data.content }} />
|
||||
</div>
|
||||
</motion.div>
|
||||
</article>
|
||||
|
||||
{/* CTA Section */}
|
||||
<section className="px-6 py-16">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
className="max-w-4xl mx-auto"
|
||||
>
|
||||
<div className="p-10 md:p-14 bg-gradient-to-br from-blue-50 to-gray-50 dark:from-blue-950/20 dark:to-gray-900/20 rounded-[2.5rem] border border-blue-100/50 dark:border-blue-900/30 shadow-xl text-center">
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-5xl mb-6 block">
|
||||
{category === 'Local Services' ? 'location_on' : 'insights'}
|
||||
</span>
|
||||
<h2 className="font-display text-3xl font-bold mb-4 text-gray-900 dark:text-white">
|
||||
{category === 'Local Services'
|
||||
? 'Ready to Get IT Support in Your Area?'
|
||||
: 'Need Expert IT Support for Your Business?'}
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-400 mb-8 max-w-2xl mx-auto">
|
||||
{category === 'Local Services'
|
||||
? 'Contact us today to learn how we can help your business with reliable IT support and managed services.'
|
||||
: 'Let us handle your IT needs so you can focus on growing your business. Get a free consultation today.'}
|
||||
</p>
|
||||
<Link
|
||||
to="/contact"
|
||||
className="inline-flex items-center gap-3 px-10 py-4 bg-blue-600 hover:bg-blue-700 text-white rounded-full font-bold text-lg transition-all hover:scale-105 shadow-xl hover:shadow-blue-500/25"
|
||||
>
|
||||
Get Started
|
||||
<span className="material-symbols-outlined">arrow_forward</span>
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
|
||||
{/* Related Content Grid */}
|
||||
<section className="px-6 py-16">
|
||||
<div className="max-w-5xl mx-auto">
|
||||
<motion.h2
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
className="font-display text-4xl font-bold mb-12 text-center text-gray-900 dark:text-white"
|
||||
>
|
||||
Why Choose Bay Area IT?
|
||||
</motion.h2>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.1 }}
|
||||
className="p-8 bg-white dark:bg-[#111] rounded-3xl border border-gray-100 dark:border-white/5 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<div className="w-14 h-14 bg-blue-50 dark:bg-blue-900/20 rounded-2xl flex items-center justify-center mb-6">
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-3xl">
|
||||
verified_user
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
Proven Expertise
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-400 leading-relaxed">
|
||||
Years of experience serving businesses across the Coastal Bend with comprehensive IT solutions.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.2 }}
|
||||
className="p-8 bg-white dark:bg-[#111] rounded-3xl border border-gray-100 dark:border-white/5 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<div className="w-14 h-14 bg-blue-50 dark:bg-blue-900/20 rounded-2xl flex items-center justify-center mb-6">
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-3xl">
|
||||
support_agent
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
24/7 Support
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-400 leading-relaxed">
|
||||
Remote-first support and practical escalation to keep work moving when issues appear.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="p-8 bg-white dark:bg-[#111] rounded-3xl border border-gray-100 dark:border-white/5 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<div className="w-14 h-14 bg-blue-50 dark:bg-blue-900/20 rounded-2xl flex items-center justify-center mb-6">
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-3xl">
|
||||
handshake
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
Local Partnership
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-400 leading-relaxed">
|
||||
A trusted local partner who understands your community and business needs.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Services Section */}
|
||||
<Services preview={true} />
|
||||
|
||||
{/* Areas We Serve & CTA */}
|
||||
<AreasWeServe />
|
||||
<CTA />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlogPostPage;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import React, { useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import SEO from '../../components/SEO';
|
||||
|
||||
const ContactPage: React.FC = () => {
|
||||
useEffect(() => {
|
||||
@@ -13,7 +14,14 @@ const ContactPage: React.FC = () => {
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="pt-20 min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
||||
<>
|
||||
<SEO
|
||||
title="Contact Bay Area IT | Free IT Assessment in Corpus Christi"
|
||||
description="Talk to Bay Area IT about managed IT support, help desk coverage, business email, networking, and technology support across Corpus Christi and the Coastal Bend."
|
||||
keywords={['contact Bay Area IT', 'Corpus Christi IT consultation', 'managed IT assessment']}
|
||||
canonicalUrl="https://bayareait.services/contact"
|
||||
/>
|
||||
<div className="pt-20 min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
||||
<div className="absolute top-0 left-0 right-0 h-[800px] bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(0,0,0,0.2),rgba(0,0,0,0))] dark:bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(255,255,255,0.25),rgba(255,255,255,0))] pointer-events-none" />
|
||||
<div className="absolute bottom-0 right-0 w-[500px] h-[500px] bg-gray-100/50 dark:bg-white/5 rounded-full blur-[100px] pointer-events-none" />
|
||||
{/* Hero */}
|
||||
@@ -200,8 +208,9 @@ const ContactPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContactPage;
|
||||
|
||||
@@ -1,92 +1,106 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import Hero from '../../components/Hero';
|
||||
import Mission from '../../components/Mission';
|
||||
import Services from '../../components/Services';
|
||||
import Process from '../../components/Process';
|
||||
import Blog from '../../components/Blog';
|
||||
import Testimonials from '../../components/Testimonials';
|
||||
import CTA from '../../components/CTA';
|
||||
import SEO from '../../components/SEO';
|
||||
import FAQ from '../../components/FAQ';
|
||||
import AreasWeServe from '../../components/AreasWeServe';
|
||||
import { locationData } from '../data/seoData';
|
||||
|
||||
const HomePage: React.FC = () => {
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
// Enhanced LocalBusiness Schema per SEO plan
|
||||
const schema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ITService",
|
||||
"name": "Bay Area IT Services",
|
||||
"image": "https://bayarea-cc.com/logo.png",
|
||||
"@id": "https://bayarea-cc.com",
|
||||
"url": "https://bayarea-cc.com",
|
||||
"telephone": "+1-361-XXX-XXXX", // TODO: Replace with actual phone
|
||||
"priceRange": "$$",
|
||||
"address": {
|
||||
"@type": "PostalAddress",
|
||||
"streetAddress": "[YOUR STREET]", // TODO: Add actual address
|
||||
"addressLocality": "Corpus Christi",
|
||||
"addressRegion": "TX",
|
||||
"postalCode": "[YOUR ZIP]", // TODO: Add actual ZIP
|
||||
"addressCountry": "US"
|
||||
},
|
||||
"geo": {
|
||||
"@type": "GeoCoordinates",
|
||||
"latitude": 27.800583,
|
||||
"longitude": -97.39638
|
||||
},
|
||||
"areaServed": [
|
||||
{ "@type": "City", "name": "Corpus Christi" },
|
||||
{ "@type": "City", "name": "Portland" },
|
||||
{ "@type": "City", "name": "Rockport" },
|
||||
{ "@type": "City", "name": "Aransas Pass" },
|
||||
{ "@type": "City", "name": "Kingsville" }
|
||||
],
|
||||
"serviceType": [
|
||||
"IT Support",
|
||||
"Business IT Support",
|
||||
"Outsourced IT Services",
|
||||
"Computer Network Support",
|
||||
"Cyber Security"
|
||||
],
|
||||
"openingHoursSpecification": {
|
||||
"@type": "OpeningHoursSpecification",
|
||||
"dayOfWeek": [
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday"
|
||||
],
|
||||
"opens": "08:00",
|
||||
"closes": "18:00"
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title="IT Service & IT Support for Businesses in Corpus Christi, TX"
|
||||
description="Reliable IT support and IT services for businesses in Corpus Christi, TX. Fast response, outsourced IT support & help desk solutions. Call now."
|
||||
keywords={["IT Service", "IT Support", "Corpus Christi", "Business IT Support"]}
|
||||
canonicalUrl={window.location.href}
|
||||
schema={schema}
|
||||
/>
|
||||
<Hero />
|
||||
<Mission />
|
||||
<Services preview={true} />
|
||||
<Process />
|
||||
<Blog />
|
||||
<Testimonials />
|
||||
<AreasWeServe />
|
||||
<FAQ items={locationData[0].faq} />
|
||||
<CTA />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomePage;
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import LoadingScreen from '../../components/LoadingScreen';
|
||||
import Hero from '../../components/Hero';
|
||||
import Mission from '../../components/Mission';
|
||||
import Services from '../../components/Services';
|
||||
import Process from '../../components/Process';
|
||||
import Blog from '../../components/Blog';
|
||||
import Testimonials from '../../components/Testimonials';
|
||||
import CTA from '../../components/CTA';
|
||||
import SEO from '../../components/SEO';
|
||||
import FAQ from '../../components/FAQ';
|
||||
import AreasWeServe from '../../components/AreasWeServe';
|
||||
import { locationData } from '../data/seoData';
|
||||
|
||||
const HomePage: React.FC = () => {
|
||||
const [isLoading, setIsLoading] = useState(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
return !sessionStorage.getItem('home_loaded');
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
|
||||
if (isLoading) {
|
||||
sessionStorage.setItem('home_loaded', 'true');
|
||||
}
|
||||
}, [isLoading]);
|
||||
|
||||
// Enhanced LocalBusiness Schema per SEO plan
|
||||
const schema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "ITService",
|
||||
"name": "Bay Area IT",
|
||||
"image": "https://bayareait.services/logo.svg",
|
||||
"@id": "https://bayareait.services",
|
||||
"url": "https://bayareait.services",
|
||||
"telephone": "+1-361-765-8400",
|
||||
"priceRange": "$$",
|
||||
"address": {
|
||||
"@type": "PostalAddress",
|
||||
"streetAddress": "1001 Blucher St",
|
||||
"addressLocality": "Corpus Christi",
|
||||
"addressRegion": "TX",
|
||||
"postalCode": "78401",
|
||||
"addressCountry": "US"
|
||||
},
|
||||
"geo": {
|
||||
"@type": "GeoCoordinates",
|
||||
"latitude": 27.800583,
|
||||
"longitude": -97.39638
|
||||
},
|
||||
"areaServed": [
|
||||
{ "@type": "City", "name": "Corpus Christi" },
|
||||
{ "@type": "City", "name": "Portland" },
|
||||
{ "@type": "City", "name": "Rockport" },
|
||||
{ "@type": "City", "name": "Aransas Pass" },
|
||||
{ "@type": "City", "name": "Kingsville" }
|
||||
],
|
||||
"serviceType": [
|
||||
"IT Support",
|
||||
"IT Help Desk",
|
||||
"Computer Support",
|
||||
"Outsourced IT Services",
|
||||
"Computer Network Support",
|
||||
"Cyber Security"
|
||||
],
|
||||
"openingHoursSpecification": {
|
||||
"@type": "OpeningHoursSpecification",
|
||||
"dayOfWeek": [
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday"
|
||||
],
|
||||
"opens": "08:00",
|
||||
"closes": "18:00"
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{isLoading && <LoadingScreen onComplete={() => setIsLoading(false)} />}
|
||||
<SEO
|
||||
title="IT Service & IT Support for Businesses in Corpus Christi, TX"
|
||||
description="Reliable IT support and IT services for businesses in Corpus Christi, TX. Fast response, outsourced IT support & help desk solutions. Call now."
|
||||
keywords={["IT Service", "IT Support", "Corpus Christi", "IT Help Desk"]}
|
||||
canonicalUrl="https://bayareait.services/"
|
||||
schema={schema}
|
||||
/>
|
||||
<Hero />
|
||||
<Mission />
|
||||
<Services preview={true} />
|
||||
<Process />
|
||||
<Blog />
|
||||
<Testimonials />
|
||||
<AreasWeServe />
|
||||
<FAQ items={locationData[0].faq} />
|
||||
<CTA />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomePage;
|
||||
|
||||
121
src/pages/LegalPage.tsx
Normal file
121
src/pages/LegalPage.tsx
Normal file
@@ -0,0 +1,121 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import SEO from '../../components/SEO';
|
||||
|
||||
interface LegalSection {
|
||||
title: string;
|
||||
body: string[];
|
||||
}
|
||||
|
||||
interface LegalPageProps {
|
||||
title: string;
|
||||
description: string;
|
||||
canonicalUrl: string;
|
||||
eyebrow: string;
|
||||
intro: string;
|
||||
sections: LegalSection[];
|
||||
}
|
||||
|
||||
const LegalPage: React.FC<LegalPageProps> = ({
|
||||
title,
|
||||
description,
|
||||
canonicalUrl,
|
||||
eyebrow,
|
||||
intro,
|
||||
sections,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title={title}
|
||||
description={description}
|
||||
canonicalUrl={canonicalUrl}
|
||||
keywords={['Bay Area IT legal', 'privacy policy', 'terms of service']}
|
||||
/>
|
||||
|
||||
<div className="pt-20 min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
||||
<div className="absolute top-0 left-0 right-0 h-[720px] bg-[radial-gradient(ellipse_75%_50%_at_50%_-20%,rgba(255,255,255,0.08),rgba(255,255,255,0))] pointer-events-none" />
|
||||
<div className="absolute top-32 left-1/2 -translate-x-1/2 w-[760px] h-[420px] bg-white/5 rounded-full blur-[120px] pointer-events-none" />
|
||||
|
||||
<section className="px-6 py-20 border-b border-white/10 relative z-10">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<motion.p
|
||||
initial={{ opacity: 0, y: 16 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="text-xs uppercase tracking-[0.35em] text-gray-500 mb-6"
|
||||
>
|
||||
{eyebrow}
|
||||
</motion.p>
|
||||
<motion.h1
|
||||
initial={{ opacity: 0, y: 18 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.05 }}
|
||||
className="font-display text-4xl md:text-6xl font-bold text-gray-900 dark:text-white mb-6"
|
||||
>
|
||||
{title}
|
||||
</motion.h1>
|
||||
<motion.p
|
||||
initial={{ opacity: 0, y: 18 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.1 }}
|
||||
className="max-w-3xl text-lg md:text-xl leading-relaxed text-gray-600 dark:text-gray-300"
|
||||
>
|
||||
{intro}
|
||||
</motion.p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="px-6 py-16 md:py-20 relative z-10">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="grid gap-6">
|
||||
{sections.map((section, index) => (
|
||||
<motion.article
|
||||
key={section.title}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: '-10%' }}
|
||||
transition={{ delay: index * 0.04 }}
|
||||
className="rounded-[2rem] border border-white/10 bg-white/5 backdrop-blur-sm p-8 md:p-10 shadow-[0_30px_80px_rgba(0,0,0,0.18)]"
|
||||
>
|
||||
<h2 className="font-display text-2xl md:text-3xl font-bold text-gray-900 dark:text-white mb-5">
|
||||
{section.title}
|
||||
</h2>
|
||||
<div className="space-y-4 text-base md:text-lg leading-relaxed text-gray-600 dark:text-gray-300">
|
||||
{section.body.map((paragraph, paragraphIndex) => {
|
||||
const [before, after] = paragraph.split('info@bayareaaffiliates.com');
|
||||
|
||||
return (
|
||||
<p key={`${section.title}-${paragraphIndex}`}>
|
||||
{after !== undefined ? (
|
||||
<>
|
||||
{before}
|
||||
<a
|
||||
href="mailto:info@bayareaaffiliates.com"
|
||||
className="text-gray-900 dark:text-white underline decoration-white/30 underline-offset-4 transition-opacity hover:opacity-75"
|
||||
>
|
||||
info@bayareaaffiliates.com
|
||||
</a>
|
||||
{after}
|
||||
</>
|
||||
) : (
|
||||
paragraph
|
||||
)}
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</motion.article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LegalPage;
|
||||
@@ -1,14 +1,16 @@
|
||||
import React, { useEffect, useRef, useLayoutEffect } from 'react';
|
||||
import { motion, useMotionTemplate, useMotionValue } from 'framer-motion';
|
||||
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||
import { motion, useMotionTemplate, useMotionValue, useReducedMotion } from 'framer-motion';
|
||||
import { Link } from 'react-router-dom';
|
||||
import gsap from 'gsap';
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||
import SEO from '../../components/SEO';
|
||||
import Breadcrumb from '../../components/Breadcrumb';
|
||||
import Services from '../../components/Services';
|
||||
import CTA from '../../components/CTA';
|
||||
import FAQ from '../../components/FAQ';
|
||||
import AreasWeServe from '../../components/AreasWeServe';
|
||||
import { LocationData } from '../data/seoData';
|
||||
import FAQ from '../../components/FAQ';
|
||||
import AreasWeServe from '../../components/AreasWeServe';
|
||||
import { LocationData } from '../data/seoData';
|
||||
import heroBg from '../assets/hero-bg.webp';
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
@@ -21,14 +23,43 @@ const LocationPage: React.FC<LocationPageProps> = ({ data }) => {
|
||||
const parallaxWrapperRef = useRef<HTMLDivElement>(null);
|
||||
const mouseX = useMotionValue(0);
|
||||
const mouseY = useMotionValue(0);
|
||||
const prefersReducedMotion = useReducedMotion();
|
||||
const [isInteractive, setIsInteractive] = useState(false);
|
||||
const maskImage = useMotionTemplate`radial-gradient(100px circle at ${mouseX}px ${mouseY}px, black, transparent)`;
|
||||
const webkitMaskImage = useMotionTemplate`radial-gradient(100px circle at ${mouseX}px ${mouseY}px, black, transparent)`;
|
||||
|
||||
useEffect(() => {
|
||||
if (prefersReducedMotion || typeof window === 'undefined') {
|
||||
setIsInteractive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const mediaQuery = window.matchMedia('(pointer: fine) and (hover: hover)');
|
||||
const updateState = () => setIsInteractive(mediaQuery.matches);
|
||||
|
||||
updateState();
|
||||
|
||||
if (typeof mediaQuery.addEventListener === 'function') {
|
||||
mediaQuery.addEventListener('change', updateState);
|
||||
return () => mediaQuery.removeEventListener('change', updateState);
|
||||
}
|
||||
|
||||
mediaQuery.addListener(updateState);
|
||||
return () => mediaQuery.removeListener(updateState);
|
||||
}, [prefersReducedMotion]);
|
||||
|
||||
const handleMouseMove = ({ currentTarget, clientX, clientY }: React.MouseEvent) => {
|
||||
if (!isInteractive) return;
|
||||
const { left, top } = currentTarget.getBoundingClientRect();
|
||||
mouseX.set(clientX - left);
|
||||
mouseY.set(clientY - top + 75);
|
||||
};
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!isInteractive) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ctx = gsap.context(() => {
|
||||
// Parallax Background
|
||||
if (parallaxWrapperRef.current) {
|
||||
@@ -52,20 +83,20 @@ const LocationPage: React.FC<LocationPageProps> = ({ data }) => {
|
||||
}, containerRef);
|
||||
|
||||
return () => ctx.revert();
|
||||
}, []);
|
||||
}, [isInteractive]);
|
||||
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
const schema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "LocalBusiness",
|
||||
"name": "Bay Area IT Services",
|
||||
"url": window.location.href,
|
||||
"areaServed": {
|
||||
"@type": "City",
|
||||
"name": data.city
|
||||
const schema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "LocalBusiness",
|
||||
"name": "Bay Area IT",
|
||||
"url": `https://bayareait.services/${data.slug}`,
|
||||
"areaServed": {
|
||||
"@type": "City",
|
||||
"name": data.city
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,7 +106,7 @@ const LocationPage: React.FC<LocationPageProps> = ({ data }) => {
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
keywords={data.keywords}
|
||||
canonicalUrl={window.location.href}
|
||||
canonicalUrl={`https://bayareait.services/${data.slug}`}
|
||||
schema={schema}
|
||||
/>
|
||||
|
||||
@@ -83,7 +114,7 @@ const LocationPage: React.FC<LocationPageProps> = ({ data }) => {
|
||||
{/* Hero Section */}
|
||||
<section
|
||||
ref={containerRef}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseMove={isInteractive ? handleMouseMove : undefined}
|
||||
className="relative min-h-[90vh] flex items-center justify-center overflow-hidden pt-20 group"
|
||||
>
|
||||
{/* Parallax Background */}
|
||||
@@ -91,21 +122,25 @@ const LocationPage: React.FC<LocationPageProps> = ({ data }) => {
|
||||
<div ref={parallaxWrapperRef} className="absolute w-full h-[120%] -top-[10%] left-0">
|
||||
{/* Base Layer */}
|
||||
<img
|
||||
alt="Abstract dark technology background"
|
||||
className="w-full h-full object-cover opacity-90 dark:opacity-70 brightness-75 contrast-150"
|
||||
src="/src/assets/hero-bg.png"
|
||||
alt="Abstract dark technology background"
|
||||
className="w-full h-full object-cover opacity-90 dark:opacity-70 brightness-75 contrast-150"
|
||||
src={heroBg}
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
fetchPriority="high"
|
||||
/>
|
||||
|
||||
{/* Highlight Layer */}
|
||||
<motion.img
|
||||
style={{
|
||||
maskImage: useMotionTemplate`radial-gradient(100px circle at ${mouseX}px ${mouseY}px, black, transparent)`,
|
||||
WebkitMaskImage: useMotionTemplate`radial-gradient(100px circle at ${mouseX}px ${mouseY}px, black, transparent)`,
|
||||
}}
|
||||
alt=""
|
||||
className="absolute inset-0 w-full h-full object-cover mix-blend-screen opacity-100 brightness-150 contrast-150 filter saturate-150"
|
||||
src="/src/assets/hero-bg.png"
|
||||
/>
|
||||
{isInteractive && (
|
||||
<motion.img
|
||||
style={{ maskImage, WebkitMaskImage: webkitMaskImage }}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 w-full h-full object-cover mix-blend-screen opacity-100 brightness-150 contrast-150 filter saturate-150"
|
||||
src={heroBg}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-background-light via-transparent to-transparent dark:from-background-dark dark:via-transparent dark:to-transparent"></div>
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-background-light/50 dark:from-background-dark/50 to-transparent"></div>
|
||||
@@ -142,10 +177,10 @@ const LocationPage: React.FC<LocationPageProps> = ({ data }) => {
|
||||
Get IT Support
|
||||
</motion.a>
|
||||
<motion.a
|
||||
href="/it-support-corpus-christi"
|
||||
className="px-8 py-3 bg-white/10 dark:bg-white/10 backdrop-blur-sm border-2 border-white/40 dark:border-white/40 text-white dark:text-white rounded-full font-medium shadow-xl"
|
||||
whileHover={{ scale: 1.05, backgroundColor: "rgba(255,255,255,0.2)", borderColor: "#ffffff" }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
href="/services"
|
||||
className="px-8 py-3 bg-white/10 dark:bg-white/10 backdrop-blur-sm border-2 border-white/40 dark:border-white/40 text-white dark:text-white rounded-full font-medium shadow-xl"
|
||||
whileHover={{ scale: 1.05, backgroundColor: "rgba(255,255,255,0.2)", borderColor: "#ffffff" }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
View All Services
|
||||
</motion.a>
|
||||
@@ -156,6 +191,13 @@ const LocationPage: React.FC<LocationPageProps> = ({ data }) => {
|
||||
{/* Main Content Section */}
|
||||
<section className="px-6 py-16 relative">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="mb-6">
|
||||
<Breadcrumb items={[
|
||||
{ label: 'Home', to: '/' },
|
||||
{ label: 'Locations', to: '/locations' },
|
||||
{ label: data.city },
|
||||
]} />
|
||||
</div>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
@@ -190,7 +232,7 @@ const LocationPage: React.FC<LocationPageProps> = ({ data }) => {
|
||||
</h3>
|
||||
<p className="text-lg text-gray-700 dark:text-gray-300 leading-relaxed">
|
||||
We are based in Corpus Christi and proudly serve businesses throughout the entire surrounding area.
|
||||
Learn more about our <Link to="/it-support-corpus-christi" className="text-blue-600 dark:text-blue-400 font-bold hover:underline">IT support in Corpus Christi</Link> and our commitment to local businesses.
|
||||
Learn more about our <Link to="/locations/it-support-corpus-christi" className="text-blue-600 dark:text-blue-400 font-bold hover:underline">IT support in Corpus Christi</Link> and our commitment to local businesses.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -200,7 +242,7 @@ const LocationPage: React.FC<LocationPageProps> = ({ data }) => {
|
||||
)}
|
||||
|
||||
{/* Services Section */}
|
||||
<Services featuredIds={[10, 9, 11]} />
|
||||
<Services featuredIds={[6, 4, 3]} />
|
||||
|
||||
{/* Areas We Serve & CTA */}
|
||||
<AreasWeServe />
|
||||
|
||||
106
src/pages/LocationsPage.tsx
Normal file
106
src/pages/LocationsPage.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Link } from 'react-router-dom';
|
||||
import SEO from '../../components/SEO';
|
||||
import CTA from '../../components/CTA';
|
||||
import { locationData } from '../data/seoData';
|
||||
|
||||
const cityLocations = locationData.filter((loc) =>
|
||||
loc.slug.startsWith('locations/it-support-'),
|
||||
);
|
||||
|
||||
const LocationsPage: React.FC = () => {
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title="IT Support Service Areas - Corpus Christi & Coastal Bend, TX"
|
||||
description="Bay Area IT provides IT support and IT services throughout the Coastal Bend. View all cities we serve in the Corpus Christi area."
|
||||
keywords={['IT support Corpus Christi', 'IT services Coastal Bend', 'local IT support Texas']}
|
||||
canonicalUrl="https://bayareait.services/locations"
|
||||
/>
|
||||
|
||||
<div className="min-h-screen bg-background-light dark:bg-background-dark pt-20">
|
||||
<section className="py-20 px-6 border-b border-gray-200 dark:border-white/10">
|
||||
<div className="max-w-4xl mx-auto text-center">
|
||||
<span className="text-xs font-semibold uppercase tracking-widest text-gray-500 dark:text-gray-500 mb-3 block">
|
||||
Service Areas
|
||||
</span>
|
||||
<h1 className="font-display text-4xl md:text-5xl font-bold mb-6 text-gray-900 dark:text-white tracking-tight">
|
||||
IT Support Across the{' '}
|
||||
<span className="text-gray-400 dark:text-gray-500">Coastal Bend</span>
|
||||
</h1>
|
||||
<p className="text-xl text-gray-600 dark:text-gray-300 max-w-2xl mx-auto leading-relaxed">
|
||||
We provide professional IT support and managed IT services for businesses
|
||||
throughout Corpus Christi and the surrounding area. Remote-first, on-site
|
||||
when needed.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-20 px-6">
|
||||
<div className="max-w-5xl mx-auto">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{cityLocations.map((loc, i) => (
|
||||
<motion.div
|
||||
key={loc.slug}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.4, delay: i * 0.07 }}
|
||||
>
|
||||
<Link
|
||||
to={`/${loc.slug}`}
|
||||
className="group block p-8 bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-2xl hover:border-gray-400 dark:hover:border-white/30 hover:shadow-xl transition-all duration-300"
|
||||
>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<span className="material-symbols-outlined text-3xl text-gray-400 dark:text-gray-500 group-hover:text-gray-700 dark:group-hover:text-gray-300 transition-colors">
|
||||
location_on
|
||||
</span>
|
||||
<span className="material-symbols-outlined text-sm text-gray-400 dark:text-gray-600 group-hover:text-gray-700 dark:group-hover:text-white group-hover:translate-x-1 transition-all duration-200">
|
||||
arrow_forward
|
||||
</span>
|
||||
</div>
|
||||
<h2 className="font-display text-xl font-bold text-gray-900 dark:text-white mb-2">
|
||||
{loc.city}
|
||||
</h2>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 leading-relaxed">
|
||||
{loc.description}
|
||||
</p>
|
||||
</Link>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-16 px-6 bg-gray-50 dark:bg-white/5 border-t border-gray-200 dark:border-white/10">
|
||||
<div className="max-w-4xl mx-auto text-center">
|
||||
<h2 className="font-display text-2xl md:text-3xl font-bold mb-4 text-gray-900 dark:text-white">
|
||||
Based in Corpus Christi. Serving the Region.
|
||||
</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto mb-8 leading-relaxed">
|
||||
Our team is locally based with over 25 years supporting Coastal Bend businesses.
|
||||
Most issues are resolved remotely for speed. On-site support is available across
|
||||
all cities we serve.
|
||||
</p>
|
||||
<p className="text-gray-500 dark:text-gray-400">
|
||||
Not seeing your city?{' '}
|
||||
<Link to="/contact" className="text-gray-900 dark:text-white font-medium underline hover:no-underline transition-all">
|
||||
Contact us
|
||||
</Link>{' '}
|
||||
and we may still be able to help.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<CTA />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LocationsPage;
|
||||
55
src/pages/PrivacyPolicyPage.tsx
Normal file
55
src/pages/PrivacyPolicyPage.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import LegalPage from './LegalPage';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Information We Collect',
|
||||
body: [
|
||||
'We may collect personal information such as your name, email address, phone number, and other relevant details when you contact us for our IT support services.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'How We Use Your Information',
|
||||
body: [
|
||||
'Your information is used to provide and improve our services, respond to your inquiries, and communicate important updates.',
|
||||
'We do not sell or rent your personal information to third parties.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Data Security',
|
||||
body: [
|
||||
'We implement a variety of security measures to maintain the safety of your personal information. However, no method of transmission over the internet or electronic storage is 100% secure.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Your Consent',
|
||||
body: [
|
||||
'By using our website and services, you consent to this Privacy Policy.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Changes to This Privacy Policy',
|
||||
body: [
|
||||
'We reserve the right to update this Privacy Policy at any time. Any changes will be effective immediately upon posting on this page.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Contact Us',
|
||||
body: [
|
||||
'If you have any questions regarding this Privacy Policy, please contact us at info@bayareaaffiliates.com.',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const PrivacyPolicyPage: React.FC = () => (
|
||||
<LegalPage
|
||||
title="Privacy Policy"
|
||||
description="Read the Bay Area Affiliates, Inc. Privacy Policy to understand how we collect, use, and protect your information."
|
||||
canonicalUrl="https://bayareait.services/privacy-policy"
|
||||
eyebrow="Bay Area Affiliates, Inc."
|
||||
intro="At Bay Area Affiliates, Inc., we are committed to protecting your privacy. This page explains how we collect, use, disclose, and safeguard information when you visit our website and use our services."
|
||||
sections={sections}
|
||||
/>
|
||||
);
|
||||
|
||||
export default PrivacyPolicyPage;
|
||||
@@ -1,232 +1,274 @@
|
||||
import React, { useEffect, useRef, useLayoutEffect } from 'react';
|
||||
import { motion, useMotionTemplate, useMotionValue } from 'framer-motion';
|
||||
import { Link } from 'react-router-dom';
|
||||
import gsap from 'gsap';
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||
import SEO from '../../components/SEO';
|
||||
import Services from '../../components/Services';
|
||||
import CTA from '../../components/CTA';
|
||||
import FAQ from '../../components/FAQ';
|
||||
import AreasWeServe from '../../components/AreasWeServe';
|
||||
import { ServiceData } from '../data/seoData';
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
interface ServicePageProps {
|
||||
data: ServiceData;
|
||||
}
|
||||
|
||||
const ServicePage: React.FC<ServicePageProps> = ({ data }) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const parallaxWrapperRef = useRef<HTMLDivElement>(null);
|
||||
const mouseX = useMotionValue(0);
|
||||
const mouseY = useMotionValue(0);
|
||||
|
||||
const handleMouseMove = ({ currentTarget, clientX, clientY }: React.MouseEvent) => {
|
||||
const { left, top } = currentTarget.getBoundingClientRect();
|
||||
mouseX.set(clientX - left);
|
||||
mouseY.set(clientY - top + 75);
|
||||
};
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const ctx = gsap.context(() => {
|
||||
// Parallax Background
|
||||
if (parallaxWrapperRef.current) {
|
||||
gsap.to(parallaxWrapperRef.current, {
|
||||
yPercent: 30,
|
||||
ease: "none",
|
||||
scrollTrigger: {
|
||||
trigger: containerRef.current,
|
||||
start: "top top",
|
||||
end: "bottom top",
|
||||
scrub: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Text Stagger Animation
|
||||
gsap.fromTo(".hero-stagger",
|
||||
{ y: 50, opacity: 0 },
|
||||
{ y: 0, opacity: 1, duration: 1, stagger: 0.2, ease: "power3.out", delay: 0.2 }
|
||||
);
|
||||
}, containerRef);
|
||||
|
||||
return () => ctx.revert();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
keywords={data.keywords}
|
||||
canonicalUrl={window.location.href}
|
||||
/>
|
||||
|
||||
<div className="min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
||||
{/* Hero Section */}
|
||||
<section
|
||||
ref={containerRef}
|
||||
onMouseMove={handleMouseMove}
|
||||
className="relative min-h-[90vh] flex items-center justify-center overflow-hidden pt-20 group"
|
||||
>
|
||||
{/* Parallax Background */}
|
||||
<div className="absolute inset-0 z-0 pointer-events-none">
|
||||
<div ref={parallaxWrapperRef} className="absolute w-full h-[120%] -top-[10%] left-0">
|
||||
{/* Base Layer */}
|
||||
<img
|
||||
alt="Abstract dark technology background"
|
||||
className="w-full h-full object-cover opacity-90 dark:opacity-70 brightness-75 contrast-150"
|
||||
src="/src/assets/hero-bg.png"
|
||||
/>
|
||||
|
||||
{/* Highlight Layer */}
|
||||
<motion.img
|
||||
style={{
|
||||
maskImage: useMotionTemplate`radial-gradient(100px circle at ${mouseX}px ${mouseY}px, black, transparent)`,
|
||||
WebkitMaskImage: useMotionTemplate`radial-gradient(100px circle at ${mouseX}px ${mouseY}px, black, transparent)`,
|
||||
}}
|
||||
alt=""
|
||||
className="absolute inset-0 w-full h-full object-cover mix-blend-screen opacity-100 brightness-150 contrast-150 filter saturate-150"
|
||||
src="/src/assets/hero-bg.png"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-background-light via-transparent to-transparent dark:from-background-dark dark:via-transparent dark:to-transparent"></div>
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-background-light/50 dark:from-background-dark/50 to-transparent"></div>
|
||||
</div>
|
||||
|
||||
{/* Hero Content */}
|
||||
<div className="relative z-10 text-center max-w-4xl px-6">
|
||||
<div className="hero-stagger flex items-center justify-center gap-2 mb-4">
|
||||
<span className="h-px w-8 bg-gray-400 dark:bg-gray-500"></span>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-gray-600 dark:text-gray-400 font-medium">
|
||||
Professional IT Services
|
||||
</span>
|
||||
<span className="h-px w-8 bg-gray-400 dark:bg-gray-500"></span>
|
||||
</div>
|
||||
|
||||
<h1 className="hero-stagger font-display text-4xl md:text-5xl lg:text-6xl font-medium tracking-tighter leading-[1.1] mb-5 text-gray-900 dark:text-white">
|
||||
{data.h1.split(' ').slice(0, -2).join(' ')}<br />
|
||||
<span className="text-gray-500 dark:text-gray-500">
|
||||
{data.h1.split(' ').slice(-2).join(' ')}
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p className="hero-stagger text-base md:text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto mb-6 font-light leading-relaxed">
|
||||
{data.description}
|
||||
</p>
|
||||
|
||||
<div className="hero-stagger flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||
<motion.a
|
||||
href="/contact"
|
||||
className="px-8 py-3 bg-white dark:bg-white text-black dark:text-black rounded-full font-medium shadow-xl"
|
||||
whileHover={{ scale: 1.05, backgroundColor: "#3b82f6", color: "#ffffff" }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
Get Started
|
||||
</motion.a>
|
||||
<motion.a
|
||||
href="/it-support-corpus-christi"
|
||||
className="px-8 py-3 bg-white/10 dark:bg-white/10 backdrop-blur-sm border-2 border-white/40 dark:border-white/40 text-white dark:text-white rounded-full font-medium shadow-xl"
|
||||
whileHover={{ scale: 1.05, backgroundColor: "rgba(255,255,255,0.2)", borderColor: "#ffffff" }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
View All Services
|
||||
</motion.a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Main Content Section */}
|
||||
<section className="px-6 py-16 relative">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="bg-white/80 dark:bg-white/5 backdrop-blur-xl rounded-3xl p-12 md:p-16 shadow-2xl border border-gray-100 dark:border-white/10"
|
||||
>
|
||||
<div className="prose prose-lg md:prose-xl dark:prose-invert max-w-none prose-headings:font-display prose-h2:text-3xl prose-h2:mb-6 prose-h2:mt-12 prose-h3:text-2xl prose-p:leading-relaxed prose-li:leading-relaxed prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-a:no-underline hover:prose-a:underline">
|
||||
<div dangerouslySetInnerHTML={{ __html: data.content }} />
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Feature Highlight Section */}
|
||||
<section className="px-6 py-16">
|
||||
<div className="max-w-6xl mx-auto grid md:grid-cols-3 gap-8">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.1 }}
|
||||
className="p-8 bg-white dark:bg-white/5 rounded-2xl border border-gray-100 dark:border-white/10 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-5xl mb-4 block">
|
||||
speed
|
||||
</span>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
Fast Response
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
Quick resolution of IT issues to minimize downtime and keep your business running smoothly.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.2 }}
|
||||
className="p-8 bg-white dark:bg-white/5 rounded-2xl border border-gray-100 dark:border-white/10 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-5xl mb-4 block">
|
||||
verified_user
|
||||
</span>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
Proactive Security
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
Advanced security measures and monitoring to protect your business from cyber threats.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="p-8 bg-white dark:bg-white/5 rounded-2xl border border-gray-100 dark:border-white/10 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-5xl mb-4 block">
|
||||
support_agent
|
||||
</span>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
Expert Team
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
Experienced IT professionals dedicated to providing exceptional service and support.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Services Section */}
|
||||
<Services featuredIds={data.relatedServices} />
|
||||
|
||||
{/* Areas We Serve & CTA */}
|
||||
<AreasWeServe />
|
||||
<FAQ items={data.faq} />
|
||||
<CTA />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServicePage;
|
||||
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||
import { motion, useMotionTemplate, useMotionValue, useReducedMotion } from 'framer-motion';
|
||||
import { Link } from 'react-router-dom';
|
||||
import gsap from 'gsap';
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||
import SEO from '../../components/SEO';
|
||||
import Breadcrumb from '../../components/Breadcrumb';
|
||||
import Services from '../../components/Services';
|
||||
import CTA from '../../components/CTA';
|
||||
import FAQ from '../../components/FAQ';
|
||||
import AreasWeServe from '../../components/AreasWeServe';
|
||||
import { ServiceData } from '../data/seoData';
|
||||
import heroBg from '../assets/hero-bg.webp';
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
interface ServicePageProps {
|
||||
data: ServiceData;
|
||||
}
|
||||
|
||||
const ServicePage: React.FC<ServicePageProps> = ({ data }) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const parallaxWrapperRef = useRef<HTMLDivElement>(null);
|
||||
const mouseX = useMotionValue(0);
|
||||
const mouseY = useMotionValue(0);
|
||||
const prefersReducedMotion = useReducedMotion();
|
||||
const [isInteractive, setIsInteractive] = useState(false);
|
||||
const maskImage = useMotionTemplate`radial-gradient(100px circle at ${mouseX}px ${mouseY}px, black, transparent)`;
|
||||
const webkitMaskImage = useMotionTemplate`radial-gradient(100px circle at ${mouseX}px ${mouseY}px, black, transparent)`;
|
||||
|
||||
useEffect(() => {
|
||||
if (prefersReducedMotion || typeof window === 'undefined') {
|
||||
setIsInteractive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const mediaQuery = window.matchMedia('(pointer: fine) and (hover: hover)');
|
||||
const updateState = () => setIsInteractive(mediaQuery.matches);
|
||||
|
||||
updateState();
|
||||
|
||||
if (typeof mediaQuery.addEventListener === 'function') {
|
||||
mediaQuery.addEventListener('change', updateState);
|
||||
return () => mediaQuery.removeEventListener('change', updateState);
|
||||
}
|
||||
|
||||
mediaQuery.addListener(updateState);
|
||||
return () => mediaQuery.removeListener(updateState);
|
||||
}, [prefersReducedMotion]);
|
||||
|
||||
const handleMouseMove = ({ currentTarget, clientX, clientY }: React.MouseEvent) => {
|
||||
if (!isInteractive) return;
|
||||
const { left, top } = currentTarget.getBoundingClientRect();
|
||||
mouseX.set(clientX - left);
|
||||
mouseY.set(clientY - top + 75);
|
||||
};
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!isInteractive) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ctx = gsap.context(() => {
|
||||
// Parallax Background
|
||||
if (parallaxWrapperRef.current) {
|
||||
gsap.to(parallaxWrapperRef.current, {
|
||||
yPercent: 30,
|
||||
ease: "none",
|
||||
scrollTrigger: {
|
||||
trigger: containerRef.current,
|
||||
start: "top top",
|
||||
end: "bottom top",
|
||||
scrub: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Text Stagger Animation
|
||||
gsap.fromTo(".hero-stagger",
|
||||
{ y: 50, opacity: 0 },
|
||||
{ y: 0, opacity: 1, duration: 1, stagger: 0.2, ease: "power3.out", delay: 0.2 }
|
||||
);
|
||||
}, containerRef);
|
||||
|
||||
return () => ctx.revert();
|
||||
}, [isInteractive]);
|
||||
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title={data.title}
|
||||
description={data.description}
|
||||
keywords={data.keywords}
|
||||
canonicalUrl={`https://bayareait.services/${data.slug}`}
|
||||
/>
|
||||
|
||||
<div className="min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
||||
{/* Hero Section */}
|
||||
<section
|
||||
ref={containerRef}
|
||||
onMouseMove={isInteractive ? handleMouseMove : undefined}
|
||||
className="relative min-h-[90vh] flex items-center justify-center overflow-hidden pt-20 group"
|
||||
>
|
||||
{/* Parallax Background */}
|
||||
<div className="absolute inset-0 z-0 pointer-events-none">
|
||||
<div ref={parallaxWrapperRef} className="absolute w-full h-[120%] -top-[10%] left-0">
|
||||
{/* Base Layer */}
|
||||
<img
|
||||
alt="Abstract dark technology background"
|
||||
className="w-full h-full object-cover opacity-90 dark:opacity-70 brightness-75 contrast-150"
|
||||
src={heroBg}
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
fetchPriority="high"
|
||||
/>
|
||||
|
||||
{isInteractive && (
|
||||
<motion.img
|
||||
style={{ maskImage, WebkitMaskImage: webkitMaskImage }}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 w-full h-full object-cover mix-blend-screen opacity-100 brightness-150 contrast-150 filter saturate-150"
|
||||
src={heroBg}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-background-light via-transparent to-transparent dark:from-background-dark dark:via-transparent dark:to-transparent"></div>
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-background-light/50 dark:from-background-dark/50 to-transparent"></div>
|
||||
</div>
|
||||
|
||||
{/* Hero Content */}
|
||||
<div className="relative z-10 text-center max-w-4xl px-6">
|
||||
<div className="hero-stagger flex items-center justify-center gap-2 mb-4">
|
||||
<span className="h-px w-8 bg-gray-400 dark:bg-gray-500"></span>
|
||||
<span className="text-xs uppercase tracking-[0.2em] text-gray-600 dark:text-gray-400 font-medium">
|
||||
Professional IT Services
|
||||
</span>
|
||||
<span className="h-px w-8 bg-gray-400 dark:bg-gray-500"></span>
|
||||
</div>
|
||||
|
||||
<h1 className="hero-stagger font-display text-4xl md:text-5xl lg:text-6xl font-medium tracking-tighter leading-[1.1] mb-5 text-gray-900 dark:text-white">
|
||||
{data.h1.split(' ').slice(0, -2).join(' ')}<br />
|
||||
<span className="text-gray-500 dark:text-gray-500">
|
||||
{data.h1.split(' ').slice(-2).join(' ')}
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p className="hero-stagger text-base md:text-lg text-gray-600 dark:text-gray-300 max-w-2xl mx-auto mb-6 font-light leading-relaxed">
|
||||
{data.description}
|
||||
</p>
|
||||
|
||||
<div className="hero-stagger flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||
<motion.a
|
||||
href="/contact"
|
||||
className="px-8 py-3 bg-white dark:bg-white text-black dark:text-black rounded-full font-medium shadow-xl"
|
||||
whileHover={{ scale: 1.05, backgroundColor: "#3b82f6", color: "#ffffff" }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
Get Started
|
||||
</motion.a>
|
||||
<motion.a
|
||||
href="/services"
|
||||
className="px-8 py-3 bg-white/10 dark:bg-white/10 backdrop-blur-sm border-2 border-white/40 dark:border-white/40 text-white dark:text-white rounded-full font-medium shadow-xl"
|
||||
whileHover={{ scale: 1.05, backgroundColor: "rgba(255,255,255,0.2)", borderColor: "#ffffff" }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
View All Services
|
||||
</motion.a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Main Content Section */}
|
||||
<section className="px-6 py-16 relative">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="mb-6">
|
||||
<Breadcrumb items={[
|
||||
{ label: 'Home', to: '/' },
|
||||
{ label: 'Services', to: '/services' },
|
||||
{ label: data.h1 },
|
||||
]} />
|
||||
</div>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="bg-white/80 dark:bg-white/5 backdrop-blur-xl rounded-3xl p-12 md:p-16 shadow-2xl border border-gray-100 dark:border-white/10"
|
||||
>
|
||||
<div className="prose prose-lg md:prose-xl dark:prose-invert max-w-none prose-headings:font-display prose-h2:text-3xl prose-h2:mb-6 prose-h2:mt-12 prose-h3:text-2xl prose-p:leading-relaxed prose-li:leading-relaxed prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-a:no-underline hover:prose-a:underline">
|
||||
<div dangerouslySetInnerHTML={{ __html: data.content }} />
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Feature Highlight Section */}
|
||||
<section className="px-6 py-16">
|
||||
<div className="max-w-6xl mx-auto grid md:grid-cols-3 gap-8">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.1 }}
|
||||
className="p-8 bg-white dark:bg-white/5 rounded-2xl border border-gray-100 dark:border-white/10 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-5xl mb-4 block">
|
||||
speed
|
||||
</span>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
Fast Response
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
Quick resolution of IT issues to minimize downtime and keep your business running smoothly.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.2 }}
|
||||
className="p-8 bg-white dark:bg-white/5 rounded-2xl border border-gray-100 dark:border-white/10 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-5xl mb-4 block">
|
||||
verified_user
|
||||
</span>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
Proactive Security
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
Advanced security measures and monitoring to protect your business from cyber threats.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="p-8 bg-white dark:bg-white/5 rounded-2xl border border-gray-100 dark:border-white/10 hover:shadow-xl transition-shadow"
|
||||
>
|
||||
<span className="material-symbols-outlined text-blue-600 dark:text-blue-400 text-5xl mb-4 block">
|
||||
support_agent
|
||||
</span>
|
||||
<h3 className="font-display text-xl font-bold mb-3 text-gray-900 dark:text-white">
|
||||
Expert Team
|
||||
</h3>
|
||||
<p className="text-gray-600 dark:text-gray-300">
|
||||
Experienced IT professionals dedicated to providing exceptional service and support.
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Services Section */}
|
||||
<Services featuredIds={data.relatedServices} />
|
||||
|
||||
{/* Areas We Serve & CTA */}
|
||||
<AreasWeServe />
|
||||
<FAQ items={data.faq} />
|
||||
<CTA />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServicePage;
|
||||
|
||||
@@ -1,136 +1,117 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { motion, AnimatePresence, useScroll, useTransform, useMotionValueEvent } from 'framer-motion';
|
||||
import Contact from '../../components/Contact';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { motion, AnimatePresence, useScroll, useTransform, useMotionValueEvent } from 'framer-motion';
|
||||
import Contact from '../../components/Contact';
|
||||
import SEO from '../../components/SEO';
|
||||
|
||||
const services = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Windows 11 Transition',
|
||||
description: 'Upgrade to Windows 11 before October 2025 to ensure continued security support and take advantage of the latest features.',
|
||||
challenge: 'Running outdated operating systems leaves your business vulnerable to security threats and compatibility issues.',
|
||||
approach: 'We manage the entire migration process, from hardware compatibility checks to software deployment and user training.',
|
||||
deliverables: [
|
||||
'Hardware compatibility assessment',
|
||||
'Windows 11 deployment and configuration',
|
||||
'Application compatibility testing',
|
||||
'Security policy implementation',
|
||||
'User training sessions'
|
||||
],
|
||||
needs: [
|
||||
'Current device inventory',
|
||||
'Software list',
|
||||
'User schedule for upgrades'
|
||||
],
|
||||
icon: 'desktop_windows',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBMpd_cFINnFibfNErBs8OVAAyDQYTRXix88YH91QImuGi11XGwlY_QUB2R9htcC1h_fTXUeftdEieGT-oi5p5TBjpAyW-86mSsXu-rqhRTBsJlAGuE37bxJES4DUayktXIToEcF-M4PyXdyyTPIYtpYrxK18b2-sPwMzuzCL0LpgJwd5EoYxAkrJQ7W4eBrIG2e9Cw9sY0dJpXJy-TRgwBG0nk-S7W4Y0s3U9w--AzE4fcUimeGMqWwdCncU5tnETmkrkDNFiCyKSA'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Web Services',
|
||||
description: 'Web design, domain registration, email services, and more to establish and enhance your online presence.',
|
||||
challenge: 'A poor online presence can cost you customers and credibility in a digital-first world.',
|
||||
approach: 'We build professional, responsive websites and manage your digital identity to attract and retain customers.',
|
||||
deliverables: [
|
||||
'Custom website design & development',
|
||||
'Domain registration & management',
|
||||
'Professional email setup (M365/Google)',
|
||||
'SEO optimization basics',
|
||||
'Hosting & maintenance'
|
||||
],
|
||||
needs: [
|
||||
'Brand guidelines / Logo',
|
||||
'Content & copy',
|
||||
'Domain access (if existing)'
|
||||
],
|
||||
icon: 'language',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuCxibXNCB5mU7MdWE5znMWnQUc9-d2ZoYF7LXK1CMssnvaFz2ZsGzyxXMbqDmely-UfxapqILD5-Exeo1wlQZKg8T2MK4vjlyAMaehoJoqTy2hHh8rxj46i8CKb4-ILL2JswBc98nJt_Fo1DfcDH0dHH5Zz6H4R2Jm1deViSW8Sp2zNp1sTc4eRHy1URiSRQFcr1C8rca6dKiuNDuyDiUmmesqHobXGItaBeFjJC-0OatWpKbr0zF-Y5qvk9Yl5FY2KUcDY9AcTfelu'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Performance Upgrades',
|
||||
description: 'Enhance your desktops and laptops with SSDs, maintain your Windows installations, and achieve dramatic performance boosts.',
|
||||
challenge: 'Slow computers kill productivity and frustrate employees, leading to wasted time.',
|
||||
approach: 'We breathe new life into existing hardware with cost-effective upgrades and optimizations.',
|
||||
deliverables: [
|
||||
'SSD installation & cloning',
|
||||
'RAM upgrades',
|
||||
'System cleanup & optimization',
|
||||
'Thermal paste replacement',
|
||||
'Benchmark reporting'
|
||||
],
|
||||
needs: [
|
||||
'Access to devices',
|
||||
'Data backup confirmation'
|
||||
],
|
||||
icon: 'speed',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBs2fGGwp4EkMarA9Uvy7IOqyW0Pzxzt-94Bsr8Tkbem4uHPq-vMEmGgKuEmds2zKwPrw2nVcvL3MjjKYWieLSLh5pVUbbK6T9aDxt2xhvo4trARZobhzoQCJfI-r6aGW_aqfwC5XxOr9VA3YdnNnYEgkfW_TWrUWYa6mD8X0KdVG3sLimA8p7qWxIqUzFFV82twn60rP4OwLdIsc6t1OGnJzjemxL1Aw05aDo6Ckfr0a1oZ2kD4xKeTkG--zUhezvXB9I03l6f3b46'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: 'Printer & Scanner Installation',
|
||||
description: 'Professional installation and configuration of printers and scanners to ensure seamless integration into your workflow.',
|
||||
challenge: 'Printer connectivity issues are a leading cause of office support tickets and downtime.',
|
||||
approach: 'We set up reliable printing environments with proper drivers, networking, and user access controls.',
|
||||
deliverables: [
|
||||
'Network printer setup',
|
||||
'Scanner configuration (Scan-to-Email/Folder)',
|
||||
'Print server management',
|
||||
'One-click user deployment',
|
||||
'Troubleshooting training'
|
||||
],
|
||||
needs: [
|
||||
'Printer/Scanner hardware',
|
||||
'Network access details'
|
||||
],
|
||||
icon: 'print',
|
||||
image: ''
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: 'New/Refurbished Desktop Hardware',
|
||||
description: 'Supply and installation of new or refurbished desktop hardware, tailored to meet your business requirements.',
|
||||
challenge: 'Sourcing the right hardware at the right price can be time-consuming and risky.',
|
||||
approach: 'We source high-quality new and refurbished equipment that meets your specs and budget, fully tested and ready to go.',
|
||||
deliverables: [
|
||||
'Hardware procurement',
|
||||
'Quality assurance testing',
|
||||
'Image deployment',
|
||||
'Peripherals setup',
|
||||
'Warranty management'
|
||||
],
|
||||
needs: [
|
||||
'Budget constraints',
|
||||
'Performance requirements'
|
||||
],
|
||||
icon: 'computer',
|
||||
image: ''
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: 'VPN Setup',
|
||||
description: 'Configure Virtual Private Networks to allow secure remote access to your internal network from anywhere.',
|
||||
challenge: 'Remote work requires secure access to internal resources without exposing your network to threats.',
|
||||
approach: 'We implement robust VPN solutions like WireGuard or OpenVPN for secure, encrypted remote connectivity.',
|
||||
deliverables: [
|
||||
'VPN server configuration',
|
||||
'Client software deployment',
|
||||
'Access control lists',
|
||||
'Connection testing',
|
||||
'User guides'
|
||||
],
|
||||
needs: [
|
||||
'Public IP / DNS details',
|
||||
'User list'
|
||||
],
|
||||
icon: 'vpn_lock',
|
||||
image: ''
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
title: 'Network Infrastructure Support',
|
||||
description: 'Robust network solutions to ensure connectivity, security, and efficiency, including routers, access points, and switches.',
|
||||
challenge: 'A weak network backbone leads to slow speeds, dropped calls, and security holes.',
|
||||
approach: 'We design and maintain enterprise-grade networks that handle your data traffic reliably and securely.',
|
||||
const services = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Bay Area Email Services',
|
||||
description: 'Our flagship service: enterprise cloud email with 99.99% uptime, premium deliverability, local Corpus Christi support, and 25 GB mailboxes for $5 per inbox.',
|
||||
challenge: 'Missed emails, spam-folder delivery, and server downtime quietly cost businesses leads, approvals, and customer trust.',
|
||||
approach: 'We use a serverless AWS-powered email architecture with S3 buffering for inbound mail and Amazon SES for outbound reputation, then manage DNS and migration for you locally.',
|
||||
deliverables: [
|
||||
'25 GB business mailbox for $5 per inbox',
|
||||
'99.99% uptime backed by cloud architecture',
|
||||
'S3 email buffering so incoming mail is never lost',
|
||||
'Amazon SES sending for strong inbox placement',
|
||||
'DNS setup, migration, forwarding, and auto-replies'
|
||||
],
|
||||
needs: [
|
||||
'Your domain access',
|
||||
'Mailbox count and user list',
|
||||
'Current email provider details'
|
||||
],
|
||||
icon: 'mail',
|
||||
image: '/assets/services/business-it.webp'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Shared Drive',
|
||||
description: 'Setup and management of shared drive solutions so your team can store, access, and organize files reliably.',
|
||||
challenge: 'Data growth requires scalable storage that is accessible yet secure from loss.',
|
||||
approach: 'We deploy shared drive solutions that centralize your files and make them easy for your team to access securely.',
|
||||
deliverables: [
|
||||
'Shared drive setup and configuration',
|
||||
'Folder structure and permissions',
|
||||
'User permission management',
|
||||
'Remote access configuration',
|
||||
'Backup integration'
|
||||
],
|
||||
needs: [
|
||||
'Capacity requirements',
|
||||
'Access patterns'
|
||||
],
|
||||
icon: 'storage',
|
||||
image: ''
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Printer & Scanner Installation',
|
||||
description: 'Professional installation and configuration of printers and scanners to ensure seamless integration into your workflow.',
|
||||
challenge: 'Printer connectivity issues are a leading cause of office support tickets and downtime.',
|
||||
approach: 'We set up reliable printing environments with proper drivers, networking, and user access controls.',
|
||||
deliverables: [
|
||||
'Network printer setup',
|
||||
'Scanner configuration (Scan-to-Email/Folder)',
|
||||
'Print server management',
|
||||
'One-click user deployment',
|
||||
'Troubleshooting training'
|
||||
],
|
||||
needs: [
|
||||
'Printer/Scanner hardware',
|
||||
'Network access details'
|
||||
],
|
||||
icon: 'print',
|
||||
image: ''
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: 'Web Design',
|
||||
description: 'Professional website design backed by domain registration and DNS support, so your online presence looks credible and works reliably.',
|
||||
challenge: 'If your site looks dated, loads poorly, or your domain setup is messy, customers lose trust before they ever contact you.',
|
||||
approach: 'We build clean business websites and handle the domain and DNS layer correctly, so your site, forms, and connected services stay dependable.',
|
||||
deliverables: [
|
||||
'Custom website design & development',
|
||||
'Domain registration & management',
|
||||
'DNS setup and support',
|
||||
'SEO optimization basics',
|
||||
'Hosting & maintenance'
|
||||
],
|
||||
needs: [
|
||||
'Brand guidelines / Logo',
|
||||
'Content & copy',
|
||||
'Domain access (if existing)'
|
||||
],
|
||||
icon: 'language',
|
||||
image: '/assets/services/managed-it.webp'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: 'New/Refurbished Desktop Hardware',
|
||||
description: 'Supply and installation of new or refurbished desktop hardware, tailored to meet your business requirements.',
|
||||
challenge: 'Sourcing the right hardware at the right price can be time-consuming and risky.',
|
||||
approach: 'We source high-quality new and refurbished equipment that meets your specs and budget, fully tested and ready to go.',
|
||||
deliverables: [
|
||||
'Hardware procurement',
|
||||
'Quality assurance testing',
|
||||
'Image deployment',
|
||||
'Peripherals setup',
|
||||
'Warranty management'
|
||||
],
|
||||
needs: [
|
||||
'Budget constraints',
|
||||
'Performance requirements'
|
||||
],
|
||||
icon: 'computer',
|
||||
image: ''
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: 'Network Infrastructure Support',
|
||||
description: 'Robust network solutions to ensure connectivity, security, and efficiency, including routers, access points, and switches.',
|
||||
challenge: 'A weak network backbone leads to slow speeds, dropped calls, and security holes.',
|
||||
approach: 'We design and maintain enterprise-grade networks that handle your data traffic reliably and securely.',
|
||||
deliverables: [
|
||||
'Router & Switch configuration',
|
||||
'VLAN segmentation',
|
||||
@@ -141,31 +122,31 @@ const services = [
|
||||
needs: [
|
||||
'Floor plans (for Wi-Fi)',
|
||||
'ISP details'
|
||||
],
|
||||
icon: 'lan',
|
||||
image: ''
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
title: 'Network Attached Storage',
|
||||
description: 'Selection, setup, and maintenance of Network Attached Storage solutions to provide scalable and reliable data storage.',
|
||||
challenge: 'Data growth requires scalable storage that is accessible yet secure from loss.',
|
||||
approach: 'We deploy NAS solutions that centralize your data with redundancy and easy access for your team.',
|
||||
deliverables: [
|
||||
'NAS hardware selection & setup',
|
||||
'RAID configuration',
|
||||
'User permission management',
|
||||
'Remote access configuration',
|
||||
'Backup integration'
|
||||
],
|
||||
needs: [
|
||||
'Capacity requirements',
|
||||
'Access patterns'
|
||||
],
|
||||
icon: 'storage',
|
||||
image: ''
|
||||
}
|
||||
];
|
||||
],
|
||||
icon: 'lan',
|
||||
image: ''
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
title: 'IT Help Desk',
|
||||
description: 'Fast and reliable help desk support for employees, resolving technical issues remotely or on-site.',
|
||||
challenge: 'When employees do not have a clear support channel, small technical issues quickly turn into company-wide delays.',
|
||||
approach: 'We provide a structured help desk workflow that resolves day-to-day IT issues quickly and keeps your team productive.',
|
||||
deliverables: [
|
||||
'Remote troubleshooting and issue resolution',
|
||||
'User account and access support',
|
||||
'Software and email assistance',
|
||||
'Escalation path for on-site issues',
|
||||
'Clear communication on ticket status'
|
||||
],
|
||||
needs: [
|
||||
'Primary support contacts',
|
||||
'User and device overview'
|
||||
],
|
||||
icon: 'support_agent',
|
||||
image: ''
|
||||
}
|
||||
];
|
||||
|
||||
const ServiceModal: React.FC<{ service: typeof services[0] | null; onClose: () => void }> = ({ service, onClose }) => {
|
||||
if (!service) return null;
|
||||
@@ -311,23 +292,30 @@ const ServicesPage: React.FC = () => {
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="pt-20 min-h-screen bg-[#0a0a0a] relative overflow-x-hidden">
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title="IT Services | Bay Area IT Support, Email, Networking and Web"
|
||||
description="Explore Bay Area IT services for Corpus Christi businesses, including help desk support, business email, networking, hardware, web design, and day-to-day IT support."
|
||||
keywords={['IT services Corpus Christi', 'help desk services', 'business email setup', 'network support']}
|
||||
canonicalUrl="https://bayareait.services/services"
|
||||
/>
|
||||
<div className="pt-20 min-h-screen bg-[#0a0a0a] relative overflow-x-hidden">
|
||||
{/* Gradient for Services Page */}
|
||||
<div className="absolute top-0 left-0 right-0 h-[800px] bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(255,255,255,0.15),rgba(255,255,255,0))] dark:bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(255,255,255,0.25),rgba(255,255,255,0))] pointer-events-none" />
|
||||
|
||||
{/* Hero */}
|
||||
<section className="py-20 px-6 bg-transparent border-b border-white/5 relative z-10">
|
||||
<div className="max-w-4xl mx-auto text-center">
|
||||
<span className="text-white/60 font-bold tracking-widest uppercase text-sm mb-3 block">Expertise</span>
|
||||
<h1 className="font-display text-4xl md:text-5xl font-bold mb-6 text-white">
|
||||
Complete IT solutions for <br /><span className="text-gray-500">your business</span>
|
||||
</h1>
|
||||
<p className="text-xl text-gray-400 max-w-2xl mx-auto">
|
||||
From desktop support to enterprise infrastructure, we provide the technology foundation your business needs to thrive.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<div className="max-w-4xl mx-auto text-center">
|
||||
<span className="text-white/60 font-bold tracking-widest uppercase text-sm mb-3 block">Expertise</span>
|
||||
<h1 className="font-display text-4xl md:text-5xl font-bold mb-6 text-white">
|
||||
Reliable business technology <br /><span className="text-gray-500">that keeps communication moving</span>
|
||||
</h1>
|
||||
<p className="text-xl text-gray-400 max-w-2xl mx-auto">
|
||||
From enterprise-grade email to day-to-day infrastructure and web support, we help businesses stay reachable, credible, and operational.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Timeline Section */}
|
||||
<section ref={containerRef} className="py-24 px-6 relative overflow-hidden bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(255,255,255,0.05),rgba(255,255,255,0))]">
|
||||
@@ -341,7 +329,7 @@ const ServicesPage: React.FC = () => {
|
||||
className="absolute left-4 md:left-1/2 md:-ml-[0.5px] top-0 w-px bg-white origin-top shadow-[0_0_40px_2px_rgba(255,255,255,1)] drop-shadow-[0_0_10px_rgba(255,255,255,1)] -translate-x-1/2 md:translate-x-0"
|
||||
></motion.div>
|
||||
|
||||
<div className="space-y-64 pb-64">
|
||||
<div className="space-y-40 pb-40">
|
||||
{services.map((service, index) => (
|
||||
<div
|
||||
key={service.id}
|
||||
@@ -369,10 +357,10 @@ const ServicesPage: React.FC = () => {
|
||||
|
||||
{/* Content Card */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9, filter: "blur(10px)" }}
|
||||
whileInView={{ opacity: 1, scale: 1, filter: "blur(0px)" }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.5, ease: "easeOut" }}
|
||||
initial={{ opacity: 0, y: 24 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.5, ease: "easeOut" }}
|
||||
className={`md:w-1/2 ${index % 2 === 0 ? 'md:pr-24 pl-12' : 'md:pl-24 pl-12'}`}
|
||||
>
|
||||
<div
|
||||
@@ -408,8 +396,9 @@ const ServicesPage: React.FC = () => {
|
||||
<ServiceModal service={selectedService} onClose={() => setSelectedService(null)} />
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServicesPage;
|
||||
|
||||
69
src/pages/TermsOfServicePage.tsx
Normal file
69
src/pages/TermsOfServicePage.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import React from 'react';
|
||||
import LegalPage from './LegalPage';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Service Description',
|
||||
body: [
|
||||
'Bay Area Affiliates, Inc. provides comprehensive IT support services, including hardware and software support, network infrastructure, server repair, remote support, web services, virtualization solutions, and more.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'User Responsibilities',
|
||||
body: [
|
||||
'Users are responsible for maintaining the confidentiality of their account information and for all activities that occur under their account.',
|
||||
'Users agree to provide accurate and complete information when using our services.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Payment Terms',
|
||||
body: [
|
||||
'All services rendered by Bay Area Affiliates, Inc. are subject to payment terms agreed upon in the service contract. Late payments may incur additional fees.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Limitation of Liability',
|
||||
body: [
|
||||
'Bay Area Affiliates, Inc. shall not be liable for any indirect, incidental, or consequential damages arising from the use of our services.',
|
||||
'Our total liability is limited to the amount paid for the services rendered.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Termination',
|
||||
body: [
|
||||
'Either party may terminate the service agreement at any time with written notice. Upon termination, users must cease using all services provided by Bay Area Affiliates, Inc.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Governing Law',
|
||||
body: [
|
||||
'These Terms of Service are governed by and construed in accordance with the laws of the State of Texas, without regard to its conflict of law principles.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Changes to Terms',
|
||||
body: [
|
||||
'Bay Area Affiliates, Inc. reserves the right to modify these Terms of Service at any time. Any changes will be effective immediately upon posting on our website.',
|
||||
'Continued use of our services constitutes acceptance of the updated terms.',
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Contact Us',
|
||||
body: [
|
||||
'If you have any questions about these Terms of Service, please contact us at info@bayareaaffiliates.com.',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const TermsOfServicePage: React.FC = () => (
|
||||
<LegalPage
|
||||
title="Terms of Service"
|
||||
description="Review the Bay Area Affiliates, Inc. Terms of Service for the use of our website and IT support services."
|
||||
canonicalUrl="https://bayareait.services/terms-of-service"
|
||||
eyebrow="Bay Area Affiliates, Inc."
|
||||
intro="By accessing our website and using our IT support services, you agree to comply with and be bound by the following Terms of Service."
|
||||
sections={sections}
|
||||
/>
|
||||
);
|
||||
|
||||
export default TermsOfServicePage;
|
||||
154
src/routes/seoRoutes.tsx
Normal file
154
src/routes/seoRoutes.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
import React, { lazy, useEffect, useState } from 'react';
|
||||
import { Navigate } from 'react-router-dom';
|
||||
import type { LocationData, ServiceData, BlogPostData } from '../data/seoData';
|
||||
|
||||
const LazyLocationPage = lazy(() => import('../pages/LocationPage'));
|
||||
const LazyServicePage = lazy(() => import('../pages/ServicePage'));
|
||||
const LazyBlogPostPage = lazy(() => import('../pages/BlogPostPage'));
|
||||
|
||||
type SeoRouteState<T> = {
|
||||
data: T | null;
|
||||
error: string | null;
|
||||
};
|
||||
|
||||
const routeFallback = (
|
||||
<div className="min-h-[40vh] flex items-center justify-center px-6 text-sm text-gray-500 dark:text-gray-400">
|
||||
Loading page...
|
||||
</div>
|
||||
);
|
||||
|
||||
function createSeoRoute<T extends { slug: string }>(
|
||||
loadData: () => Promise<{
|
||||
locationData?: LocationData[];
|
||||
serviceData?: ServiceData[];
|
||||
blogPostData?: BlogPostData[];
|
||||
}>,
|
||||
selectData: (module: Awaited<ReturnType<typeof loadData>>, slug: string) => T | undefined,
|
||||
Page: React.LazyExoticComponent<React.ComponentType<{ data: T }>>,
|
||||
) {
|
||||
return function SeoRoute({ slug }: { slug: string }) {
|
||||
const [state, setState] = useState<SeoRouteState<T>>({
|
||||
data: null,
|
||||
error: null,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
|
||||
setState({ data: null, error: null });
|
||||
|
||||
loadData()
|
||||
.then((module) => {
|
||||
if (!active) return;
|
||||
|
||||
const nextData = selectData(module, slug);
|
||||
setState({
|
||||
data: nextData ?? null,
|
||||
error: nextData ? null : `No SEO data found for ${slug}`,
|
||||
});
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
if (!active) return;
|
||||
|
||||
setState({
|
||||
data: null,
|
||||
error: error instanceof Error ? error.message : 'Failed to load route data',
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [slug]);
|
||||
|
||||
if (state.error) {
|
||||
return (
|
||||
<div className="min-h-[40vh] flex items-center justify-center px-6 text-center">
|
||||
<div>
|
||||
<p className="text-sm uppercase tracking-widest text-gray-500 dark:text-gray-400 mb-2">
|
||||
Route unavailable
|
||||
</p>
|
||||
<p className="text-lg text-gray-900 dark:text-white">{state.error}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!state.data) {
|
||||
return routeFallback;
|
||||
}
|
||||
|
||||
return <Page data={state.data} />;
|
||||
};
|
||||
}
|
||||
|
||||
const loadSeoData = () => import('../data/seoData');
|
||||
|
||||
// Location pages — city IT support pages under /locations/
|
||||
export const locationRoutes = [
|
||||
{ path: '/locations/it-support-corpus-christi', slug: 'locations/it-support-corpus-christi' },
|
||||
{ path: '/locations/it-support-portland-tx', slug: 'locations/it-support-portland-tx' },
|
||||
{ path: '/locations/it-support-rockport-tx', slug: 'locations/it-support-rockport-tx' },
|
||||
{ path: '/locations/it-support-aransas-pass-tx', slug: 'locations/it-support-aransas-pass-tx' },
|
||||
{ path: '/locations/it-support-kingsville-tx', slug: 'locations/it-support-kingsville-tx' },
|
||||
// Service+location hybrid pages (stored in locationData, rendered via LocationPage)
|
||||
{ path: '/services/web-design-corpus-christi', slug: 'services/web-design-corpus-christi' },
|
||||
{ path: '/services/business-email-corpus-christi', slug: 'services/business-email-corpus-christi' },
|
||||
];
|
||||
|
||||
// Service pages — all under /services/
|
||||
export const serviceRoutes = [
|
||||
{ path: '/services/it-help-desk', slug: 'services/it-help-desk' },
|
||||
{ path: '/services/computer-support', slug: 'services/computer-support' },
|
||||
{ path: '/services/business-email-services', slug: 'services/business-email-services' },
|
||||
{ path: '/services/domain-registration-dns-support', slug: 'services/domain-registration-dns-support' },
|
||||
];
|
||||
|
||||
// Authority blog posts only — location posts redirect to their location pages
|
||||
export const blogRoutes = [
|
||||
{ path: '/blog/it-support-small-business-corpus-christi', slug: 'blog/it-support-small-business-corpus-christi' },
|
||||
{ path: '/blog/outsourced-it-support-corpus-christi', slug: 'blog/outsourced-it-support-corpus-christi' },
|
||||
{ path: '/blog/it-service-vs-inhouse-it', slug: 'blog/it-service-vs-inhouse-it' },
|
||||
{ path: '/blog/common-it-problems-businesses-corpus-christi', slug: 'blog/common-it-problems-businesses-corpus-christi' },
|
||||
{ path: '/blog/it-support-cost-corpus-christi', slug: 'blog/it-support-cost-corpus-christi' },
|
||||
{ path: '/blog/business-email-vs-google-workspace-vs-microsoft-365', slug: 'blog/business-email-vs-google-workspace-vs-microsoft-365' },
|
||||
];
|
||||
|
||||
// Old flat-URL redirects — 301-equivalent for any links pointing to old paths
|
||||
export const legacyRedirects = [
|
||||
{ from: '/it-support-corpus-christi', to: '/locations/it-support-corpus-christi' },
|
||||
{ from: '/it-support-portland-tx', to: '/locations/it-support-portland-tx' },
|
||||
{ from: '/it-support-rockport-tx', to: '/locations/it-support-rockport-tx' },
|
||||
{ from: '/it-support-aransas-pass-tx', to: '/locations/it-support-aransas-pass-tx' },
|
||||
{ from: '/it-support-kingsville-tx', to: '/locations/it-support-kingsville-tx' },
|
||||
{ from: '/it-help-desk', to: '/services/it-help-desk' },
|
||||
{ from: '/computer-support', to: '/services/computer-support' },
|
||||
{ from: '/business-email-services', to: '/services/business-email-services' },
|
||||
{ from: '/domain-registration-dns-support', to: '/services/domain-registration-dns-support' },
|
||||
{ from: '/web-design-corpus-christi', to: '/services/web-design-corpus-christi' },
|
||||
{ from: '/business-email-corpus-christi', to: '/services/business-email-corpus-christi' },
|
||||
// Location blog posts → their canonical location pages
|
||||
{ from: '/blog/it-support-corpus-christi-blog', to: '/locations/it-support-corpus-christi' },
|
||||
{ from: '/blog/it-support-portland-tx-blog', to: '/locations/it-support-portland-tx' },
|
||||
{ from: '/blog/it-support-rockport-tx-blog', to: '/locations/it-support-rockport-tx' },
|
||||
{ from: '/blog/it-support-aransas-pass-blog', to: '/locations/it-support-aransas-pass-tx' },
|
||||
{ from: '/blog/it-support-kingsville-tx-blog', to: '/locations/it-support-kingsville-tx' },
|
||||
];
|
||||
|
||||
export const LocationSeoRoute = createSeoRoute<LocationData>(
|
||||
loadSeoData,
|
||||
(module, slug) => module.locationData.find((item) => item.slug === slug),
|
||||
LazyLocationPage,
|
||||
);
|
||||
|
||||
export const ServiceSeoRoute = createSeoRoute<ServiceData>(
|
||||
loadSeoData,
|
||||
(module, slug) => module.serviceData.find((item) => item.slug === slug),
|
||||
LazyServicePage,
|
||||
);
|
||||
|
||||
export const BlogSeoRoute = createSeoRoute<BlogPostData>(
|
||||
loadSeoData,
|
||||
(module, slug) => module.blogPostData.find((item) => item.slug === slug),
|
||||
LazyBlogPostPage,
|
||||
);
|
||||
Reference in New Issue
Block a user