Skip to content

Commit

Permalink
feat(website): update language previews on subset selection (#962)
Browse files Browse the repository at this point in the history
* feat: update preview text on language selection

* fix: clearer feedback on zero length answers

* fix: cleanup incorrect subset previews

* perf: debounce search queries
  • Loading branch information
ayuhito committed Apr 15, 2024
1 parent 094551c commit db13200
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 32 deletions.
4 changes: 2 additions & 2 deletions website/app/components/Dropdown.module.css
Expand Up @@ -8,7 +8,7 @@
border: none;
}

&:hover {
&:hover:not(:disabled) {
background-color: var(--mantine-color-purple-hover);
}
}
Expand All @@ -21,7 +21,7 @@
border: none;
}

&:hover {
&:hover:not(:disabled) {
background-color: var(--mantine-color-background-6);
}
}
Expand Down
5 changes: 5 additions & 0 deletions website/app/components/Dropdown.tsx
Expand Up @@ -21,6 +21,7 @@ interface DropdownBaseProps {
w?: number | string;
noBorder?: boolean;
search?: (query: string) => void;
disabled?: boolean;
}
interface DropdownItems {
label: string;
Expand All @@ -45,6 +46,7 @@ const DropdownBase = ({
noBorder,
refine,
search,
disabled,
}: DropdownBaseProps) => {
const [searchQuery, setSearchQuery] = useState('');

Expand Down Expand Up @@ -75,6 +77,7 @@ const DropdownBase = ({
onOptionSubmit={handleValueSelect}
transitionProps={{ duration: 100, transition: 'fade' }}
width={w ?? rem(250)}
disabled={disabled}
>
<Combobox.DropdownTarget>
<InputBase
Expand All @@ -88,6 +91,7 @@ const DropdownBase = ({
rightSectionPointerEvents="none"
w={w ?? rem(250)}
data-no-border={noBorder}
disabled={disabled}
>
{label}
</InputBase>
Expand Down Expand Up @@ -187,6 +191,7 @@ const DropdownCheckbox = ({
noBorder={noBorder}
refine={refine}
search={search}
disabled={items.length === 0}
/>
);
};
Expand Down
57 changes: 51 additions & 6 deletions website/app/components/search/Dropdowns.tsx
Expand Up @@ -4,6 +4,12 @@ import { useMenu, useRefinementList } from 'react-instantsearch';
import { DropdownCheckbox } from '@/components/Dropdown';
import { subsetToLanguage } from '@/utils/language/subsets';

import { type SearchState } from './observables';

interface LanguagesDropdownProps {
state$: SearchState;
}

const categoriesMap: Record<string, string> = {
serif: 'Serif',
'sans-serif': 'Sans Serif',
Expand All @@ -28,7 +34,7 @@ const transformCategories = (items: MenuItem[]): MenuItem[] => {
}));
};

const LanguagesDropdown = () => {
const LanguagesDropdown = ({ state$ }: LanguagesDropdownProps) => {
const { items, refine, searchForItems } = useRefinementList({
attribute: 'subsets',
operator: 'and',
Expand All @@ -37,13 +43,36 @@ const LanguagesDropdown = () => {
transformItems: transformSubsets,
});

const label = items.find((item) => item.isRefined)?.label ?? 'All languages';
const refinedItems = items.filter((item) => item.isRefined);

const label = () => {
if (refinedItems.length === 1) {
return refinedItems[0].label;
}

if (refinedItems.length > 1) {
return `${refinedItems[0].label} + ${refinedItems.length - 1}`;
}

if (items.length === 0) {
return 'No languages';
}

return 'All languages';
};

const refineLanguage = (value: string) => {
refine(value);
state$.language.set(
refinedItems.some((item) => item.value === value) ? 'latin' : value,
);
};

return (
<DropdownCheckbox
label={label}
label={label()}
items={items}
refine={refine}
refine={refineLanguage}
showCount
search={searchForItems}
/>
Expand All @@ -58,10 +87,26 @@ const CategoriesDropdown = () => {
transformItems: transformCategories,
});

const label = items.find((item) => item.isRefined)?.label ?? 'All categories';
const refinedItems = items.filter((item) => item.isRefined);

const label = () => {
if (refinedItems.length === 1) {
return refinedItems[0].label;
}

if (refinedItems.length > 1) {
return `${refinedItems[0].label} + ${refinedItems.length - 1}`;
}

if (items.length === 0) {
return 'No categories';
}

return 'All categories';
};

return (
<DropdownCheckbox label={label} items={items} refine={refine} showCount />
<DropdownCheckbox label={label()} items={items} refine={refine} showCount />
);
};

Expand Down
9 changes: 1 addition & 8 deletions website/app/components/search/Filters.tsx
Expand Up @@ -47,13 +47,6 @@ const Filters = ({ state$ }: FilterProps) => {
clearSortBy('prod_POPULAR');
};

state$.preview.inputView.onChange((e) => {
if (e.value !== '') {
state$.preview.label.set('Custom');
state$.preview.value.set(e.value ?? '');
}
});

return (
<Box className={classes.container}>
<SimpleGrid cols={{ base: 1, sm: 2, md: 3 }} spacing={0}>
Expand All @@ -64,7 +57,7 @@ const Filters = ({ state$ }: FilterProps) => {
<Box className={classes.filters}>
<Group justify="center" wrap="nowrap">
<CategoriesDropdown />
<LanguagesDropdown />
<LanguagesDropdown state$={state$} />
</Group>
<Group justify="center" wrap="nowrap">
<UnstyledButton
Expand Down
9 changes: 8 additions & 1 deletion website/app/components/search/Hits.tsx
Expand Up @@ -33,7 +33,6 @@ const HitComponent = observer(({ hit, state$ }: HitComponentProps) => {
hit.category === 'other';

// We want a unique preview text for each font if it's not latin

const currentPreview$ = useComputed(() => {
// If isNotLatin is true, update currentPreview to the correct preview text
if (state$.preview.inputView.get() === '' && isNotLatin) {
Expand All @@ -43,6 +42,14 @@ const HitComponent = observer(({ hit, state$ }: HitComponentProps) => {
return state$.preview.value.get();
});

// Update the preview value to a language specific sentence
// if the language is changed and preset is not custom
state$.language.onChange((e) => {
if (state$.preview.label.get() !== 'Custom') {
state$.preview.value.set(getPreviewText(e.value, hit.objectID));
}
});

return (
<Box
renderRoot={({ ...others }) => (
Expand Down
12 changes: 6 additions & 6 deletions website/app/components/search/SearchTextInput.tsx
@@ -1,5 +1,5 @@
import { TextInput } from '@mantine/core';
import { useFocusWithin } from '@mantine/hooks';
import { useDebouncedCallback, useFocusWithin } from '@mantine/hooks';
import { useState } from 'react';
import { useSearchBox } from 'react-instantsearch';

Expand All @@ -12,13 +12,13 @@ const SearchBar = () => {
const { query, refine } = useSearchBox();
const [inputValue, setInputValue] = useState(query);

const setQuery = (newQuery: string) => {
setInputValue(newQuery);
refine(newQuery);
};
const handleSearch = useDebouncedCallback((value: string) => {
refine(value);
}, 300);

const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setQuery(event.currentTarget.value);
setInputValue(event.currentTarget.value);
handleSearch(event.currentTarget.value);
};

// Track when the InstantSearch query changes to synchronize it with
Expand Down
3 changes: 2 additions & 1 deletion website/app/components/search/observables.ts
Expand Up @@ -6,7 +6,8 @@ interface SearchObject {
label: string;
value: string;
inputView: string;
}
};
language: string;
display: 'list' | 'grid';
}

Expand Down
11 changes: 11 additions & 0 deletions website/app/routes/_index.tsx
Expand Up @@ -115,6 +115,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
value: 'Sphinx of black quartz, judge my vow.',
inputView: '',
},
language: 'latin',
display: 'grid',
});

Expand Down Expand Up @@ -172,9 +173,19 @@ export default function Index() {
value: 'Sphinx of black quartz, judge my vow.',
inputView: '',
},
language: 'latin',
display: 'grid',
});

// Update the preset preview label to custom if
// a manual input is detected
state$.preview.inputView.onChange((e) => {
if (e.value !== '') {
state$.preview.label.set('Custom');
state$.preview.value.set(e.value ?? '');
}
});

return (
<InstantSearchSSRProvider {...serverState}>
<InstantSearch
Expand Down
20 changes: 12 additions & 8 deletions website/app/utils/language/language.ts
Expand Up @@ -22,6 +22,18 @@ export const getPreviewText = (subset: string, id?: string) => {
return 'searchsettingshomepersonaddshopping_cartcheck_circlefavoritelogouttrophy';
}

case 'noto-sans-symbols': {
return '⛾⛿☯☸ ⛩⛰⛱⛴⛷⛸ ♸⚥☊☍☓☤ 🄰🄱🆈🆉 ⚖♇♪♬';
}

case 'noto-sans-symbols-2': {
return '⌚✋⯧☔🛪🏟⛅🞽🕖 🚲🡽🨄 🡢🡱🏠💻🐿👁📽';
}

case 'noto-sans-math': {
return '𝞉𝞩𝟃𞻰⟥⦀⦁ 𝚢𝚣𝚤𝖿𝗀𝗁𝗂 𝑻𝑼𝑽𝗔𝗕𝗖𝗗 ϑϕϰϱϵℊℎ ⊰⊱⊲⊳⊴⊵⫕ 𞹴𞹵𞹶𞹷𞹹𞹺𞹻';
}

case 'yakuhanjp':
case 'yakuhanrp': {
return '、。!?〈〉《》「」『』【】〔〕・():;[]{}';
Expand Down Expand Up @@ -354,10 +366,6 @@ export const getPreviewText = (subset: string, id?: string) => {
return '𑴥𑴰 𑴓𑴎𑴛𑴲 𑴩𑴱𑴟𑵅𑴛𑴲𑴟𑵅𑴥𑴱𑴥𑴫𑵅𑴨𑴱𑴛𑴟𑵄𑴰𑵅𑴥𑴱𑴚𑴱𑵀 𑴁𑴞𑴱𑴦𑵁';
}

case 'math': {
return '𝞉𝞩𝟃𞻰⟥⦀⦁ 𝚢𝚣𝚤𝖿𝗀𝗁𝗂 𝑻𝑼𝑽𝗔𝗕𝗖𝗗 ϑϕϰϱϵℊℎ ⊰⊱⊲⊳⊴⊵⫕ 𞹴𞹵𞹶𞹷𞹹𞹺𞹻';
}

case 'mayan-numerals': {
return '𝋠𝋡𝋢𝋣𝋤𝋥𝋦 𝋧𝋨𝋩𝋪𝋫𝋬𝋭';
}
Expand Down Expand Up @@ -554,10 +562,6 @@ export const getPreviewText = (subset: string, id?: string) => {
return 'ꠎꠔ꠆ꠞ ꠎꠉꠔꠤ ꠡꠣꠘ꠆ꠔꠤꠘ꠆ꠎꠣꠎꠡ꠆ꠛꠣꠔꠘ꠆ꠔ꠆ꠞ꠆ꠎꠣꠘꠣꠋ ꠀꠗꠣꠞꠢ꠆ ꠝꠣꠘꠛꠙꠞꠤꠛꠣꠞꠡ꠆ꠎ ꠡꠞ꠆ꠛꠦꠡꠣꠝꠙꠤ';
}

case 'symbols': {
return '⛾⛿☯☸ ⛩⛰⛱⛴⛷⛸ ♸⚥☊☍☓☤ 🄰🄱🆈🆉 ⚖♇♪♬';
}

case 'syriac': {
return 'ܟܠ ܒܪܢܫܐ ܒܪܝܠܗ ܚܐܪܐ ܘܒܪܒܪ ܓܘ ܐܝܩܪܐ ܘܙܕܩܐ.';
}
Expand Down

0 comments on commit db13200

Please sign in to comment.