This commit is contained in:
Mckay Wrigley
2023-03-27 09:38:56 -06:00
committed by GitHub
parent 2269403806
commit 34c79c0d66
51 changed files with 1744 additions and 295 deletions
+58
View File
@@ -0,0 +1,58 @@
import { Conversation } from '@/types/chat';
import { Folder } from '@/types/folder';
import { cleanConversationHistory } from '@/utils/app/clean';
import { IconFileImport } from '@tabler/icons-react';
import { useTranslation } from 'next-i18next';
import { FC } from 'react';
import { SidebarButton } from '../Sidebar/SidebarButton';
interface Props {
onImport: (data: {
conversations: Conversation[];
folders: Folder[];
}) => void;
}
export const Import: FC<Props> = ({ onImport }) => {
const { t } = useTranslation('sidebar');
return (
<>
<input
id="import-file"
className="sr-only"
tabIndex={-1}
type="file"
accept=".json"
onChange={(e) => {
if (!e.target.files?.length) return;
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (e) => {
let json = JSON.parse(e.target?.result as string);
if (json && !json.folders) {
json = { history: cleanConversationHistory(json), folders: [] };
}
onImport({ conversations: json.history, folders: json.folders });
};
reader.readAsText(file);
}}
/>
<SidebarButton
text={t('Import conversations')}
icon={<IconFileImport size={18} />}
onClick={() => {
const importFile = document.querySelector(
'#import-file',
) as HTMLInputElement;
if (importFile) {
importFile.click();
}
}}
/>
</>
);
};
+69
View File
@@ -0,0 +1,69 @@
import { IconCheck, IconKey, IconX } from '@tabler/icons-react';
import { useTranslation } from 'next-i18next';
import { FC, KeyboardEvent, useState } from 'react';
import { SidebarButton } from '../Sidebar/SidebarButton';
interface Props {
apiKey: string;
onApiKeyChange: (apiKey: string) => void;
}
export const Key: FC<Props> = ({ apiKey, onApiKeyChange }) => {
const { t } = useTranslation('sidebar');
const [isChanging, setIsChanging] = useState(false);
const [newKey, setNewKey] = useState(apiKey);
const handleEnterDown = (e: KeyboardEvent<HTMLDivElement>) => {
if (e.key === 'Enter') {
e.preventDefault();
handleUpdateKey(newKey);
}
};
const handleUpdateKey = (newKey: string) => {
onApiKeyChange(newKey.trim());
setIsChanging(false);
};
return isChanging ? (
<div className="duration:200 flex w-full cursor-pointer items-center rounded-md py-3 px-3 transition-colors hover:bg-gray-500/10">
<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-[12.5px] leading-3 text-left text-white outline-none focus:border-neutral-100"
type="password"
value={newKey}
onChange={(e) => setNewKey(e.target.value)}
onKeyDown={handleEnterDown}
placeholder={t('API Key') || 'API Key'}
/>
<div className="flex w-[40px]">
<IconCheck
className="ml-auto min-w-[20px] text-neutral-400 hover:text-neutral-100"
size={18}
onClick={(e) => {
e.stopPropagation();
handleUpdateKey(newKey);
}}
/>
<IconX
className="ml-auto min-w-[20px] text-neutral-400 hover:text-neutral-100"
size={18}
onClick={(e) => {
e.stopPropagation();
setIsChanging(false);
setNewKey(apiKey);
}}
/>
</div>
</div>
) : (
<SidebarButton
text={t('OpenAI API Key')}
icon={<IconKey size={18} />}
onClick={() => setIsChanging(true)}
/>
);
};