feat: comprehensive SEO optimization and GDPR compliance
- Added Terms of Service and Privacy Policy pages with contact info - Implemented Google Analytics with Consent Mode v2 for GDPR compliance - Created sitemap.xml and robots.txt for search engine optimization - Added dynamic meta tags, Open Graph, and structured data (JSON-LD) - Implemented GDPR consent banner with TCF 2.2 compatibility - Enhanced sidebar with category-colored hover states and proper active/inactive styling - Fixed all ESLint warnings for clean deployment - Added comprehensive SEO utilities and privacy-first analytics tracking Ready for production deployment with full legal compliance and SEO optimization.
This commit is contained in:
75
src/components/SEOHead.js
Normal file
75
src/components/SEOHead.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { generateMetaTags } from '../utils/seo';
|
||||
|
||||
// SEO Head component that manually updates document head
|
||||
// This works without additional dependencies until we add react-helmet-async
|
||||
const SEOHead = () => {
|
||||
const location = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
const { title, meta, link, structuredData } = generateMetaTags(location.pathname);
|
||||
|
||||
// Update document title
|
||||
document.title = title;
|
||||
|
||||
// Remove existing meta tags that we manage
|
||||
const existingMeta = document.querySelectorAll('meta[data-seo="true"]');
|
||||
existingMeta.forEach(tag => tag.remove());
|
||||
|
||||
const existingLinks = document.querySelectorAll('link[data-seo="true"]');
|
||||
existingLinks.forEach(tag => tag.remove());
|
||||
|
||||
const existingStructuredData = document.querySelectorAll('script[data-seo="structured-data"]');
|
||||
existingStructuredData.forEach(tag => tag.remove());
|
||||
|
||||
// Add new meta tags
|
||||
meta.forEach(({ name, property, content }) => {
|
||||
const metaTag = document.createElement('meta');
|
||||
if (name) metaTag.setAttribute('name', name);
|
||||
if (property) metaTag.setAttribute('property', property);
|
||||
metaTag.setAttribute('content', content);
|
||||
metaTag.setAttribute('data-seo', 'true');
|
||||
document.head.appendChild(metaTag);
|
||||
});
|
||||
|
||||
// Add canonical link
|
||||
link.forEach(({ rel, href }) => {
|
||||
const linkTag = document.createElement('link');
|
||||
linkTag.setAttribute('rel', rel);
|
||||
linkTag.setAttribute('href', href);
|
||||
linkTag.setAttribute('data-seo', 'true');
|
||||
document.head.appendChild(linkTag);
|
||||
});
|
||||
|
||||
// Add structured data
|
||||
if (structuredData) {
|
||||
const script = document.createElement('script');
|
||||
script.type = 'application/ld+json';
|
||||
script.setAttribute('data-seo', 'structured-data');
|
||||
script.textContent = JSON.stringify(structuredData);
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
// Add preconnect for performance
|
||||
const preconnectLinks = [
|
||||
'https://www.googletagmanager.com',
|
||||
'https://www.google-analytics.com'
|
||||
];
|
||||
|
||||
preconnectLinks.forEach(href => {
|
||||
if (!document.querySelector(`link[rel="preconnect"][href="${href}"]`)) {
|
||||
const preconnect = document.createElement('link');
|
||||
preconnect.rel = 'preconnect';
|
||||
preconnect.href = href;
|
||||
preconnect.setAttribute('data-seo', 'true');
|
||||
document.head.appendChild(preconnect);
|
||||
}
|
||||
});
|
||||
|
||||
}, [location.pathname]);
|
||||
|
||||
return null; // This component doesn't render anything
|
||||
};
|
||||
|
||||
export default SEOHead;
|
||||
Reference in New Issue
Block a user