prmbr-image-mksaas/content-collections.ts

139 lines
3.6 KiB
TypeScript

import { defineCollection, defineConfig } from "@content-collections/core";
import { compileMDX } from "@content-collections/mdx";
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
import rehypePrettyCode, { Options } from 'rehype-pretty-code';
import rehypeSlug from 'rehype-slug';
import { codeImport } from 'remark-code-import';
import remarkGfm from 'remark-gfm';
import { createHighlighter } from 'shiki';
import path from "path";
import { getBaseUrl } from "@/lib/urls/get-base-url";
/**
* Content Collections documentation
* 1. https://www.content-collections.dev/docs/quickstart/next
* 2. https://www.content-collections.dev/docs/configuration
* 3. https://www.content-collections.dev/docs/transform#join-collections
*/
/**
* Blog Author collection
*/
export const authors = defineCollection({
name: 'author',
directory: 'content',
include: '**/author/*.mdx',
schema: (z) => ({
slug: z.string(),
name: z.string(),
avatar: z.string()
}),
transform: async (data, context) => {
return {
...data,
avatar: getBaseUrl() + data.avatar
};
}
});
/**
* Blog Category collection
*/
export const categories = defineCollection({
name: 'category',
directory: 'content',
include: '**/category/*.mdx',
schema: (z) => ({
slug: z.string(),
name: z.string(),
description: z.string()
})
});
/**
* Blog Post collection
*
* 1. For a blog post file at content/blog/2023/year-review.mdx:
* slug: /blog/2023/year-review
* slugAsParams: 2023/year-review
*
* 2. For a blog post at content/blog/first-post.mdx:
* slug: /blog/first-post
* slugAsParams: first-post
*/
export const posts = defineCollection({
name: 'post',
directory: 'content',
include: '**/blog/*.mdx',
schema: (z) => ({
title: z.string(),
description: z.string(),
image: z.string(),
date: z.string().datetime(),
published: z.boolean().default(true),
categories: z.array(z.string()),
author: z.string()
}),
transform: async (data, context) => {
const body = await compileMDX(context, data, {
remarkPlugins: [
remarkGfm,
codeImport
],
rehypePlugins: [
rehypeSlug,
rehypeAutolinkHeadings,
[rehypePrettyCode, prettyCodeOptions]
]
});
const blogAuthor = context
.documents(authors)
.find((a) => a.slug === data.author);
const blogCategories = context
.documents(categories)
.filter((c) => data.categories.includes(c.slug));
return {
...data,
author: blogAuthor,
categories: blogCategories,
image: getBaseUrl() + data.image,
slug: `/${data._meta.path}`,
slugAsParams: data._meta.path.split(path.sep).slice(1).join('/'),
body: {
raw: data.content,
code: body
}
};
}
});
const prettyCodeOptions: Options = {
theme: 'github-dark',
getHighlighter: (options) =>
createHighlighter({
...options
}),
onVisitLine(node) {
// Prevent lines from collapsing in `display: grid` mode, and allow empty
// lines to be copy/pasted
if (node.children.length === 0) {
node.children = [{ type: 'text', value: ' ' }];
}
},
onVisitHighlightedLine(node) {
if (!node.properties.className) {
node.properties.className = [];
}
node.properties.className.push('line--highlighted');
},
onVisitHighlightedChars(node) {
if (!node.properties.className) {
node.properties.className = [];
}
node.properties.className = ['word--highlighted'];
}
};
export default defineConfig({
collections: [authors, categories, posts]
});