yufan.me/src/helpers/seo.ts
2024-11-15 14:53:33 +08:00

164 lines
3.7 KiB
TypeScript

// This file is copied from https://github.com/flexdinesh/blogster/blob/main/packages/shared/src/seo.ts
// I just modified it for my personal needs.
type PageOgMeta = {
title: string;
description?: string;
type: 'website';
url?: string;
image?: string;
imageAlt?: string;
imageWidth?: string;
imageHeight?: string;
};
type PageTwitterMeta = {
title: string;
description?: string;
card: 'summary_large_image';
site?: string;
creator?: string;
image?: string;
imageAlt?: string;
};
type PostOgMeta = {
title: string;
description?: string;
type: 'article';
url?: string;
author?: string;
siteName?: string;
publishDate: string;
image?: string;
imageAlt?: string;
imageWidth?: string;
imageHeight?: string;
};
type PostTwitterMeta = {
title: string;
description?: string;
card: 'summary_large_image';
site?: string;
creator?: string;
image?: string;
imageAlt?: string;
};
export function getPageMeta({
title: pageTitle,
description,
baseUrl,
ogImageAbsoluteUrl,
ogImageAltText,
ogImageWidth,
ogImageHeight,
siteOwnerTwitterHandle,
contentAuthorTwitterHandle,
}: {
title: string;
description: string;
baseUrl?: string;
ogImageAbsoluteUrl?: string; // should always be absolute
ogImageAltText?: string;
ogImageWidth?: number;
ogImageHeight?: number;
siteOwnerTwitterHandle?: string;
contentAuthorTwitterHandle?: string;
}): { og: PageOgMeta; twitter: PageTwitterMeta } {
if (!pageTitle) {
throw Error('title is required for page SEO');
}
if (ogImageAbsoluteUrl) {
ogImageAltText = !ogImageAltText ? `Preview image for ${pageTitle}` : ogImageAltText;
}
const og: PageOgMeta = {
title: pageTitle,
description: description,
type: 'website',
url: baseUrl,
image: ogImageAbsoluteUrl,
imageAlt: ogImageAltText,
imageWidth: ogImageWidth ? String(ogImageWidth) : undefined,
imageHeight: ogImageHeight ? String(ogImageHeight) : undefined,
};
const twitter: PageTwitterMeta = {
title: pageTitle,
description: description,
card: 'summary_large_image',
site: siteOwnerTwitterHandle,
creator: contentAuthorTwitterHandle || siteOwnerTwitterHandle,
image: ogImageAbsoluteUrl,
imageAlt: ogImageAltText,
};
return {
og,
twitter,
};
}
export function getBlogPostMeta({
title: pageTitle,
description,
pageUrl,
authorName,
publishDate,
ogImageAbsoluteUrl,
ogImageAltText,
ogImageWidth,
ogImageHeight,
siteOwnerTwitterHandle,
contentAuthorTwitterHandle,
}: {
title: string;
description: string;
pageUrl?: string;
authorName?: string;
publishDate: string;
ogImageAbsoluteUrl?: string; // should always be absolute
ogImageAltText?: string;
ogImageWidth?: number;
ogImageHeight?: number;
siteOwnerTwitterHandle?: string;
contentAuthorTwitterHandle?: string;
}): { og: PostOgMeta; twitter: PostTwitterMeta } {
if (!pageTitle) {
throw Error('title is required for page SEO');
}
if (ogImageAbsoluteUrl && !ogImageAltText) {
ogImageAltText = `Preview image for ${pageTitle}`;
}
const og: PostOgMeta = {
title: pageTitle,
description: description,
type: 'article',
url: pageUrl,
author: authorName,
publishDate: publishDate,
image: ogImageAbsoluteUrl,
imageAlt: ogImageAltText,
imageWidth: ogImageWidth ? String(ogImageWidth) : undefined,
imageHeight: ogImageHeight ? String(ogImageHeight) : undefined,
};
const twitter: PostTwitterMeta = {
title: pageTitle,
description: description,
card: 'summary_large_image',
site: siteOwnerTwitterHandle,
creator: contentAuthorTwitterHandle || siteOwnerTwitterHandle,
image: ogImageAbsoluteUrl,
imageAlt: ogImageAltText,
};
return {
og,
twitter,
};
}