on master help sign in
Merge pull request #1674 from urbit/mp/index-headings
42d9133matildepark
components/Search.js+15
@@ -282,6 +282,11 @@ class Search extends Component {
282 }`}
282 }`}
283 >
283 >
284 {item.content.content}
284 {item.content.content}
285+ {item?.content?.foundOnPage && (
286+ <span className="italic block">
287+ Found in page content
288+ </span>
289+ )}
285 </p>
290 </p>
286 </div>
291 </div>
287 </li>
292 </li>
@@ -323,6 +328,11 @@ class Search extends Component {
323 }`}
328 }`}
324 >
329 >
325 {item.content.content}
330 {item.content.content}
331+ {item?.content?.foundOnPage && (
332+ <span className="italic block">
333+ Found in page content
334+ </span>
335+ )}
326 </p>
336 </p>
327 </div>
337 </div>
328 </li>
338 </li>
@@ -364,6 +374,11 @@ class Search extends Component {
364 }`}
374 }`}
365 >
375 >
366 {item.content.content}
376 {item.content.content}
377+ {item?.content?.foundOnPage && (
378+ <span className="italic block">
379+ Found in page content
380+ </span>
381+ )}
367 </p>
382 </p>
368 </div>
383 </div>
369 </li>
384 </li>
lib/cache.js+8
@@ -2,6 +2,7 @@ const fs = require("fs");
2const path = require("path");
2const path = require("path");
3const matter = require("gray-matter");
3const matter = require("gray-matter");
4const toml = require("@iarna/toml");
4const toml = require("@iarna/toml");
5+const markdoc = require("@markdoc/markdoc");
5
6
6const options = {
7const options = {
7 engines: {
8 engines: {
@@ -37,6 +38,8 @@ function buildSearchIndex(dir) {
37 fs.readFileSync(path.join(dir, page.name)),
38 fs.readFileSync(path.join(dir, page.name)),
38 options
39 options
39 );
40 );
41+ const parsed = markdoc.parse(pageContent);
42+ const transform = markdoc.transform(parsed);
40 return {
43 return {
41 title: pageData.title,
44 title: pageData.title,
42 base: page.name,
45 base: page.name,
@@ -46,6 +49,11 @@ function buildSearchIndex(dir) {
46 page.name.replace(/.md$/, "")
49 page.name.replace(/.md$/, "")
47 ),
50 ),
48 content: pageData.description || "",
51 content: pageData.description || "",
52+ headings: transform.children
53+ .filter((e) => e.name === "h2" || e.name === "h3")
54+ .map((e) => e.children)
55+ .flat()
56+ .filter((e) => typeof e === "string"),
49 parent: metadata.data.title,
57 parent: metadata.data.title,
50 };
58 };
51 })
59 })
pages/api/search.js+22−1
@@ -8,7 +8,28 @@ export default (req, res) => {
8 e?.slug.includes(req.query.q.toLowerCase()) ||
8 e?.slug.includes(req.query.q.toLowerCase()) ||
9 e?.parent.toLowerCase().includes(req.query.q.toLowerCase())
9 e?.parent.toLowerCase().includes(req.query.q.toLowerCase())
10 );
10 );
11+
12+ results.push(
13+ ...index
14+ .filter((e) => !results.includes(e))
15+ .filter((e) => {
16+ let found = false;
17+ e.headings.forEach((heading) => {
18+ if (heading.toLowerCase().includes(req.query.q.toLowerCase())) {
19+ found = true;
20+ }
21+ });
22+ return found;
23+ })
24+ .map((e) => ({ ...e, foundOnPage: true }))
25+ );
26+
11− const sorted = levenSort(results, req.q, ["title", "slug", "parent"]);
27+ const sorted = levenSort(results, req.q, [
28+ "title",
29+ "slug",
30+ "parent",
31+ "headings",
32+ ]);
12 res.statusCode = 200;
33 res.statusCode = 200;
13 res.setHeader("Content-Type", "application/json");
34 res.setHeader("Content-Type", "application/json");
14 res.end(JSON.stringify({ results: sorted }));
35 res.end(JSON.stringify({ results: sorted }));