contentlayer-datapad
v1.0.22 contentlayer config datapad reading time table of contents lqip
datapad
Awesome Contentlayer configuration with GFM, LQIP, TOC and more.
It includes the following plugins:
- GitHub Flavored Markdown via remark-gfm
- Syntax Highlighting via rehype-pretty-code and shiki
ids
on headings via rehype-slug- Anchor links on headings via rehype-autolink-headings
- Accessible emojis via rehype-accessible-emojis
- Reading time via reading-time
- Minification via rehype-preset-minify
- Table of Contents extraction via pliny/mdx-plugins
- LQIP image generation via lqip-modern for next/image
Installation
yarn add contentlayer-datapad
Setup
import { defineDocumentType, makeSource } from 'contentlayer/source-files';
import {
computeFields,
remarkPlugins,
rehypePlugins,
} from 'contentlayer-datapad';
export const Blog = defineDocumentType(() => ({
name: 'Blog',
filePathPattern: `blog/**/*.mdx`,
contentType: 'mdx',
fields: {
title: {
type: 'string',
required: true,
},
description: {
type: 'string',
required: true,
},
date: {
type: 'date',
required: true,
},
image: {
type: 'string',
required: false,
},
},
computedFields: computeFields<'Blog'>({}),
}));
const source = makeSource({
contentDirPath: './content',
documentTypes: [Blog],
mdx: {
remarkPlugins: remarkPlugins(),
rehypePlugins: rehypePlugins({}),
},
});
export default source;
Also, update your Tailwind config to include the following:
import type { Config } from 'tailwindcss';
const config: Config = {
content: ['./node_modules/contentlayer-datapad/**/*.js'],
// ...
};
export default config;
Configuration
computeFields
computeFields
accepts a configuration object with the following properties:
Property | Type | Description | Default |
---|---|---|---|
openGraphEndpoint | string |
The endpoint of the Open Graph image generator (i.e. @vercel/og) | '/api/og' |
imagesFolder | string |
The folder where your images are stored, prepended to the document image path | './public' |
The computed fields are:
Field Name | Type | Description | Example Output |
---|---|---|---|
slug |
string |
The slug of the document, used in the URL | '/blog/my-post' |
slugAsParams |
string |
The slug as a path segment | 'my-post' |
readingTime |
string |
The estimated time to read the document, in minutes | '5 min read' |
toc |
json |
The table of contents of the document | [{ value: 'Heading 1', depth: 1, url: '#heading-1' }] |
imageBlur |
string |
The LQIP image data of the document | 'UklGRkgAAABXRUJQVlA4IDwAAADQAQCdASoQAAkABUB8JYwC7ADbW2wxAAD+5fWSusCgEGgrbEnESec12AakPGs5RtCwUs8GJTOZH7EgIAA=' |
remarkPlugins
remarkPlugins
does not accept any configuration.
rehypePlugins
rehypePlugins
accepts a configuration object with the following properties:
Property | Type | Description | Default |
---|---|---|---|
shikiTheme | Theme |
The theme to use for syntax highlighting | 'one-dark-pro' |
Usage
Here's how to use the custom fields in your Next.js app:
import { allBlogs } from 'contentlayer/generated';
import Image from 'next/image';
import type { Toc } from 'contentlayer-datapad';
return allBlogs.sort(sortBlogPostByDate).map((post) => (
<div key={post.name}>
<Image
src={src}
width={1920}
height={1080}
alt=""
blurDataURL={`data:image/jpg;base64,${post.imageBlur}`}
placeholder="blur"
/>
<p>{post.readingTime}</p>
<ul>
{(post.toc as Toc).map((item) => (
<li
key={item.url}
style={{
paddingLeft: `${item.depth - 2}rem`,
}}
>
<a href={item.url}>{item.value}</a>
</li>
))}
</ul>
</div>
));
npm i contentlayer-datapad
Metadata
- ISC
- Whatever
- Hayden Bleasel
- released 1/19/2024