154 lines
4.8 KiB
TypeScript
154 lines
4.8 KiB
TypeScript
|
import {
|
||
|
Button,
|
||
|
Drawer,
|
||
|
DrawerBody,
|
||
|
DrawerCloseButton,
|
||
|
DrawerContent,
|
||
|
DrawerFooter,
|
||
|
DrawerHeader,
|
||
|
DrawerOverlay,
|
||
|
Icon,
|
||
|
IconButton,
|
||
|
Input,
|
||
|
InputRightElement,
|
||
|
Stack,
|
||
|
Textarea,
|
||
|
useDisclosure
|
||
|
} from '@chakra-ui/react';
|
||
|
import { TbFolder, TbHelp, TbSettings } from 'react-icons/tb';
|
||
|
|
||
|
import React from 'react';
|
||
|
import { invoke } from '@tauri-apps/api';
|
||
|
import { open } from '@tauri-apps/api/dialog';
|
||
|
import { useForm } from 'react-hook-form';
|
||
|
import { useTranslation } from 'react-i18next';
|
||
|
import { SettingsItem } from './SettingsItem';
|
||
|
import RootContext from '../store';
|
||
|
import { parseIpfsGateways } from '../scripts/ipfs';
|
||
|
|
||
|
interface Config {
|
||
|
index_dir: string;
|
||
|
ipfs_gateways: string;
|
||
|
}
|
||
|
|
||
|
const Settings: React.FC = () => {
|
||
|
const { t } = useTranslation();
|
||
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||
|
const btnRef = React.useRef<HTMLButtonElement | null>(null);
|
||
|
const {
|
||
|
register,
|
||
|
handleSubmit,
|
||
|
watch,
|
||
|
setValue,
|
||
|
formState: { errors }
|
||
|
} = useForm<Config>();
|
||
|
const [submitting, setSubmitting] = React.useState(false);
|
||
|
const rootContext = React.useContext(RootContext);
|
||
|
|
||
|
React.useEffect(() => {
|
||
|
isOpen &&
|
||
|
invoke('get_config').then((conf) => {
|
||
|
const config = conf as {
|
||
|
index_dir: string;
|
||
|
ipfs_gateways: string[];
|
||
|
};
|
||
|
setValue('index_dir', config.index_dir, { shouldValidate: true });
|
||
|
setValue('ipfs_gateways', config.ipfs_gateways.join('\n'), { shouldValidate: true });
|
||
|
});
|
||
|
}, [isOpen]);
|
||
|
|
||
|
const onSubmit = async (newConfig: Config) => {
|
||
|
setSubmitting(true);
|
||
|
|
||
|
const ipfsGateways: string[]= parseIpfsGateways(newConfig.ipfs_gateways);
|
||
|
const config = {
|
||
|
index_dir: newConfig.index_dir,
|
||
|
ipfs_gateways: ipfsGateways
|
||
|
};
|
||
|
await invoke('set_config', { newConfig: config });
|
||
|
rootContext.ipfs_gateways = ipfsGateways;
|
||
|
onClose();
|
||
|
setSubmitting(false);
|
||
|
};
|
||
|
|
||
|
return (
|
||
|
<>
|
||
|
<IconButton
|
||
|
ref={btnRef}
|
||
|
aria-label={t('settings.title')}
|
||
|
title={t('settings.title') ?? ''}
|
||
|
icon={<Icon as={TbSettings} boxSize={5} />}
|
||
|
onClick={onOpen}
|
||
|
variant="ghost"
|
||
|
/>
|
||
|
<Drawer isOpen={isOpen} placement="right" size="md" onClose={onClose} finalFocusRef={btnRef}>
|
||
|
<DrawerOverlay />
|
||
|
<DrawerContent>
|
||
|
<DrawerCloseButton />
|
||
|
<DrawerHeader>{t('settings.title')}</DrawerHeader>
|
||
|
|
||
|
<DrawerBody>
|
||
|
<form id="settings-form" onSubmit={handleSubmit(onSubmit)}>
|
||
|
<Stack spacing={4}>
|
||
|
<SettingsItem
|
||
|
label={t('settings.index_dir')}
|
||
|
help={t('settings.index_dir_help') ?? undefined}
|
||
|
error={errors.index_dir?.message}
|
||
|
element={
|
||
|
<Input
|
||
|
{...register('index_dir', { required: t('settings.index_dir_required') ?? true })}
|
||
|
aria-invalid={errors.index_dir ? 'true' : 'false'}
|
||
|
/>
|
||
|
}
|
||
|
rightElement={
|
||
|
<InputRightElement>
|
||
|
<IconButton
|
||
|
aria-label={t('settings.index_dir_browse')}
|
||
|
title={t('settings.index_dir_browse') ?? ''}
|
||
|
tabIndex={-1}
|
||
|
icon={<Icon as={TbFolder} />}
|
||
|
variant="unstyled"
|
||
|
pt={1}
|
||
|
onClick={async () => {
|
||
|
const selected = (await open({
|
||
|
defaultPath: watch('index_dir'),
|
||
|
directory: true,
|
||
|
multiple: false
|
||
|
})) as string | null;
|
||
|
if (selected) setValue('index_dir', selected, { shouldValidate: true });
|
||
|
}}
|
||
|
/>
|
||
|
</InputRightElement>
|
||
|
}
|
||
|
/>
|
||
|
<SettingsItem
|
||
|
label={t('settings.ipfs_gateways')}
|
||
|
help={t('settings.ipfs_gateways_help') ?? undefined}
|
||
|
error={errors.ipfs_gateways?.message}
|
||
|
element={
|
||
|
<Textarea
|
||
|
{...register('ipfs_gateways')}
|
||
|
aria-invalid={errors.ipfs_gateways ? 'true' : 'false'}
|
||
|
/>
|
||
|
}
|
||
|
/>
|
||
|
</Stack>
|
||
|
</form>
|
||
|
</DrawerBody>
|
||
|
|
||
|
<DrawerFooter>
|
||
|
<Button variant="outline" mr={3} onClick={onClose}>
|
||
|
{t('settings.cancel')}
|
||
|
</Button>
|
||
|
<Button colorScheme="blue" type="submit" form="settings-form" isLoading={submitting}>
|
||
|
{t('settings.save')}
|
||
|
</Button>
|
||
|
</DrawerFooter>
|
||
|
</DrawerContent>
|
||
|
</Drawer>
|
||
|
</>
|
||
|
);
|
||
|
};
|
||
|
|
||
|
export default Settings;
|