contentlayer-datapad
v1.0.22
Published
Awesome Contentlayer configuration with GFM, LQIP, TOC and more.
Downloads
166
Maintainers
Readme
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>
));