Search Provider icons
This commit is contained in:
@@ -29,23 +29,12 @@ export function AppItem({
|
|||||||
const { ref, width, height } = useElementSize();
|
const { ref, width, height } = useElementSize();
|
||||||
const allIcons: any = { ...fa6, ...vsc, ...si };
|
const allIcons: any = { ...fa6, ...vsc, ...si };
|
||||||
const Icon = allIcons[icon];
|
const Icon = allIcons[icon];
|
||||||
const { isMobile, theme } = useCommonHooks();
|
const { isMobile, filter } = useCommonHooks();
|
||||||
const [textDecoration, setTextDecoration] = useState<string>('none');
|
const [textDecoration, setTextDecoration] = useState<string>('none');
|
||||||
const [hover, setHover] = useState<boolean>(false);
|
const [hover, setHover] = useState<boolean>(false);
|
||||||
const validUrl =
|
const validUrl =
|
||||||
url.startsWith('http://') || url.startsWith('https://') ? url : `http://${url}`;
|
url.startsWith('http://') || url.startsWith('https://') ? url : `http://${url}`;
|
||||||
|
|
||||||
const filter = () => {
|
|
||||||
if (selectedTheme && selectedTheme.appShadowsEnabled === 1) {
|
|
||||||
return 'drop-shadow(2px 2px color-mix(in srgb, var(--mantine-color-accent-0), transparent 30%))';
|
|
||||||
}
|
|
||||||
if (!selectedTheme && theme.appShadowsEnabled === 1) {
|
|
||||||
return 'drop-shadow(2px 2px color-mix(in srgb, var(--mantine-color-accent-0), transparent 30%))';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'none';
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
component='a'
|
component='a'
|
||||||
@@ -113,7 +102,7 @@ export function AppItem({
|
|||||||
style={{
|
style={{
|
||||||
height: scale * 32,
|
height: scale * 32,
|
||||||
width: scale * 32,
|
width: scale * 32,
|
||||||
filter: filter(),
|
filter: filter(selectedTheme),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -65,16 +65,27 @@ export function useCommonHooks() {
|
|||||||
key: 'providerPrefix',
|
key: 'providerPrefix',
|
||||||
defaultValue: '/g',
|
defaultValue: '/g',
|
||||||
});
|
});
|
||||||
|
const [defaultProviderIcon, setDefaultProviderIcon] = useLocalStorage<string>({
|
||||||
|
key: 'providerIcon',
|
||||||
|
defaultValue: 'FaGoogle',
|
||||||
|
});
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [providerLabel, setProviderLabel] = useState(defaultProviderLabel);
|
const [providerLabel, setProviderLabel] = useState(defaultProviderLabel);
|
||||||
const [providerURL, setProviderURL] = useState(defaultProviderURL);
|
const [providerURL, setProviderURL] = useState(defaultProviderURL);
|
||||||
const [providerPrefix, setProviderPrefix] = useState(defaultProviderPrefix);
|
const [providerPrefix, setProviderPrefix] = useState(defaultProviderPrefix);
|
||||||
|
const [providerIcon, setProviderIcon] = useState(defaultProviderIcon);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setProviderLabel(defaultProviderLabel);
|
setProviderLabel(defaultProviderLabel);
|
||||||
setProviderURL(defaultProviderURL);
|
setProviderURL(defaultProviderURL);
|
||||||
setProviderPrefix(defaultProviderPrefix);
|
setProviderPrefix(defaultProviderPrefix);
|
||||||
}, [defaultProviderLabel, defaultProviderURL, defaultProviderPrefix]);
|
setProviderIcon(defaultProviderIcon);
|
||||||
|
}, [
|
||||||
|
defaultProviderLabel,
|
||||||
|
defaultProviderURL,
|
||||||
|
defaultProviderPrefix,
|
||||||
|
defaultProviderIcon,
|
||||||
|
]);
|
||||||
|
|
||||||
const [currentUser, setCurrentUser] = useLocalStorage<User>({
|
const [currentUser, setCurrentUser] = useLocalStorage<User>({
|
||||||
key: 'user',
|
key: 'user',
|
||||||
@@ -141,6 +152,17 @@ export function useCommonHooks() {
|
|||||||
mutateAsync({ method: 'DELETE', endpoint: endpoint, body: item });
|
mutateAsync({ method: 'DELETE', endpoint: endpoint, body: item });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const filter = (selectedTheme?: Theme) => {
|
||||||
|
if (selectedTheme && selectedTheme.appShadowsEnabled === 1) {
|
||||||
|
return 'drop-shadow(2px 2px color-mix(in srgb, var(--mantine-color-accent-0), transparent 30%))';
|
||||||
|
}
|
||||||
|
if (!selectedTheme && theme.appShadowsEnabled === 1) {
|
||||||
|
return 'drop-shadow(2px 2px color-mix(in srgb, var(--mantine-color-accent-0), transparent 30%))';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'none';
|
||||||
|
};
|
||||||
|
|
||||||
function fixDigits(k: number) {
|
function fixDigits(k: number) {
|
||||||
if (k < 10) {
|
if (k < 10) {
|
||||||
return `0${k}`;
|
return `0${k}`;
|
||||||
@@ -195,6 +217,7 @@ export function useCommonHooks() {
|
|||||||
theme,
|
theme,
|
||||||
setTheme,
|
setTheme,
|
||||||
urlPattern,
|
urlPattern,
|
||||||
|
filter,
|
||||||
fixDigits,
|
fixDigits,
|
||||||
reorder,
|
reorder,
|
||||||
getObjectDiff,
|
getObjectDiff,
|
||||||
@@ -230,12 +253,16 @@ export function useCommonHooks() {
|
|||||||
setProviderURL,
|
setProviderURL,
|
||||||
providerPrefix,
|
providerPrefix,
|
||||||
setProviderPrefix,
|
setProviderPrefix,
|
||||||
|
providerIcon,
|
||||||
|
setProviderIcon,
|
||||||
defaultProviderLabel,
|
defaultProviderLabel,
|
||||||
setDefaultProviderLabel,
|
setDefaultProviderLabel,
|
||||||
defaultProviderURL,
|
defaultProviderURL,
|
||||||
setDefaultProviderURL,
|
setDefaultProviderURL,
|
||||||
defaultProviderPrefix,
|
defaultProviderPrefix,
|
||||||
setDefaultProviderPrefix,
|
setDefaultProviderPrefix,
|
||||||
|
defaultProviderIcon,
|
||||||
|
setDefaultProviderIcon,
|
||||||
currentUser,
|
currentUser,
|
||||||
setCurrentUser,
|
setCurrentUser,
|
||||||
currentLocation,
|
currentLocation,
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ export default function Search({
|
|||||||
setProviderURL,
|
setProviderURL,
|
||||||
providerPrefix,
|
providerPrefix,
|
||||||
setProviderPrefix,
|
setProviderPrefix,
|
||||||
|
providerIcon,
|
||||||
|
setProviderIcon,
|
||||||
searchValue,
|
searchValue,
|
||||||
setSearchValue,
|
setSearchValue,
|
||||||
defaultProviderURL,
|
defaultProviderURL,
|
||||||
@@ -89,10 +91,13 @@ export default function Search({
|
|||||||
setDefaultProviderLabel,
|
setDefaultProviderLabel,
|
||||||
defaultProviderPrefix,
|
defaultProviderPrefix,
|
||||||
setDefaultProviderPrefix,
|
setDefaultProviderPrefix,
|
||||||
|
defaultProviderIcon,
|
||||||
|
setDefaultProviderIcon,
|
||||||
} = useCommonHooks();
|
} = useCommonHooks();
|
||||||
const [placeholderValue, setPlaceholderValue] = useState<string>('');
|
const [placeholderValue, setPlaceholderValue] = useState<string>('');
|
||||||
const [value, setValue] = useState(0);
|
const [value, setValue] = useState(0);
|
||||||
const [historyMultiplier, setHistoryMultiplier] = useState(1);
|
const [historyMultiplier, setHistoryMultiplier] = useState(1);
|
||||||
|
const Icon = allIcons[providerIcon];
|
||||||
|
|
||||||
const handleResetSearch = () => {
|
const handleResetSearch = () => {
|
||||||
setSearchValue('');
|
setSearchValue('');
|
||||||
@@ -259,6 +264,7 @@ export default function Search({
|
|||||||
setProviderLabel('Google Search');
|
setProviderLabel('Google Search');
|
||||||
setProviderURL('https://www.google.com/search?q=');
|
setProviderURL('https://www.google.com/search?q=');
|
||||||
setProviderPrefix('/g');
|
setProviderPrefix('/g');
|
||||||
|
setProviderIcon('FaGoogle');
|
||||||
} else if (item.target.value.startsWith('/')) {
|
} else if (item.target.value.startsWith('/')) {
|
||||||
const provider = providers?.find(
|
const provider = providers?.find(
|
||||||
(p: Provider) => p.prefix === item.target.value.split(' ')[0],
|
(p: Provider) => p.prefix === item.target.value.split(' ')[0],
|
||||||
@@ -266,6 +272,7 @@ export default function Search({
|
|||||||
setProviderLabel(provider?.name ?? 'Invalid Search');
|
setProviderLabel(provider?.name ?? 'Invalid Search');
|
||||||
setProviderURL(provider?.url ?? '');
|
setProviderURL(provider?.url ?? '');
|
||||||
setProviderPrefix(provider?.prefix ?? '');
|
setProviderPrefix(provider?.prefix ?? '');
|
||||||
|
setProviderIcon(provider?.icon ?? '');
|
||||||
} else if (item.target.value.startsWith('!')) {
|
} else if (item.target.value.startsWith('!')) {
|
||||||
if (item.target.value === '!w' || item.target.value === '!weather') {
|
if (item.target.value === '!w' || item.target.value === '!weather') {
|
||||||
setProviderLabel('Show weather');
|
setProviderLabel('Show weather');
|
||||||
@@ -283,6 +290,7 @@ export default function Search({
|
|||||||
setProviderLabel(defaultProviderLabel);
|
setProviderLabel(defaultProviderLabel);
|
||||||
setProviderURL(defaultProviderURL);
|
setProviderURL(defaultProviderURL);
|
||||||
setProviderPrefix(defaultProviderPrefix);
|
setProviderPrefix(defaultProviderPrefix);
|
||||||
|
setProviderIcon(defaultProviderIcon);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -333,7 +341,12 @@ export default function Search({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderItem: any = (item: any) => {
|
const renderItem: any = (item: any) => {
|
||||||
const Icon = allIcons[item.option.icon];
|
const Icon =
|
||||||
|
allIcons[
|
||||||
|
(item.option.icon ?? item.option.prefix === '/g')
|
||||||
|
? 'FaGoogle'
|
||||||
|
: (providers.find((p: Provider) => p.prefix === item.option.prefix)?.icon ?? '')
|
||||||
|
];
|
||||||
return !searchValue.startsWith('!') ? (
|
return !searchValue.startsWith('!') ? (
|
||||||
item.option.value === 'load' ? (
|
item.option.value === 'load' ? (
|
||||||
<Group
|
<Group
|
||||||
@@ -363,6 +376,7 @@ export default function Search({
|
|||||||
handleSearchHistoryItem={handleSearchHistoryItem}
|
handleSearchHistoryItem={handleSearchHistoryItem}
|
||||||
searchEndpoint={searchEndpoint}
|
searchEndpoint={searchEndpoint}
|
||||||
setSearchValue={setSearchValue}
|
setSearchValue={setSearchValue}
|
||||||
|
Icon={Icon}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
@@ -470,6 +484,7 @@ export default function Search({
|
|||||||
);
|
);
|
||||||
setDefaultProviderPrefix(defaultProviderData[0]?.prefix ?? '/g');
|
setDefaultProviderPrefix(defaultProviderData[0]?.prefix ?? '/g');
|
||||||
setDefaultProviderLabel(defaultProviderData[0]?.name ?? 'Google Search');
|
setDefaultProviderLabel(defaultProviderData[0]?.name ?? 'Google Search');
|
||||||
|
setDefaultProviderIcon(defaultProviderData[0]?.icon ?? 'FaGoogle');
|
||||||
}
|
}
|
||||||
}, [defaultProviderData, defaultProviderDataIsFetched]);
|
}, [defaultProviderData, defaultProviderDataIsFetched]);
|
||||||
|
|
||||||
@@ -520,7 +535,18 @@ export default function Search({
|
|||||||
spellCheck={true}
|
spellCheck={true}
|
||||||
searchable
|
searchable
|
||||||
autoFocus={!isMobile}
|
autoFocus={!isMobile}
|
||||||
leftSection={providerLabel}
|
leftSection={
|
||||||
|
providerIcon ? (
|
||||||
|
<Icon
|
||||||
|
style={{
|
||||||
|
height: 32,
|
||||||
|
width: 32,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
providerLabel
|
||||||
|
)
|
||||||
|
}
|
||||||
rightSection={<div />}
|
rightSection={<div />}
|
||||||
clearable
|
clearable
|
||||||
onClear={handleResetSearch}
|
onClear={handleResetSearch}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ function SearchSelectItem({
|
|||||||
handleSearchHistoryItem,
|
handleSearchHistoryItem,
|
||||||
searchEndpoint,
|
searchEndpoint,
|
||||||
setSearchValue,
|
setSearchValue,
|
||||||
|
Icon,
|
||||||
}: any) {
|
}: any) {
|
||||||
const { isMobile, theme } = useCommonHooks();
|
const { isMobile, theme } = useCommonHooks();
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
@@ -22,7 +23,6 @@ function SearchSelectItem({
|
|||||||
const dateString = isMobile
|
const dateString = isMobile
|
||||||
? `${month}/${day}/${year}`
|
? `${month}/${day}/${year}`
|
||||||
: `${month}/${day}/${year} ${hours}:${minutes}`;
|
: `${month}/${day}/${year} ${hours}:${minutes}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group
|
<Group
|
||||||
w={'100%'}
|
w={'100%'}
|
||||||
@@ -39,24 +39,48 @@ function SearchSelectItem({
|
|||||||
setShowFillButton(false);
|
setShowFillButton(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Group m={0} p={0} w={'160px'}>
|
<Group
|
||||||
<Text
|
m={0}
|
||||||
style={{
|
p={0}
|
||||||
backgroundColor: `${theme.primaryColor}33`,
|
w={'120px'}
|
||||||
fontWeight: 600,
|
justify='center'
|
||||||
borderRadius: '15px',
|
style={{
|
||||||
padding: '.25rem',
|
overflow: 'hidden',
|
||||||
}}
|
whiteSpace: 'nowrap',
|
||||||
>
|
}}
|
||||||
{item.option.provider}
|
>
|
||||||
</Text>
|
{Icon ? (
|
||||||
|
<Icon
|
||||||
|
style={{
|
||||||
|
height: 32,
|
||||||
|
width: 32,
|
||||||
|
backgroundColor: `${theme.primaryColor}33`,
|
||||||
|
borderRadius: '15px',
|
||||||
|
padding: '.25rem',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
backgroundColor: `${theme.primaryColor}33`,
|
||||||
|
fontWeight: 600,
|
||||||
|
borderRadius: '15px',
|
||||||
|
padding: '.25rem',
|
||||||
|
marginRight: '.25rem',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.option.provider}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
<Group
|
<Group
|
||||||
m={0}
|
m={0}
|
||||||
p={0}
|
p={0}
|
||||||
gap={0}
|
gap={0}
|
||||||
justify='space-between'
|
justify='space-between'
|
||||||
w={'calc(100% - 160px)'}
|
w={'calc(100% - 120px)'}
|
||||||
style={{
|
style={{
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
|
|||||||
@@ -1,17 +1,29 @@
|
|||||||
import { Box, Card, Group, Stack, Text, TextInput } from '@mantine/core';
|
import {
|
||||||
|
Box,
|
||||||
|
Card,
|
||||||
|
type ComboboxItem,
|
||||||
|
type ComboboxLikeRenderOptionInput,
|
||||||
|
Group,
|
||||||
|
Select,
|
||||||
|
Stack,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
} from '@mantine/core';
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { DeleteItemModal, ManagementPill } from 'components';
|
import { DeleteItemModal, ManagementPill } from 'components';
|
||||||
import { useCommonHooks, useMutationAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cardClasses, textClasses, textInputClasses } from 'styles';
|
import { cardClasses, selectClasses, textClasses, textInputClasses } from 'styles';
|
||||||
import type { Provider } from 'types';
|
import type { Provider } from 'types';
|
||||||
|
|
||||||
function DebouncedSearchProvider({
|
function DebouncedSearchProvider({
|
||||||
searchProvider,
|
searchProvider,
|
||||||
setIsOpen,
|
setIsOpen,
|
||||||
|
allIcons,
|
||||||
}: {
|
}: {
|
||||||
searchProvider: Provider;
|
searchProvider: Provider;
|
||||||
setIsOpen: (isOpen: boolean) => void;
|
setIsOpen: (isOpen: boolean) => void;
|
||||||
|
allIcons: any;
|
||||||
}) {
|
}) {
|
||||||
const { handleDelete, isMobile, theme } = useCommonHooks();
|
const { handleDelete, isMobile, theme } = useCommonHooks();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
@@ -81,7 +93,7 @@ function DebouncedSearchProvider({
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Stack w={'100%'} align='center'>
|
<Stack w={'100%'} align='center'>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center' pos={'relative'}>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={'Name'}
|
label={'Name'}
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
@@ -100,6 +112,7 @@ function DebouncedSearchProvider({
|
|||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
w={'30%'}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={'Prefix'}
|
label={'Prefix'}
|
||||||
@@ -119,11 +132,63 @@ function DebouncedSearchProvider({
|
|||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
w={'30%'}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label={'Icon'}
|
||||||
|
className={selectClasses.settingsItem}
|
||||||
|
classNames={{
|
||||||
|
wrapper: selectClasses.menuSelectWrapper,
|
||||||
|
input: selectClasses.menuSelectInput,
|
||||||
|
label: selectClasses.menuSelectLabel,
|
||||||
|
options: selectClasses.menuSelectOptions,
|
||||||
|
option: selectClasses.menuSelectOption,
|
||||||
|
dropdown: selectClasses.dropdown,
|
||||||
|
}}
|
||||||
|
w={'30%'}
|
||||||
|
mt={'.75rem'}
|
||||||
|
limit={100}
|
||||||
|
placeholder='Search for an icon...'
|
||||||
|
defaultSearchValue={provider?.icon ?? ''}
|
||||||
|
defaultValue={provider?.icon}
|
||||||
|
data={Object.keys(allIcons).map((icon) => {
|
||||||
|
return { value: icon, label: icon };
|
||||||
|
})}
|
||||||
|
comboboxProps={{
|
||||||
|
zIndex: 3000,
|
||||||
|
}}
|
||||||
|
styles={
|
||||||
|
theme.textShadowsEnabled
|
||||||
|
? {
|
||||||
|
label: { boxShadow: '2px 2px var(--mantine-color-border-0)' },
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onChange={(value: string | null) => {
|
||||||
|
setUpdate({
|
||||||
|
...provider,
|
||||||
|
icon: value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => {
|
||||||
|
const Icon = allIcons[item.option.value];
|
||||||
|
return (
|
||||||
|
<Group>
|
||||||
|
{item.option.value}
|
||||||
|
<Icon />
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
searchable
|
||||||
|
clearable
|
||||||
|
maxDropdownHeight={175}
|
||||||
|
onDropdownOpen={() => setIsOpen(true)}
|
||||||
|
onDropdownClose={() => setIsOpen(false)}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={'Url'}
|
label={'Url'}
|
||||||
w={isMobile ? '80%' : '100%'}
|
w={isMobile ? '80%' : '94%'}
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={provider.url}
|
defaultValue={provider.url}
|
||||||
|
|||||||
@@ -1,11 +1,42 @@
|
|||||||
import { Card, isLightColor, Stack, Text } from '@mantine/core';
|
import { Box, Card, isLightColor, Stack, Text } from '@mantine/core';
|
||||||
import HintItem from 'components/HelpModal/HintItem';
|
import HintItem from 'components/HelpModal/HintItem';
|
||||||
import { cardClasses } from 'styles';
|
import { cardClasses } from 'styles';
|
||||||
import type { Provider } from 'types';
|
import type { Provider } from 'types';
|
||||||
|
|
||||||
function SearchProviderSettingsItem({ provider }: { provider: Provider }) {
|
function SearchProviderSettingsItem({
|
||||||
|
provider,
|
||||||
|
Icon,
|
||||||
|
filter,
|
||||||
|
}: {
|
||||||
|
provider: Provider;
|
||||||
|
Icon: any;
|
||||||
|
filter: any;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<Card className={cardClasses.settingsItemHover} classNames={cardClasses}>
|
<Card className={cardClasses.settingsItemHover} classNames={cardClasses}>
|
||||||
|
{Icon && (
|
||||||
|
<Box
|
||||||
|
pos={'absolute'}
|
||||||
|
top={0}
|
||||||
|
left={0}
|
||||||
|
style={{
|
||||||
|
color: 'var(--mantine-color-primary-0)',
|
||||||
|
backgroundColor: 'var(--mantine-color-accent-0',
|
||||||
|
padding: '0.5rem',
|
||||||
|
borderBottomRightRadius: '.5rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
style={{
|
||||||
|
height: 32,
|
||||||
|
width: 32,
|
||||||
|
filter: filter(),
|
||||||
|
padding: 0,
|
||||||
|
margin: 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
<Stack
|
<Stack
|
||||||
gap={0}
|
gap={0}
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
|
type ComboboxItem,
|
||||||
|
type ComboboxLikeRenderOptionInput,
|
||||||
Grid,
|
Grid,
|
||||||
GridCol,
|
GridCol,
|
||||||
Group,
|
Group,
|
||||||
Popover,
|
Popover,
|
||||||
|
Select,
|
||||||
Stack,
|
Stack,
|
||||||
Switch,
|
Switch,
|
||||||
TextInput,
|
TextInput,
|
||||||
@@ -15,13 +18,23 @@ import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
|||||||
import { AddItemModal, NoItemsFound, SettingsHeader } from 'components';
|
import { AddItemModal, NoItemsFound, SettingsHeader } from 'components';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import * as fa6 from 'react-icons/fa6';
|
||||||
import { FiPower } from 'react-icons/fi';
|
import { FiPower } from 'react-icons/fi';
|
||||||
import { popoverClasses, switchClasses, textInputClasses, toolTipClasses } from 'styles';
|
import * as si from 'react-icons/si';
|
||||||
|
import * as vsc from 'react-icons/vsc';
|
||||||
|
import {
|
||||||
|
popoverClasses,
|
||||||
|
selectClasses,
|
||||||
|
switchClasses,
|
||||||
|
textInputClasses,
|
||||||
|
toolTipClasses,
|
||||||
|
} from 'styles';
|
||||||
import type { Provider } from 'types';
|
import type { Provider } from 'types';
|
||||||
import DebouncedSearchProvider from './DebouncedSearchProvider';
|
import DebouncedSearchProvider from './DebouncedSearchProvider';
|
||||||
import SearchProviderSettingsItem from './SearchProviderSettingsItem';
|
import SearchProviderSettingsItem from './SearchProviderSettingsItem';
|
||||||
|
|
||||||
const SearchProviderSettings = () => {
|
const SearchProviderSettings = () => {
|
||||||
|
const allIcons: any = { ...fa6, ...vsc, ...si };
|
||||||
const defaultProvider = {
|
const defaultProvider = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
name: '',
|
name: '',
|
||||||
@@ -42,7 +55,7 @@ const SearchProviderSettings = () => {
|
|||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
});
|
});
|
||||||
const [providers, setProviders] = useState<Provider[]>([]);
|
const [providers, setProviders] = useState<Provider[]>([]);
|
||||||
const { isMobile, theme } = useCommonHooks();
|
const { isMobile, theme, filter } = useCommonHooks();
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
@@ -91,7 +104,7 @@ const SearchProviderSettings = () => {
|
|||||||
>
|
>
|
||||||
<Stack gap={0} w={'100%'} align='center'>
|
<Stack gap={0} w={'100%'} align='center'>
|
||||||
<Stack w={'100%'} align='center'>
|
<Stack w={'100%'} align='center'>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center' pos={'relative'}>
|
||||||
<TextInput
|
<TextInput
|
||||||
key={form.key('name')}
|
key={form.key('name')}
|
||||||
{...form.getInputProps('name')}
|
{...form.getInputProps('name')}
|
||||||
@@ -107,6 +120,7 @@ const SearchProviderSettings = () => {
|
|||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
w={'30%'}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
key={form.key('prefix')}
|
key={form.key('prefix')}
|
||||||
@@ -123,6 +137,52 @@ const SearchProviderSettings = () => {
|
|||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
w={'30%'}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
key={form.key('icon')}
|
||||||
|
{...form.getInputProps('icon')}
|
||||||
|
label={'Icon'}
|
||||||
|
className={selectClasses.settingsItem}
|
||||||
|
classNames={{
|
||||||
|
wrapper: selectClasses.menuSelectWrapper,
|
||||||
|
input: selectClasses.menuSelectInput,
|
||||||
|
label: selectClasses.menuSelectLabel,
|
||||||
|
options: selectClasses.menuSelectOptions,
|
||||||
|
option: selectClasses.menuSelectOption,
|
||||||
|
dropdown: selectClasses.dropdown,
|
||||||
|
}}
|
||||||
|
w={'30%'}
|
||||||
|
mt={'.75rem'}
|
||||||
|
limit={100}
|
||||||
|
placeholder='Search for an icon...'
|
||||||
|
data={Object.keys(allIcons).map((icon) => {
|
||||||
|
return { value: icon, label: icon };
|
||||||
|
})}
|
||||||
|
comboboxProps={{
|
||||||
|
zIndex: 3000,
|
||||||
|
}}
|
||||||
|
styles={
|
||||||
|
theme.textShadowsEnabled
|
||||||
|
? {
|
||||||
|
label: { boxShadow: '2px 2px var(--mantine-color-border-0)' },
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => {
|
||||||
|
const Icon = allIcons[item.option.value];
|
||||||
|
return (
|
||||||
|
<Group>
|
||||||
|
{item.option.value}
|
||||||
|
<Icon />
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
searchable
|
||||||
|
clearable
|
||||||
|
maxDropdownHeight={175}
|
||||||
|
onDropdownOpen={() => setIsOpen(true)}
|
||||||
|
onDropdownClose={() => setIsOpen(false)}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<TextInput
|
<TextInput
|
||||||
@@ -131,7 +191,7 @@ const SearchProviderSettings = () => {
|
|||||||
label={'Url'}
|
label={'Url'}
|
||||||
placeholder='eg. https://www.google.com/search?q='
|
placeholder='eg. https://www.google.com/search?q='
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
w={'64%'}
|
w={'94%'}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
withAsterisk
|
withAsterisk
|
||||||
styles={
|
styles={
|
||||||
@@ -228,13 +288,18 @@ const SearchProviderSettings = () => {
|
|||||||
>
|
>
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
<Box>
|
<Box>
|
||||||
<SearchProviderSettingsItem provider={provider} />
|
<SearchProviderSettingsItem
|
||||||
|
provider={provider}
|
||||||
|
Icon={allIcons[provider.icon || '']}
|
||||||
|
filter={filter}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown w={isMobile ? '90%' : undefined}>
|
<Popover.Dropdown w={isMobile ? '90%' : undefined}>
|
||||||
<DebouncedSearchProvider
|
<DebouncedSearchProvider
|
||||||
searchProvider={provider}
|
searchProvider={provider}
|
||||||
setIsOpen={setIsOpen}
|
setIsOpen={setIsOpen}
|
||||||
|
allIcons={allIcons}
|
||||||
/>
|
/>
|
||||||
</Popover.Dropdown>
|
</Popover.Dropdown>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -4,4 +4,6 @@ export interface Provider {
|
|||||||
url: string;
|
url: string;
|
||||||
prefix: string;
|
prefix: string;
|
||||||
default: number;
|
default: number;
|
||||||
|
enabled: number;
|
||||||
|
icon: string | null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user