feat: Implement Algolia DocSearch, update build configurations, and refine UI components.
This commit is contained in:
120
lib/markdown.ts
120
lib/markdown.ts
@@ -8,10 +8,30 @@ import rehypeSlug from "rehype-slug";
|
||||
import rehypeCodeTitles from "rehype-code-titles";
|
||||
import { page_routes, ROUTES } from "./routes-config";
|
||||
import { visit } from "unist-util-visit";
|
||||
import type { Node, Parent } from "unist";
|
||||
import matter from "gray-matter";
|
||||
|
||||
// Type definitions for unist-util-visit
|
||||
interface Element extends Node {
|
||||
type: string;
|
||||
tagName?: string;
|
||||
properties?: Record<string, unknown> & {
|
||||
className?: string[];
|
||||
raw?: string;
|
||||
};
|
||||
children?: Node[];
|
||||
value?: string;
|
||||
raw?: string; // For internal use in processing
|
||||
}
|
||||
|
||||
interface TextNode extends Node {
|
||||
type: 'text';
|
||||
value: string;
|
||||
}
|
||||
|
||||
// custom components imports
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell } from "@/components/ui/table";
|
||||
import Pre from "@/components/markdown/PreMdx";
|
||||
import Note from "@/components/markdown/NoteMdx";
|
||||
import { Stepper, StepperItem } from "@/components/markdown/StepperMdx";
|
||||
@@ -27,6 +47,7 @@ import CardGroup from "@/components/markdown/CardGroupMdx";
|
||||
import Kbd from "@/components/markdown/KeyboardMdx";
|
||||
import { Release, Changes } from "@/components/markdown/ReleaseMdx";
|
||||
import { File, Files, Folder } from "@/components/markdown/FileTreeMdx";
|
||||
import AccordionGroup from "@/components/markdown/AccordionGroupMdx";
|
||||
|
||||
// add custom components
|
||||
const components = {
|
||||
@@ -34,20 +55,22 @@ const components = {
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
pre: Pre,
|
||||
Note,
|
||||
Stepper,
|
||||
StepperItem,
|
||||
img: Image,
|
||||
a: Link,
|
||||
Outlet,
|
||||
Youtube,
|
||||
Tooltip,
|
||||
Card,
|
||||
Button,
|
||||
Accordion,
|
||||
AccordionGroup,
|
||||
CardGroup,
|
||||
Kbd,
|
||||
// Table Components
|
||||
table: Table,
|
||||
thead: TableHeader,
|
||||
tbody: TableBody,
|
||||
tfoot: TableFooter,
|
||||
tr: TableRow,
|
||||
th: TableHead,
|
||||
td: TableCell,
|
||||
// Release Note Components
|
||||
Release,
|
||||
Changes,
|
||||
@@ -55,6 +78,56 @@ const components = {
|
||||
File,
|
||||
Files,
|
||||
Folder,
|
||||
pre: Pre,
|
||||
Note,
|
||||
Stepper,
|
||||
StepperItem,
|
||||
img: Image,
|
||||
a: Link,
|
||||
Outlet,
|
||||
};
|
||||
|
||||
// helper function to handle rehype code titles, since by default we can't inject into the className of rehype-code-titles
|
||||
const handleCodeTitles = () => (tree: Node) => {
|
||||
visit(tree, "element", (node: Element, index: number | null, parent: Parent | null) => {
|
||||
// Ensure the visited node is valid
|
||||
if (!parent || index === null || node.tagName !== 'div') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is the title div from rehype-code-titles
|
||||
const isTitleDiv = node.properties?.className?.includes('rehype-code-title');
|
||||
if (!isTitleDiv) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the next <pre> element, skipping over other nodes like whitespace text
|
||||
let nextElement = null;
|
||||
for (let i = index + 1; i < parent.children.length; i++) {
|
||||
const sibling = parent.children[i];
|
||||
if (sibling.type === 'element') {
|
||||
nextElement = sibling as Element;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the next element is a <pre>, move the title to it
|
||||
if (nextElement && nextElement.tagName === 'pre') {
|
||||
const titleNode = node.children?.[0] as TextNode;
|
||||
if (titleNode && titleNode.type === 'text') {
|
||||
if (!nextElement.properties) {
|
||||
nextElement.properties = {};
|
||||
}
|
||||
nextElement.properties['data-title'] = titleNode.value;
|
||||
|
||||
// Remove the original title div
|
||||
parent.children.splice(index, 1);
|
||||
|
||||
// Return the same index to continue visiting from the correct position
|
||||
return index;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// can be used for other pages like blogs, Guides etc
|
||||
@@ -67,6 +140,7 @@ async function parseMdx<Frontmatter>(rawMdx: string) {
|
||||
rehypePlugins: [
|
||||
preProcess,
|
||||
rehypeCodeTitles,
|
||||
handleCodeTitles,
|
||||
rehypePrism,
|
||||
rehypeSlug,
|
||||
rehypeAutolinkHeadings,
|
||||
@@ -139,11 +213,11 @@ function justGetFrontmatterFromMD<Frontmatter>(rawMd: string): Frontmatter {
|
||||
}
|
||||
|
||||
export async function getAllChilds(pathString: string) {
|
||||
const items = pathString.split("/").filter((it) => it != "");
|
||||
const items = pathString.split("/").filter((it) => it !== "");
|
||||
let page_routes_copy = ROUTES;
|
||||
|
||||
let prevHref = "";
|
||||
for (let it of items) {
|
||||
for (const it of items) {
|
||||
const found = page_routes_copy.find((innerIt) => innerIt.href == `/${it}`);
|
||||
if (!found) break;
|
||||
prevHref += found.href;
|
||||
@@ -170,20 +244,28 @@ export async function getAllChilds(pathString: string) {
|
||||
}
|
||||
|
||||
// for copying the code in pre
|
||||
const preProcess = () => (tree: any) => {
|
||||
visit(tree, (node) => {
|
||||
if (node?.type === "element" && node?.tagName === "pre") {
|
||||
const [codeEl] = node.children;
|
||||
if (codeEl.tagName !== "code") return;
|
||||
node.raw = codeEl.children?.[0].value;
|
||||
const preProcess = () => (tree: Node) => {
|
||||
visit(tree, (node: Node) => {
|
||||
const element = node as Element;
|
||||
if (element?.type === "element" && element?.tagName === "pre" && element.children) {
|
||||
const [codeEl] = element.children as Element[];
|
||||
if (codeEl.tagName !== "code" || !codeEl.children?.[0]) return;
|
||||
|
||||
const textNode = codeEl.children[0] as TextNode;
|
||||
if (textNode.type === 'text' && textNode.value) {
|
||||
element.raw = textNode.value;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const postProcess = () => (tree: any) => {
|
||||
visit(tree, "element", (node) => {
|
||||
if (node?.type === "element" && node?.tagName === "pre") {
|
||||
node.properties["raw"] = node.raw;
|
||||
const postProcess = () => (tree: Node) => {
|
||||
visit(tree, "element", (node: Node) => {
|
||||
const element = node as Element;
|
||||
if (element?.type === "element" && element?.tagName === "pre") {
|
||||
if (element.properties && element.raw) {
|
||||
element.properties.raw = element.raw;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user