104 lines
2.8 KiB
TypeScript
104 lines
2.8 KiB
TypeScript
import { FC, useEffect, useRef } from 'react';
|
|
|
|
import { useTranslation } from 'next-i18next';
|
|
|
|
import { Plugin, PluginList } from '@/types/plugin';
|
|
|
|
interface Props {
|
|
plugin: Plugin | null;
|
|
onPluginChange: (plugin: Plugin) => void;
|
|
onKeyDown: (e: React.KeyboardEvent<HTMLSelectElement>) => void;
|
|
}
|
|
|
|
export const PluginSelect: FC<Props> = ({
|
|
plugin,
|
|
onPluginChange,
|
|
onKeyDown,
|
|
}) => {
|
|
const { t } = useTranslation('chat');
|
|
|
|
const selectRef = useRef<HTMLSelectElement>(null);
|
|
|
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLSelectElement>) => {
|
|
const selectElement = selectRef.current;
|
|
const optionCount = selectElement?.options.length || 0;
|
|
|
|
if (e.key === '/' && e.metaKey) {
|
|
e.preventDefault();
|
|
if (selectElement) {
|
|
selectElement.selectedIndex =
|
|
(selectElement.selectedIndex + 1) % optionCount;
|
|
selectElement.dispatchEvent(new Event('change'));
|
|
}
|
|
} else if (e.key === '/' && e.shiftKey && e.metaKey) {
|
|
e.preventDefault();
|
|
if (selectElement) {
|
|
selectElement.selectedIndex =
|
|
(selectElement.selectedIndex - 1 + optionCount) % optionCount;
|
|
selectElement.dispatchEvent(new Event('change'));
|
|
}
|
|
} else if (e.key === 'Enter') {
|
|
e.preventDefault();
|
|
if (selectElement) {
|
|
selectElement.dispatchEvent(new Event('change'));
|
|
}
|
|
|
|
onPluginChange(
|
|
PluginList.find(
|
|
(plugin) =>
|
|
plugin.name === selectElement?.selectedOptions[0].innerText,
|
|
) as Plugin,
|
|
);
|
|
} else {
|
|
onKeyDown(e);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (selectRef.current) {
|
|
selectRef.current.focus();
|
|
}
|
|
}, []);
|
|
|
|
return (
|
|
<div className="flex flex-col">
|
|
<div className="mb-1 w-full rounded border border-neutral-200 bg-transparent pr-2 text-neutral-900 dark:border-neutral-600 dark:text-white">
|
|
<select
|
|
ref={selectRef}
|
|
className="w-full cursor-pointer bg-transparent p-2"
|
|
placeholder={t('Select a plugin') || ''}
|
|
value={plugin?.id || ''}
|
|
onChange={(e) => {
|
|
onPluginChange(
|
|
PluginList.find(
|
|
(plugin) => plugin.id === e.target.value,
|
|
) as Plugin,
|
|
);
|
|
}}
|
|
onKeyDown={(e) => {
|
|
handleKeyDown(e);
|
|
}}
|
|
>
|
|
<option
|
|
key="chatgpt"
|
|
value="chatgpt"
|
|
className="dark:bg-[#343541] dark:text-white"
|
|
>
|
|
ChatGPT
|
|
</option>
|
|
|
|
{PluginList.map((plugin) => (
|
|
<option
|
|
key={plugin.id}
|
|
value={plugin.id}
|
|
className="dark:bg-[#343541] dark:text-white"
|
|
>
|
|
{plugin.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|