import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { LitroPage } from '@beatzball/litro/runtime';
import { definePageData } from '@beatzball/litro';
import type { Post } from 'litro:content';
import { getPosts } from 'litro:content';
import { siteConfig } from '../../server/starlight.config.js';
import { starlightHead } from '../../src/route-meta.js';
import { formatDate, isoDate } from '../../src/date-utils.js';
// Register components used in render()
import '../../src/components/starlight-header.js';
export interface BlogIndexData {
posts: Post[];
siteTitle: string;
nav: typeof siteConfig.nav;
}
export const pageData = definePageData(async (_event) => {
const all = await getPosts();
// Filter to only blog posts (URL prefix from contentDir='content')
const posts = all.filter(p => p.url.startsWith('/content/blog/'));
return {
posts,
siteTitle: siteConfig.title,
nav: siteConfig.nav,
} satisfies BlogIndexData;
});
export const routeMeta = {
head: starlightHead,
title: 'Blog — {{projectName}}',
};
@customElement('page-blog')
export class BlogIndexPage extends LitroPage {
override render() {
const data = this.serverData as BlogIndexData | null;
const { posts = [], siteTitle = '{{projectName}}', nav = [] } = data ?? {};
return html`
Blog
${posts.length === 0 ? html`
No posts yet.
` : html`
${posts.map(post => {
const blogSlug = post.url.slice('/content/blog/'.length);
return html`
-
${post.title}
${post.description ? html`
${post.description}
` : ''}
${post.tags.filter(t => t !== 'posts').length > 0 ? html`
${post.tags.filter(t => t !== 'posts').map(tag => html`
#${tag}
`)}
` : ''}
`;
})}
`}
`;
}
}
export default BlogIndexPage;