feat: restructure the sidebar of the brains management page (#1325)

* 🧩 Possibility to chose which buttons to display in the sidebar

* Button "Back to chat"

* 💄 Remove the frame around the brains library page

* Give a size to the image in the profile button (for performance)

* Optional prop showButtons in the sidebar

* remove duration on waitFor and set sidebar animation duration to 200ms
This commit is contained in:
Matthieu Jacq 2023-10-04 18:12:27 +02:00 committed by GitHub
parent 85eba3da70
commit f030db6952
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 81 additions and 67 deletions

View File

@ -14,48 +14,49 @@ export const BrainsList = (): JSX.Element => {
const { searchQuery, setSearchQuery, brains, isOnBrainsLibraryPage } =
useBrainsList();
const { t } = useTranslation("brain");
const { t } = useTranslation(["brain", "chat"]);
return (
<Sidebar showFooter={false}>
<div className="flex flex-col flex-1">
<Sidebar showButtons={["user"]}>
<div className="flex flex-col p-2 gap-2">
<Link href="/chat">
<Button type="button" className="bg-primary text-white py-2 w-full">
{t("chat:back_to_chat")}
</Button>
</Link>
<AddBrainModal triggerClassName="border-solid border-2 border-gray-300" />
</div>
<div className="px-2 pt-2 pb-4">
<BrainSearchBar
searchQuery={searchQuery}
setSearchQuery={setSearchQuery}
/>
<div
data-testid="brains-list-items"
className="flex-1 overflow-auto scrollbar h-full"
>
{brains.map((brain) => (
<BrainListItem brain={brain} key={brain.id} />
))}
</div>
<div className="m-2 mb flex flex-col">
{isOnBrainsLibraryPage ? (
<Link href="/brains-management" className="flex flex-row flex-1">
<Button
type="button"
className="bg-primary text-white py-2 mb-2 flex flex-row flex-1"
>
{t("brain_management_button_label")}
</Button>
</Link>
) : (
<Link
href="/brains-management/library"
className="flex flex-row flex-1"
</div>
<div
data-testid="brains-list-items"
className="flex-1 overflow-auto scrollbar h-full min-h-[50px]"
>
{brains.map((brain) => (
<BrainListItem brain={brain} key={brain.id} />
))}
</div>
<div className="p-2 mb flex flex-col">
{isOnBrainsLibraryPage ? (
<Link href="/brains-management" className="flex flex-row flex-1">
<Button
type="button"
className="bg-primary text-white py-2 mb-2 flex flex-row flex-1"
>
<Button
type="button"
className="bg-primary text-white py-2 mb-2 flex flex-row flex-1"
>
{t("brain_library_button_label")}
</Button>
</Link>
)}
<AddBrainModal triggerClassName="border-solid border-2 border-gray-300" />
</div>
{t("brain:brain_management_button_label")}
</Button>
</Link>
) : (
<Link href="/brains-management/library">
<Button type="button" className="bg-primary text-white py-2 w-full">
{t("brain_library_button_label")}
</Button>
</Link>
)}
</div>
</Sidebar>
);

View File

@ -14,15 +14,13 @@ export const BrainSearchBar = ({
const { t } = useTranslation(["brain"]);
return (
<div className="m-2">
<Field
name="brainsearch"
placeholder={t("searchBrain")}
autoFocus
autoComplete="off"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
<Field
name="brainsearch"
placeholder={t("searchBrain")}
autoFocus
autoComplete="off"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
);
};

View File

@ -13,7 +13,7 @@ const BrainsLibrary = (): JSX.Element => {
const { t } = useTranslation("brain");
return (
<div className="flex flex-1 flex-col items-center m-5 md:m-20 border-2 border-gray-100 border-solid rounded-xl">
<div className="flex flex-1 flex-col items-center">
<div className="flex">
<Field
value={searchBarText}

View File

@ -12,7 +12,7 @@ export const ChatsList = (): JSX.Element => {
useChatNotificationsSync();
return (
<Sidebar showFooter={true}>
<Sidebar showButtons={["myBrains", "user"]}>
<div className="flex flex-col flex-1 h-full" data-testid="chats-list">
<div className="pt-2">
<NewChatButton />

View File

@ -7,16 +7,19 @@ import { SidebarHeader } from "@/lib/components/Sidebar/components/SidebarHeader
import { useDevice } from "@/lib/hooks/useDevice";
import { cn } from "@/lib/utils";
import { SidebarFooter } from "./components/SidebarFooter/SidebarFooter";
import {
SidebarFooter,
SidebarFooterButtons,
} from "./components/SidebarFooter/SidebarFooter";
type SidebarProps = {
children: React.ReactNode;
showFooter: boolean;
showButtons?: SidebarFooterButtons[];
};
export const Sidebar = ({
children,
showFooter,
showButtons,
}: SidebarProps): JSX.Element => {
const { isMobile } = useDevice();
const pathname = usePathname();
@ -27,7 +30,7 @@ export const Sidebar = ({
}, [isMobile, pathname]);
return (
<MotionConfig transition={{ mass: 1, damping: 10 }}>
<MotionConfig transition={{ mass: 1, damping: 10, duration: 0.2 }}>
<motion.div
drag="x"
dragConstraints={{ right: 0, left: 0 }}
@ -68,7 +71,7 @@ export const Sidebar = ({
>
<SidebarHeader setOpen={setOpen} />
<div className="overflow-auto flex flex-col flex-1">{children}</div>
{showFooter && <SidebarFooter />}
{showButtons && <SidebarFooter showButtons={showButtons} />}
</motion.div>
</motion.div>
</MotionConfig>

View File

@ -16,7 +16,7 @@ vi.mock("@/lib/hooks/useDevice");
const renderSidebar = async () => {
await act(() =>
render(
<Sidebar showFooter={false}>
<Sidebar>
<div data-testid="sidebar-test-content">📦</div>
</Sidebar>
)
@ -73,7 +73,6 @@ describe("Sidebar", () => {
expect(closeSidebarButton);
fireEvent.click(closeSidebarButton);
await waitFor(() => expect(sidebarContent).not.toBeVisible());
});
});

View File

@ -2,12 +2,18 @@ import { BrainManagementButton } from "@/lib/components/Sidebar/components/Sideb
import { UserButton } from "./components/UserButton";
export const SidebarFooter = (): JSX.Element => {
export type SidebarFooterButtons = "myBrains" | "user";
type SidebarFooterProps = {
showButtons: SidebarFooterButtons[];
};
export const SidebarFooter = ({showButtons}: SidebarFooterProps): JSX.Element => {
return (
<div className="bg-gray-50 dark:bg-gray-900 border-t dark:border-white/10 mt-auto p-2">
<div className="max-w-screen-xl flex justify-center items-center flex-col">
<BrainManagementButton />
<UserButton />
{showButtons.includes('myBrains') && <BrainManagementButton />}
{showButtons.includes('user') && <UserButton />}
</div>
</div>
);

View File

@ -16,6 +16,7 @@ export const UserButton = (): JSX.Element => {
<Image
alt="gravatar"
fill={true}
sizes="32px"
src={gravatarUrl}
className="rounded-xl"
/>

View File

@ -34,15 +34,16 @@
"feed_brain_placeholder": "Choose which @brain you want to feed with these files",
"feedingBrain": "Your newly added knowledge is being processed, you can keep chatting in the meantime !",
"add_content_card_button_tooltip": "Add knowledge to a brain",
"back_to_chat": "Back to chat",
"onboarding": {
"download_message_1": "Hi 👋🏻 Want to discover Quivr ? 😇",
"download_message_2": "Step 1: Download “Quivr documentation”",
"upload_message_1":"Congratulations on your first step 🥳",
"upload_message_2":"Step 2: Now Drag and drop it on the chat or in the 📎",
"upload_message_1": "Congratulations on your first step 🥳",
"upload_message_2": "Step 2: Now Drag and drop it on the chat or in the 📎",
"how_to_use_quivr": "How to user Quivr",
"what_is_quivr":"What is Quivr ?",
"what_is_quivr": "What is Quivr ?",
"what_is_brain": "What is a brain ?",
"last_step":"Last step 🥳",
"ask_question_to_file":"Ask a question to your file. Ex : 'What are you talking about ?'"
"last_step": "Last step 🥳",
"ask_question_to_file": "Ask a question to your file. Ex : 'What are you talking about ?'"
}
}

View File

@ -34,7 +34,8 @@
"feed_brain_placeholder": "Elige cuál @cerebro quieres alimentar con estos archivos",
"feedingBrain": "Su conocimiento recién agregado se está procesando, ¡puede seguir chateando mientras tanto!",
"add_content_card_button_tooltip": "Agregar conocimiento a un cerebro",
"onboarding":{
"back_to_chat": "Volver al chat",
"onboarding": {
"download_message_1": "Hola 👋🏻 ¿Quieres descubrir Quivr? 😇",
"download_message_2": "Paso 1: Descargar la documentación de “Quivr”",
"upload_message_1": "¡Felicidades por tu primer paso 🥳!",

View File

@ -34,7 +34,8 @@
"feed_brain_placeholder": "Choisissez le @cerveau que vous souhaitez nourrir avec ces fichiers",
"feedingBrain": "Vos nouvelles connaissances sont en cours de traitement. Vous pouvez continuer à discuter en attendant !",
"add_content_card_button_tooltip": "Ajouter des connaissances à un cerveau",
"onboarding":{
"back_to_chat": "Retour au chat",
"onboarding": {
"download_message_1": "Salut 👋🏻 Envie de découvrir Quivr ? 😇",
"download_message_2": "Étape 1 : Téléchargez la documentation de “Quivr”",
"upload_message_1": "Félicitations pour votre première étape 🥳!",

View File

@ -34,7 +34,8 @@
"feed_brain_placeholder": "Escolha qual @cérebro você deseja alimentar com esses arquivos",
"feedingBrain": "Seu conhecimento recém-adicionado está sendo processado, você pode continuar conversando enquanto isso!",
"add_content_card_button_tooltip": "Adicionar conhecimento a um cérebro",
"onboarding":{
"back_to_chat": "Voltar para o chat",
"onboarding": {
"download_message_1": "Oi 👋🏻 Quer descobrir o Quivr? 😇",
"download_message_2": "Passo 1: Baixe a documentação do 'Quivr'",
"upload_message_1": "Parabéns pelo seu primeiro passo 🥳!",

View File

@ -34,7 +34,8 @@
"feed_brain_placeholder": "Выберите, какой @мозг вы хотите питать этими файлами",
"feedingBrain": "Ваш недавно добавленный знаний обрабатывается, вы можете продолжить общение в это время!",
"add_content_card_button_tooltip": "Добавить знаний в мозг",
"onboarding":{
"back_to_chat": "Вернуться к чату",
"onboarding": {
"download_message_1": "Привет 👋🏻 Хочешь узнать о Quivr? 😇",
"download_message_2": "Шаг 1: Скачайте документацию Quivr",
"upload_message_1": "Поздравляем с первым шагом 🥳!",

View File

@ -35,7 +35,8 @@
"feed_brain_placeholder": "选择要用这些文件喂养的 @大脑",
"feedingBrain": "您新添加的知识正在处理中,同时您可以继续聊天!",
"add_content_card_button_tooltip": "向大脑添加知识",
"onboarding":{
"back_to_chat": "返回聊天",
"onboarding": {
"download_message_1": "你好 👋🏻 想要发现 Quivr 吗? 😇",
"download_message_2": "步骤 1下载“Quivr 文档”",
"upload_message_1": "恭喜您迈出第一步 🥳!",