import Head from 'next/head'; import { FC, Fragment, ReactNode } from 'react'; import config from '@config/seo_meta.json'; const storeUrl = process.env.NEXT_PUBLIC_STORE_URL || process.env.NEXT_PUBLIC_VERCEL_URL; const storeBaseUrl = storeUrl ? `https://${storeUrl}` : null; interface OgImage { url?: string; width?: string; height?: string; alt?: string; } interface Props { title?: string; description?: string; robots?: string; openGraph?: { title?: string; type?: string; locale?: string; description?: string; site_name?: string; url?: string; images?: OgImage[]; }; children?: ReactNode; } const ogImage = ({ url, width, height, alt }: OgImage, index: number) => { // generate full URL for OG image url with store base URL const imgUrl = storeBaseUrl ? new URL(url!, storeBaseUrl).toString() : url; return ( ); }; const SEO: FC = ({ title, description, openGraph, robots, children, }) => { /** * @see https://nextjs.org/docs/api-reference/next/head * * meta or any other elements need to be contained as direct children of the Head element, * or wrapped into maximum one level of or arrays * otherwise the tags won't be correctly picked up on client-side navigations. * * The `key` property makes the tag is only rendered once, */ return ( {title ? `${config.titleTemplate.replace(/%s/g, title)}` : config.title} {openGraph?.locale && ( )} {openGraph?.images?.length ? openGraph.images.map((img, index) => ogImage(img, index)) : ogImage(config.openGraph.images[0], 0)} {config.twitter.cardType && ( )} {config.twitter.site && ( )} {config.twitter.handle && ( )} {children} ); }; export default SEO;