push (#414)
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
import { Message } from '@/types/chat';
|
||||
import { OpenAIModel } from '@/types/openai';
|
||||
import { Plugin } from '@/types/plugin';
|
||||
import { Prompt } from '@/types/prompt';
|
||||
import { IconPlayerStop, IconRepeat, IconSend } from '@tabler/icons-react';
|
||||
import {
|
||||
IconBolt,
|
||||
IconBrandGoogle,
|
||||
IconPlayerStop,
|
||||
IconRepeat,
|
||||
IconSend,
|
||||
} from '@tabler/icons-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import {
|
||||
FC,
|
||||
@@ -12,6 +19,7 @@ import {
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { PluginSelect } from './PluginSelect';
|
||||
import { PromptList } from './PromptList';
|
||||
import { VariableModal } from './VariableModal';
|
||||
|
||||
@@ -19,9 +27,8 @@ interface Props {
|
||||
messageIsStreaming: boolean;
|
||||
model: OpenAIModel;
|
||||
conversationIsEmpty: boolean;
|
||||
messages: Message[];
|
||||
prompts: Prompt[];
|
||||
onSend: (message: Message) => void;
|
||||
onSend: (message: Message, plugin: Plugin | null) => void;
|
||||
onRegenerate: () => void;
|
||||
stopConversationRef: MutableRefObject<boolean>;
|
||||
textareaRef: MutableRefObject<HTMLTextAreaElement | null>;
|
||||
@@ -31,7 +38,6 @@ export const ChatInput: FC<Props> = ({
|
||||
messageIsStreaming,
|
||||
model,
|
||||
conversationIsEmpty,
|
||||
messages,
|
||||
prompts,
|
||||
onSend,
|
||||
onRegenerate,
|
||||
@@ -47,6 +53,8 @@ export const ChatInput: FC<Props> = ({
|
||||
const [promptInputValue, setPromptInputValue] = useState('');
|
||||
const [variables, setVariables] = useState<string[]>([]);
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [showPluginSelect, setShowPluginSelect] = useState(false);
|
||||
const [plugin, setPlugin] = useState<Plugin | null>(null);
|
||||
|
||||
const promptListRef = useRef<HTMLUListElement | null>(null);
|
||||
|
||||
@@ -82,8 +90,9 @@ export const ChatInput: FC<Props> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
onSend({ role: 'user', content });
|
||||
onSend({ role: 'user', content }, plugin);
|
||||
setContent('');
|
||||
setPlugin(null);
|
||||
|
||||
if (window.innerWidth < 640 && textareaRef && textareaRef.current) {
|
||||
textareaRef.current.blur();
|
||||
@@ -149,6 +158,9 @@ export const ChatInput: FC<Props> = ({
|
||||
} else if (e.key === 'Enter' && !isTyping && !isMobile() && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
handleSend();
|
||||
} else if (e.key === '/' && e.metaKey) {
|
||||
e.preventDefault();
|
||||
setShowPluginSelect(!showPluginSelect);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -214,8 +226,9 @@ export const ChatInput: FC<Props> = ({
|
||||
if (textareaRef && textareaRef.current) {
|
||||
textareaRef.current.style.height = 'inherit';
|
||||
textareaRef.current.style.height = `${textareaRef.current?.scrollHeight}px`;
|
||||
textareaRef.current.style.overflow = `${textareaRef?.current?.scrollHeight > 400 ? 'auto' : 'hidden'
|
||||
}`;
|
||||
textareaRef.current.style.overflow = `${
|
||||
textareaRef?.current?.scrollHeight > 400 ? 'auto' : 'hidden'
|
||||
}`;
|
||||
}
|
||||
}, [content]);
|
||||
|
||||
@@ -241,7 +254,7 @@ export const ChatInput: FC<Props> = ({
|
||||
<div className="stretch mx-2 mt-4 flex flex-row gap-3 last:mb-2 md:mx-4 md:mt-[52px] md:last:mb-6 lg:mx-auto lg:max-w-3xl">
|
||||
{messageIsStreaming && (
|
||||
<button
|
||||
className="absolute top-0 left-0 right-0 mb-3 md:mb-0 md:mt-2 mx-auto flex w-fit items-center gap-3 rounded border border-neutral-200 bg-white py-2 px-4 text-black hover:opacity-50 dark:border-neutral-600 dark:bg-[#343541] dark:text-white"
|
||||
className="absolute top-0 left-0 right-0 mx-auto mb-3 flex w-fit items-center gap-3 rounded border border-neutral-200 bg-white py-2 px-4 text-black hover:opacity-50 dark:border-neutral-600 dark:bg-[#343541] dark:text-white md:mb-0 md:mt-2"
|
||||
onClick={handleStopConversation}
|
||||
>
|
||||
<IconPlayerStop size={16} /> {t('Stop Generating')}
|
||||
@@ -250,7 +263,7 @@ export const ChatInput: FC<Props> = ({
|
||||
|
||||
{!messageIsStreaming && !conversationIsEmpty && (
|
||||
<button
|
||||
className="absolute top-0 left-0 right-0 mb-3 md:mb-0 md:mt-2 mx-auto flex w-fit items-center gap-3 rounded border border-neutral-200 bg-white py-2 px-4 text-black hover:opacity-50 dark:border-neutral-600 dark:bg-[#343541] dark:text-white"
|
||||
className="absolute top-0 left-0 right-0 mx-auto mb-3 flex w-fit items-center gap-3 rounded border border-neutral-200 bg-white py-2 px-4 text-black hover:opacity-50 dark:border-neutral-600 dark:bg-[#343541] dark:text-white md:mb-0 md:mt-2"
|
||||
onClick={onRegenerate}
|
||||
>
|
||||
<IconRepeat size={16} /> {t('Regenerate response')}
|
||||
@@ -258,16 +271,42 @@ export const ChatInput: FC<Props> = ({
|
||||
)}
|
||||
|
||||
<div className="relative mx-2 flex w-full flex-grow flex-col rounded-md border border-black/10 bg-white shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 dark:bg-[#40414F] dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] sm:mx-4">
|
||||
<button
|
||||
className="absolute left-2 top-2 rounded-sm p-1 text-neutral-800 opacity-60 hover:bg-neutral-200 hover:text-neutral-900 dark:bg-opacity-50 dark:text-neutral-100 dark:hover:text-neutral-200"
|
||||
onClick={() => setShowPluginSelect(!showPluginSelect)}
|
||||
onKeyDown={(e) => {}}
|
||||
>
|
||||
{plugin ? <IconBrandGoogle size={20} /> : <IconBolt size={20} />}
|
||||
</button>
|
||||
|
||||
{showPluginSelect && (
|
||||
<div className="absolute left-0 bottom-14 bg-white dark:bg-[#343541]">
|
||||
<PluginSelect
|
||||
plugin={plugin}
|
||||
onPluginChange={(plugin: Plugin) => {
|
||||
setPlugin(plugin);
|
||||
setShowPluginSelect(false);
|
||||
|
||||
if (textareaRef && textareaRef.current) {
|
||||
textareaRef.current.focus();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
className="m-0 w-full resize-none border-0 bg-transparent p-0 py-2 pr-8 pl-2 text-black dark:bg-transparent dark:text-white md:py-3 md:pl-4"
|
||||
className="m-0 w-full resize-none border-0 bg-transparent p-0 py-2 pr-8 pl-10 text-black dark:bg-transparent dark:text-white md:py-3 md:pl-10"
|
||||
style={{
|
||||
resize: 'none',
|
||||
bottom: `${textareaRef?.current?.scrollHeight}px`,
|
||||
maxHeight: '400px',
|
||||
overflow: `${textareaRef.current && textareaRef.current.scrollHeight > 400
|
||||
? 'auto' : 'hidden'
|
||||
}`,
|
||||
overflow: `${
|
||||
textareaRef.current && textareaRef.current.scrollHeight > 400
|
||||
? 'auto'
|
||||
: 'hidden'
|
||||
}`,
|
||||
}}
|
||||
placeholder={
|
||||
t('Type a message or type "/" to select a prompt...') || ''
|
||||
@@ -279,6 +318,7 @@ export const ChatInput: FC<Props> = ({
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
|
||||
<button
|
||||
className="absolute right-2 top-2 rounded-sm p-1 text-neutral-800 opacity-60 hover:bg-neutral-200 hover:text-neutral-900 dark:bg-opacity-50 dark:text-neutral-100 dark:hover:text-neutral-200"
|
||||
onClick={handleSend}
|
||||
|
||||
Reference in New Issue
Block a user