import { forwardRef, useImperativeHandle, useState } from 'react'; import { Autocomplete, CloseButton, Stack, Title, Text, Group, Loader, createStyles, Box, Image, SelectItemProps, ScrollArea, } from '@mantine/core'; import { IconSearch } from '@tabler/icons-react'; import { useTranslation } from 'next-i18next'; import { useGetDashboardIcons } from '../../hooks/icons/useGetDashboardIcons'; import { humanFileSize } from '../../tools/humanFileSize'; import { DebouncedImage } from './DebouncedImage'; export const IconSelector = forwardRef( ( { defaultValue, value, onChange, }: { defaultValue: string; value?: string; onChange: (debouncedValue: string | undefined) => void; }, ref ) => { const { t } = useTranslation('layout/modals/add-app'); const { classes } = useStyles(); const { data, isLoading } = useGetDashboardIcons(); const [currentValue, setValue] = useState(value ?? defaultValue); const flatIcons = data === undefined ? [] : data.flatMap((repository) => repository.entries.map((entry) => ({ url: entry.url, label: entry.name, size: entry.size, value: entry.url, group: repository.name, copyright: repository.copyright, })) ); useImperativeHandle(ref, () => ({ chooseFirstOrDefault(searchTerm: string) { const match = flatIcons.find((icon) => icon.label.toLowerCase().includes(searchTerm.toLowerCase()) ); if (!match) { return; } onChange(match.url); }, })); return ( {t('appearance.icon.autocomplete.title')} {t('appearance.icon.autocomplete.text')} } icon={} rightSection={ (value ?? currentValue).length > 0 ? ( onChange(undefined)} /> ) : null } itemComponent={AutoCompleteItem} className={classes.textInput} data={flatIcons} limit={25} label={t('appearance.icon.label')} description={t('appearance.icon.description', { suggestionsCount: data?.reduce((a, b) => a + b.count, 0) ?? 0, })} filter={(search, item) => item.value .toLowerCase() .replaceAll('_', '') .replaceAll(' ', '-') .includes(search.toLowerCase().replaceAll('_', '').replaceAll(' ', '-')) } dropdownComponent={(props: any) => } onChange={(event) => { onChange(event); setValue(event); }} dropdownPosition="bottom" variant="default" value={value} withAsterisk withinPortal required /> {(!data || isLoading) && ( {t('appearance.icon.noItems.title')} {t('appearance.icon.noItems.text')} )} ); } ); const useStyles = createStyles(() => ({ textInput: { flexGrow: 1, }, })); const AutoCompleteItem = forwardRef( ({ label, size, copyright, url, ...others }: ItemProps, ref) => (
({ backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[2], borderRadius: theme.radius.md, })} p={2} > {label} {humanFileSize(size, false)} {copyright && ( © {copyright} )}
) ); interface ItemProps extends SelectItemProps { url: string; group: string; size: number; copyright: string | undefined; }