Files
unique/src/components/SEO.astro
T

101 lines
2.8 KiB
Plaintext

---
export interface OgImage {
url: string;
width: number;
height: number;
alt: string;
type?: string;
}
interface Props {
title: string;
description: string;
canonicalPath?: string;
canonicalOverride?: string;
ogType?: 'website' | 'article';
ogImage?: OgImage;
noindex?: boolean;
publishedTime?: Date;
modifiedTime?: Date;
articleTags?: string[];
jsonLd?: Record<string, unknown> | Record<string, unknown>[];
}
const {
title,
description,
canonicalPath,
canonicalOverride,
ogType = 'website',
ogImage,
noindex = false,
publishedTime,
modifiedTime,
articleTags = [],
jsonLd,
} = Astro.props;
const SITE_NAME = 'Unique';
const titleTag = title === SITE_NAME ? SITE_NAME : `${title} — ${SITE_NAME}`;
const canonicalUrl =
canonicalOverride ??
new URL(canonicalPath ?? Astro.url.pathname, Astro.site).href;
const jsonLdBlocks = jsonLd
? Array.isArray(jsonLd)
? jsonLd
: [jsonLd]
: [];
---
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{titleTag}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonicalUrl} />
{noindex && <meta name="robots" content="noindex,nofollow" />}
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<meta name="theme-color" content="#fafaf7" />
<link rel="alternate" type="application/rss+xml" title={`${SITE_NAME} — RSS`} href="/rss.xml" />
<meta property="og:type" content={ogType} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonicalUrl} />
<meta property="og:site_name" content={SITE_NAME} />
<meta property="og:locale" content="en_US" />
{ogImage && (
<>
<meta property="og:image" content={ogImage.url} />
<meta property="og:image:width" content={String(ogImage.width)} />
<meta property="og:image:height" content={String(ogImage.height)} />
<meta property="og:image:alt" content={ogImage.alt} />
{ogImage.type && <meta property="og:image:type" content={ogImage.type} />}
</>
)}
{ogType === 'article' && publishedTime && (
<meta property="article:published_time" content={publishedTime.toISOString()} />
)}
{ogType === 'article' && modifiedTime && (
<meta property="article:modified_time" content={modifiedTime.toISOString()} />
)}
{ogType === 'article' &&
articleTags.map((t) => <meta property="article:tag" content={t} />)}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
{ogImage && (
<>
<meta name="twitter:image" content={ogImage.url} />
<meta name="twitter:image:alt" content={ogImage.alt} />
</>
)}
{jsonLdBlocks.map((block) => (
<script type="application/ld+json" is:inline set:html={JSON.stringify(block)} />
))}