chore: some small improvements (#223)

* chore: stylize error message div
chore: correct styles for sidebar btn
chore: add spinner and replace header "Please wait" on spinner
chore: correct Russian translate
chore: hide clear conversation btn if not conversations
chore: stylize "Need OpenAI key" div

* chore: corrent Russian translate
This commit is contained in:
Danil Shishkevich 2023-03-27 20:43:01 +07:00 committed by GitHub
parent d8e3844fb9
commit 3ca503a3f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 83 additions and 27 deletions

View File

@ -6,9 +6,10 @@ import {
OpenAIModel,
} from '@/types';
import { throttle } from '@/utils';
import { IconClearAll, IconSettings } from '@tabler/icons-react';
import { IconClearAll, IconKey, IconSettings } from '@tabler/icons-react';
import { useTranslation } from 'next-i18next';
import { FC, memo, MutableRefObject, useEffect, useRef, useState } from 'react';
import { Spinner } from '../Global/Spinner';
import { ChatInput } from './ChatInput';
import { ChatLoader } from './ChatLoader';
import { ChatMessage } from './ChatMessage';
@ -110,16 +111,22 @@ export const Chat: FC<Props> = memo(
<div className="overflow-none relative flex-1 bg-white dark:bg-[#343541]">
{!(apiKey || serverSideApiKeyIsSet) ? (
<div className="mx-auto flex h-full w-[300px] flex-col justify-center space-y-6 sm:w-[500px]">
<div className="mx-auto mb-5">
<IconKey size={36} />
</div>
<div className="text-center text-2xl font-semibold text-gray-800 dark:text-gray-100">
{t('OpenAI API Key Required')}
</div>
<div className="text-center text-gray-500 dark:text-gray-400">
<div className="mb-2">
{t(
'Please set your OpenAI API key in the bottom left of the sidebar.',
)}
</div>
<div className="text-center text-gray-500 dark:text-gray-400">
{t("If you don't have an OpenAI API key, you can get one here: ")}
<div>
{t(
"If you don't have an OpenAI API key, you can get one here: ",
)}
<a
href="https://platform.openai.com/account/api-keys"
target="_blank"
@ -130,6 +137,7 @@ export const Chat: FC<Props> = memo(
</a>
</div>
</div>
</div>
) : modelError ? (
<ErrorMessageDiv error={modelError} />
) : (
@ -142,11 +150,17 @@ export const Chat: FC<Props> = memo(
<>
<div className="mx-auto flex w-[350px] flex-col space-y-10 pt-12 sm:w-[600px]">
<div className="text-center text-3xl font-semibold text-gray-800 dark:text-gray-100">
{models.length === 0 ? t('Loading...') : 'Chatbot UI'}
{models.length === 0 ? (
<div>
<Spinner size="16px" className="mx-auto" />
</div>
) : (
'Chatbot UI'
)}
</div>
{models.length > 0 && (
<div className="flex h-full flex-col space-y-4 rounded border border-neutral-200 p-4 dark:border-neutral-600">
<div className="flex h-full flex-col space-y-4 rounded-lg border border-neutral-200 p-4 dark:border-neutral-600">
<ModelSelect
model={conversation.model}
models={models}

View File

@ -1,4 +1,5 @@
import { ErrorMessage } from '@/types';
import { IconCircleX } from '@tabler/icons-react';
import { FC } from 'react';
interface Props {
@ -7,16 +8,20 @@ interface Props {
export const ErrorMessageDiv: FC<Props> = ({ error }) => {
return (
<div className="mx-auto flex h-full w-[300px] flex-col justify-center space-y-6 sm:w-[500px]">
<div className="text-center text-red-500">
{error.title} {error.code ? <i>({error.code}) </i> : ''}
<div className="mx-6 flex h-full flex-col items-center justify-center text-red-500">
<div className="mb-5">
<IconCircleX size={36} />
</div>
<div className="mb-3 text-2xl font-medium">{error.title}</div>
{error.messageLines.map((line, index) => (
<div key={index} className="text-center text-red-500">
<div key={index} className="text-center">
{' '}
{line}{' '}
</div>
))}
<div className="text-xs dark:text-red-400 opacity-50 mt-4">
{error.code ? <i>Code: {error.code}</i> : ''}
</div>
</div>
);
};

View File

@ -0,0 +1,32 @@
import { FC } from 'react';
interface Props {
size?: string;
className?: string;
}
export const Spinner: FC<Props> = ({ size = '1em', className="" }) => {
return (
<svg
stroke="currentColor"
fill="none"
strokeWidth="2"
viewBox="0 0 24 24"
strokeLinecap="round"
strokeLinejoin="round"
className={`animate-spin ${className}`}
height={size}
width={size}
xmlns="http://www.w3.org/2000/svg"
>
<line x1="12" y1="2" x2="12" y2="6"></line>
<line x1="12" y1="18" x2="12" y2="22"></line>
<line x1="4.93" y1="4.93" x2="7.76" y2="7.76"></line>
<line x1="16.24" y1="16.24" x2="19.07" y2="19.07"></line>
<line x1="2" y1="12" x2="6" y2="12"></line>
<line x1="18" y1="12" x2="22" y2="12"></line>
<line x1="4.93" y1="19.07" x2="7.76" y2="16.24"></line>
<line x1="16.24" y1="7.76" x2="19.07" y2="4.93"></line>
</svg>
);
};

View File

@ -18,7 +18,7 @@ export const ClearConversations: FC<Props> = ({ onClearConversations }) => {
};
return isConfirming ? (
<div className="flex w-full cursor-pointer items-center rounded-md py-3 px-3 hover:bg-[#343541]">
<div className="flex w-full cursor-pointer items-center rounded-lg py-3 px-3 hover:bg-gray-500/10">
<IconTrash size={18} />
<div className="ml-3 flex-1 text-left text-[12.5px] leading-3 text-white">

View File

@ -30,7 +30,7 @@ export const Key: FC<Props> = ({ apiKey, onApiKeyChange }) => {
<IconKey size={18} />
<input
className="ml-2 h-[20px] flex-1 overflow-hidden overflow-ellipsis border-b border-neutral-400 bg-transparent pr-1 text-left text-white outline-none focus:border-neutral-100"
className="ml-2 h-[20px] flex-1 overflow-hidden overflow-ellipsis border-b border-neutral-400 bg-transparent pr-1 text-[12.5px] leading-3 text-left text-white outline-none focus:border-neutral-100"
type="password"
value={newKey}
onChange={(e) => setNewKey(e.target.value)}

View File

@ -202,6 +202,7 @@ export const Sidebar: FC<Props> = ({
<SidebarSettings
lightMode={lightMode}
apiKey={apiKey}
conversationsCount={conversations.length}
onToggleLightMode={onToggleLightMode}
onApiKeyChange={onApiKeyChange}
onClearConversations={onClearConversations}

View File

@ -10,6 +10,7 @@ import { SidebarButton } from './SidebarButton';
interface Props {
lightMode: 'light' | 'dark';
apiKey: string;
conversationsCount: number;
onToggleLightMode: (mode: 'light' | 'dark') => void;
onApiKeyChange: (apiKey: string) => void;
onClearConversations: () => void;
@ -23,6 +24,7 @@ interface Props {
export const SidebarSettings: FC<Props> = ({
lightMode,
apiKey,
conversationsCount,
onToggleLightMode,
onApiKeyChange,
onClearConversations,
@ -32,7 +34,9 @@ export const SidebarSettings: FC<Props> = ({
const { t } = useTranslation('sidebar');
return (
<div className="flex flex-col items-center space-y-1 border-t border-white/20 pt-1 text-sm">
{conversationsCount > 0 ? (
<ClearConversations onClearConversations={onClearConversations} />
) : null}
<Import onImport={onImportConversations} />

View File

@ -6,7 +6,7 @@
"System Prompt": "Системное сообщение",
"You are ChatGPT, a large language model trained by OpenAI. Follow the user's instructions carefully. Respond using markdown.": "Вы ChatGPT, большая языковая модель, созданная компанией OpenAI. Следуйте инструкциям пользователя. Отвечайте на сообщения, используя Markdown",
"Enter a prompt": "Введите сообщение",
"Regenerate response": "Сгенерировать сообщение снова",
"Regenerate response": "Перегенерировать сообщение",
"Sorry, there was an error.": "Просим прощения, произошла ошибка",
"Model": "Модель",
"Conversation": "Чат",
@ -17,11 +17,11 @@
"AI": "Бот",
"You": "Вы",
"Cancel": "Отмена",
"Save & Submit": "Сохранить и отправить",
"Save & Submit": "Отредактировать",
"Make sure your OpenAI API key is set in the bottom left of the sidebar.": "Убедитесь, что вы ввели API-ключ OpenAI.",
"If you completed this step, OpenAI may be experiencing issues.": "Если вы выполнили этот шаг, то возможно OpenAI может испытывать проблемы",
"Message limit is {{maxLength}} characters. You have entered {{valueLength}} characters.": "Лимит сообщения: {{maxLength}} символов. Вы ввели {{valueLength}} символов.",
"Please enter a message": "Пожалуйста введите сообщение",
"Chatbot UI is an advanced chatbot kit for OpenAI's chat models aiming to mimic ChatGPT's interface and functionality.": "Chatbot UI - продвинутый интерфейс чатбота для чат-моделей OpenAI, которое имитирует интерфейс ChatGPT",
"Chatbot UI is an advanced chatbot kit for OpenAI's chat models aiming to mimic ChatGPT's interface and functionality.": "Chatbot UI - продвинутый интерфейс чатбота для чат-моделей OpenAI, имитирующий интерфейс ChatGPT",
"Are you sure you want to clear all messages?": "Вы уверены, что хотите удалить все сообщения?"
}