chore: improve article auto-excerpt, allow inline code to wrap

This commit is contained in:
radishzzz 2025-04-15 16:53:29 +01:00
parent dfc30d7f85
commit 018f1c9b6c
11 changed files with 230 additions and 58 deletions

View file

@ -8,7 +8,7 @@ lang: zh
abbrlink: birth-of-retypeset
---
[Retypeset](https://github.com/radishzzz/astro-theme-retypeset) 是一款基于 Astro 框架的静态博客主题,中文名为重新编排。作为一名编程小白,我花三个月时间开发了这款主题,感受颇多。这篇文章,就来分享一下 Retypeset 诞生的故事。
Retypeset 是一款基于 Astro 框架的静态博客主题,中文名为重新编排。作为一名编程小白,我花三个月时间开发了这款主题,感受颇多。这篇文章,就来分享一下 Retypeset 诞生的故事。
## 初遇

View file

@ -14,7 +14,7 @@ Retypeset is a static blog theme based on the [Astro](https://astro.build/) fram
## Theme Configuration
Customize your blog through the configuration file [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts).
Customize your blog by modifying the configuration file [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts).
### Site Information

View file

@ -14,7 +14,7 @@ Retypeset es un tema de blog estático basado en el framework [Astro](https://as
## Configuración del Tema
Personaliza tu blog a través del archivo de configuración [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts).
Personaliza tu blog mediante la modificación del archivo de configuración [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts).
### Información del Sitio

View file

@ -10,11 +10,11 @@ lang: ja
abbrlink: theme-guide
---
Retypesetは、日本語では「再組版」と呼ばれる、[Astro](https://astro.build/) フレームワークをベースにした静的ブログテーマです。本ガイドではテーマの設定方法と新しい記事の作成方法を紹介し、個人ブログを素早く構築できるようサポートします。
Retypesetは、日本語では「再組版」と呼ばれる、[Astro](https://astro.build/) フレームワークをベースにした静的ブログテーマです。本ガイドではテーマの設定方法と新しい記事の作成方法を紹介し、個人ブログを素早く構築できるよう支援します。
## テーマ設定
設定ファイル [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts) からあなたのブログをカスタマイズできます。
設定ファイル [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts) を変更してあなたのブログをカスタマイズできます。
### サイト情報

View file

@ -14,7 +14,7 @@ Retypeset — это статическая тема блога, основан
## Конфигурация темы
Настройте свой блог через конфигурационный файл [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts).
Настройте свой блог путем изменения конфигурационного файла [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts).
### Информация о сайте

View file

@ -10,11 +10,11 @@ lang: zh-tw
abbrlink: theme-guide
---
Retypeset 是一款基於 [Astro](https://astro.build/) 框架的靜態部落格主題,中文名為重新編排。本文為 Retypeset 主題上手指南,主要介紹主題配置與如何創建新文章,幫助你快速搭建個人部落格。
Retypeset 是一款基於 [Astro](https://astro.build/) 框架的靜態部落格主題,中文名為重新編排。本文為 Retypeset 主題上手指南,主要介紹主題配置與如何創建新文章,幫助你快速搭建個人部落格。
## 主題配置
通過配置文件 [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts) 自定義你的部落格。
通過修改配置文件 [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts) 自定義你的部落格。
### 站點信息

View file

@ -10,11 +10,11 @@ lang: zh
abbrlink: theme-guide
---
Retypeset 是一款基于 [Astro](https://astro.build/) 框架的静态博客主题,中文名为重新编排。本文为 Retypeset 主题上手指南,主要介绍主题配置与如何创建新文章,帮助你快速搭建个人博客。
Retypeset 是一款基于 [Astro](https://astro.build/) 框架的静态博客主题,中文名为重新编排。本文为 Retypeset 主题上手指南,主要介绍主题配置与如何创建新文章,帮助你快速搭建个人博客。
## 主题配置
通过配置文件 [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts) 自定义你的博客。
通过修改配置文件 [src/config.ts](https://github.com/radishzzz/astro-theme-retypeset/blob/master/src/config.ts) 自定义你的博客。
### 站点信息

View file

@ -19,7 +19,7 @@
/* Links */
.heti :where(a) {
--at-apply: 'underline decoration-secondary/40 underline-0.075em underline-offset-0.14em lg:underline-0.1em';
--at-apply: 'underline decoration-secondary/40 underline-0.075em underline-offset-0.1em lg:underline-0.1em';
--at-apply: 'font-medium transition-colors tracking-0 hover:(c-primary decoration-secondary/80) ';
}
@ -102,7 +102,7 @@ html.dark .heti pre :where(span) {
/* Inline Code */
.heti :where(code) {
--at-apply: 'p-0.5 bg-secondary/5 rounded text-0.85em border border-solid border-secondary/5';
--at-apply: 'px-1 py-0.5 bg-secondary/5 rounded text-0.85em border border-solid border-secondary/5 break-all';
counter-reset: line;
}
.heti :where(code) span.line {

View file

@ -30,6 +30,15 @@ const EXCERPT_LENGTHS: Record<ExcerptScene, {
},
}
const HTML_ENTITIES: Record<string, string> = {
'&lt;': '<',
'&gt;': '>',
'&amp;': '&',
'&quot;': '"',
'&apos;': '\'',
'&nbsp;': ' ',
}
// Generate an excerpt from Markdown content
export function generateExcerpt(
content: string,
@ -39,33 +48,41 @@ export function generateExcerpt(
if (!content)
return ''
// Remove Markdown headings
const contentWithoutHeadings = content
.replace(/^#{1,6}\s+\S.*$/gm, '')
.replace(/\n{2,}/g, '\n\n')
const length = isCJKLang(lang)
? EXCERPT_LENGTHS[scene].cjk
: EXCERPT_LENGTHS[scene].other
// Remove all HTML tags and decode HTML entities
const plainText = parser.render(content)
// Remove all HTML tags
let plainText = parser.render(contentWithoutHeadings)
.replace(/<[^>]*>/g, '')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
.replace(/&quot;/g, '"')
.replace(/&apos;/g, '\'')
.replace(/&nbsp;/g, ' ')
// Decode HTML entities using the mapping table
Object.entries(HTML_ENTITIES).forEach(([entity, char]) => {
plainText = plainText.replace(new RegExp(entity, 'g'), char)
})
// Replace line breaks with spaces
const normalizedText = plainText.replace(/\s+/g, ' ')
// Remove spaces after CJK punctuation marks
.replace(/([。?!:"」』])\s+/g, '$1')
const excerpt = normalizedText.slice(0, length).trim()
// Add ellipsis if text was truncated
return normalizedText.length > length ? `${excerpt}...` : excerpt
// Remove trailing punctuation from the excerpt
if (normalizedText.length > length)
return `${excerpt.replace(/\p{P}+$/u, '')}...`
return excerpt
}
// Automatically generate a description for the article
// Automatically Generate article description
export function generateDescription(
post: CollectionEntry<'posts'>,
scene: ExcerptScene,
): string {
// If the article already has a description, return it directly
// Prioritize existing description
if (post.data.description)
return post.data.description