SEO
This commit is contained in:
@@ -11,7 +11,19 @@ interface BreadcrumbProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Breadcrumb: React.FC<BreadcrumbProps> = ({ items }) => {
|
const Breadcrumb: React.FC<BreadcrumbProps> = ({ items }) => {
|
||||||
|
const breadcrumbSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'BreadcrumbList',
|
||||||
|
itemListElement: items.map((item, index) => ({
|
||||||
|
'@type': 'ListItem',
|
||||||
|
position: index + 1,
|
||||||
|
name: item.label,
|
||||||
|
...(item.to ? { item: `https://bayareait.services${item.to}` } : {}),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<nav aria-label="breadcrumb" className="text-sm text-gray-500 dark:text-gray-400 flex items-center gap-1.5">
|
<nav aria-label="breadcrumb" className="text-sm text-gray-500 dark:text-gray-400 flex items-center gap-1.5">
|
||||||
{items.map((item, i) => (
|
{items.map((item, i) => (
|
||||||
<React.Fragment key={i}>
|
<React.Fragment key={i}>
|
||||||
@@ -29,6 +41,11 @@ const Breadcrumb: React.FC<BreadcrumbProps> = ({ items }) => {
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</nav>
|
</nav>
|
||||||
|
<script
|
||||||
|
type="application/ld+json"
|
||||||
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbSchema) }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,20 @@ const BlogPostPage: React.FC<BlogPostPageProps> = ({ data }) => {
|
|||||||
? 'Local Services'
|
? 'Local Services'
|
||||||
: 'IT Insights';
|
: 'IT Insights';
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "BlogPosting",
|
||||||
|
"headline": data.h1,
|
||||||
|
"description": data.description,
|
||||||
|
"url": `https://bayareait.services/${data.slug}`,
|
||||||
|
"image": data.image ? `https://bayareait.services${data.image}` : "https://bayareait.services/logo.svg",
|
||||||
|
"publisher": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "Bay Area IT",
|
||||||
|
"url": "https://bayareait.services"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SEO
|
<SEO
|
||||||
@@ -31,6 +45,7 @@ const BlogPostPage: React.FC<BlogPostPageProps> = ({ data }) => {
|
|||||||
description={data.description}
|
description={data.description}
|
||||||
keywords={data.keywords}
|
keywords={data.keywords}
|
||||||
canonicalUrl={`https://bayareait.services/${data.slug}`}
|
canonicalUrl={`https://bayareait.services/${data.slug}`}
|
||||||
|
schema={schema}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden pt-32 pb-16">
|
<div className="min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden pt-32 pb-16">
|
||||||
|
|||||||
@@ -1,12 +1,42 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import SEO from '../../components/SEO';
|
import SEO from '../../components/SEO';
|
||||||
|
|
||||||
const ContactPage: React.FC = () => {
|
const ContactPage: React.FC = () => {
|
||||||
|
const [isSubmitted, setIsSubmitted] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const formData = new FormData(event.currentTarget);
|
||||||
|
const name = String(formData.get('name') || '').trim();
|
||||||
|
const phone = String(formData.get('phone') || '').trim();
|
||||||
|
const email = String(formData.get('email') || '').trim();
|
||||||
|
const company = String(formData.get('company') || '').trim();
|
||||||
|
const message = String(formData.get('message') || '').trim();
|
||||||
|
|
||||||
|
const subject = encodeURIComponent(`Website inquiry from ${name || 'Bay Area IT visitor'}`);
|
||||||
|
const body = encodeURIComponent(
|
||||||
|
[
|
||||||
|
`Name: ${name || 'Not provided'}`,
|
||||||
|
`Phone: ${phone || 'Not provided'}`,
|
||||||
|
`Email: ${email || 'Not provided'}`,
|
||||||
|
`Company: ${company || 'Not provided'}`,
|
||||||
|
'',
|
||||||
|
'Message:',
|
||||||
|
message || 'No message provided',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
|
||||||
|
window.location.href = `mailto:info@bayareaaffiliates.com?subject=${subject}&body=${body}`;
|
||||||
|
setIsSubmitted(true);
|
||||||
|
event.currentTarget.reset();
|
||||||
|
};
|
||||||
|
|
||||||
const faqs = [
|
const faqs = [
|
||||||
{ q: 'How quickly can you start?', a: 'Most assessments can begin within 48 hours of contact. Emergency support is available 24/7.' },
|
{ q: 'How quickly can you start?', a: 'Most assessments can begin within 48 hours of contact. Emergency support is available 24/7.' },
|
||||||
{ q: 'How do you price services?', a: 'Transparent monthly pricing based on devices and services needed. No hidden fees or surprise charges.' },
|
{ q: 'How do you price services?', a: 'Transparent monthly pricing based on devices and services needed. No hidden fees or surprise charges.' },
|
||||||
@@ -44,32 +74,37 @@ const ContactPage: React.FC = () => {
|
|||||||
className="bg-white/5 backdrop-blur-sm p-8 md:p-10 rounded-3xl shadow-xl border border-white/10"
|
className="bg-white/5 backdrop-blur-sm p-8 md:p-10 rounded-3xl shadow-xl border border-white/10"
|
||||||
>
|
>
|
||||||
<h3 className="text-2xl font-bold mb-8 text-white">Send us a message</h3>
|
<h3 className="text-2xl font-bold mb-8 text-white">Send us a message</h3>
|
||||||
<form className="space-y-6">
|
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="name" className="block text-sm font-medium text-gray-300 mb-2">Name *</label>
|
<label htmlFor="name" className="block text-sm font-medium text-gray-300 mb-2">Name *</label>
|
||||||
<input type="text" id="name" required className="w-full px-4 py-3 rounded-xl bg-black/20 border border-white/10 focus:border-white/30 focus:ring-1 focus:ring-white/30 outline-none transition-all text-white placeholder-gray-600" placeholder="John Doe" />
|
<input type="text" id="name" name="name" required className="w-full px-4 py-3 rounded-xl bg-black/20 border border-white/10 focus:border-white/30 focus:ring-1 focus:ring-white/30 outline-none transition-all text-white placeholder-gray-600" placeholder="John Doe" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="phone" className="block text-sm font-medium text-gray-300 mb-2">Phone</label>
|
<label htmlFor="phone" className="block text-sm font-medium text-gray-300 mb-2">Phone</label>
|
||||||
<input type="tel" id="phone" className="w-full px-4 py-3 rounded-xl bg-black/20 border border-white/10 focus:border-white/30 focus:ring-1 focus:ring-white/30 outline-none transition-all text-white placeholder-gray-600" placeholder="(555) 000-0000" />
|
<input type="tel" id="phone" name="phone" className="w-full px-4 py-3 rounded-xl bg-black/20 border border-white/10 focus:border-white/30 focus:ring-1 focus:ring-white/30 outline-none transition-all text-white placeholder-gray-600" placeholder="(555) 000-0000" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="email" className="block text-sm font-medium text-gray-300 mb-2">Email *</label>
|
<label htmlFor="email" className="block text-sm font-medium text-gray-300 mb-2">Email *</label>
|
||||||
<input type="email" id="email" required className="w-full px-4 py-3 rounded-xl bg-black/20 border border-white/10 focus:border-white/30 focus:ring-1 focus:ring-white/30 outline-none transition-all text-white placeholder-gray-600" placeholder="john@company.com" />
|
<input type="email" id="email" name="email" required className="w-full px-4 py-3 rounded-xl bg-black/20 border border-white/10 focus:border-white/30 focus:ring-1 focus:ring-white/30 outline-none transition-all text-white placeholder-gray-600" placeholder="john@company.com" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="company" className="block text-sm font-medium text-gray-300 mb-2">Company</label>
|
<label htmlFor="company" className="block text-sm font-medium text-gray-300 mb-2">Company</label>
|
||||||
<input type="text" id="company" className="w-full px-4 py-3 rounded-xl bg-black/20 border border-white/10 focus:border-white/30 focus:ring-1 focus:ring-white/30 outline-none transition-all text-white placeholder-gray-600" placeholder="Acme Inc." />
|
<input type="text" id="company" name="company" className="w-full px-4 py-3 rounded-xl bg-black/20 border border-white/10 focus:border-white/30 focus:ring-1 focus:ring-white/30 outline-none transition-all text-white placeholder-gray-600" placeholder="Acme Inc." />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="message" className="block text-sm font-medium text-gray-300 mb-2">Message *</label>
|
<label htmlFor="message" className="block text-sm font-medium text-gray-300 mb-2">Message *</label>
|
||||||
<textarea id="message" rows={4} required className="w-full px-4 py-3 rounded-xl bg-black/20 border border-white/10 focus:border-white/30 focus:ring-1 focus:ring-white/30 outline-none transition-all text-white placeholder-gray-600 resize-none" placeholder="How can we help you?"></textarea>
|
<textarea id="message" name="message" rows={4} required className="w-full px-4 py-3 rounded-xl bg-black/20 border border-white/10 focus:border-white/30 focus:ring-1 focus:ring-white/30 outline-none transition-all text-white placeholder-gray-600 resize-none" placeholder="How can we help you?"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" className="w-full py-4 bg-white text-black font-bold rounded-xl transition-all hover:bg-gray-200 hover:scale-[1.02] shadow-[0_0_20px_rgba(255,255,255,0.1)]">
|
<button type="submit" className="w-full py-4 bg-white text-black font-bold rounded-xl transition-all hover:bg-gray-200 hover:scale-[1.02] shadow-[0_0_20px_rgba(255,255,255,0.1)]">
|
||||||
Send Message
|
Send Message
|
||||||
</button>
|
</button>
|
||||||
|
{isSubmitted && (
|
||||||
|
<p className="text-sm text-gray-400">
|
||||||
|
Your mail client should open with the message prefilled. If it does not, email us at info@bayareaaffiliates.com.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</form>
|
</form>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,23 @@ const ServicePage: React.FC<ServicePageProps> = ({ data }) => {
|
|||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "Service",
|
||||||
|
"name": data.h1,
|
||||||
|
"description": data.description,
|
||||||
|
"url": `https://bayareait.services/${data.slug}`,
|
||||||
|
"provider": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "Bay Area IT",
|
||||||
|
"url": "https://bayareait.services"
|
||||||
|
},
|
||||||
|
"areaServed": {
|
||||||
|
"@type": "AdministrativeArea",
|
||||||
|
"name": "Corpus Christi and the Coastal Bend"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SEO
|
<SEO
|
||||||
@@ -96,6 +113,7 @@ const ServicePage: React.FC<ServicePageProps> = ({ data }) => {
|
|||||||
description={data.description}
|
description={data.description}
|
||||||
keywords={data.keywords}
|
keywords={data.keywords}
|
||||||
canonicalUrl={`https://bayareait.services/${data.slug}`}
|
canonicalUrl={`https://bayareait.services/${data.slug}`}
|
||||||
|
schema={schema}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
<div className="min-h-screen bg-background-light dark:bg-background-dark relative overflow-x-hidden">
|
||||||
|
|||||||
Reference in New Issue
Block a user