MAJOR REFACTOR (#494)
* move index to home folder, create state and context files and barrell folder * Sanity Check Commit: reducer added to home.tsx manual QA all working * WIP: promptBar * fix missing json parse on folders and prompts * split context and add promptbar context * add context to nested prompt componets and componetize Folder componet * remove log * Create buttons folder and componetize sidebar action button * tidy up prompt handlers * componetized sidebar * added back chatbar componet to left side sidebar * monster commit: Componetized the common code between chatbar and promptbar into new componet Sidebar and added context to both bars * add useFetch service * added prettier import sort to keep imports ordered and easier to indentify * added react query and useFetch to work with RQ * added apiService, errorService and reactQuery * add callback and tidy up error service * refactor chat and child componets to useContext * fix extra calls and bad calls to mel endpoint * minor import cleanup --------- Co-authored-by: jc.durbin <jc.durbin@ardanis.com>
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
import { IconX } from '@tabler/icons-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { FC } from 'react';
|
||||
|
||||
interface Props {
|
||||
placeholder: string;
|
||||
searchTerm: string;
|
||||
onSearch: (searchTerm: string) => void;
|
||||
}
|
||||
|
||||
export const Search: FC<Props> = ({ placeholder, searchTerm, onSearch }) => {
|
||||
const { t } = useTranslation('sidebar');
|
||||
|
||||
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
onSearch(e.target.value);
|
||||
};
|
||||
|
||||
const clearSearch = () => {
|
||||
onSearch('');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative flex items-center">
|
||||
<input
|
||||
className="w-full flex-1 rounded-md border border-neutral-600 bg-[#202123] px-4 py-3 pr-10 text-[14px] leading-3 text-white"
|
||||
type="text"
|
||||
placeholder={t(placeholder) || ''}
|
||||
value={searchTerm}
|
||||
onChange={handleSearchChange}
|
||||
/>
|
||||
|
||||
{searchTerm && (
|
||||
<IconX
|
||||
className="absolute right-4 cursor-pointer text-neutral-300 hover:text-neutral-400"
|
||||
size={18}
|
||||
onClick={clearSearch}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
import { IconFolderPlus, IconMistOff, IconPlus } from '@tabler/icons-react';
|
||||
import { ReactNode } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import {
|
||||
CloseSidebarButton,
|
||||
OpenSidebarButton,
|
||||
} from './components/OpenCloseButton';
|
||||
|
||||
import Search from '../Search';
|
||||
|
||||
interface Props<T> {
|
||||
isOpen: boolean;
|
||||
addItemButtonTitle: string;
|
||||
side: 'left' | 'right';
|
||||
items: T[];
|
||||
itemComponent: ReactNode;
|
||||
folderComponent: ReactNode;
|
||||
footerComponent?: ReactNode;
|
||||
searchTerm: string;
|
||||
handleSearchTerm: (searchTerm: string) => void;
|
||||
toggleOpen: () => void;
|
||||
handleCreateItem: () => void;
|
||||
handleCreateFolder: () => void;
|
||||
handleDrop: (e: any) => void;
|
||||
}
|
||||
|
||||
const Sidebar = <T,>({
|
||||
isOpen,
|
||||
addItemButtonTitle,
|
||||
side,
|
||||
items,
|
||||
itemComponent,
|
||||
folderComponent,
|
||||
footerComponent,
|
||||
searchTerm,
|
||||
handleSearchTerm,
|
||||
toggleOpen,
|
||||
handleCreateItem,
|
||||
handleCreateFolder,
|
||||
handleDrop,
|
||||
}: Props<T>) => {
|
||||
const { t } = useTranslation('promptbar');
|
||||
|
||||
const allowDrop = (e: any) => {
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
const highlightDrop = (e: any) => {
|
||||
e.target.style.background = '#343541';
|
||||
};
|
||||
|
||||
const removeHighlight = (e: any) => {
|
||||
e.target.style.background = 'none';
|
||||
};
|
||||
|
||||
return isOpen ? (
|
||||
<div>
|
||||
<div
|
||||
className={`fixed top-0 z-50 flex h-full w-[260px] flex-none flex-col space-y-2 bg-[#202123] p-2 text-[14px] transition-all sm:relative sm:top-0`}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
className="text-sidebar flex w-[190px] flex-shrink-0 cursor-pointer select-none items-center gap-3 rounded-md border border-white/20 p-3 text-white transition-colors duration-200 hover:bg-gray-500/10"
|
||||
onClick={() => {
|
||||
handleCreateItem();
|
||||
handleSearchTerm('');
|
||||
}}
|
||||
>
|
||||
<IconPlus size={16} />
|
||||
{addItemButtonTitle}
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="ml-2 flex flex-shrink-0 cursor-pointer items-center gap-3 rounded-md border border-white/20 p-3 text-sm text-white transition-colors duration-200 hover:bg-gray-500/10"
|
||||
onClick={handleCreateFolder}
|
||||
>
|
||||
<IconFolderPlus size={16} />
|
||||
</button>
|
||||
</div>
|
||||
{items?.length > 0 && (
|
||||
<Search
|
||||
placeholder={t('Search prompts...') || ''}
|
||||
searchTerm={searchTerm}
|
||||
onSearch={handleSearchTerm}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex-grow overflow-auto">
|
||||
{items?.length > 0 && (
|
||||
<div className="flex border-b border-white/20 pb-2">
|
||||
{folderComponent}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{items?.length > 0 ? (
|
||||
<div
|
||||
className="pt-2"
|
||||
onDrop={handleDrop}
|
||||
onDragOver={allowDrop}
|
||||
onDragEnter={highlightDrop}
|
||||
onDragLeave={removeHighlight}
|
||||
>
|
||||
{itemComponent}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-8 select-none text-center text-white opacity-50">
|
||||
<IconMistOff className="mx-auto mb-3" />
|
||||
<span className="text-[14px] leading-normal">
|
||||
{t('No prompts.')}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{footerComponent}
|
||||
</div>
|
||||
|
||||
<CloseSidebarButton onClick={toggleOpen} side={side} />
|
||||
</div>
|
||||
) : (
|
||||
<OpenSidebarButton onClick={toggleOpen} side={side} />
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
@@ -0,0 +1,42 @@
|
||||
import { IconArrowBarLeft, IconArrowBarRight } from '@tabler/icons-react';
|
||||
|
||||
interface Props {
|
||||
onClick: any;
|
||||
side: 'left' | 'right';
|
||||
}
|
||||
|
||||
export const CloseSidebarButton = ({ onClick, side }: Props) => {
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className={`fixed top-5 ${
|
||||
side === 'right' ? 'right-[270px]' : 'left-[270px]'
|
||||
} z-50 h-7 w-7 hover:text-gray-400 dark:text-white dark:hover:text-gray-300 sm:top-0.5 sm:${
|
||||
side === 'right' ? 'right-[270px]' : 'left-[270px]'
|
||||
} sm:h-8 sm:w-8 sm:text-neutral-700`}
|
||||
onClick={onClick}
|
||||
>
|
||||
{side === 'right' ? <IconArrowBarRight /> : <IconArrowBarLeft />}
|
||||
</button>
|
||||
<div
|
||||
onClick={onClick}
|
||||
className="absolute top-0 left-0 z-10 h-full w-full bg-black opacity-70 sm:hidden"
|
||||
></div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const OpenSidebarButton = ({ onClick, side }: Props) => {
|
||||
return (
|
||||
<button
|
||||
className={`fixed top-2.5 ${
|
||||
side === 'right' ? 'right-2' : 'left-2'
|
||||
} z-50 h-7 w-7 text-white hover:text-gray-400 dark:text-white dark:hover:text-gray-300 sm:top-0.5 sm:${
|
||||
side === 'right' ? 'right-2' : 'left-2'
|
||||
} sm:h-8 sm:w-8 sm:text-neutral-700`}
|
||||
onClick={onClick}
|
||||
>
|
||||
{side === 'right' ? <IconArrowBarLeft /> : <IconArrowBarRight />}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './Sidebar';
|
||||
Reference in New Issue
Block a user