--- import { type CollectionEntry, getCollection, render } from 'astro:content'; import BlogPost from '../../layouts/BlogPost.astro'; import * as Gemtext from 'gemtext'; export async function getStaticPaths() { const posts = await getCollection('blog'); return posts.map((post) => ({ params: { slug: post.id }, props: post, })); } type Props = CollectionEntry<'blog'>; function htmlEscape(str: string) { return str.replace(/&/g, '&').replace(//g, '>'); } const GemtextHTMLRenderer: Gemtext.Renderer = { preamble: function (): string { return ''; }, postamble: function (): string { return ''; }, text: function (content: string): string { content = content.trim(); if (content === '') { return ''; } return `

${htmlEscape(content)}

` }, link: function (url: string, alt: string): string { url = url.replaceAll(/^\/images\//g, '/images/capsule/'); const imgExtensions: (string | undefined)[] = ['webp', 'png', 'svg', 'gif', 'jpg', 'jpeg', 'apng'] if (imgExtensions.includes(url.split('.').at(-1)?.toLowerCase())) { return `${alt}`; } return `

=> ${alt}

`; }, preformatted: function (content: string[], alt: string): string { return `
${htmlEscape(content.join('\n'))}
` }, heading: function (level: number, text: string): string { return `${htmlEscape(text)}`; }, unorderedList: function (content: string[]): string { return ``; }, quote: function (content: string): string { return `
${htmlEscape(content)}
`; } }; function postProcessGemtextToHtml(html: string): string { html = mergeAdjacentBlockquotes(html); return html; } function mergeAdjacentBlockquotes(html: string): string { return html.replaceAll(/\<\/blockquote\>\/gm, '
'); } const post = Astro.props; const Content = post.filePath?.endsWith('.gmi') ? postProcessGemtextToHtml(Gemtext.parse((post.body ?? '').replace(`# ${post.data.title}`, '')).generate(GemtextHTMLRenderer)) : (await render(post)).Content; --- { post.filePath?.endsWith('.gmi') ? : }