|
import Head from 'next/head'; |
|
import { useRouter } from 'next/router'; |
|
|
|
|
|
const defaultMeta = { |
|
title: 'Next.js + Tailwind CSS + TypeScript Starter', |
|
siteName: 'Next.js + Tailwind CSS + TypeScript Starter', |
|
description: |
|
'A starter for Next.js, Tailwind CSS, and TypeScript with Absolute Import, Seo, Link component, pre-configured with Husky', |
|
|
|
url: 'https://tsnext-tw.thcl.dev', |
|
type: 'website', |
|
robots: 'follow, index', |
|
|
|
|
|
|
|
|
|
image: 'https://tsnext-tw.thcl.dev/images/large-og.png', |
|
}; |
|
|
|
type SeoProps = { |
|
date?: string; |
|
templateTitle?: string; |
|
} & Partial<typeof defaultMeta>; |
|
|
|
export default function Seo(props: SeoProps) { |
|
const router = useRouter(); |
|
const meta = { |
|
...defaultMeta, |
|
...props, |
|
}; |
|
meta['title'] = props.templateTitle |
|
? `${props.templateTitle} | ${meta.siteName}` |
|
: meta.title; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
<Head> |
|
<title>{meta.title}</title> |
|
<meta name='robots' content={meta.robots} /> |
|
<meta content={meta.description} name='description' /> |
|
<meta property='og:url' content={`${meta.url}${router.asPath}`} /> |
|
<link rel='canonical' href={`${meta.url}${router.asPath}`} /> |
|
{/* Open Graph */} |
|
<meta property='og:type' content={meta.type} /> |
|
<meta property='og:site_name' content={meta.siteName} /> |
|
<meta property='og:description' content={meta.description} /> |
|
<meta property='og:title' content={meta.title} /> |
|
<meta name='image' property='og:image' content={meta.image} /> |
|
{/* Twitter */} |
|
<meta name='twitter:card' content='summary_large_image' /> |
|
{/* // !STARTERCONF Remove or change to your handle */} |
|
{/* <meta name='twitter:site' content='@th_clarence' /> */} |
|
<meta name='twitter:title' content={meta.title} /> |
|
<meta name='twitter:description' content={meta.description} /> |
|
<meta name='twitter:image' content={meta.image} /> |
|
{meta.date && ( |
|
<> |
|
<meta property='article:published_time' content={meta.date} /> |
|
<meta |
|
name='publish_date' |
|
property='og:publish_date' |
|
content={meta.date} |
|
/> |
|
{/* // !STARTERCONF Remove or change to your name */} |
|
<meta |
|
name='author' |
|
property='article:author' |
|
content='Theodorus Clarence' |
|
/> |
|
</> |
|
)} |
|
|
|
{} |
|
{favicons.map((linkProps) => ( |
|
<link key={linkProps.href} {...linkProps} /> |
|
))} |
|
<meta name='msapplication-TileColor' content='#ffffff' /> |
|
<meta name='msapplication-config' content='/favicon/browserconfig.xml' /> |
|
<meta name='theme-color' content='#ffffff' /> |
|
</Head> |
|
); |
|
} |
|
|
|
|
|
|
|
const favicons: Array<React.ComponentPropsWithoutRef<'link'>> = [ |
|
{ |
|
rel: 'apple-touch-icon', |
|
sizes: '180x180', |
|
href: '/favicon/apple-touch-icon.png', |
|
}, |
|
{ |
|
rel: 'icon', |
|
type: 'image/png', |
|
sizes: '32x32', |
|
href: '/favicon/favicon-32x32.png', |
|
}, |
|
{ |
|
rel: 'icon', |
|
type: 'image/png', |
|
sizes: '16x16', |
|
href: '/favicon/favicon-16x16.png', |
|
}, |
|
{ rel: 'manifest', href: '/favicon/site.webmanifest' }, |
|
{ |
|
rel: 'mask-icon', |
|
href: '/favicon/safari-pinned-tab.svg', |
|
color: '#00e887', |
|
}, |
|
{ rel: 'shortcut icon', href: '/favicon/favicon.ico' }, |
|
]; |
|
|