yufan.me/src/helpers/seo.ts
Yufan Sheng 0126b71722
feat: add upyun support. move images to upyun on build. ()
* style: better reply button.

* feat: add astro badge.

* chore: drop useless styles.

* feat: use new options.ts for global configuration.

* fix: the invalid import.meta.env.PROD in astro build.

* feat: move og to new assert prefix.

* chore: add better og description.

* chore: make sure all the images link could be correctly replaced.

* feat: add upyun uploader.
2024-11-15 14:53:43 +08:00

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