69 lines
2.2 KiB
TypeScript
69 lines
2.2 KiB
TypeScript
|
|
import React, { useEffect } from 'react';
|
|
|
|
interface SEOProps {
|
|
title: string;
|
|
description: string;
|
|
keywords?: string[];
|
|
canonicalUrl?: string;
|
|
schema?: object; // JSON-LD schema
|
|
}
|
|
|
|
const SEO: React.FC<SEOProps> = ({ title, description, keywords, canonicalUrl, schema }) => {
|
|
useEffect(() => {
|
|
// Update Title
|
|
document.title = title;
|
|
|
|
// Helper to set meta tag
|
|
const setMetaTag = (name: string, content: string) => {
|
|
let element = document.querySelector(`meta[name="${name}"]`);
|
|
if (!element) {
|
|
element = document.createElement('meta');
|
|
element.setAttribute('name', name);
|
|
document.head.appendChild(element);
|
|
}
|
|
element.setAttribute('content', content);
|
|
};
|
|
|
|
// Update Meta Description
|
|
setMetaTag('description', description);
|
|
|
|
// Update Keywords
|
|
if (keywords && keywords.length > 0) {
|
|
setMetaTag('keywords', keywords.join(', '));
|
|
}
|
|
|
|
// Update Canonical
|
|
if (canonicalUrl) {
|
|
let link = document.querySelector('link[rel="canonical"]');
|
|
if (!link) {
|
|
link = document.createElement('link');
|
|
link.setAttribute('rel', 'canonical');
|
|
document.head.appendChild(link);
|
|
}
|
|
link.setAttribute('href', canonicalUrl);
|
|
}
|
|
|
|
// Inject Schema
|
|
if (schema) {
|
|
const scriptId = 'seo-schema-script';
|
|
let script = document.getElementById(scriptId);
|
|
if (!script) {
|
|
script = document.createElement('script');
|
|
script.id = scriptId;
|
|
script.setAttribute('type', 'application/ld+json');
|
|
document.head.appendChild(script);
|
|
}
|
|
script.textContent = JSON.stringify(schema);
|
|
}
|
|
|
|
// Cleanup function not strictly necessary for single page app navigation
|
|
// unless we want to remove specific tags on unmount, but usually we just overwrite them.
|
|
|
|
}, [title, description, keywords, canonicalUrl, schema]);
|
|
|
|
return null;
|
|
};
|
|
|
|
export default SEO;
|