diff --git a/client/package.json b/client/package.json
index 10a66b1d..860a7f3f 100644
--- a/client/package.json
+++ b/client/package.json
@@ -21,6 +21,7 @@
"@tailwindcss/typography": "^0.4.1",
"color": "^4.0.1",
"eventemitter3": "^4.0.7",
+ "flexsearch": "^0.7.21",
"gray-matter": "^4.0.3",
"lottie-web": "^5.7.13",
"match-sorter": "^6.3.1",
@@ -43,6 +44,7 @@
},
"devDependencies": {
"@types/color": "^3.0.2",
+ "@types/flexsearch": "^0.7.1",
"@types/markdown-it": "^12.2.3",
"@types/react": "^17.0.27",
"@types/react-dom": "^17.0.9",
diff --git a/client/src/docs/index.tsx b/client/src/docs/index.tsx
index a06ae98a..4ffc5ff6 100644
--- a/client/src/docs/index.tsx
+++ b/client/src/docs/index.tsx
@@ -1,14 +1,90 @@
import * as React from "react";
-import {NavLink, Outlet, Route, Routes, useLocation} from "react-router-dom";
+import {Link, NavLink, Route, Routes, useLocation} from "react-router-dom";
import "prismjs/themes/prism-tomorrow.css";
import Menubar from "@thorium/ui/Menubar";
+import {Popover, Transition} from "@headlessui/react";
+import {Index} from "flexsearch";
import "./docs.css";
+const docIndex = new Index();
+
+function Search() {
+ const [results, setResults] = React.useState<{title: string; path: string}[]>(
+ []
+ );
+ return (
+
+
+ <>
+ {
+ const value = e.target.value;
+ if (value.length > 2) {
+ const results = docIndex
+ .search(value)
+ .map(id => (typeof id === "string" ? JSON.parse(id) : id));
+ setResults(results);
+ }
+ }}
+ onChange={e => {
+ const value = e.target.value;
+ if (value.length > 2) {
+ const results = docIndex
+ .search(value)
+ .map(id => (typeof id === "string" ? JSON.parse(id) : id));
+ setResults(results);
+ } else {
+ setResults([]);
+ }
+ }}
+ />
+ 0}
+ >
+
+
+
+ {results.map(item => (
+
{
+ setResults([]);
+ }}
+ key={item.path}
+ to={item.path}
+ className="flex items-center px-2 py-1 m-1 transition duration-150 ease-in-out rounded-lg hover:bg-gray-800 focus:outline-none focus-visible:ring focus-visible:ring-orange-500 focus-visible:ring-opacity-50"
+ >
+
{item.title}
+
+ ))}
+
+
+
+
+ >
+
+
+ );
+}
+
const ROUTES = import.meta.globEager("/src/docs/**/*.{tsx,jsx,md,mdx}");
type RouteType = {
path: string;
component: React.ComponentType;
+ content: string;
section: string;
frontmatter: {
title: string;
@@ -32,12 +108,19 @@ export const routes = Object.keys(ROUTES)
return {
path: path.toLowerCase().replace(/\s/g, "-"),
component: ROUTES[route].default,
+ content: ROUTES[route].content,
section: routeParts[0],
frontmatter: ROUTES[route].frontmatter,
};
})
.filter(isRoute);
+routes.forEach(route => {
+ docIndex.add(
+ JSON.stringify({...route.frontmatter, path: route.path}),
+ route.content
+ );
+});
type Heading = {
title: string;
id: string;
@@ -228,6 +311,7 @@ export default function DocLayout() {