jonbio/components/SEO.tsx

195 lines
4.9 KiB
TypeScript
Raw Normal View History

import Head from 'next/head'
import { useRouter } from 'next/router'
2021-01-09 17:50:45 +08:00
import siteMetadata from '@/data/siteMetadata'
2023-07-07 11:17:22 +08:00
import { CoreContent } from 'pliny/utils/contentlayer'
import type { Blog, Authors } from 'contentlayer/generated'
interface CommonSEOProps {
title: string
description: string
ogType: string
ogImage:
| string
| {
'@type': string
url: string
}[]
twImage: string
canonicalUrl?: string
}
2021-01-09 17:50:45 +08:00
2023-07-07 11:17:22 +08:00
const CommonSEO = ({
title,
description,
ogType,
ogImage,
twImage,
canonicalUrl,
}: CommonSEOProps) => {
const router = useRouter()
2021-01-10 17:35:37 +08:00
return (
<Head>
<title>{title}</title>
<meta name="robots" content="follow, index" />
<meta name="description" content={description} />
<meta property="og:url" content={`${siteMetadata.siteUrl}${router.asPath}`} />
2021-08-12 18:43:24 +03:00
<meta property="og:type" content={ogType} />
<meta property="og:site_name" content={siteMetadata.title} />
<meta property="og:description" content={description} />
<meta property="og:title" content={title} />
2023-07-07 11:17:22 +08:00
{Array.isArray(ogImage) ? (
2021-08-12 18:43:24 +03:00
ogImage.map(({ url }) => <meta property="og:image" content={url} key={url} />)
) : (
<meta property="og:image" content={ogImage} key={ogImage} />
)}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content={siteMetadata.twitter} />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
2021-08-12 18:43:24 +03:00
<meta name="twitter:image" content={twImage} />
2022-01-18 12:28:41 +03:00
<link
rel="canonical"
href={canonicalUrl ? canonicalUrl : `${siteMetadata.siteUrl}${router.asPath}`}
/>
2021-08-12 18:43:24 +03:00
</Head>
)
}
2023-07-07 11:17:22 +08:00
interface PageSEOProps {
title: string
description: string
}
export const PageSEO = ({ title, description }: PageSEOProps) => {
2021-08-12 18:43:24 +03:00
const ogImageUrl = siteMetadata.siteUrl + siteMetadata.socialBanner
const twImageUrl = siteMetadata.siteUrl + siteMetadata.socialBanner
return (
<CommonSEO
title={title}
description={description}
ogType="website"
ogImage={ogImageUrl}
twImage={twImageUrl}
/>
)
}
2023-07-07 11:17:22 +08:00
export const TagSEO = ({ title, description }: PageSEOProps) => {
2021-08-12 18:43:24 +03:00
const ogImageUrl = siteMetadata.siteUrl + siteMetadata.socialBanner
const twImageUrl = siteMetadata.siteUrl + siteMetadata.socialBanner
const router = useRouter()
return (
<>
<CommonSEO
title={title}
description={description}
ogType="website"
ogImage={ogImageUrl}
twImage={twImageUrl}
/>
<Head>
<link
rel="alternate"
type="application/rss+xml"
title={`${description} - RSS feed`}
href={`${siteMetadata.siteUrl}${router.asPath}/feed.xml`}
/>
2021-08-12 18:43:24 +03:00
</Head>
</>
2021-08-09 20:55:52 +02:00
)
}
2023-07-07 11:17:22 +08:00
interface BlogSeoProps extends CoreContent<Blog> {
authorDetails?: CoreContent<Authors>[]
url: string
}
2022-01-18 12:28:41 +03:00
export const BlogSEO = ({
authorDetails,
title,
summary,
date,
lastmod,
url,
images = [],
canonicalUrl,
2023-07-07 11:17:22 +08:00
}: BlogSeoProps) => {
2021-01-10 17:35:37 +08:00
const publishedAt = new Date(date).toISOString()
const modifiedAt = new Date(lastmod || date).toISOString()
2023-07-07 11:17:22 +08:00
const imagesArr =
2021-01-18 23:41:48 +08:00
images.length === 0
? [siteMetadata.socialBanner]
: typeof images === 'string'
2021-01-18 23:47:17 +08:00
? [images]
: images
const featuredImages = imagesArr.map((img) => {
return {
'@type': 'ImageObject',
2022-06-10 00:50:23 +00:00
url: img.includes('http') ? img : siteMetadata.siteUrl + img,
}
})
let authorList
if (authorDetails) {
authorList = authorDetails.map((author) => {
return {
'@type': 'Person',
name: author.name,
}
})
} else {
authorList = {
'@type': 'Person',
name: siteMetadata.author,
}
}
const structuredData = {
'@context': 'https://schema.org',
'@type': 'Article',
mainEntityOfPage: {
'@type': 'WebPage',
'@id': url,
},
headline: title,
image: featuredImages,
datePublished: publishedAt,
dateModified: modifiedAt,
author: authorList,
publisher: {
'@type': 'Organization',
name: siteMetadata.author,
logo: {
'@type': 'ImageObject',
url: `${siteMetadata.siteUrl}${siteMetadata.siteLogo}`,
},
},
description: summary,
}
2021-08-12 18:43:24 +03:00
const twImageUrl = featuredImages[0].url
2021-01-10 17:35:37 +08:00
return (
<>
2021-08-12 18:43:24 +03:00
<CommonSEO
title={title}
2023-07-07 11:17:22 +08:00
description={summary || ''}
2021-08-12 18:43:24 +03:00
ogType="article"
ogImage={featuredImages}
twImage={twImageUrl}
2022-01-18 12:28:41 +03:00
canonicalUrl={canonicalUrl}
2021-08-12 18:43:24 +03:00
/>
<Head>
{date && <meta property="article:published_time" content={publishedAt} />}
{lastmod && <meta property="article:modified_time" content={modifiedAt} />}
<script
type="application/ld+json"
2021-08-12 18:43:24 +03:00
dangerouslySetInnerHTML={{
__html: JSON.stringify(structuredData, null, 2),
}}
/>
</Head>
2021-01-10 17:35:37 +08:00
</>
)
}