feat: automatically generate Open Graph cards

This commit is contained in:
radishzzz 2025-03-13 05:00:18 +00:00
parent 9b9bdb2811
commit a556a622ab
14 changed files with 59 additions and 30 deletions

View file

@ -84,6 +84,7 @@
"msvalidate",
"noopener",
"noreferrer",
"Noto",
"oklch",
"overlayscrollbars",
"pagefind",

View file

@ -19,7 +19,7 @@
# Retypeset
Retypeset is a static blog theme based on the <a href="https://astro.build/">Astro</a> framework, inspired by <a href="https://astro-theme-typography.vercel.app/">Typography</a>. Retypeset establishes a new visual standard and reimagines the layout of all pages, offering a reading experience similar to paper books, reviving the beauty of typography. Details in every sight, elegance in every space.
Retypeset is a static blog theme based on the [Astro](https://astro.build/) framework, inspired by [Typography](https://astro-theme-typography.vercel.app/). Retypeset establishes a new visual standard and reimagines the layout of all pages, offering a reading experience similar to paper books, reviving the beauty of typography. Details in every sight, elegance in every space.
- [Live Demo](https://retypeset.radishzz.cc/)
- [Mobile design](https://mastergo.com/file/151079538766773?fileOpenFrom=home&page_id=M&source=link_share&shareId=151079538766773)

View file

@ -19,7 +19,7 @@
# 重新编排
Retypeset 是一款基于 <a href="https://astro.build/">Astro</a> 框架的静态博客主题,设计灵感来自 <a href="https://astro-theme-typography.vercel.app/">Typography</a>。本主题通过建立全新的视觉规范,对所有页面进行重新编排,打造纸质书页般的阅读体验,再现版式之美。所见皆为细节,方寸尽显优雅。
Retypeset 是一款基于 [Astro](https://astro.build/) 框架的静态博客主题,设计灵感来自 [Typography](https://astro-theme-typography.vercel.app/)。本主题通过建立全新的视觉规范,对所有页面进行重新编排,打造纸质书页般的阅读体验,再现版式之美。所见皆为细节,方寸尽显优雅。
- [在线预览](https://retypeset.radishzz.cc/)
- [移动端设计稿](https://mastergo.com/file/151079538766773?fileOpenFrom=home&page_id=M&source=link_share&shareId=151079538766773)

View file

@ -43,8 +43,7 @@
"sanitize-html": "^2.14.0",
"sharp": "^0.33.5",
"typescript": "~5.8.2",
"unist-util-visit": "^5.0.0",
"vite": "^6.2.1"
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"@antfu/eslint-config": "^4.10.1",

11
pnpm-lock.yaml generated
View file

@ -95,9 +95,6 @@ importers:
unist-util-visit:
specifier: ^5.0.0
version: 5.0.0
vite:
specifier: ^6.2.1
version: 6.2.1(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.28.2)(terser@5.37.0)(yaml@2.7.0)
devDependencies:
'@antfu/eslint-config':
specifier: ^4.10.1
@ -1622,8 +1619,8 @@ packages:
duplexer@0.1.2:
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
electron-to-chromium@1.5.114:
resolution: {integrity: sha512-DFptFef3iktoKlFQK/afbo274/XNWD00Am0xa7M8FZUepHlHT8PEuiNBoRfFHbH1okqN58AlhbJ4QTkcnXorjA==}
electron-to-chromium@1.5.115:
resolution: {integrity: sha512-MN1nahVHAQMOz6dz6bNZ7apgqc9InZy7Ja4DBEVCTdeiUcegbyOYE9bi/f2Z/z6ZxLi0RxLpyJ3EGe+4h3w73A==}
emmet@2.4.11:
resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==}
@ -5216,7 +5213,7 @@ snapshots:
browserslist@4.24.4:
dependencies:
caniuse-lite: 1.0.30001703
electron-to-chromium: 1.5.114
electron-to-chromium: 1.5.115
node-releases: 2.0.19
update-browserslist-db: 1.1.3(browserslist@4.24.4)
@ -5475,7 +5472,7 @@ snapshots:
duplexer@0.1.2: {}
electron-to-chromium@1.5.114: {}
electron-to-chromium@1.5.115: {}
emmet@2.4.11:
dependencies:

BIN
public/image/Astro-Icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="85" height="107" fill="none"><path fill="#fff" d="M27.59 91.137c-4.834-4.42-6.246-13.704-4.232-20.43 3.492 4.241 8.33 5.584 13.342 6.343 7.737 1.17 15.336.732 22.523-2.804.822-.405 1.582-.943 2.48-1.489.675 1.957.85 3.932.615 5.943-.573 4.896-3.01 8.678-6.885 11.545-1.55 1.147-3.19 2.172-4.79 3.253-4.917 3.323-6.247 7.22-4.4 12.888.044.139.084.277.183.614-2.51-1.124-4.344-2.76-5.742-4.911-1.475-2.27-2.177-4.78-2.214-7.498-.019-1.322-.019-2.656-.197-3.96-.434-3.178-1.926-4.601-4.737-4.683-2.884-.084-5.166 1.699-5.771 4.507-.046.216-.113.429-.18.68z"/><path fill="url(#a)" d="M27.59 91.137c-4.834-4.42-6.246-13.704-4.232-20.43 3.492 4.241 8.33 5.584 13.342 6.343 7.737 1.17 15.336.732 22.523-2.804.822-.405 1.582-.943 2.48-1.489.675 1.957.85 3.932.615 5.943-.573 4.896-3.01 8.678-6.885 11.545-1.55 1.147-3.19 2.172-4.79 3.253-4.917 3.323-6.247 7.22-4.4 12.888.044.139.084.277.183.614-2.51-1.124-4.344-2.76-5.742-4.911-1.475-2.27-2.177-4.78-2.214-7.498-.019-1.322-.019-2.656-.197-3.96-.434-3.178-1.926-4.601-4.737-4.683-2.884-.084-5.166 1.699-5.771 4.507-.046.216-.113.429-.18.68z"/><path fill="#fff" d="M0 69.587s14.314-6.973 28.668-6.973L39.49 29.12c.405-1.62 1.588-2.72 2.924-2.72s2.518 1.1 2.924 2.72L56.16 62.614c17 0 28.668 6.973 28.668 6.973S60.514 3.352 60.467 3.219C59.769 1.261 58.591 0 57.003 0H27.827c-1.588 0-2.718 1.261-3.464 3.22C24.311 3.35 0 69.586 0 69.586"/><defs><linearGradient id="a" x1="22.47" x2="69.145" y1="107" y2="84.947" gradientUnits="userSpaceOnUse"><stop stop-color="#D83333"/><stop offset="1" stop-color="#F041FF"/></linearGradient></defs></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -14,8 +14,8 @@ export const themeConfig: ThemeConfig = {
// site url
url: 'https://retypeset.radishzz.cc',
// favicon url
// support only webp, svg or png
favicon: '/image/Logo.svg', // https://example.com/logo.svg
// support only ico or png for best compatibility with Open Graph and RSS avatar
favicon: '/image/Astro-Icon.png', // https://example.com/logo.png
},
// SITE INFORMATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END

View file

@ -7,4 +7,4 @@ pin: 99
lang: en
---
Retypeset is a static blog theme based on the <a href="https://astro.build/">Astro</a> framework, inspired by <a href="https://astro-theme-typography.vercel.app/">Typography</a>. Retypeset establishes a new visual standard and reimagines the layout of all pages, offering a reading experience similar to paper books, reviving the beauty of typography. Details in every sight, elegance in every space.
Retypeset is a static blog theme based on the [Astro](https://astro.build/) framework, inspired by [Typography](https://astro-theme-typography.vercel.app/). Retypeset establishes a new visual standard and reimagines the layout of all pages, offering a reading experience similar to paper books, reviving the beauty of typography. Details in every sight, elegance in every space.

View file

@ -7,4 +7,4 @@ pin: 99
lang: zh
---
Retypeset 是一款基于<a href="https://astro.build/">Astro</a>框架的静态博客主题,设计灵感来自<a href="https://astro-theme-typography.vercel.app/">Typography</a>。本主题通过建立全新的视觉规范,对所有页面进行重新编排,打造纸质书页般的阅读体验,再现版式之美。所见皆为细节,方寸尽显优雅。
Retypeset 是一款基于[Astro](https://astro.build/)框架的静态博客主题,设计灵感来自[Typography](https://astro-theme-typography.vercel.app/)。本主题通过建立全新的视觉规范,对所有页面进行重新编排,打造纸质书页般的阅读体验,再现版式之美。所见皆为细节,方寸尽显优雅。

View file

@ -13,23 +13,23 @@ const { postTitle, postDescription, postSlug } = Astro.props
const { title, subtitle, description, author, url, favicon } = themeConfig.site
const { mode, light: { background: lightMode }, dark: { background: darkMode } } = themeConfig.color
const { locale, moreLocale } = themeConfig.global
// TODO: Change openGraph image fallback url
const { verification = {}, twitterID = '', googleAnalyticsID = '', umamiAnalyticsID = '', openGraph = 'https://placehold.co/1200x630' } = themeConfig.seo ?? {}
const { verification = {}, twitterID = '', googleAnalyticsID = '', umamiAnalyticsID = '', openGraph: ogUrl } = themeConfig.seo ?? {}
const { google = '', bing = '', yandex = '', baidu = '' } = verification
const { commentURL = '', imageHostURL = '', customGoogleAnalyticsJS = '', customUmamiAnalyticsJS = '' } = themeConfig.preload
const initMetaTheme = mode === 'dark' ? darkMode : lightMode
const pageTitle = postTitle ? `${postTitle} | ${title}` : `${title} - ${subtitle}`
const pageDescription = postDescription || description
const pageImage = postSlug ? `${url}/og/${postSlug}.png` : `${openGraph}`
// TODO: Change openGraph image fallback url
const openGraph = typeof ogUrl === 'string' ? ogUrl : 'https://placehold.co/1200x630'
const pageImage = postSlug ? `${url}/og/${postSlug}.png` : openGraph
---
<head>
<!-- Basic info -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
{favicon.toLowerCase().endsWith('.webp') && <link rel="icon" type="image/webp" href={favicon} />}
{favicon.toLowerCase().endsWith('.svg') && <link rel="icon" type="image/svg+xml" href={favicon} />}
{favicon.toLowerCase().endsWith('.png') && <link rel="icon" type="image/png" href={favicon} />}
{favicon.toLowerCase().endsWith('.ico') && <link rel="icon" type="image/x-icon" href={favicon} />}
<title>{pageTitle}</title>
<meta name="description" content={pageDescription} />
<meta name="author" content={author} />
@ -65,7 +65,7 @@ const pageImage = postSlug ? `${url}/og/${postSlug}.png` : `${openGraph}`
<meta property="og:site_name" content={title} />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={pageTitle} />
<meta name="twitter:description" content={pageDescription} />
<meta name="twitter:image" content={pageImage} />

View file

@ -2,6 +2,7 @@
import Waline from '@/components/Comments/Waline.astro'
import Layout from '@/layouts/Layout.astro'
import { checkSlugDuplication } from '@/utils/content'
import { generateDescription } from '@/utils/description'
import { generateMultiLangPostPaths } from '@/utils/i18n/route'
import { getCollection } from 'astro:content'
@ -17,10 +18,15 @@ export async function getStaticPaths() {
}
const { post } = Astro.props
const description = generateDescription(post)
const { Content, remarkPluginFrontmatter } = await post.render()
---
<Layout>
<Layout
postTitle={post.data.title}
postDescription={description}
postSlug={post.slug}
>
<article>
<h1>{post.data.title}</h1>
<time>

View file

@ -1,16 +1,23 @@
import { themeConfig } from '@/config'
import { generateDescription } from '@/utils/description'
import { OGImageRoute } from 'astro-og-canvas'
import { getCollection } from 'astro:content'
// eslint-disable-next-line antfu/no-top-level-await
const blogEntries = await getCollection('posts')
// 确定favicon路径是完整URL还是相对路径
const logoPath = themeConfig.site.favicon.startsWith('http')
? themeConfig.site.favicon
: `./public${themeConfig.site.favicon}`
// Convert to page data objects
const pages = Object.fromEntries(
blogEntries.map(({ slug, data }) => [
slug,
blogEntries.map(post => [
post.slug,
{
title: data.title,
description: data.description || '',
title: post.data.title,
description: post.data.description || generateDescription(post),
},
]),
)
@ -22,7 +29,27 @@ export const { getStaticPaths, GET } = OGImageRoute({
getImageOptions: (_path, page) => ({
title: page.title,
description: page.description,
border: { width: 10 },
padding: 40,
logo: {
path: logoPath,
size: [80],
},
font: {
title: {
families: ['Noto Sans SC'],
weight: 'Bold',
color: [34, 33, 36],
lineHeight: 1.5,
},
description: {
families: ['Noto Sans SC'],
color: [72, 71, 74],
lineHeight: 1.5,
},
},
fonts: [
'https://raw.githubusercontent.com/notofonts/noto-cjk/main/Sans/SubsetOTF/SC/NotoSansSC-Bold.otf',
'https://raw.githubusercontent.com/notofonts/noto-cjk/main/Sans/SubsetOTF/SC/NotoSansSC-Regular.otf',
],
bgGradient: [[242, 241, 245]],
}),
})

View file

@ -5,7 +5,7 @@ import sanitizeHtml from 'sanitize-html'
const parser = new MarkdownIt()
// Generate an excerpt from Markdown content
export function generateExcerpt(content: string, length: number = 100): string {
export function generateExcerpt(content: string, length: number = 98): string {
if (!content)
return ''