yufan.me/src/helpers/seo.ts

155 lines
3.7 KiB
TypeScript
Raw Normal View History

2024-06-14 02:11:26 +08:00
// 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.
import { urlJoin } from '@/helpers/tools';
import options from '@/options';
2024-06-14 02:11:26 +08:00
export interface PageMeta {
2024-06-14 02:11:26 +08:00
title: string;
description: string;
baseUrl?: string;
ogImageUrl?: string;
ogImageAltText: string;
ogImageWidth?: number;
ogImageHeight?: number;
siteOwnerTwitterHandle?: string;
contentAuthorTwitterHandle?: string;
}
2024-06-14 02:11:26 +08:00
export interface PostMeta {
title: string;
description: string;
pageUrl?: string;
authorName?: string;
publishDate: string;
ogImageUrl?: string;
ogImageAltText: string;
ogImageWidth?: number;
ogImageHeight?: number;
siteOwnerTwitterHandle?: string;
contentAuthorTwitterHandle?: string;
}
export interface TwitterOgMeta {
2024-06-14 02:11:26 +08:00
title: string;
description?: string;
card: 'summary_large_image';
site?: string;
creator?: string;
image?: string;
imageAlt?: string;
}
2024-06-14 02:11:26 +08:00
export interface PageOgMeta {
2024-06-14 02:11:26 +08:00
title: string;
description?: string;
type: 'website';
2024-06-14 02:11:26 +08:00
url?: string;
image?: string;
imageAlt?: string;
imageWidth?: string;
imageHeight?: string;
}
2024-06-14 02:11:26 +08:00
export interface PostOgMeta {
2024-06-14 02:11:26 +08:00
title: string;
description?: string;
type: 'article';
url?: string;
author?: string;
siteName?: string;
publishDate: string;
2024-06-14 02:11:26 +08:00
image?: string;
imageAlt?: string;
imageWidth?: string;
imageHeight?: string;
}
2024-06-14 02:11:26 +08:00
const parseOgImageUrl = (ogImageUrl?: string): string =>
typeof ogImageUrl === 'undefined'
? options.defaultOpenGraph()
: ogImageUrl.startsWith('/')
? urlJoin(options.assetsPrefix(), ogImageUrl)
: ogImageUrl;
export const getPageMeta = ({
title,
2024-06-14 02:11:26 +08:00
description,
baseUrl,
ogImageUrl,
2024-06-14 02:11:26 +08:00
ogImageAltText,
ogImageWidth,
ogImageHeight,
siteOwnerTwitterHandle,
contentAuthorTwitterHandle,
}: PageMeta): { og: PageOgMeta; twitter: TwitterOgMeta } => {
if (!title) {
2024-06-14 02:11:26 +08:00
throw Error('title is required for page SEO');
}
const ogImageAbsoluteUrl = parseOgImageUrl(ogImageUrl);
2024-06-14 02:11:26 +08:00
return {
og: {
title: title,
description: description,
type: 'website',
url: baseUrl,
image: ogImageAbsoluteUrl,
imageAlt: ogImageAltText,
imageWidth: ogImageWidth ? String(ogImageWidth) : undefined,
imageHeight: ogImageHeight ? String(ogImageHeight) : undefined,
},
twitter: {
title: title,
description: description,
card: 'summary_large_image',
site: siteOwnerTwitterHandle,
creator: contentAuthorTwitterHandle || siteOwnerTwitterHandle,
image: ogImageAbsoluteUrl,
imageAlt: ogImageAltText,
},
2024-06-14 02:11:26 +08:00
};
};
2024-06-14 02:11:26 +08:00
export const getBlogPostMeta = ({
title,
2024-06-14 02:11:26 +08:00
description,
pageUrl,
authorName,
publishDate,
ogImageUrl,
2024-06-14 02:11:26 +08:00
ogImageAltText,
ogImageWidth,
ogImageHeight,
siteOwnerTwitterHandle,
contentAuthorTwitterHandle,
}: PostMeta): { og: PostOgMeta; twitter: TwitterOgMeta } => {
if (!title) {
2024-06-14 02:11:26 +08:00
throw Error('title is required for page SEO');
}
const ogImageAbsoluteUrl = parseOgImageUrl(ogImageUrl);
2024-06-14 02:11:26 +08:00
return {
og: {
title: title,
description: description,
type: 'article',
url: pageUrl,
author: authorName,
publishDate: publishDate,
image: ogImageAbsoluteUrl,
imageAlt: ogImageAltText,
imageWidth: ogImageWidth ? String(ogImageWidth) : undefined,
imageHeight: ogImageHeight ? String(ogImageHeight) : undefined,
},
twitter: {
title: title,
description: description,
card: 'summary_large_image',
site: siteOwnerTwitterHandle,
creator: contentAuthorTwitterHandle || siteOwnerTwitterHandle,
image: ogImageAbsoluteUrl,
imageAlt: ogImageAltText,
},
2024-06-14 02:11:26 +08:00
};
};