-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontentlayer.config.ts
143 lines (127 loc) · 3.8 KB
/
contentlayer.config.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import fs from 'fs'
import path from 'path'
import { defineDocumentType, makeSource } from 'contentlayer2/source-files'
import type { Options, LineElement, CharsElement } from 'rehype-pretty-code'
import rehypePrettyCode from 'rehype-pretty-code'
import rehypeSlug from 'rehype-slug'
import { codeImport } from 'remark-code-import'
import { visit } from 'unist-util-visit'
/* @SOURCE for rehype content blocks; https://github.com/shadcn/ui/blob/main/apps/www/contentlayer.config.js */
const rehypePrettyCodeOptions: Options = {
// Use one of Shiki's packaged themes
theme: 'one-dark-pro',
// Keep the background or use a custom background color
keepBackground: false,
// Prevent collapsing of single-line blocks
grid: true,
onVisitHighlightedLine(element: LineElement) {
// Each line element by default has `[data-line]`
element.properties.className?.push('highlighted')
},
onVisitHighlightedChars(element: CharsElement) {
// Each word element has no className by default
element.properties.className = ['word']
},
}
export const Post = defineDocumentType(() => ({
name: 'Post',
filePathPattern: './articles/*.mdx',
contentType: 'mdx',
fields: {
title: {
type: 'string',
description: 'The title of the post',
required: true,
},
date: {
type: 'date',
description: 'The date of the post',
required: true,
},
excerpt: {
type: 'string',
description: 'The excerpt of the post',
required: false,
},
},
computedFields: {
url: {
type: 'string',
resolve: (post) => `/${post._raw.flattenedPath}`,
},
slug: {
type: 'string',
resolve: (post) => post._raw.flattenedPath.replace('articles/', ''),
},
},
}))
export const Static = defineDocumentType(() => ({
name: 'Static',
filePathPattern: './data/*.mdx',
contentType: 'mdx',
fields: {
title: {
type: 'string',
description: 'The title of the post',
required: true,
},
},
computedFields: {
slug: {
type: 'string',
resolve: (post) => post._raw.flattenedPath.replace('data/', ''),
},
},
}))
const GENERATED_FILE_PATH = path.resolve('.contentlayer/generated/index.mjs')
export default makeSource({
contentDirPath: 'content',
documentTypes: [Post, Static],
mdx: {
remarkPlugins: [codeImport],
rehypePlugins: [
() => (tree) => {
visit(tree, (node) => {
if (node?.type === 'element' && node?.tagName === 'pre') {
const [codeEl] = node.children
if (codeEl.tagName !== 'code') {
return
}
node.__rawString__ = codeEl.children?.[0].value
node.__src__ = node.properties?.__src__
}
})
},
[rehypePrettyCode, rehypePrettyCodeOptions],
() => (tree) => {
visit(tree, (node) => {
if (node?.type === 'element' && node?.tagName === 'figure') {
if (!('data-rehype-pretty-code-figure' in node.properties)) {
return
}
const preElement = node.children.at(-1)
if (preElement.tagName !== 'pre') {
return
}
preElement.properties.__rawString__ = node.__rawString__
if (node.__src__) {
preElement.properties.__src__ = node.__src__
}
}
})
},
rehypeSlug,
],
},
onSuccess: async () => {
if (fs.existsSync(GENERATED_FILE_PATH)) {
let content = fs.readFileSync(GENERATED_FILE_PATH, 'utf-8')
// Remove invalid syntax like `with { type: 'json' }`
content = content.replace(/ with \{.*?\}/g, '')
fs.writeFileSync(GENERATED_FILE_PATH, content, 'utf-8')
console.log(
'Patched .contentlayer/generated/index.mjs after Contentlayer generation.'
)
}
},
})