mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-11-29 04:04:02 +03:00
Merge pull request #5485 from urbit/lf/recency-improvements
landscape: better leap searching
This commit is contained in:
commit
f1f57abec0
32419
pkg/interface/package-lock.json
generated
32419
pkg/interface/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -25,6 +25,7 @@
|
|||||||
"css-loader": "^3.6.0",
|
"css-loader": "^3.6.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"formik": "^2.1.5",
|
"formik": "^2.1.5",
|
||||||
|
"fuzzy": "^0.1.3",
|
||||||
"immer": "^9.0.2",
|
"immer": "^9.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Box, Row, Text } from '@tlon/indigo-react';
|
import { Box, Row, Text } from '@tlon/indigo-react';
|
||||||
import { omit } from 'lodash';
|
import { omit } from 'lodash';
|
||||||
import Mousetrap from 'mousetrap';
|
import Mousetrap from 'mousetrap';
|
||||||
|
import fuzzy from 'fuzzy';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import f from 'lodash/fp';
|
import f from 'lodash/fp';
|
||||||
import React, {
|
import React, {
|
||||||
@ -44,6 +45,19 @@ const SEARCHED_CATEGORIES = [
|
|||||||
const settingsSel = (s: SettingsState) => s.leap;
|
const settingsSel = (s: SettingsState) => s.leap;
|
||||||
const CAT_LIMIT = 6;
|
const CAT_LIMIT = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flatten `catMap` according to ordering in `cats`
|
||||||
|
*/
|
||||||
|
function flattenCattegoryMap(cats: string[], catMap: Map<string, OmniboxItem[]>) {
|
||||||
|
let res = [] as OmniboxItem[];
|
||||||
|
cats.forEach(cat => {
|
||||||
|
res = res.concat(_.take(catMap.get(cat), CAT_LIMIT));
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export function Omnibox(props: OmniboxProps): ReactElement {
|
export function Omnibox(props: OmniboxProps): ReactElement {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
@ -124,29 +138,28 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
|||||||
);
|
);
|
||||||
}, [index]);
|
}, [index]);
|
||||||
|
|
||||||
const results = useMemo(() => {
|
const [results, categoryOrder] = useMemo(
|
||||||
|
(): [Map<string, OmniboxItem[]>, string[]] => {
|
||||||
if (query.length <= 1) {
|
if (query.length <= 1) {
|
||||||
return initialResults;
|
return [initialResults, ['other']];
|
||||||
}
|
}
|
||||||
const q = query.toLowerCase();
|
const q = query.toLowerCase();
|
||||||
const resultsMap = new Map<string, OmniboxItem[]>();
|
const resultsMap = new Map<string, OmniboxItem[]>();
|
||||||
|
let categoryMaxes: Record<string, number> = {};
|
||||||
|
|
||||||
SEARCHED_CATEGORIES.map((category) => {
|
SEARCHED_CATEGORIES.map((category) => {
|
||||||
const categoryIndex = index.get(category);
|
const categoryIndex = index.get(category);
|
||||||
resultsMap.set(
|
const fuzzied = fuzzy
|
||||||
category,
|
.filter(q, categoryIndex, { extract: res => res.title });
|
||||||
categoryIndex.filter((result) => {
|
categoryMaxes[category] = fuzzied
|
||||||
return (
|
.map(a => a.score)
|
||||||
result.title.toLowerCase().includes(q) ||
|
.reduce((a,b) => Math.max(a,b), 0);
|
||||||
result.link.toLowerCase().includes(q) ||
|
resultsMap.set(category, fuzzied.map(a => a.original));
|
||||||
result.app.toLowerCase().includes(q) ||
|
|
||||||
(result.host !== null
|
|
||||||
? result.host.toLowerCase().includes(q)
|
|
||||||
: false)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
return resultsMap;
|
let order = Object.entries(categoryMaxes)
|
||||||
|
.sort(([,a],[,b]) => b - a)
|
||||||
|
.map(([id]) => id);
|
||||||
|
return [resultsMap, order];
|
||||||
}, [query, index]);
|
}, [query, index]);
|
||||||
|
|
||||||
const navigate = useCallback(
|
const navigate = useCallback(
|
||||||
@ -181,7 +194,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const setPreviousSelected = useCallback(() => {
|
const setPreviousSelected = useCallback(() => {
|
||||||
const flattenedResults = Array.from(results.values()).map(f.take(CAT_LIMIT)).flat();
|
const flattenedResults = flattenCattegoryMap(categoryOrder, results);
|
||||||
const totalLength = flattenedResults.length;
|
const totalLength = flattenedResults.length;
|
||||||
if (selected.length) {
|
if (selected.length) {
|
||||||
const currentIndex = flattenedResults.indexOf(
|
const currentIndex = flattenedResults.indexOf(
|
||||||
@ -201,10 +214,10 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
|||||||
const { app, link } = flattenedResults[totalLength - 1];
|
const { app, link } = flattenedResults[totalLength - 1];
|
||||||
setSelected([app, link]);
|
setSelected([app, link]);
|
||||||
}
|
}
|
||||||
}, [results, selected]);
|
}, [results, categoryOrder, selected]);
|
||||||
|
|
||||||
const setNextSelected = useCallback(() => {
|
const setNextSelected = useCallback(() => {
|
||||||
const flattenedResults = Array.from(results.values()).map(f.take(CAT_LIMIT)).flat();
|
const flattenedResults = flattenCattegoryMap(categoryOrder, results);
|
||||||
if (selected.length) {
|
if (selected.length) {
|
||||||
const currentIndex = flattenedResults.indexOf(
|
const currentIndex = flattenedResults.indexOf(
|
||||||
// @ts-ignore unclear how to give this spread a return signature
|
// @ts-ignore unclear how to give this spread a return signature
|
||||||
@ -223,7 +236,7 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
|||||||
const { app, link } = flattenedResults[0];
|
const { app, link } = flattenedResults[0];
|
||||||
setSelected([app, link]);
|
setSelected([app, link]);
|
||||||
}
|
}
|
||||||
}, [selected, results]);
|
}, [results, categoryOrder, selected]);
|
||||||
|
|
||||||
const setSelection = (app, link) => {
|
const setSelection = (app, link) => {
|
||||||
setLeapCursor('pointer');
|
setLeapCursor('pointer');
|
||||||
@ -255,14 +268,15 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
|||||||
}
|
}
|
||||||
if (evt.key === 'Enter') {
|
if (evt.key === 'Enter') {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
let values = flattenCattegoryMap(categoryOrder, results);
|
||||||
if (selected.length) {
|
if (selected.length) {
|
||||||
navigate(selected[0], selected[1], evt.shiftKey);
|
navigate(selected[0], selected[1], evt.shiftKey);
|
||||||
} else if (Array.from(results.values()).flat().length === 0) {
|
} else if (values.length === 0) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
navigate(
|
navigate(
|
||||||
Array.from(results.values()).flat()[0].app,
|
values[0].app,
|
||||||
Array.from(results.values()).flat()[0].link,
|
values[0].link,
|
||||||
evt.shiftKey
|
evt.shiftKey
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -275,15 +289,16 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
|||||||
query,
|
query,
|
||||||
props.show,
|
props.show,
|
||||||
results,
|
results,
|
||||||
|
categoryOrder,
|
||||||
setPreviousSelected,
|
setPreviousSelected,
|
||||||
setNextSelected
|
setNextSelected
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const flattenedResultLinks: [string, string][] = Array.from(results.values())
|
const flattenedResultLinks: [string, string][] =
|
||||||
.flat()
|
flattenCattegoryMap(categoryOrder, results)
|
||||||
.map(result => [result.app, result.link]);
|
.map(result => [result.app, result.link]);
|
||||||
if (!flattenedResultLinks.includes(selected as [string, string])) {
|
if (!flattenedResultLinks.includes(selected as [string, string])) {
|
||||||
setSelected(flattenedResultLinks[0] || []);
|
setSelected(flattenedResultLinks[0] || []);
|
||||||
}
|
}
|
||||||
@ -319,10 +334,10 @@ export function Omnibox(props: OmniboxProps): ReactElement {
|
|||||||
borderBottomLeftRadius={2}
|
borderBottomLeftRadius={2}
|
||||||
borderBottomRightRadius={2}
|
borderBottomRightRadius={2}
|
||||||
>
|
>
|
||||||
{SEARCHED_CATEGORIES.map(category =>
|
{categoryOrder.map(category =>
|
||||||
({
|
({
|
||||||
category,
|
category,
|
||||||
categoryResults: _.take(results.get(category).sort(sortResults), CAT_LIMIT)
|
categoryResults: _.take(results.get(category), CAT_LIMIT)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.filter(category => category.categoryResults.length > 0)
|
.filter(category => category.categoryResults.length > 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user