Cascade uses Contentlayer as its blog tool of choice. Contentlayer is a content management system that allows you to create, edit, and manage content in a structured way directly in your code.
You can swap Contentlayer with any other CMS of your choice. You will have to
change the way you fetch data and plug it into existing code.
Contentlayer offers thin API on top of your local filesystem. This allows you to write blogposts straight in your editor, you define the structure of your content in a simple configuration file and start writing your blog posts.
Copy
// contentlayer.config.tsimport { defineDocumentType, makeSource } from "contentlayer/source-files";import rehypeAutolinkHeadings from "rehype-autolink-headings";import rehypePrettyCode from "rehype-pretty-code";import rehypeSlug from "rehype-slug";export const Post = defineDocumentType(() => ({ name: "Post", filePathPattern: `blog/**/*.md`, contentType: "mdx", fields: { title: { type: "string", required: true }, image: { type: "string", required: true, }, description: { type: "string", required: true }, date: { type: "date", required: true }, published: { type: "boolean", required: true, default: false, }, }, computedFields: { slug: { type: "string", resolve: (post) => `/${post._raw.flattenedPath}`, }, slugAsParams: { type: "string", resolve: (doc) => doc._raw.flattenedPath.split("/").slice(1).join("/"), }, },}));export default makeSource({ contentDirPath: "./content", documentTypes: [Post], mdx: { rehypePlugins: [ rehypeSlug, [ //@ts-expect-error would still work even though types are incorrect, need to fix this after contentlayer gets enough maintenenace rehypePrettyCode, { theme: "dracula", onVisitLine(node: { children: string | unknown[] }) { // 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: { properties: { className: string[] }; }) { node.properties.className.push("line--highlighted"); }, onVisitHighlightedWord(node: { properties: { className: string[] }; }) { node.properties.className = ["word--highlighted"]; }, }, ], [ rehypeAutolinkHeadings, { properties: { className: ["subheading-anchor"], ariaLabel: "Link to section", }, }, ], ], },});