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 isMySearch
is 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 forMySearch
in 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 renderMySearch
in 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}