diff --git a/packages/guider/package.json b/packages/guider/package.json
index 3a536b5..f6e07dd 100644
--- a/packages/guider/package.json
+++ b/packages/guider/package.json
@@ -1,6 +1,6 @@
{
"name": "@neato/guider",
- "version": "1.0.1",
+ "version": "1.0.2",
"description": "Beautiful documentation sites, without all the hassle",
"main": "./dist/index.js",
"type": "module",
diff --git a/packages/guider/src/client/partials/header/search/content.ts b/packages/guider/src/client/partials/header/search/content.ts
index 8b305f4..7199bb2 100644
--- a/packages/guider/src/client/partials/header/search/content.ts
+++ b/packages/guider/src/client/partials/header/search/content.ts
@@ -8,6 +8,7 @@ type ContentDocument = {
id: number;
url: string;
title: string;
+ pageTitle?: string;
content: string;
},
never[]
@@ -21,6 +22,7 @@ type SearchData = Record<
heading?: { id: string; depth: number; text: string };
content: string;
}[];
+ pageTitle: string;
}
>;
@@ -28,6 +30,7 @@ export type SearchResult = {
id: string;
type: 'section';
title: string;
+ pageTitle?: string;
content: string;
url: string;
};
@@ -53,7 +56,7 @@ async function fetchDocument(basePath: string, key: string) {
document: {
id: 'id',
index: ['title', 'content'],
- store: ['content', 'url', 'title'],
+ store: ['content', 'url', 'title', 'pageTitle'],
},
context: {
resolution: 9,
@@ -69,6 +72,7 @@ async function fetchDocument(basePath: string, key: string) {
searchDocument.add({
id: pageId,
title: section.heading?.text ?? '',
+ pageTitle: data.pageTitle,
url: url + (section.heading ? `#${section.heading.id}` : ''),
content: section.content,
});
@@ -113,6 +117,7 @@ export function useSearch(key: string) {
type: 'section',
id: res.id.toString(),
title: res.doc.title,
+ pageTitle: res.doc.pageTitle,
content: res.doc.content,
url: res.doc.url,
};
diff --git a/packages/guider/src/client/partials/header/search/screen.tsx b/packages/guider/src/client/partials/header/search/screen.tsx
index 8d063f4..d251b1c 100644
--- a/packages/guider/src/client/partials/header/search/screen.tsx
+++ b/packages/guider/src/client/partials/header/search/screen.tsx
@@ -26,16 +26,22 @@ function SearchMessage(props: { title: string; text: string; icon: string }) {
);
}
-function SearchResults(props: { results: SearchResult[] }) {
+function SearchResults(props: {
+ results: SearchResult[];
+ onClose?: () => void;
+}) {
return (
{props.results.map((v) => {
+ let title = v.pageTitle ? `${v.pageTitle} / ${v.title}` : v.title;
+ if (v.pageTitle === v.title) title = v.title;
return (
{({ active }) => (
- {v.title}
+ {title}
) : query.length > 0 && results ? (
-
+
) : null}
diff --git a/packages/guider/src/webpack/loader/md-loader.ts b/packages/guider/src/webpack/loader/md-loader.ts
index 741c98a..a7e2237 100644
--- a/packages/guider/src/webpack/loader/md-loader.ts
+++ b/packages/guider/src/webpack/loader/md-loader.ts
@@ -1,5 +1,6 @@
import { compile } from '@mdx-js/mdx';
import remarkFrontmatter from 'remark-frontmatter';
+import type { Heading } from '@vcarl/remark-headings';
import remarkHeadings from '@vcarl/remark-headings';
import remarkHeadingId from 'remark-heading-id';
import grayMatter from 'gray-matter';
@@ -8,10 +9,6 @@ import rehypeExtractExcerpt from 'rehype-extract-excerpt';
import remarkLinkRewrite from 'remark-link-rewrite';
import { remarkNpm2Yarn } from '@theguild/remark-npm2yarn';
import remarkGfm from 'remark-gfm';
-import { SKIP, visit } from 'unist-util-visit';
-import type { Heading, HeadingData, Root } from 'mdast';
-import { phrasing } from 'mdast-util-phrasing';
-import type { VFileWithOutput } from 'unified';
import {
transformerNotationDiff,
transformerNotationHighlight,
@@ -19,14 +16,10 @@ import {
transformerNotationWordHighlight,
transformerNotationErrorLevel,
} from '@shikijs/transformers';
+import { remarkSearchData } from './search-data';
const EXPORT_FOOTER = 'export default ';
-interface Section {
- heading?: { id: string; depth: Heading['depth']; text: string };
- content: string;
-}
-
export async function mdLoader(source: string) {
const meta = grayMatter(source);
const file = await compile(source, {
@@ -75,67 +68,7 @@ export async function mdLoader(source: string) {
},
},
],
- () => {
- return (root: Root, vFile: VFileWithOutput) => {
- const sections: Section[] = [];
-
- let currentSection: Section | undefined;
- let previousParentNode: any;
-
- visit(root, (node, _, parent) => {
- if (node.type === 'heading') {
- if (currentSection) {
- sections.push(currentSection);
- }
-
- const heading = node;
- const id = (heading.data as HeadingData & { id: string })?.id;
- const depth = heading.depth;
- let text = '';
- visit(heading, ['text', 'inlineCode'], (hChild: any) => {
- text += hChild.value;
- });
-
- currentSection = {
- heading: {
- id,
- depth,
- text,
- },
- content: '',
- };
-
- return SKIP;
- }
-
- const types = ['text', 'inlineCode'];
-
- if (types.includes(node.type)) {
- if (!currentSection) {
- currentSection = {
- heading: undefined,
- content: '',
- };
- }
-
- if (
- previousParentNode &&
- previousParentNode !== parent &&
- !phrasing(previousParentNode)
- ) {
- currentSection.content += ' ';
- }
- currentSection.content += (node as any).value;
-
- previousParentNode = parent;
- }
- });
-
- if (currentSection) sections.push(currentSection);
-
- vFile.data = { ...vFile.data, sections };
- };
- },
+ remarkSearchData,
],
rehypePlugins: [
rehypeExtractExcerpt,
@@ -168,6 +101,10 @@ export async function mdLoader(source: string) {
excerpt: file.data.excerpt,
};
+ const firstHeading = (file.data.headings as Heading[]).find(
+ (h) => h.depth === 1,
+ );
+
const script = `
import { createMdxPage } from "@neato/guider/client";
@@ -185,6 +122,7 @@ export async function mdLoader(source: string) {
script,
searchData: {
sections: file.data.sections,
+ pageTitle: meta.data?.title ?? firstHeading?.value ?? undefined,
},
};
}
diff --git a/packages/guider/src/webpack/loader/search-data.ts b/packages/guider/src/webpack/loader/search-data.ts
new file mode 100644
index 0000000..ae76d43
--- /dev/null
+++ b/packages/guider/src/webpack/loader/search-data.ts
@@ -0,0 +1,75 @@
+import { SKIP, visit } from 'unist-util-visit';
+import type { Heading, Root } from 'mdast';
+import { phrasing } from 'mdast-util-phrasing';
+import type { VFileWithOutput } from 'unified';
+
+interface Section {
+ heading?: { id: string; depth: Heading['depth']; text: string };
+ content: string;
+}
+
+declare module 'mdast' {
+ interface HeadingData {
+ id: string;
+ }
+}
+
+export function remarkSearchData() {
+ return (root: Root, vFile: VFileWithOutput) => {
+ const sections: Section[] = [];
+
+ let currentSection: Section | undefined;
+ let previousParentNode: any;
+
+ visit(root, (node, _, parent) => {
+ if (node.type === 'heading') {
+ if (currentSection) {
+ sections.push(currentSection);
+ }
+
+ const heading = node;
+ const id = heading.data?.id ?? '';
+ const depth = heading.depth;
+ let text = '';
+ visit(heading, ['text', 'inlineCode'], (hChild: any) => {
+ text += hChild.value;
+ });
+
+ currentSection = {
+ heading: {
+ id,
+ depth,
+ text,
+ },
+ content: '',
+ };
+
+ return SKIP;
+ }
+
+ if (node.type === 'text' || node.type === 'inlineCode') {
+ if (!currentSection) {
+ currentSection = {
+ heading: undefined,
+ content: '',
+ };
+ }
+
+ if (
+ previousParentNode &&
+ previousParentNode !== parent &&
+ !phrasing(previousParentNode)
+ ) {
+ currentSection.content += ' ';
+ }
+ currentSection.content += node.value;
+
+ previousParentNode = parent;
+ }
+ });
+
+ if (currentSection) sections.push(currentSection);
+
+ vFile.data = { ...vFile.data, sections };
+ };
+}