feat: ause astro collection to type safe data fetching

This commit is contained in:
Ruidy 2025-01-01 21:54:00 +01:00
parent edb5d23348
commit 5acac485c7
No known key found for this signature in database
GPG key ID: E00F51288CB857CC
10 changed files with 52 additions and 28 deletions

View file

@ -1,5 +1,4 @@
--- ---
layout: "../../layouts/BlogPostLayout.astro"
title: My first blog post title: My first blog post
description: This is my first blog post description: This is my first blog post
pubDate: 2024-12-30 pubDate: 2024-12-30

View file

@ -1,5 +1,4 @@
--- ---
layout: "../../layouts/BlogPostLayout.astro"
title: My Second Blog Post title: My Second Blog Post
author: Astro Learner author: Astro Learner
description: "After learning some Astro, I couldn't stop!" description: "After learning some Astro, I couldn't stop!"

View file

@ -1,5 +1,4 @@
--- ---
layout: "../../layouts/BlogPostLayout.astro"
title: My Third Blog Post title: My Third Blog Post
author: Astro Learner author: Astro Learner
description: "I had some challenges, but asking in the community really helped!" description: "I had some challenges, but asking in the community really helped!"

View file

@ -1,5 +1,4 @@
--- ---
layout: "../../layouts/BlogPostLayout.astro"
title: My Fourth Blog Post title: My Fourth Blog Post
author: Astro Learner author: Astro Learner
description: "This post will show up on its own!" description: "This post will show up on its own!"

19
src/content.config.ts Normal file
View file

@ -0,0 +1,19 @@
import { glob } from "astro/loaders";
import { defineCollection, z } from "astro:content";
const blog = defineCollection({
loader: glob({ pattern: "**/[^_]*.md", base: "./src/blog" }),
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.date(),
author: z.string(),
tags: z.array(z.string()),
image: z.object({
url: z.string(),
alt: z.string(),
}),
}),
});
export const collections = { blog };

View file

@ -4,7 +4,7 @@ const { frontmatter } = Astro.props;
--- ---
<BaseLayout pageTitle={frontmatter.title}> <BaseLayout pageTitle={frontmatter.title}>
<p>Published on: {frontmatter.pubDate.toString().slice(0, 10)}</p> <p>Published on: {frontmatter.pubDate.toLocaleDateString()}</p>
<p><em>{frontmatter.description}</em></p> <p><em>{frontmatter.description}</em></p>
<p>Written by: {frontmatter.author}</p> <p>Written by: {frontmatter.author}</p>
<img src={frontmatter.image.url} alt={frontmatter.image.alt} width="500" /> <img src={frontmatter.image.url} alt={frontmatter.image.alt} width="500" />

View file

@ -2,12 +2,11 @@
import "../styles/global.css"; import "../styles/global.css";
import BaseLayout from "../layouts/BaseLayout.astro"; import BaseLayout from "../layouts/BaseLayout.astro";
import BLogPost from "../components/BLogPost.astro"; import BLogPost from "../components/BLogPost.astro";
import { getCollection } from "astro:content";
const pageTitle = "Blog posts"; const pageTitle = "Blog posts";
const allPosts = Object.values( const allPosts = await getCollection("blog");
import.meta.glob("./posts/*.md", { eager: true }),
);
--- ---
<BaseLayout pageTitle={pageTitle}> <BaseLayout pageTitle={pageTitle}>
@ -16,7 +15,7 @@ const allPosts = Object.values(
<ul> <ul>
{ {
allPosts.map((post: any) => ( allPosts.map((post: any) => (
<BLogPost url={post.url} title={post.frontmatter.title} /> <BLogPost url=`blog/${post.id}/` title={post.data.title} />
)) ))
} }
</ul> </ul>

View file

@ -0,0 +1,19 @@
---
import { getCollection, render } from "astro:content";
import BlogPostLayout from "../../layouts/BlogPostLayout.astro";
export async function getStaticPaths() {
const posts = await getCollection("blog");
return posts.map((post) => ({
params: { slug: post.id },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await render(post);
---
<BlogPostLayout frontmatter={post.data}>
<Content />
</BlogPostLayout>

View file

@ -1,18 +1,13 @@
--- ---
import { getCollection } from "astro:content";
import BLogPost from "../../components/BLogPost.astro"; import BLogPost from "../../components/BLogPost.astro";
import BaseLayout from "../../layouts/BaseLayout.astro"; import BaseLayout from "../../layouts/BaseLayout.astro";
export async function getStaticPaths() { export async function getStaticPaths() {
const posts = Object.values( const posts = await getCollection("blog");
import.meta.glob("../posts/*.md", { eager: true }), const tags = [...new Set(posts.flatMap((post) => post.data.tags))];
); return tags.map((tag) => {
const tags = [ const filteredPosts = posts.filter((post) => post.data.tags?.includes(tag));
...new Set(posts.flatMap((post: any) => post.frontmatter.tags)),
];
return tags.map((tag: any) => {
const filteredPosts = posts.filter((post: any) =>
post.frontmatter.tags?.includes(tag),
);
return { params: { tag }, props: { posts: filteredPosts } }; return { params: { tag }, props: { posts: filteredPosts } };
}); });
} }
@ -25,8 +20,8 @@ const { posts } = Astro.props;
<p>Posts tagged with {tag}</p> <p>Posts tagged with {tag}</p>
<ul> <ul>
{ {
posts.map((post: any) => ( posts.map((post) => (
<BLogPost url={post.url} title={post.frontmatter.title} /> <BLogPost url=`/blog/${post.id}` title={post.data.title} />
)) ))
} }
</ul> </ul>

View file

@ -1,13 +1,9 @@
--- ---
import { getCollection } from "astro:content";
import BaseLayout from "../../layouts/BaseLayout.astro"; import BaseLayout from "../../layouts/BaseLayout.astro";
const tags = [ const posts = await getCollection("blog");
...new Set( const tags = [...new Set(posts.flatMap((post) => post.data.tags))];
Object.values(import.meta.glob("../posts/*.md", { eager: true })).flatMap(
(post: any) => post.frontmatter.tags,
),
),
];
--- ---
<BaseLayout pageTitle="Tags"> <BaseLayout pageTitle="Tags">