From 25e7e03ad0e80e61919d2e036f38f3ac00898535 Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sun, 19 Oct 2025 21:21:12 +0000 Subject: [PATCH] Add reusable SEO component for per-page meta updates cgen-15bd42da815c402e9d5ea00d1462eca7 --- client/components/SEO.tsx | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 client/components/SEO.tsx diff --git a/client/components/SEO.tsx b/client/components/SEO.tsx new file mode 100644 index 00000000..404e8e85 --- /dev/null +++ b/client/components/SEO.tsx @@ -0,0 +1,52 @@ +import { useEffect } from "react"; + +export type SEOProps = { + pageTitle: string; + description?: string; + image?: string | null; + canonical?: string | null; + noIndex?: boolean; +}; + +function upsertMeta(selector: string, attrs: Record) { + let el = document.querySelector(selector) as HTMLElement | null; + if (!el) { + const tag = selector.startsWith('meta[') ? 'meta' : selector.startsWith('link[') ? 'link' : 'meta'; + el = document.createElement(tag); + document.head.appendChild(el); + } + Object.entries(attrs).forEach(([k, v]) => (el as any).setAttribute(k, v)); +} + +export default function SEO({ pageTitle, description, image, canonical, noIndex }: SEOProps) { + useEffect(() => { + const title = `AeThex | ${pageTitle}`; + document.title = title; + + if (canonical) { + upsertMeta('link[rel="canonical"]', { rel: 'canonical', href: canonical }); + upsertMeta('meta[property="og:url"]', { property: 'og:url', content: canonical }); + } + + if (description) { + upsertMeta('meta[name="description"]', { name: 'description', content: description }); + upsertMeta('meta[property="og:description"]', { property: 'og:description', content: description }); + upsertMeta('meta[name="twitter:description"]', { name: 'twitter:description', content: description }); + } + + upsertMeta('meta[property="og:title"]', { property: 'og:title', content: title }); + upsertMeta('meta[name="twitter:title"]', { name: 'twitter:title', content: title }); + + if (image) { + upsertMeta('meta[property="og:image"]', { property: 'og:image', content: image }); + upsertMeta('meta[name="twitter:image"]', { name: 'twitter:image', content: image }); + } + + if (noIndex) { + upsertMeta('meta[name="robots"]', { name: 'robots', content: 'noindex, nofollow' }); + upsertMeta('meta[name="googlebot"]', { name: 'googlebot', content: 'noindex, nofollow' }); + } + }, [pageTitle, description, image, canonical, noIndex]); + + return null; +}