Advancement in the new spotlight

This commit is contained in:
ajnart
2022-11-29 16:22:27 +09:00
parent c71f962967
commit 940513dc32

View File

@@ -1,8 +1,21 @@
import { Button, Group } from '@mantine/core'; import {
import { IconSearch, IconBrandYoutube, IconDownload, IconMovie } from '@tabler/icons'; ActionIcon,
import { SpotlightProvider, openSpotlight } from '@mantine/spotlight'; Group,
import type { SpotlightAction } from '@mantine/spotlight'; Kbd,
import { useState } from 'react'; Select,
Text,
TextInput,
} from '@mantine/core';
import {
IconSearch,
IconBrandYoutube,
IconDownload,
IconMovie,
IconBrandGoogle,
} from '@tabler/icons';
import { forwardRef, useState } from 'react';
import { useHotkeys } from '@mantine/hooks';
import { showNotification } from '@mantine/notifications';
import { IModule } from '../ModuleTypes'; import { IModule } from '../ModuleTypes';
export const SpotlightModule: IModule = { export const SpotlightModule: IModule = {
@@ -12,95 +25,157 @@ export const SpotlightModule: IModule = {
id: 'spotlight', id: 'spotlight',
}; };
interface SearchEngine { const searchEngines = [
name: string;
enabled: boolean;
description: string;
icon: React.ReactNode;
url: string;
shortcut: string;
}
const searchEngines: SearchEngine[] = [
{ {
name: 'Google', label: 'Google',
enabled: true, disabled: false,
description: 'Search using your search engine (defined in settings)', description: 'Search using your search engine (defined in settings)',
icon: <IconSearch />, icon: <IconSearch />,
url: 'https://www.google.com/search?q=', url: 'https://www.google.com/search?q=',
shortcut: 'g', shortcut: 'g',
}, },
{ {
name: 'Youtube', label: 'Youtube',
enabled: true, disabled: false,
description: 'Search Youtube', description: 'Search Youtube',
icon: <IconBrandYoutube />, icon: <IconBrandYoutube />,
url: 'https://www.youtube.com/results?search_query=', url: 'https://www.youtube.com/results?search_query=',
shortcut: 'y', shortcut: 'y',
}, },
{ {
name: 'Download', label: 'Download',
enabled: true, disabled: false,
description: 'Search for torrents', description: 'Search for torrents',
icon: <IconDownload />, icon: <IconDownload />,
url: 'https://1337x.to/search/', url: 'https://1337x.to/search/',
shortcut: 't', shortcut: 't',
}, },
{ {
name: 'Movies', label: 'Movies',
disabled: true,
description: 'Search for movies using Overseerr',
icon: <IconMovie />, icon: <IconMovie />,
enabled: false, url: 'https://www.imdb.com/find?q=',
shortcut: 'm',
},
];
const data: ItemProps[] = [
{
icon: <IconBrandGoogle />,
disabled: false,
label: 'Google',
value: 'google',
description: 'Search using your search engine (defined in settings)',
url: 'https://www.google.com/search?q=',
shortcut: 'g',
},
{
icon: <IconDownload />,
disabled: false,
label: 'Download',
value: 'download',
description: 'Search for torrents',
url: 'https://1337x.to/search/',
shortcut: 't',
},
{
icon: <IconBrandYoutube />,
disabled: false,
label: 'Youtube',
value: 'youtube',
description: 'Search Youtube',
url: 'https://www.youtube.com/results?search_query=',
shortcut: 'y',
},
{
icon: <IconMovie />,
disabled: true,
label: 'Movies',
value: 'movies',
description: 'Search for movies using Overseerr', description: 'Search for movies using Overseerr',
url: 'https://www.imdb.com/find?q=', url: 'https://www.imdb.com/find?q=',
shortcut: 'm', shortcut: 'm',
}, },
]; ];
function SpotlightControl() { interface ItemProps extends React.ComponentPropsWithoutRef<'div'> {
label: string;
disabled: boolean;
value: string;
description: string;
icon: React.ReactNode;
url: string;
shortcut: string;
}
export function SpotlightModuleComponent(props: any) {
const [selectedSearchEngine, setSearchEngine] = useState<ItemProps>(data[0]);
const SelectItem = forwardRef<HTMLDivElement, ItemProps>(
({ icon, label, description, shortcut, ...others }: ItemProps, ref) => (
<div ref={ref} {...others}>
<Group position="apart" noWrap>
<Group noWrap>
{icon}
<div>
<Text size="sm">{label}</Text>
<Text size="xs" opacity={0.65}>
{description}
</Text>
</div>
</Group>
<Kbd>{shortcut}</Kbd>
</Group>
</div>
)
);
const [opened, setOpened] = useState(false);
useHotkeys([['mod+K', () => setOpened(!opened)]]);
return ( return (
<Group position="center"> <Group grow>
<Button onClick={() => openSpotlight()}>Open spotlight</Button> <Select
icon={selectedSearchEngine.icon}
onSearchChange={(search) =>
setSearchEngine(
data.find((item) => item.label.toLowerCase().includes(search.toLowerCase())) ||
selectedSearchEngine
)
}
withinPortal
defaultValue={selectedSearchEngine.value}
itemComponent={SelectItem}
data={data}
maxDropdownHeight={400}
/>
<TextInput />
</Group> </Group>
); );
} }
export function SpotlightModuleComponent(props: any) { function tryMatchSearch(
const [selectedSearchEngine, setSearchEngine] = useState<SearchEngine>(searchEngines[0]); query: string,
const actions: SpotlightAction[] = searchEngines.map((engine) => ({ selectedSearchEngine: ItemProps,
title: engine.name, setSearchEngine: React.Dispatch<React.SetStateAction<ItemProps>>,
description: engine.description, searchEngines: ItemProps[]
icon: engine.icon,
onTrigger: () => {
setSearchEngine(engine);
},
closeOnTrigger: false,
}));
return (
<SpotlightProvider
actions={actions}
searchIcon={selectedSearchEngine.icon}
searchPlaceholder={selectedSearchEngine.description}
shortcut="mod + k"
nothingFoundMessage="Press enter to search..."
onQueryChange={(researchString) =>
useSearchBrowser(researchString, selectedSearchEngine, setSearchEngine, searchEngines)
}
>
<SpotlightControl />
</SpotlightProvider>
);
}
function useSearchBrowser(
search: string,
selectedSearchEngine: SearchEngine,
setSearchEngine: React.Dispatch<React.SetStateAction<SearchEngine>>,
searchEngines: SearchEngine[]
): void { ): void {
// First check if the value of search contains any shortcut // First check if the value of search contains any shortcut. Make sure it is not disabled
const foundSearchEngine = searchEngines.find((engine) => search.includes(`!${engine.shortcut}`)); const foundSearchEngine = searchEngines.find(
(engine) => query.includes(`!${engine.shortcut}`) && !engine.disabled
);
if (foundSearchEngine) { if (foundSearchEngine) {
// If a shortcut is found, use it // If a shortcut is found, use it. Except if it is disabled
setSearchEngine(foundSearchEngine); setSearchEngine(foundSearchEngine);
search.replace(`!${foundSearchEngine.shortcut}`, ''); showNotification({
radius: 'lg',
disallowClose: true,
id: 'spotlight',
autoClose: 1000,
icon: <ActionIcon size="sm">{foundSearchEngine.icon}</ActionIcon>,
message: `Using ${foundSearchEngine.label} as search engine`,
});
} else { } else {
// If no shortcut is found, do nothing (for now) // If no shortcut is found, do nothing (for now)
} }