From aac3c142e5ee2a07aaf76cd2d3915cc0a8fee626 Mon Sep 17 00:00:00 2001 From: moloch-- <875022+moloch--@users.noreply.github.com> Date: Sat, 16 Dec 2023 15:41:06 -0600 Subject: [PATCH] Implement search --- docs/sliver-docs/components/markdown.tsx | 125 +++++++++++++++++ docs/sliver-docs/components/navbar.tsx | 27 +++- docs/sliver-docs/package-lock.json | 7 + docs/sliver-docs/package.json | 1 + docs/sliver-docs/pages/_app.tsx | 22 ++- docs/sliver-docs/pages/docs/index.tsx | 129 +----------------- .../pages/docs/md/Beginner's Guide.md | 37 ----- docs/sliver-docs/pages/search/index.tsx | 67 +++++++++ docs/sliver-docs/util/docs.ts | 8 ++ docs/sliver-docs/util/search-context.ts | 40 ++++++ 10 files changed, 300 insertions(+), 163 deletions(-) create mode 100644 docs/sliver-docs/components/markdown.tsx delete mode 100644 docs/sliver-docs/pages/docs/md/Beginner's Guide.md create mode 100644 docs/sliver-docs/pages/search/index.tsx create mode 100644 docs/sliver-docs/util/docs.ts create mode 100644 docs/sliver-docs/util/search-context.ts diff --git a/docs/sliver-docs/components/markdown.tsx b/docs/sliver-docs/components/markdown.tsx new file mode 100644 index 0000000000..afd3c620ba --- /dev/null +++ b/docs/sliver-docs/components/markdown.tsx @@ -0,0 +1,125 @@ +import CodeViewer, { CodeSchema } from "@/components/code"; +import { Themes } from "@/util/themes"; +import { useTheme } from "next-themes"; +import Image from "next/image"; +import Markdown from "react-markdown"; +import remarkGfm from "remark-gfm"; + +export type MarkdownProps = { + markdown: string; +}; + +const MarkdownViewer = (props: MarkdownProps) => { + const { theme } = useTheme(); + + return ( +
+ ; + } + if (url.host === "sliver.sh") { + return ( + + {children} + + ); + } + return ( + + {children} + + ); + }, + + pre(props) { + // We need to look at the child nodes to avoid wrapping + // a monaco code block in a
 tag
+            const { children, className, node, ...rest } = props;
+            const childClass = (children as any)?.props?.className;
+            if (
+              childClass &&
+              childClass.startsWith("language-") &&
+              childClass !== "language-plaintext"
+            ) {
+              // @ts-ignore
+              return 
{children}
; + } + + return ( +
+                {children}
+              
+ ); + }, + + img(props) { + const { src, alt, ...rest } = props; + return ( + // @ts-ignore + {alt + ); + }, + + code(props) { + const { children, className, node, ...rest } = props; + const langTag = /language-(\w+)/.exec(className || ""); + const lang = langTag ? langTag[1] : "plaintext"; + if (lang === "plaintext") { + return ( + + + {children} + + + ); + } + return ( + + ); + }, + }} + > + {props.markdown} + +
+ ); +}; + +export default MarkdownViewer; diff --git a/docs/sliver-docs/components/navbar.tsx b/docs/sliver-docs/components/navbar.tsx index ba2f937469..6f5d9c881f 100644 --- a/docs/sliver-docs/components/navbar.tsx +++ b/docs/sliver-docs/components/navbar.tsx @@ -1,9 +1,16 @@ import { SliversIcon } from "@/components/icons/slivers"; +import { useSearchContext } from "@/util/search-context"; import { Themes } from "@/util/themes"; -import { faHome, faMoon, faSun } from "@fortawesome/free-solid-svg-icons"; +import { + faHome, + faMoon, + faSearch, + faSun, +} from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Button, + Input, Link, Navbar, NavbarBrand, @@ -18,12 +25,15 @@ export type TopNavbarProps = {}; export default function TopNavbar(props: TopNavbarProps) { const router = useRouter(); + const search = useSearchContext(); const { theme, setTheme } = useTheme(); const lightDarkModeIcon = React.useMemo( () => (theme === Themes.DARK ? faSun : faMoon), [theme] ); + const [query, setQuery] = React.useState(""); + return ( + setQuery(e.target.value)} + onClear={() => setQuery("")} + startContent={} + onKeyDown={(e) => { + if (e.key === "Enter") { + router.push(`/search`, { query: { search: query } }); + setQuery(""); + } + }} + /> + + + +
+ +
+ + + ))} + +
+ + ); +}; + +export default SearchPage; diff --git a/docs/sliver-docs/util/docs.ts b/docs/sliver-docs/util/docs.ts new file mode 100644 index 0000000000..5f3661210d --- /dev/null +++ b/docs/sliver-docs/util/docs.ts @@ -0,0 +1,8 @@ +export type Doc = { + name: string; + content: string; +}; + +export type Docs = { + docs: Doc[]; +}; \ No newline at end of file diff --git a/docs/sliver-docs/util/search-context.ts b/docs/sliver-docs/util/search-context.ts new file mode 100644 index 0000000000..5f20e87965 --- /dev/null +++ b/docs/sliver-docs/util/search-context.ts @@ -0,0 +1,40 @@ +import lunr from "lunr"; +import React from "react"; +import { Doc, Docs } from "./docs"; + + +export class SearchCtx { + + private _docs: Docs = { docs: [] }; + private _docsIndex: lunr.Index; + + constructor() { + this._docsIndex = lunr(function () { + this.ref("name"); + this.field("content"); + }); + } + + public searchDocs = (query: string): Doc[] => { + const results = this._docsIndex.search(query); + const docs = results.map((result) => { + return this._docs.docs.find((doc) => doc.name === result.ref); + }); + return docs.filter((doc) => doc !== undefined) as Doc[]; + } + + public addDocs = (docs: Docs) => { + this._docs = docs; + this._docsIndex = lunr(function () { + this.ref("name"); + this.field("content"); + docs.docs.forEach((doc) => { + this.add(doc); + }); + }); + } + +} + +export const SearchContext = React.createContext(new SearchCtx()); +export const useSearchContext = () => React.useContext(SearchContext);