Migrate blog to new astro Content Collections

This commit is contained in:
prototypa
2023-01-01 18:32:52 -05:00
parent 785b66968a
commit d7b7baa414
15 changed files with 71 additions and 40 deletions

4
.gitignore vendored
View File

@ -20,4 +20,6 @@ pnpm-debug.log*
.DS_Store .DS_Store
package-lock.json package-lock.json
pnpm-lock.yaml pnpm-lock.yaml
src/content/types.generated.d.ts

View File

@ -55,4 +55,8 @@ export default defineConfig({
}, },
}, },
}, },
experimental: {
contentCollections: true,
},
}); });

View File

View File

@ -1,7 +1,7 @@
{ {
"name": "@onwidget/astrowind", "name": "@onwidget/astrowind",
"description": "A template to make your website using Astro + Tailwind CSS.", "description": "A template to make your website using Astro + Tailwind CSS.",
"version": "0.8.7", "version": "0.9.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "astro dev", "dev": "astro dev",

View File

@ -4,10 +4,10 @@ import Grid from '~/components/blog/Grid.astro';
import { findPostsByIds } from '~/utils/posts'; import { findPostsByIds } from '~/utils/posts';
const ids = [ const ids = [
'get-started-website-with-astro-tailwind-css', 'get-started-website-with-astro-tailwind-css.md',
'how-to-customize-astrowind-to-your-brand', 'how-to-customize-astrowind-to-your-brand.md',
'useful-resources-to-create-websites', 'useful-resources-to-create-websites.md',
'astrowind-template-in-depth', 'astrowind-template-in-depth.md',
]; ];
const posts = await findPostsByIds(ids); const posts = await findPostsByIds(ids);
--- ---

View File

@ -54,10 +54,10 @@ const items = [
<div class="space-y-8"> <div class="space-y-8">
{subitems.map(({ question, answer }) => ( {subitems.map(({ question, answer }) => (
<div> <div>
<p class="mb-4 text-xl font-bold"> <h3 class="mb-4 text-xl font-bold">
<Icon name="tabler:arrow-down-right" class="w-7 h-7 text-primary-500 inline-block" /> <Icon name="tabler:arrow-down-right" class="w-7 h-7 text-primary-500 inline-block" />
{question} {question}
</p> </h3>
{answer.split('\n\n').map((paragraph) => ( {answer.split('\n\n').map((paragraph) => (
<p class="text-gray-700 dark:text-gray-400 mb-2" set:html={paragraph} /> <p class="text-gray-700 dark:text-gray-400 mb-2" set:html={paragraph} />
))} ))}

27
src/content/config.js Normal file
View File

@ -0,0 +1,27 @@
import { z, defineCollection } from 'astro:content';
const blog = defineCollection({
schema: {
title: z.string(),
description: z.string().optional(),
image: z.string().optional(),
canonical: z.string().url().optional(),
permalink: z.string().optional(),
publishDate: z.string().transform((str) => new Date(str)),
draft: z.boolean().optional(),
excerpt: z.string().optional(),
category: z.string().optional(),
tags: z.array(z.string()).optional(),
authors: z.array(z.string()).optional(),
},
slug: ({ defaultSlug, data }) => {
return data.permalink || defaultSlug;
},
});
export const collections = {
blog: blog,
};

View File

@ -2,7 +2,7 @@ import slugify from 'limax';
import { SITE, BLOG } from '~/config.mjs'; import { SITE, BLOG } from '~/config.mjs';
const trim = (str, ch) => { const trim = (str = "", ch) => {
let start = 0, let start = 0,
end = str.length || 0; end = str.length || 0;
while (start < end && str[start] === ch) ++start; while (start < end && str[start] === ch) ++start;

View File

@ -1,44 +1,29 @@
import { getCollection, getEntry } from 'astro:content';
const getNormalizedPost = async (post) => { const getNormalizedPost = async (post) => {
const { frontmatter, Content, file } = post; const { id, slug, data } = post;
const ID = file.split('/').pop().split('.').shift(); const { Content, injectedFrontmatter } = await post.render();
return { return {
id: ID, id: id,
slug: slug,
publishDate: frontmatter.publishDate, ...data,
draft: frontmatter.draft,
canonical: frontmatter.canonical,
slug: frontmatter.slug || ID,
title: frontmatter.title,
description: frontmatter.description,
image: frontmatter.image,
Content: Content, Content: Content,
// or 'body' in case you consume from API // or 'body' in case you consume from API
excerpt: frontmatter.excerpt, readingTime: injectedFrontmatter.readingTime,
authors: frontmatter.authors,
category: frontmatter.category,
tags: frontmatter.tags,
readingTime: frontmatter.readingTime,
}; };
}; };
const load = async function () { const load = async function () {
const posts = import.meta.glob(['~/../data/blog/**/*.md', '~/../data/blog/**/*.mdx'], { const posts = await getCollection('blog');
eager: true, const normalizedPosts = posts.map(async (post) => await getNormalizedPost(post));
});
const normalizedPosts = Object.keys(posts).map(async (key) => {
const post = await posts[key];
return await getNormalizedPost(post);
});
const results = (await Promise.all(normalizedPosts)) const results = (await Promise.all(normalizedPosts))
.sort((a, b) => new Date(b.publishDate).valueOf() - new Date(a.publishDate).valueOf()) .sort((a, b) => b.publishDate.valueOf() - a.publishDate.valueOf())
.filter((post) => !post.draft); .filter((post) => !post.draft);
return results; return results;
}; };
@ -52,19 +37,31 @@ export const fetchPosts = async () => {
}; };
/** */ /** */
export const findPostsByIds = async (ids) => { export const findPostsBySlugs = async (slugs) => {
if (!Array.isArray(ids)) return []; if (!Array.isArray(slugs)) return [];
const posts = await fetchPosts(); const posts = await fetchPosts();
return ids.reduce(function (r, id) { return slugs.reduce(function (r, slug) {
posts.some(function (post) { posts.some(function (post) {
return id === post.id && r.push(post); return slug === post.slug && r.push(post);
}); });
return r; return r;
}, []); }, []);
}; };
/** */
export const findPostsByIds = async (ids) => {
if (!Array.isArray(ids)) return [];
return await Promise.all(
ids.map(async (id) => {
const post = await getEntry('blog', id);
return await getNormalizedPost(post);
})
);
};
/** */ /** */
export const findLatestPosts = async ({ count }) => { export const findLatestPosts = async ({ count }) => {
const _count = count || 4; const _count = count || 4;

View File

@ -2,6 +2,7 @@
"extends": "astro/tsconfigs/base", "extends": "astro/tsconfigs/base",
"compilerOptions": { "compilerOptions": {
"types": ["astro/client"], "types": ["astro/client"],
"strictNullChecks": true,
"allowJs": true, "allowJs": true,
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {