Files
myeasycms-v2/apps/web/contentlayer.config.js
giancarlo bce3479368 Cleanup
2024-03-24 02:23:22 +08:00

222 lines
5.1 KiB
JavaScript

import { defineDocumentType, makeSource } from 'contentlayer/source-files';
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
import rehypeSlug from 'rehype-slug';
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000';
export const Post = defineDocumentType(() => ({
name: 'Post',
filePathPattern: `posts/*.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,
},
live: {
type: 'boolean',
description: 'Whether the post is live or not',
required: true,
default: false,
},
image: {
type: 'string',
description: 'The path to the cover image',
},
description: {
type: 'string',
description: 'The description of the post',
},
},
computedFields: {
url: {
type: 'string',
resolve: (post) => `/blog/${getSlug(post._raw.sourceFileName)}`,
},
readingTime: {
type: 'number',
resolve: (post) => calculateReadingTime(post.body.raw),
},
slug: {
type: 'string',
resolve: (post) => getSlug(post._raw.sourceFileName),
},
structuredData: {
type: 'object',
resolve: (doc) => ({
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: doc.title,
datePublished: doc.date,
dateModified: doc.date,
description: doc.description,
image: [siteUrl, doc.image].join(''),
url: [siteUrl, 'blog', doc._raw.flattenedPath].join('/'),
author: {
'@type': 'Organization',
name: `Makerkit`,
},
}),
},
},
}));
export const DocumentationPage = defineDocumentType(() => ({
name: 'DocumentationPage',
filePathPattern: `docs/**/*.mdx`,
contentType: 'mdx',
fields: {
title: {
type: 'string',
description: 'The title of the post',
required: true,
},
label: {
type: 'string',
description: 'The label of the page in the sidebar',
required: true,
},
cardCTA: {
type: 'string',
description: 'The label of the CTA link on the card',
required: false,
},
description: {
type: 'string',
description: 'The description of the post',
},
show_child_cards: {
type: 'boolean',
default: false,
},
collapsible: {
type: 'boolean',
required: false,
default: false,
},
collapsed: {
type: 'boolean',
required: false,
default: false,
},
},
computedFields: {
url: {
type: 'string',
resolve: (post) => `/blog/${getSlug(post._raw.sourceFileName)}`,
},
readingTime: {
type: 'number',
resolve: (post) => calculateReadingTime(post.body.raw),
},
slug: {
type: 'string',
resolve: (post) => getSlug(post._raw.sourceFileName),
},
structuredData: {
type: 'object',
resolve: (doc) => ({
'@context': 'https://schema.org',
'@type': 'LearningResource',
headline: doc.title,
datePublished: doc.date,
dateModified: doc.date,
description: doc.description,
image: [siteUrl, doc.image].join(''),
url: [siteUrl, 'blog', doc._raw.flattenedPath].join('/'),
author: {
'@type': 'Organization',
name: `Makerkit`,
},
}),
},
path: {
type: 'string',
resolve: (doc) => {
if (doc._id.startsWith('docs/index.md')) {
return '/docs';
}
return urlFromFilePath(doc);
},
},
pathSegments: {
type: 'json',
resolve: (doc) => getPathSegments(doc).map(getMetaFromFolderName),
},
resolvedPath: {
type: 'string',
resolve: (doc) => {
return getPathSegments(doc)
.map(getMetaFromFolderName)
.map(({ pathName }) => pathName)
.join('/');
},
},
},
}));
export default makeSource({
contentDirPath: './content',
documentTypes: [Post, DocumentationPage],
mdx: {
remarkPlugins: [],
rehypePlugins: [
rehypeSlug,
[
rehypeAutolinkHeadings,
{
properties: {
className: ['anchor'],
},
},
],
],
},
});
function calculateReadingTime(content) {
const wordsPerMinute = 235;
const numberOfWords = content.split(/\s/g).length;
const minutes = numberOfWords / wordsPerMinute;
return Math.ceil(minutes);
}
function getSlug(fileName) {
return fileName.replace('.mdx', '');
}
function urlFromFilePath(doc) {
let urlPath = doc._raw.flattenedPath.replace(/^app\/?/, '/');
if (!urlPath.startsWith('/')) {
urlPath = `/${urlPath}`;
}
return urlPath;
}
function getMetaFromFolderName(dirName) {
const re = /^((\d+)-)?(.*)$/;
const [, , orderStr, pathName] = dirName.match(re) ?? [];
const order = orderStr ? parseInt(orderStr) : 0;
return { order, pathName };
}
function getPathSegments(doc) {
return (
urlFromFilePath(doc)
.split('/')
// skip `/docs` prefix
.slice(2)
);
}