Markdown Overview Buttons Tabs Footnotes Collapse ToC Navigation Formula Page-Specific Meta Custom Components
For this recipe, we're going to assume that we've got a nice search API that gives you a JSON array of URLs of matching documentation pages, based on a given query, and now we want to use it instead of the GitHub search for our docs.
We are assuming that the API, when requested with:
1link$curl https://my-search.cloud?q=whatever
would respond with something like:
1link${
2link$ "results": [
3link$ "https://johndoe.github.io/my-project/",
4link$ "https://johndoe.github.io/my-project/docs/stuff",
5link$ "https://johndoe.github.io/my-project/docs/whatever/overview"
6link$ ]
7link$}
Lets create a search component in .codedoc/content/my-search.tsx:
1linkimport { ajax } from 'rxjs/ajax';
2linkimport { Subject, of } from 'rxjs';
3linkimport { switchMap, map, catchError, share } from 'rxjs/operators';
4linkimport { RendererLike, ComponentThis } from '@connectv/html';
5linkimport { transport } from '@connectv/sdh/transport';
6linkimport { ToCSearchBtn } from '@codedoc/core/components';
7link
8link
9linkexport function MySearch(this: ComponentThis, options: SearchOptions, renderer: RendererLike<any, any>) {
10link const query = new Subject();
11link const prefix = 'https://johndoe.github.io/my-project';
12link
13link const results = query.pipe(
14link switchMap(q =>
15link ajax.getJSON(
16link `https://my-search.cloud?q=${encodeURIComponent(q)}`
17link ).pipe(catchError(() => of(undefined))) // --> no sweat in case of error
18link ),
19link map(res =>
20link (res.results || [])
21link .map(url => url.substr(prefix.length)) // --> returned URLs must be relative to domain root
22link ),
23link share(),
24link );
25link
26link return <ToCSearchBtn label="Search via my-search ..." query={query} results={results}/>;
27link}
28link
29link
30linkexport const MySearch$ = /*#__PURE__*/transport(MySearch);
touch_app NOTE
Note that although we have defined the component
MySearch, we also export a transported version of it namedMySearch$. The reason isMySearchis a client-side component, i.e. it should be rendered and bound on the browser. However, we want to feed it to the rest of our layout components on the server-side, i.e. when we are building the HTML files.MySearch$basically acts as a placeholder forMySearchin server-side code, allowing you to include it where you need it. When included, it will cause the code for the client-side component, i.e.MySearch, to be included in codedoc bundle, alongside an initialization script that would renderMySearchin place of the placeholder on the browser.
Now lets configure our ToC to use MySearch$ instead of the default GithubSearch$ component.
For that purpose, we just need to modify .codedoc/content/index.tsx:
1linkimport { RendererLike } from '@connectv/html';
2linkimport { File } from 'rxline/fs';
3linkimport { Page, Meta, ContentNav, Fonts, ToC } from '@codedoc/core/components';
4link
5linkimport { config } from '../config';
6linkimport { Header } from './header';
7linkimport { Footer } from './footer';
8linkimport { MySearch$ } from './my-search'; // --> import the component
9link
10link
11linkexport function content(_content: HTMLElement, toc: HTMLElement, renderer: RendererLike<any, any>, file: File<string>) {
12link return (
13link <Page title={config.page.title.extractor(_content, config, file)}
14link favicon={config.page.favicon}
15link meta={<Meta {...config.page.meta}/>}
16link fonts={<Fonts {...config.page.fonts}/>}
17link
18link scripts={config.page.scripts}
19link stylesheets={config.page.stylesheets}
20link
21link header={<Header {...config}/>}
22link footer={<Footer {...config}/>}
23link toc={
24link <ToC search={<MySearch$/>}>{toc}</ToC> // --> give it to ToC for search
25link }>
26link {_content}
27link <ContentNav content={_content}/>
28link </Page>
29link )
30link}