Update content categorization and handle hierarchical documentation
Enhancements were implemented to support hierarchical documentation. Local CMS now respects parent ID and order attributes of content items, and content can be categories as 'blog' or 'documentation'. Changes were also made to the wordpress integration supporting these new categorizations. Introduced working with nested documentation pages.
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
title: Installing Makerkit
|
||||
label: Installing Makerkit
|
||||
description: Learn how to install Makerkit on your local machine
|
||||
categories:
|
||||
- documentation
|
||||
---
|
||||
|
||||
If you have bought a license for MakerKit, you have access to all the
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
title: Clone the MakerKit SaaS boilerplate repository
|
||||
label: Clone the repository
|
||||
description: Learn how to clone the MakerKit repository and install the NodeJS dependencies.
|
||||
categories:
|
||||
- documentation
|
||||
---
|
||||
|
||||
If you have bought a license for MakerKit, you have access to all the
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
title: Getting Started
|
||||
label: Getting Started
|
||||
description: Getting started with the Makerkit Kit
|
||||
categories:
|
||||
- documentation
|
||||
---
|
||||
|
||||
Makerkit is a Next.js/Remix SaaS Starter that helps you build your own SaaS in minutes. It comes with a fully integrated Stripe billing system, a landing page, and a dashboard.
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
title: Authentication Overview
|
||||
label: Overview
|
||||
description: Learn how authentication works in MakerKit and how to configure it.
|
||||
categories:
|
||||
- documentation
|
||||
---
|
||||
|
||||
The way you want your users to authenticate can be driven via configuration.
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
title: Supabase Setup
|
||||
label: Supabase Setup
|
||||
description: How to setup authentication in MakerKit using Supabase.
|
||||
categories:
|
||||
- documentation
|
||||
---
|
||||
|
||||
Supabase needs a few settings to be configured in their Dashboard to work correctly. This guide will walk you through the steps to get your Supabase authentication setup.
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
title: Authentication
|
||||
label: Authentication
|
||||
description: Learn everything about Authentication in Makerkit
|
||||
categories:
|
||||
- documentation
|
||||
---
|
||||
|
||||
MakerKit uses Supabase to manage authentication within your application.
|
||||
|
||||
@@ -6,7 +6,7 @@ description: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiu
|
||||
image: /assets/images/posts/lorem-ipsum.webp
|
||||
author: John Doe
|
||||
categories:
|
||||
- posts
|
||||
- blog
|
||||
---
|
||||
|
||||
## Fecerat avis invenio mentis
|
||||
|
||||
@@ -66,6 +66,13 @@ export const Post = defineDocumentType(() => ({
|
||||
type: 'string',
|
||||
resolve: (post) => `/blog/${getSlug(post._raw.sourceFileName)}`,
|
||||
},
|
||||
parentId: {
|
||||
type: 'string',
|
||||
resolve: (doc) => {
|
||||
const segments = getPathSegments(doc);
|
||||
return segments.length > 1 ? segments.slice(0, -1).join('/') : 'blog';
|
||||
},
|
||||
},
|
||||
structuredData: {
|
||||
type: 'object',
|
||||
resolve: (doc) => ({
|
||||
@@ -124,6 +131,33 @@ export const DocumentationPage = defineDocumentType(() => ({
|
||||
type: 'number',
|
||||
resolve: (post) => calculateReadingTime(post.body.raw),
|
||||
},
|
||||
parentId: {
|
||||
type: 'string',
|
||||
resolve: (doc) => {
|
||||
const segments = getPathSegments(doc);
|
||||
|
||||
if (segments.length > 1) {
|
||||
const { pathName } = getMetaFromFolderName(segments[0]);
|
||||
|
||||
if (pathName === 'index') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return pathName;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
order: {
|
||||
type: 'number',
|
||||
resolve: (doc) => {
|
||||
const segments = getPathSegments(doc);
|
||||
const { order } = getMetaFromFolderName(segments[segments.length - 1]);
|
||||
|
||||
return order;
|
||||
},
|
||||
},
|
||||
structuredData: {
|
||||
type: 'object',
|
||||
resolve: (doc) => ({
|
||||
|
||||
@@ -7,14 +7,7 @@ async function getAllContentItems() {
|
||||
'../.contentlayer/generated'
|
||||
);
|
||||
|
||||
return [
|
||||
...allPosts.map((item) => {
|
||||
return { ...item, type: 'post' };
|
||||
}),
|
||||
...allDocumentationPages.map((item) => {
|
||||
return { ...item, type: 'page', categories: ['documentation'] };
|
||||
}),
|
||||
];
|
||||
return [...allPosts, ...allDocumentationPages];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,29 +34,14 @@ export class ContentlayerClient implements CmsClient {
|
||||
)
|
||||
: true;
|
||||
|
||||
const typeMatch = options?.type ? item.type === options.type : true;
|
||||
const path = item._raw.flattenedPath;
|
||||
const splitPath = path.split('/');
|
||||
const matchesParentIds = options?.parentIds
|
||||
? options.parentIds.includes(item.parentId ?? '')
|
||||
: true;
|
||||
|
||||
const depthMatch =
|
||||
options?.depth !== undefined
|
||||
? splitPath.length - 1 === options.depth
|
||||
: true;
|
||||
|
||||
return tagMatch && categoryMatch && typeMatch && depthMatch;
|
||||
return tagMatch && categoryMatch && matchesParentIds;
|
||||
})
|
||||
.slice(startOffset, endOffset)
|
||||
.map((post) => {
|
||||
const children: Cms.ContentItem[] = [];
|
||||
|
||||
for (const item of allContentItems) {
|
||||
if (item.url.startsWith(post.url + '/')) {
|
||||
children.push(this.mapPost(item));
|
||||
}
|
||||
}
|
||||
|
||||
return this.mapPost(post, children);
|
||||
});
|
||||
.map((post) => this.mapPost(post))
|
||||
.slice(startOffset, endOffset);
|
||||
|
||||
return Promise.resolve(promise);
|
||||
}
|
||||
@@ -76,15 +54,7 @@ export class ContentlayerClient implements CmsClient {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const children: Cms.ContentItem[] = [];
|
||||
|
||||
for (const item of allContentItems) {
|
||||
if (item.url.startsWith(post.url + '/')) {
|
||||
children.push(this.mapPost(item));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve(post ? this.mapPost(post, children) : undefined);
|
||||
return Promise.resolve(post ? this.mapPost(post) : undefined);
|
||||
}
|
||||
|
||||
async getCategoryBySlug(slug: string) {
|
||||
@@ -108,13 +78,6 @@ export class ContentlayerClient implements CmsClient {
|
||||
const allContentItems = await getAllContentItems();
|
||||
|
||||
const categories = allContentItems
|
||||
.filter((item) => {
|
||||
if (options?.type) {
|
||||
return item.type === options.type;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.slice(startOffset, endOffset)
|
||||
.flatMap((post) => post.categories)
|
||||
.filter((category): category is string => !!category)
|
||||
@@ -132,13 +95,6 @@ export class ContentlayerClient implements CmsClient {
|
||||
const allContentItems = await getAllContentItems();
|
||||
|
||||
const tags = allContentItems
|
||||
.filter((item) => {
|
||||
if (options?.type) {
|
||||
return item.type === options.type;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.slice(startOffset, endOffset)
|
||||
.flatMap((post) => post.tags)
|
||||
.filter((tag): tag is string => !!tag)
|
||||
@@ -167,9 +123,10 @@ export class ContentlayerClient implements CmsClient {
|
||||
title: post.title,
|
||||
description: post.description ?? '',
|
||||
content: post.body?.code,
|
||||
order: 'order' in post ? post.order : 0,
|
||||
image: 'image' in post ? post.image : undefined,
|
||||
publishedAt: 'date' in post ? new Date(post.date) : new Date(),
|
||||
parentId: 'parentId' in post ? post.parentId : undefined,
|
||||
parentId: 'parentId' in post ? (post.parentId as string) : undefined,
|
||||
url: post.url,
|
||||
slug: post.slug,
|
||||
author: 'author' in post ? post.author : '',
|
||||
|
||||
Reference in New Issue
Block a user