mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-22 16:46:34 +03:00
fix: various search fixes
This commit is contained in:
parent
1ff2bd84cc
commit
b797c965b2
|
@ -8,3 +8,4 @@ export * from './dropdown';
|
||||||
export * from './mixins';
|
export * from './mixins';
|
||||||
export * from './tabs';
|
export * from './tabs';
|
||||||
export * from './samples';
|
export * from './samples';
|
||||||
|
export * from './perfect-scrollbar';
|
||||||
|
|
|
@ -3,6 +3,7 @@ import styled, { withProps } from '../../styled-components';
|
||||||
export const OperationEndpointWrap = styled.div`
|
export const OperationEndpointWrap = styled.div`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
margin-bottom: 5px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ServerRelativeURL = styled.span`
|
export const ServerRelativeURL = styled.span`
|
||||||
|
|
|
@ -24,7 +24,7 @@ export class Redoc extends React.Component<RedocProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.store.menu.updateOnHash();
|
this.props.store.onDidMount();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
|
|
@ -82,6 +82,8 @@ export interface SearchBoxProps {
|
||||||
marker: MarkerService;
|
marker: MarkerService;
|
||||||
getItemById: (id: string) => IMenuItem | undefined;
|
getItemById: (id: string) => IMenuItem | undefined;
|
||||||
onActivate: (item: IMenuItem) => void;
|
onActivate: (item: IMenuItem) => void;
|
||||||
|
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchBoxState {
|
export interface SearchBoxState {
|
||||||
|
@ -89,6 +91,11 @@ export interface SearchBoxState {
|
||||||
term: string;
|
term: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SearchResult {
|
||||||
|
item: IMenuItem;
|
||||||
|
score: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxState> {
|
export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxState> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -145,8 +152,14 @@ export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxStat
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const items: IMenuItem[] = this.state.results.map(res => this.props.getItemById(res.id));
|
const results: SearchResult[] = this.state.results.map(res => ({
|
||||||
items.sort((a, b) => (a.depth > b.depth ? 1 : a.depth < b.depth ? -1 : 0));
|
item: this.props.getItemById(res.id),
|
||||||
|
score: res.score,
|
||||||
|
}));
|
||||||
|
results.sort(
|
||||||
|
(a, b) =>
|
||||||
|
a.item.depth > b.item.depth ? 1 : a.item.depth < b.item.depth ? -1 : b.score - a.score,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -158,14 +171,14 @@ export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxStat
|
||||||
type="text"
|
type="text"
|
||||||
onChange={this.search}
|
onChange={this.search}
|
||||||
/>
|
/>
|
||||||
{items.length > 0 && (
|
{results.length > 0 && (
|
||||||
<SearchResultsBox>
|
<SearchResultsBox>
|
||||||
{items.map(item => (
|
{results.map(res => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
item={item}
|
item={res.item}
|
||||||
onActivate={this.props.onActivate}
|
onActivate={this.props.onActivate}
|
||||||
withoutChildren={true}
|
withoutChildren={true}
|
||||||
key={item.id}
|
key={res.item.id}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</SearchResultsBox>
|
</SearchResultsBox>
|
||||||
|
|
|
@ -2,6 +2,7 @@ export * from './RedocStandalone';
|
||||||
export * from './Redoc/Redoc';
|
export * from './Redoc/Redoc';
|
||||||
// export * from './Redoc/elements';
|
// export * from './Redoc/elements';
|
||||||
export * from './Schema/';
|
export * from './Schema/';
|
||||||
|
export * from './SearchBox/SearchBox';
|
||||||
export * from './Operation/Operation';
|
export * from './Operation/Operation';
|
||||||
export * from './RedocStandalone';
|
export * from './RedocStandalone';
|
||||||
|
|
||||||
|
|
|
@ -59,15 +59,21 @@ export class AppStore {
|
||||||
this.spec = new SpecStore(spec, specUrl, this.options);
|
this.spec = new SpecStore(spec, specUrl, this.options);
|
||||||
this.menu = new MenuStore(this.spec, this.scroll);
|
this.menu = new MenuStore(this.spec, this.scroll);
|
||||||
|
|
||||||
this.search = new SearchStore(this.spec);
|
this.search = new SearchStore();
|
||||||
|
this.search.indexItems(this.menu.items);
|
||||||
|
this.search.done();
|
||||||
|
|
||||||
this.disposer = observe(this.menu, 'activeItemIdx', change => {
|
this.disposer = observe(this.menu, 'activeItemIdx', change => {
|
||||||
this.updateMarkOnMenu(change.newValue as number);
|
this.updateMarkOnMenu(change.newValue as number);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDidMount() {
|
||||||
|
this.menu.updateOnHash();
|
||||||
|
this.updateMarkOnMenu(this.menu.activeItemIdx);
|
||||||
|
}
|
||||||
|
|
||||||
updateMarkOnMenu(idx: number) {
|
updateMarkOnMenu(idx: number) {
|
||||||
console.log('update marker');
|
|
||||||
const start = Math.max(0, idx);
|
const start = Math.max(0, idx);
|
||||||
const end = Math.min(this.menu.flatItems.length, start + 5);
|
const end = Math.min(this.menu.flatItems.length, start + 5);
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ export class MarkerService {
|
||||||
}
|
}
|
||||||
|
|
||||||
mark(term?: string) {
|
mark(term?: string) {
|
||||||
console.log('mark', term);
|
|
||||||
if (!term && !this.prevTerm) return;
|
if (!term && !this.prevTerm) return;
|
||||||
this.map.forEach(val => {
|
this.map.forEach(val => {
|
||||||
val.unmark();
|
val.unmark();
|
||||||
|
|
|
@ -16,6 +16,7 @@ export interface IMenuItem {
|
||||||
id: string;
|
id: string;
|
||||||
absoluteIdx?: number;
|
absoluteIdx?: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
description?: string;
|
||||||
depth: number;
|
depth: number;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
items: IMenuItem[];
|
items: IMenuItem[];
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
import { SpecStore } from '../index';
|
import { OperationModel } from './models';
|
||||||
import { GroupModel, OperationModel } from './models';
|
|
||||||
import worker from './SearchWorker.worker';
|
import worker from './SearchWorker.worker';
|
||||||
|
import { IMenuItem } from './MenuStore';
|
||||||
|
|
||||||
export class SearchStore {
|
export class SearchStore {
|
||||||
searchWorker = new worker();
|
searchWorker = new worker();
|
||||||
|
|
||||||
constructor(private spec: SpecStore) {
|
constructor() {}
|
||||||
this.indexGroups(this.spec.operationGroups);
|
|
||||||
this.done();
|
|
||||||
}
|
|
||||||
|
|
||||||
indexGroups(groups: Array<GroupModel | OperationModel>) {
|
indexItems(groups: Array<IMenuItem | OperationModel>) {
|
||||||
groups.forEach(group => {
|
groups.forEach(group => {
|
||||||
if (group.type !== 'group') {
|
if (group.type !== 'group') {
|
||||||
this.add(group.name, group.description || '', group.id);
|
this.add(group.name, group.description || '', group.id);
|
||||||
}
|
}
|
||||||
this.indexGroups(group.items);
|
this.indexItems(group.items);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,10 @@ export interface SearchDocument {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SearchResult extends SearchDocument {
|
||||||
|
score: number;
|
||||||
|
}
|
||||||
|
|
||||||
const store: { [id: string]: SearchDocument } = {};
|
const store: { [id: string]: SearchDocument } = {};
|
||||||
|
|
||||||
let resolveIndex: (v: lunr.Index) => void;
|
let resolveIndex: (v: lunr.Index) => void;
|
||||||
|
@ -39,7 +43,7 @@ export async function done() {
|
||||||
resolveIndex(builder.build());
|
resolveIndex(builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function search(q: string): Promise<SearchDocument[]> {
|
export async function search(q: string): Promise<SearchResult[]> {
|
||||||
if (q.trim().length === 0) {
|
if (q.trim().length === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -54,5 +58,5 @@ export async function search(q: string): Promise<SearchDocument[]> {
|
||||||
t.term(exp, {});
|
t.term(exp, {});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.map(res => store[res.ref]);
|
.map(res => ({ ...store[res.ref], score: res.score }));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user