diff options
author | Marcin Aman <maman@virtuslab.com> | 2020-07-29 17:32:13 +0200 |
---|---|---|
committer | Paweł Marks <Kordyjan@users.noreply.github.com> | 2020-08-03 13:47:51 +0200 |
commit | b14e0617a126ed3b8b9256542ce857c060e3e295 (patch) | |
tree | caa9ff76d95027f7262ac6b26679df548774cee4 /plugins/base/frontend/src/main/components | |
parent | 6e6876e2e9576f1ccd2816bab5c1a5ea7e23409f (diff) | |
download | dokka-b14e0617a126ed3b8b9256542ce857c060e3e295.tar.gz dokka-b14e0617a126ed3b8b9256542ce857c060e3e295.tar.bz2 dokka-b14e0617a126ed3b8b9256542ce857c060e3e295.zip |
Split into files and move svg to external one
Diffstat (limited to 'plugins/base/frontend/src/main/components')
6 files changed, 123 insertions, 115 deletions
diff --git a/plugins/base/frontend/src/main/components/search/dokkaFuzzyFilter.tsx b/plugins/base/frontend/src/main/components/search/dokkaFuzzyFilter.tsx new file mode 100644 index 00000000..725fbaee --- /dev/null +++ b/plugins/base/frontend/src/main/components/search/dokkaFuzzyFilter.tsx @@ -0,0 +1,63 @@ +import {Select} from "@jetbrains/ring-ui"; +import {Option, OptionWithHighlightComponent, OptionWithSearchResult, SearchRank} from "./types"; +import fuzzyHighlight from '@jetbrains/ring-ui/components/global/fuzzy-highlight.js' +import React from "react"; +import {SearchResultRow} from "./searchResultRow"; + +const orderRecords = (records: OptionWithSearchResult[], searchPhrase: string): OptionWithSearchResult[] => { + return records.sort((a: OptionWithSearchResult, b: OptionWithSearchResult) => { + //Prefer higher rank + const byRank = b.rank - a.rank + if(byRank !== 0){ + return byRank + } + //Prefer exact matches + const aIncludes = a.name.toLowerCase().includes(searchPhrase.toLowerCase()) ? 1 : 0 + const bIncludes = b.name.toLowerCase().includes(searchPhrase.toLowerCase()) ? 1 : 0 + const byIncludes = bIncludes - aIncludes + if(byIncludes != 0){ + return byIncludes + } + + //Prefer matches that are closer + const byFirstMatchedPosition = a.highlight.indexOf("**") - b.highlight.indexOf("**") + if(byFirstMatchedPosition == 0) { + return a.name.toLowerCase().localeCompare(b.name.toLowerCase()) + } + return byFirstMatchedPosition + }) +} + +const highlightMatchedPhrases = (records: OptionWithSearchResult[]): OptionWithHighlightComponent[] => { + // @ts-ignore + return records.map(record => { + return { + ...record, + template: <SearchResultRow searchResult={record}/> + } + }) +} + +export class DokkaFuzzyFilterComponent extends Select { + getListItems(rawFilterString: string, _: Option[]) { + const matchedRecords = this.props.data + .map((record: Option) => { + const bySearchKey = fuzzyHighlight(rawFilterString.trim(), record.searchKey, false) + if(bySearchKey.matched){ + return { + ...bySearchKey, + ...record, + rank: SearchRank.SearchKeyMatch + } + } + return { + ...fuzzyHighlight(rawFilterString.trim(), record.name, false), + ...record, + rank: SearchRank.NameMatch + } + }) + .filter((record: OptionWithSearchResult) => record.matched) + + return highlightMatchedPhrases(orderRecords(matchedRecords, rawFilterString)) + } +}
\ No newline at end of file diff --git a/plugins/base/frontend/src/main/components/search/dokkaSearchAnchor.tsx b/plugins/base/frontend/src/main/components/search/dokkaSearchAnchor.tsx new file mode 100644 index 00000000..ad0b5f8f --- /dev/null +++ b/plugins/base/frontend/src/main/components/search/dokkaSearchAnchor.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import SearchIcon from 'react-svg-loader!./searchIcon.svg'; + +export const DokkaSearchAnchor = ({wrapperProps, buttonProps, popup}: any) => { + return ( + <span {...wrapperProps}> + <button type="button" {...buttonProps}> + <SearchIcon /> + </button> + {popup} + </span> + ) +}
\ No newline at end of file diff --git a/plugins/base/frontend/src/main/components/search/search.tsx b/plugins/base/frontend/src/main/components/search/search.tsx index b4c5b1cd..c7976edb 100644 --- a/plugins/base/frontend/src/main/components/search/search.tsx +++ b/plugins/base/frontend/src/main/components/search/search.tsx @@ -1,107 +1,10 @@ import React, {useCallback, useState} from 'react'; import {Select, List} from '@jetbrains/ring-ui'; -import fuzzyHighlight from '@jetbrains/ring-ui/components/global/fuzzy-highlight.js' import '@jetbrains/ring-ui/components/input-size/input-size.scss'; import './search.scss'; -import {IWindow, Option, Props, Page} from "./types"; - -enum SearchRank { - SearchKeyMatch = 1, - NameMatch = 0 -} -type OptionWithSearchResult = Option & { - matched: boolean, - highlight: string, - rank: SearchRank -} - -type OptionWithHighlightComponent = Option & { - name: React.FC<SearchProps> -} - -type SearchProps = { - searchResult: OptionWithSearchResult, -} - -const orderRecords = (records: OptionWithSearchResult[], searchPhrase: string): OptionWithSearchResult[] => { - return records.sort((a: OptionWithSearchResult, b: OptionWithSearchResult) => { - //Prefer higher rank - const byRank = b.rank - a.rank - if(byRank !== 0){ - return byRank - } - //Prefer exact matches - const aIncludes = a.name.toLowerCase().includes(searchPhrase.toLowerCase()) ? 1 : 0 - const bIncludes = b.name.toLowerCase().includes(searchPhrase.toLowerCase()) ? 1 : 0 - const byIncludes = bIncludes - aIncludes - if(byIncludes != 0){ - return byIncludes - } - - //Prefer matches that are closer - const byFirstMatchedPosition = a.highlight.indexOf("**") - b.highlight.indexOf("**") - if(byFirstMatchedPosition == 0) { - return a.name.toLowerCase().localeCompare(b.name.toLowerCase()) - } - return byFirstMatchedPosition - }) -} - -const SearchResultRow: React.FC<SearchProps> = ({searchResult}: SearchProps) => { - const signatureFromSearchResult = (searchResult: OptionWithSearchResult): string => { - if(searchResult.rank == SearchRank.SearchKeyMatch){ - return searchResult.name.replace(searchResult.searchKey, searchResult.highlight) - } - return searchResult.highlight - } - - const renderHighlightMarkersAsHtml = (record: string): string => { - return record.replace(/\*\*(.*?)\*\*/g, '<span class="phraseHighlight">$1</span>') - } - - return ( - <div className="template-wrapper"> - <span dangerouslySetInnerHTML={ - {__html: renderHighlightMarkersAsHtml(signatureFromSearchResult(searchResult)) } - }/> - <span className="template-description">{searchResult.description}</span> - </div> - ) -} - -const highlightMatchedPhrases = (records: OptionWithSearchResult[]): OptionWithHighlightComponent[] => { - // @ts-ignore - return records.map(record => { - return { - ...record, - template: <SearchResultRow searchResult={record}/> - } - }) -} - -class DokkaFuzzyFilterComponent extends Select { - getListItems(rawFilterString: string, _: Option[]) { - const matchedRecords = this.props.data - .map((record: Option) => { - const bySearchKey = fuzzyHighlight(rawFilterString.trim(), record.searchKey, true) - if(bySearchKey.matched){ - return { - ...bySearchKey, - ...record, - rank: SearchRank.SearchKeyMatch - } - } - return { - ...fuzzyHighlight(rawFilterString.trim(), record.name), - ...record, - rank: SearchRank.NameMatch - } - }) - .filter((record: OptionWithSearchResult) => record.matched) - - return highlightMatchedPhrases(orderRecords(matchedRecords, rawFilterString)) - } -} +import {IWindow, Option, Props} from "./types"; +import {DokkaSearchAnchor} from "./dokkaSearchAnchor"; +import {DokkaFuzzyFilterComponent} from "./dokkaFuzzyFilter"; const WithFuzzySearchFilterComponent: React.FC<Props> = ({data}: Props) => { const [selected, onSelected] = useState<Option>(data[0]); @@ -136,19 +39,6 @@ const WithFuzzySearchFilterComponent: React.FC<Props> = ({data}: Props) => { ) } -const DokkaSearchAnchor = ({wrapperProps, buttonProps, popup}) => { - return ( - <span {...wrapperProps}> - <button type="button" {...buttonProps}> - <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"> - <path d="M19.64 18.36l-6.24-6.24a7.52 7.52 0 1 0-1.28 1.28l6.24 6.24zM7.5 13.4a5.9 5.9 0 1 1 5.9-5.9 5.91 5.91 0 0 1-5.9 5.9z"/> - </svg> - </button> - {popup} - </span> - ) -} - export const WithFuzzySearchFilter = () => { let data: Option[] = []; const pages = (window as IWindow).pages; diff --git a/plugins/base/frontend/src/main/components/search/searchIcon.svg b/plugins/base/frontend/src/main/components/search/searchIcon.svg new file mode 100644 index 00000000..391b1cab --- /dev/null +++ b/plugins/base/frontend/src/main/components/search/searchIcon.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"> + <path d="M19.64 18.36l-6.24-6.24a7.52 7.52 0 1 0-1.28 1.28l6.24 6.24zM7.5 13.4a5.9 5.9 0 1 1 5.9-5.9 5.91 5.91 0 0 1-5.9 5.9z"/> +</svg>
\ No newline at end of file diff --git a/plugins/base/frontend/src/main/components/search/searchResultRow.tsx b/plugins/base/frontend/src/main/components/search/searchResultRow.tsx new file mode 100644 index 00000000..9ae19cb9 --- /dev/null +++ b/plugins/base/frontend/src/main/components/search/searchResultRow.tsx @@ -0,0 +1,24 @@ +import React from "react"; +import {OptionWithSearchResult, SearchProps, SearchRank} from "./types"; + +export const SearchResultRow: React.FC<SearchProps> = ({searchResult}: SearchProps) => { + const signatureFromSearchResult = (searchResult: OptionWithSearchResult): string => { + if(searchResult.rank == SearchRank.SearchKeyMatch){ + return searchResult.name.replace(searchResult.searchKey, searchResult.highlight) + } + return searchResult.highlight + } + + const renderHighlightMarkersAsHtml = (record: string): string => { + return record.replace(/\*\*(.*?)\*\*/g, '<span class="phraseHighlight">$1</span>') + } + + return ( + <div className="template-wrapper"> + <span dangerouslySetInnerHTML={ + {__html: renderHighlightMarkersAsHtml(signatureFromSearchResult(searchResult)) } + }/> + <span className="template-description">{searchResult.description}</span> + </div> + ) +}
\ No newline at end of file diff --git a/plugins/base/frontend/src/main/components/search/types.ts b/plugins/base/frontend/src/main/components/search/types.ts index a6736a2d..922935bd 100644 --- a/plugins/base/frontend/src/main/components/search/types.ts +++ b/plugins/base/frontend/src/main/components/search/types.ts @@ -1,3 +1,5 @@ +import React from "react"; + export type Page = { name: string; kind: string; @@ -23,7 +25,20 @@ export type Props = { data: Option[] }; +export enum SearchRank { + SearchKeyMatch = 1, + NameMatch = 0 +} +export type OptionWithSearchResult = Option & { + matched: boolean, + highlight: string, + rank: SearchRank +} + +export type OptionWithHighlightComponent = Option & { + name: React.FC<SearchProps> +} -export type State = { - selected: any +export type SearchProps = { + searchResult: OptionWithSearchResult, } |