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

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:
2026-02-21 21:45:30 +01:00
parent 36455ef479
commit f696e55600
2 changed files with 40 additions and 6 deletions

View File

@@ -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)