Word match
This commit is contained in:
@@ -483,6 +483,7 @@ const labelForOption = (option: SearchOption) => {
|
||||
|
||||
case "date":
|
||||
return t("date");
|
||||
|
||||
case "location":
|
||||
return t("location");
|
||||
|
||||
|
||||
@@ -160,11 +160,11 @@ const localizedSearchData = () =>
|
||||
locale: i18n.language,
|
||||
holidays: holidays().map((h) => ({
|
||||
...h,
|
||||
lowercasedName: h.label.toLowerCase(),
|
||||
searchTerms: h.label.toLowerCase().split(" "),
|
||||
})),
|
||||
labelledFileTypes: labelledFileTypes().map((t) => ({
|
||||
...t,
|
||||
lowercasedName: t.label.toLowerCase(),
|
||||
searchTerms: t.label.toLowerCase().split(" "),
|
||||
})),
|
||||
});
|
||||
|
||||
|
||||
@@ -63,17 +63,17 @@ export interface LabelledFileType {
|
||||
}
|
||||
|
||||
/**
|
||||
* An annotated version of {@link T} that includes its searchable "lowercased"
|
||||
* label or name.
|
||||
* An annotated version of {@link T} that includes a list of lowercased words
|
||||
* that it should match.
|
||||
*
|
||||
* Precomputing these lowercased values saves us from doing the lowercasing
|
||||
* during the search itself.
|
||||
*/
|
||||
export type Searchable<T> = T & {
|
||||
/**
|
||||
* The name or label of T, lowercased.
|
||||
* The name or label of T, split into words and lowercased.
|
||||
*/
|
||||
lowercasedName: string;
|
||||
searchTerms: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,13 +53,13 @@ export class SearchWorker {
|
||||
.then((ts) => {
|
||||
this.locationTags = ts.map((t) => ({
|
||||
...t,
|
||||
lowercasedName: t.name.toLowerCase(),
|
||||
searchTerms: t.name.toLowerCase().split(" "),
|
||||
}));
|
||||
}),
|
||||
fetchCities().then((cs) => {
|
||||
this.cities = cs.map((c) => ({
|
||||
...c,
|
||||
lowercasedName: c.name.toLowerCase(),
|
||||
searchTerms: c.name.toLowerCase().split(" "),
|
||||
}));
|
||||
}),
|
||||
]);
|
||||
@@ -77,7 +77,10 @@ export class SearchWorker {
|
||||
*/
|
||||
setPeople(people: Person[]) {
|
||||
this.searchablePeople = people.map((person) => {
|
||||
return { ...person, lowercasedName: person.name.toLowerCase() };
|
||||
return {
|
||||
...person,
|
||||
searchTerms: person.name.toLowerCase().split(" "),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -165,9 +168,17 @@ const fileTypeSuggestions = (
|
||||
labelledFileTypes: Searchable<LabelledFileType>[],
|
||||
): SearchSuggestion[] =>
|
||||
labelledFileTypes
|
||||
.filter(({ lowercasedName }) => lowercasedName.startsWith(s))
|
||||
.filter(searchableMatch(s))
|
||||
.map(({ fileType, label }) => ({ type: "fileType", fileType, label }));
|
||||
|
||||
/**
|
||||
* A helper function to directly pass to filters on Searchable<T>[].
|
||||
*/
|
||||
const searchableMatch =
|
||||
(s: string) =>
|
||||
({ searchTerms }: { searchTerms: string[] }) =>
|
||||
searchTerms.some((t) => t.startsWith(s));
|
||||
|
||||
const fileNameSuggestion = (
|
||||
s: string,
|
||||
searchString: string,
|
||||
@@ -211,7 +222,7 @@ const peopleSuggestions = (
|
||||
searchablePeople: Searchable<Person>[],
|
||||
): SearchSuggestion[] =>
|
||||
searchablePeople
|
||||
.filter(({ lowercasedName }) => lowercasedName.startsWith(s))
|
||||
.filter(searchableMatch(s))
|
||||
.map((person) => ({ type: "person", person, label: person.name }));
|
||||
|
||||
const dateSuggestions = (
|
||||
@@ -247,7 +258,7 @@ const parseDateComponents = (
|
||||
[
|
||||
parseChrono(s, locale),
|
||||
parseYearComponents(s),
|
||||
holidays.filter(searchableIncludes(s)),
|
||||
holidays.filter(searchableMatch(s)),
|
||||
].flat();
|
||||
|
||||
const parseChrono = (
|
||||
@@ -299,14 +310,6 @@ const parseYearComponents = (s: string): LabelledSearchDateComponents[] => {
|
||||
return [];
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper function to directly pass to filters on Searchable<T>[].
|
||||
*/
|
||||
const searchableIncludes =
|
||||
(s: string) =>
|
||||
({ lowercasedName }: { lowercasedName: string }) =>
|
||||
lowercasedName.includes(s);
|
||||
|
||||
/**
|
||||
* Zod schema describing world_cities.json.
|
||||
*
|
||||
@@ -335,17 +338,15 @@ const locationSuggestions = (
|
||||
locationTags: Searchable<LocationTag>[],
|
||||
cities: Searchable<City>[],
|
||||
): SearchSuggestion[] => {
|
||||
const matchingLocationTags = locationTags.filter(searchableIncludes(s));
|
||||
const matchingLocationTags = locationTags.filter(searchableMatch(s));
|
||||
|
||||
const matchingLocationTagLNames = new Set(
|
||||
matchingLocationTags.map((t) => t.lowercasedName),
|
||||
matchingLocationTags.map((t) => t.searchTerms),
|
||||
);
|
||||
|
||||
const matchingCities = cities.filter(
|
||||
(c) =>
|
||||
c.lowercasedName.startsWith(s) &&
|
||||
!matchingLocationTagLNames.has(c.lowercasedName),
|
||||
);
|
||||
const matchingCities = cities
|
||||
.filter(searchableMatch(s))
|
||||
.filter((c) => !matchingLocationTagLNames.has(c.searchTerms));
|
||||
|
||||
return [
|
||||
matchingLocationTags.map(
|
||||
|
||||
Reference in New Issue
Block a user