4
0
forked from crowetic/commerce
Dom Sip db170558d5
feat: replace next-seo with custom solution (#660)
* replace next-seo with custom solution

* Updated check

Co-authored-by: LFades <luis@vercel.com>
2022-02-18 04:26:31 -05:00

158 lines
3.9 KiB
TypeScript

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 (
<Fragment key={`og:image:${index}`}>
<meta
key={`og:image:url:${index}`}
property="og:image"
content={imgUrl}
/>
<meta
key={`og:image:width:${index}`}
property="og:image:width"
content={width}
/>
<meta
key={`og:image:height:${index}`}
property="og:image:height"
content={height}
/>
<meta
key={`og:image:alt:${index}`}
property="og:image:alt"
content={alt}
/>
</Fragment>
)
}
const SEO: FC<Props> = ({
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 <React.Fragment> 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 (
<Head>
<title key="title">
{title ? `${config.titleTemplate.replace(/%s/g, title)}` : config.title}
</title>
<meta
key="description"
name="description"
content={description || config.description}
/>
<meta
key="og:type"
property="og:type"
content={openGraph?.type ?? config.openGraph.type}
/>
<meta
key="og:title"
property="og:title"
content={
openGraph?.title ?? config.openGraph.title ?? title ?? config.title
}
/>
<meta
key="og:description"
property="og:description"
content={
openGraph?.description ??
config.openGraph.description ??
description ??
config.description
}
/>
<meta
key="og:site_name"
property="og:site_name"
content={openGraph?.site_name ?? config.openGraph.site_name}
/>
<meta
key="og:url"
property="og:url"
content={openGraph?.url ?? config.openGraph.url}
></meta>
{openGraph?.locale && (
<meta key="og:locale" property="og:locale" content={openGraph.locale} />
)}
{openGraph?.images?.length
? openGraph.images.map((img, index) => ogImage(img, index))
: ogImage(config.openGraph.images[0], 0)}
{config.twitter.cardType && (
<meta
key="twitter:card"
name="twitter:card"
content={config.twitter.cardType}
/>
)}
{config.twitter.site && (
<meta
key="twitter:site"
name="twitter:site"
content={config.twitter.site}
/>
)}
{config.twitter.handle && (
<meta
key="twitter:creator"
name="twitter:creator"
content={config.twitter.handle}
/>
)}
<meta key="robots" name="robots" content={robots ?? 'index,follow'} />
<meta
key="googlebot"
name="googlebot"
content={robots ?? 'index,follow'}
></meta>
{children}
</Head>
)
}
export default SEO