feat(blog): improve blog overview teasers layout
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 19s
Build & Deploy / 🧪 QA (push) Successful in 5m42s
Build & Deploy / 🏗️ Build (push) Failing after 31s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Smoke Test (push) Has been skipped
Build & Deploy / ⚡ Lighthouse (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 19s
Build & Deploy / 🧪 QA (push) Successful in 5m42s
Build & Deploy / 🏗️ Build (push) Failing after 31s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Smoke Test (push) Has been skipped
Build & Deploy / ⚡ Lighthouse (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s
Increases the line clamps for title and excerpt in the blog overview grid. Also parses the markdown content to auto-generate a fallback excerpt if omitted in frontmatter.
This commit is contained in:
40
lib/blog.ts
40
lib/blog.ts
@@ -4,6 +4,31 @@ import matter from 'gray-matter';
|
||||
import { mapSlugToFileSlug } from './slugs';
|
||||
import { config } from '@/lib/config';
|
||||
|
||||
export function extractExcerpt(content: string): string {
|
||||
if (!content) return '';
|
||||
// Remove frontmatter if present (though matter() usually strips it out)
|
||||
let text = content.replace(/^---[\s\S]*?---/, '');
|
||||
// Remove MDX component imports and usages
|
||||
text = text.replace(/<[^>]+>/g, '');
|
||||
text = text.replace(/^[ \t]*import\s+.*$/gm, '');
|
||||
text = text.replace(/^[ \t]*export\s+.*$/gm, '');
|
||||
// Remove markdown headings
|
||||
text = text.replace(/^#+.*$/gm, '');
|
||||
// Extract first paragraph or combined lines
|
||||
const paragraphs = text
|
||||
.split(/\n\s*\n/)
|
||||
.filter((p) => p.trim() && !p.trim().startsWith('---') && !p.trim().startsWith('#'));
|
||||
if (paragraphs.length === 0) return '';
|
||||
|
||||
const excerpt = paragraphs[0]
|
||||
.replace(/[*_`]/g, '') // remove markdown bold/italic/code
|
||||
.replace(/\[(.*?)\]\(.*?\)/g, '$1') // replace links with their text
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
|
||||
return excerpt.length > 200 ? excerpt.slice(0, 197) + '...' : excerpt;
|
||||
}
|
||||
|
||||
export interface PostFrontmatter {
|
||||
title: string;
|
||||
date: string;
|
||||
@@ -46,7 +71,10 @@ export async function getPostBySlug(slug: string, locale: string): Promise<PostM
|
||||
|
||||
const postInfo = {
|
||||
slug: fileSlug,
|
||||
frontmatter: data as PostFrontmatter,
|
||||
frontmatter: {
|
||||
...data,
|
||||
excerpt: data.excerpt || extractExcerpt(content),
|
||||
} as PostFrontmatter,
|
||||
content,
|
||||
};
|
||||
|
||||
@@ -70,7 +98,10 @@ export async function getAllPosts(locale: string): Promise<PostMdx[]> {
|
||||
const { data, content } = matter(fileContent);
|
||||
return {
|
||||
slug: file.replace(/\.mdx$/, ''),
|
||||
frontmatter: data as PostFrontmatter,
|
||||
frontmatter: {
|
||||
...data,
|
||||
excerpt: data.excerpt || extractExcerpt(content),
|
||||
} as PostFrontmatter,
|
||||
content,
|
||||
};
|
||||
})
|
||||
@@ -95,7 +126,10 @@ export async function getAllPostsMetadata(locale: string): Promise<Partial<PostM
|
||||
const { data } = matter(fileContent);
|
||||
return {
|
||||
slug: file.replace(/\.mdx$/, ''),
|
||||
frontmatter: data as PostFrontmatter,
|
||||
frontmatter: {
|
||||
...data,
|
||||
excerpt: data.excerpt || extractExcerpt(fileContent.replace(/^---[\s\S]*?---/, '')),
|
||||
} as PostFrontmatter,
|
||||
};
|
||||
})
|
||||
.filter(isPostVisible)
|
||||
|
||||
Reference in New Issue
Block a user