|
|
|
import NextHead from 'next/head';
|
|
|
|
import siteConfig from '../content/site.json';
|
|
|
|
import { RoadmapType } from '../lib/roadmap';
|
|
|
|
|
|
|
|
type HelmetProps = {
|
|
|
|
title?: string;
|
|
|
|
keywords?: string[];
|
|
|
|
canonical?: string;
|
|
|
|
description?: string;
|
|
|
|
noIndex?: boolean;
|
|
|
|
roadmap?: RoadmapType;
|
|
|
|
};
|
|
|
|
|
|
|
|
function getRichSnippetJson(roadmap: RoadmapType) {
|
|
|
|
return {
|
|
|
|
'@context': 'https://schema.org',
|
|
|
|
'@type': 'Article',
|
|
|
|
mainEntityOfPage: {
|
|
|
|
'@type': 'WebPage',
|
|
|
|
'@id': `https://roadmap.sh/${roadmap.id}`,
|
|
|
|
},
|
|
|
|
headline: roadmap.seo.title,
|
|
|
|
description: roadmap.seo.description,
|
|
|
|
image: roadmap.jsonUrl
|
|
|
|
? `https://roadmap.sh/roadmaps/${roadmap.id}.png`
|
|
|
|
: undefined,
|
|
|
|
author: {
|
|
|
|
'@type': 'Person',
|
|
|
|
name: 'Kamran Ahmed',
|
|
|
|
url: 'https://twitter.com/kamranahmedse',
|
|
|
|
},
|
|
|
|
publisher: {
|
|
|
|
'@type': 'Organization',
|
|
|
|
name: 'roadmap.sh',
|
|
|
|
logo: {
|
|
|
|
'@type': 'ImageObject',
|
|
|
|
url: 'https://roadmap.sh/brand-square.png',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const Helmet = (props: HelmetProps) => {
|
|
|
|
const { roadmap, title, canonical, description, keywords, noIndex = false } = props;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<NextHead>
|
|
|
|
<meta charSet="UTF-8" />
|
|
|
|
|
|
|
|
<title>{title || siteConfig.title}</title>
|
|
|
|
<meta
|
|
|
|
name="description"
|
|
|
|
content={description || siteConfig.description}
|
|
|
|
/>
|
|
|
|
|
|
|
|
<meta name="author" content={siteConfig.author} />
|
|
|
|
<meta
|
|
|
|
name="keywords"
|
|
|
|
content={keywords ? keywords.join(',') : siteConfig.keywords.join(',')}
|
|
|
|
/>
|
|
|
|
|
|
|
|
{noIndex && <meta name="robots" content="noindex" /> }
|
|
|
|
|
|
|
|
<meta
|
|
|
|
name="viewport"
|
|
|
|
content="width=device-width, user-scalable=yes, initial-scale=1.0, maximum-scale=3.0, minimum-scale=1.0"
|
|
|
|
/>
|
|
|
|
{canonical && <link rel="canonical" href={canonical} />}
|
|
|
|
<meta httpEquiv="Content-Language" content="en" />
|
|
|
|
<meta property="og:title" content={title || siteConfig.title} />
|
|
|
|
<meta
|
|
|
|
property="og:description"
|
|
|
|
content={description || siteConfig.description}
|
|
|
|
/>
|
|
|
|
<meta
|
|
|
|
property="og:image"
|
|
|
|
content={`${siteConfig.url.web}${siteConfig.logoSquare}`}
|
|
|
|
/>
|
|
|
|
<meta property="og:url" content={siteConfig.url.web} />
|
|
|
|
<meta property="og:type" content="website" />
|
|
|
|
<meta
|
|
|
|
property="article:publisher"
|
|
|
|
content={`https://facebook.com/${siteConfig.facebook}`}
|
|
|
|
/>
|
|
|
|
<meta property="og:site_name" content={siteConfig.name} />
|
|
|
|
<meta property="article:author" content={siteConfig.author} />
|
|
|
|
|
|
|
|
<meta name="twitter:card" content="summary" />
|
|
|
|
<meta name="twitter:site" content={`@${siteConfig.twitter}`} />
|
|
|
|
<meta name="twitter:title" content={title || siteConfig.title} />
|
|
|
|
<meta
|
|
|
|
name="twitter:description"
|
|
|
|
content={description || siteConfig.description}
|
|
|
|
/>
|
|
|
|
<meta
|
|
|
|
name="twitter:image"
|
|
|
|
content={`${siteConfig.url.web}${siteConfig.logoSquare}`}
|
|
|
|
/>
|
|
|
|
<meta name="twitter:image:alt" content="roadmap.sh" />
|
|
|
|
|
|
|
|
<meta name="mobile-web-app-capable" content="yes" />
|
|
|
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
|
|
<meta
|
|
|
|
name="apple-mobile-web-app-status-bar-style"
|
|
|
|
content="black-translucent"
|
|
|
|
/>
|
|
|
|
<link
|
|
|
|
rel="apple-touch-icon"
|
|
|
|
sizes="180x180"
|
|
|
|
href="/manifest/apple-touch-icon.png"
|
|
|
|
/>
|
|
|
|
<meta name="msapplication-TileColor" content="#101010" />
|
|
|
|
<meta name="theme-color" content="#848a9a" />
|
|
|
|
|
|
|
|
<link rel="manifest" href="/manifest/manifest.json" />
|
|
|
|
<link
|
|
|
|
rel="icon"
|
|
|
|
type="image/png"
|
|
|
|
sizes="32x32"
|
|
|
|
href="/manifest/icon32.png"
|
|
|
|
/>
|
|
|
|
<link
|
|
|
|
rel="icon"
|
|
|
|
type="image/png"
|
|
|
|
sizes="16x16"
|
|
|
|
href="/manifest/icon16.png"
|
|
|
|
/>
|
|
|
|
<link
|
|
|
|
rel="shortcut icon"
|
|
|
|
href="/manifest/favicon.ico"
|
|
|
|
type="image/x-icon"
|
|
|
|
/>
|
|
|
|
<link rel="icon" href="/manifest/favicon.ico" type="image/x-icon" />
|
|
|
|
|
|
|
|
{roadmap?.id && (
|
|
|
|
<script
|
|
|
|
type="application/ld+json"
|
|
|
|
dangerouslySetInnerHTML={{
|
|
|
|
__html: JSON.stringify(getRichSnippetJson(roadmap)),
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
|
|
|
|
{/* Global Site Tag (gtag.js) - Google Analytics */}
|
|
|
|
{process.env.GA_SECRET && (
|
|
|
|
<>
|
|
|
|
<script
|
|
|
|
async
|
|
|
|
src={`https://www.googletagmanager.com/gtag/js?id=${process.env.GA_SECRET}`}
|
|
|
|
/>
|
|
|
|
<script
|
|
|
|
dangerouslySetInnerHTML={{
|
|
|
|
__html: `
|
|
|
|
window.dataLayer = window.dataLayer || [];
|
|
|
|
function gtag(){dataLayer.push(arguments);}
|
|
|
|
gtag('js', new Date());
|
|
|
|
gtag('config', '${process.env.GA_SECRET}');
|
|
|
|
`,
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</NextHead>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default Helmet;
|