diff --git a/frontend/app/App.tsx b/frontend/app/App.tsx index 6f1c6eb96b9d..decff4c83dc5 100644 --- a/frontend/app/App.tsx +++ b/frontend/app/App.tsx @@ -5,6 +5,7 @@ import { PropsWithChildren, useEffect } from "react"; import { BrainProvider } from "@/lib/context"; import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext"; +import { SideBarProvider } from "@/lib/context/SidebarProvider/sidebar-provider"; import { useSupabase } from "@/lib/context/SupabaseProvider"; import { UpdateMetadata } from "@/lib/helpers/updateMetadata"; import { usePageTracking } from "@/services/analytics/june/usePageTracking"; @@ -40,7 +41,9 @@ const AppWithQueryClient = ({ children }: PropsWithChildren): JSX.Element => { return ( - {children} + + {children} + ); diff --git a/frontend/app/chat/[chatId]/__tests__/page.test.tsx b/frontend/app/chat/[chatId]/__tests__/page.test.tsx index be9cb7d48dbd..53e4a3d6a9ac 100644 --- a/frontend/app/chat/[chatId]/__tests__/page.test.tsx +++ b/frontend/app/chat/[chatId]/__tests__/page.test.tsx @@ -11,6 +11,7 @@ import { ChatProviderMock, } from "@/lib/context/ChatProvider/mocks/ChatProviderMock"; import { KnowledgeToFeedProvider } from "@/lib/context/KnowledgeToFeedProvider"; +import { SideBarProvider } from "@/lib/context/SidebarProvider/sidebar-provider"; import { SupabaseContextMock, SupabaseProviderMock, @@ -87,7 +88,9 @@ describe("Chat page", () => { - , + + , + diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/MenuControlButton.tsx b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/MenuControlButton.tsx new file mode 100644 index 000000000000..df09271433c2 --- /dev/null +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/components/MenuControlButton.tsx @@ -0,0 +1,25 @@ +import { useTranslation } from "react-i18next"; +import { LuPanelLeftClose, LuPanelRightClose } from "react-icons/lu"; + +import Button from "@/lib/components/ui/Button"; +import { useSideBarContext } from "@/lib/context/SidebarProvider/hooks/useSideBarContext"; + +export const MenuControlButton = (): JSX.Element => { + const { isOpened, setIsOpened } = useSideBarContext(); + const Icon = isOpened ? LuPanelLeftClose : LuPanelRightClose; + const { t } = useTranslation("chat"); + + return ( + + ); +}; diff --git a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx index 4619e6eeb3a8..711cc7caa0a9 100644 --- a/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx +++ b/frontend/app/chat/[chatId]/components/ActionsBar/components/ChatInput/index.tsx @@ -9,6 +9,7 @@ import { getBrainIconFromBrainType } from "@/lib/helpers/getBrainIconFromBrainTy import { OnboardingQuestions } from "./components"; import { ActionsModal } from "./components/ActionsModal/ActionsModal"; import { ChatEditor } from "./components/ChatEditor/ChatEditor"; +import { MenuControlButton } from "./components/MenuControlButton"; import { useChatInput } from "./hooks/useChatInput"; type ChatInputProps = { @@ -37,6 +38,7 @@ export const ChatInput = ({ }} className="sticky bottom-0 bg-white dark:bg-black w-full flex items-center gap-2 z-20 p-2" > + {!shouldDisplayFeedOrSecretsCard && ( )} - +
{children}
{showButtons && }
diff --git a/frontend/lib/components/Sidebar/__tests__/Sidebar.test.tsx b/frontend/lib/components/Sidebar/__tests__/Sidebar.test.tsx index 49add34037f9..1327cc4175bb 100644 --- a/frontend/lib/components/Sidebar/__tests__/Sidebar.test.tsx +++ b/frontend/lib/components/Sidebar/__tests__/Sidebar.test.tsx @@ -9,6 +9,7 @@ import { import { afterEach, describe, expect, it, vi } from "vitest"; import { Sidebar } from "@/lib/components/Sidebar/Sidebar"; +import { SideBarProvider } from "@/lib/context/SidebarProvider/sidebar-provider"; import { useDevice } from "@/lib/hooks/useDevice"; vi.mock("@/lib/hooks/useDevice"); @@ -16,9 +17,11 @@ vi.mock("@/lib/hooks/useDevice"); const renderSidebar = async () => { await act(() => render( - -
📦
-
+ + +
📦
+
+
) ); }; diff --git a/frontend/lib/components/Sidebar/components/SidebarHeader.tsx b/frontend/lib/components/Sidebar/components/SidebarHeader.tsx index 92b833aee7e6..f76a2657c9aa 100644 --- a/frontend/lib/components/Sidebar/components/SidebarHeader.tsx +++ b/frontend/lib/components/Sidebar/components/SidebarHeader.tsx @@ -1,13 +1,11 @@ -import { Dispatch, SetStateAction } from "react"; -import { LuPanelLeft } from "react-icons/lu"; +import { LuPanelLeftClose } from "react-icons/lu"; import { Logo } from "@/lib/components/Logo/Logo"; +import { useSideBarContext } from "@/lib/context/SidebarProvider/hooks/useSideBarContext"; -type SidebarProps = { - setOpen: Dispatch>; -}; +export const SidebarHeader = (): JSX.Element => { + const { setIsOpened } = useSideBarContext(); -export const SidebarHeader = ({ setOpen }: SidebarProps): JSX.Element => { return (
@@ -17,9 +15,9 @@ export const SidebarHeader = ({ setOpen }: SidebarProps): JSX.Element => { className="p-3 text-2xl bg:white dark:bg-black text-black dark:text-white hover:text-primary dark:hover:text-gray-200 transition-colors" type="button" data-testid="close-sidebar-button" - onClick={() => setOpen(false)} + onClick={() => setIsOpened(false)} > - +
diff --git a/frontend/lib/context/SidebarProvider/hooks/useSideBarContext.ts b/frontend/lib/context/SidebarProvider/hooks/useSideBarContext.ts new file mode 100644 index 000000000000..912b31f56b48 --- /dev/null +++ b/frontend/lib/context/SidebarProvider/hooks/useSideBarContext.ts @@ -0,0 +1,13 @@ +import { useContext } from "react"; + +import { SideBarContext } from "../sidebar-provider"; + +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export const useSideBarContext = () => { + const context = useContext(SideBarContext); + if (context === undefined) { + throw new Error("useSideBarContext must be used within a SideBarProvider"); + } + + return context; +}; diff --git a/frontend/lib/context/SidebarProvider/sidebar-provider.tsx b/frontend/lib/context/SidebarProvider/sidebar-provider.tsx new file mode 100644 index 000000000000..503a32f6dd4d --- /dev/null +++ b/frontend/lib/context/SidebarProvider/sidebar-provider.tsx @@ -0,0 +1,36 @@ +import { createContext, useEffect, useState } from "react"; + +import { useDevice } from "@/lib/hooks/useDevice"; + +type SideBarContextType = { + isOpened: boolean; + setIsOpened: React.Dispatch>; +}; + +export const SideBarContext = createContext( + undefined +); + +export const SideBarProvider = ({ + children, +}: { + children: React.ReactNode; +}): JSX.Element => { + const { isMobile } = useDevice(); + const [isOpened, setIsOpened] = useState(!isMobile); + + useEffect(() => { + setIsOpened(!isMobile); + }, [isMobile]); + + return ( + + {children} + + ); +}; diff --git a/frontend/public/locales/en/chat.json b/frontend/public/locales/en/chat.json index fed0def615ca..a3038ee52d39 100644 --- a/frontend/public/locales/en/chat.json +++ b/frontend/public/locales/en/chat.json @@ -21,6 +21,7 @@ "last30Days": "Previous 30 days", "last7Days": "Previous 7 days", "limit_reached": "You have reached the limit of requests, please try again later", + "menu": "Menu", "missing_brain": "Please select a brain to chat with", "new_discussion": "New discussion", "new_prompt": "Create new prompt", diff --git a/frontend/public/locales/es/chat.json b/frontend/public/locales/es/chat.json index c84eeb056fb1..dd512662ba8b 100644 --- a/frontend/public/locales/es/chat.json +++ b/frontend/public/locales/es/chat.json @@ -21,6 +21,7 @@ "last30Days": "Últimos 30 días", "last7Days": "Últimos 7 días", "limit_reached": "Has alcanzado el límite de peticiones, intente de nuevo más tarde", + "menu": "Menú", "missing_brain": "No hay cerebro seleccionado", "new_discussion": "Nueva discusión", "new_prompt": "Crear nueva instrucción", diff --git a/frontend/public/locales/fr/chat.json b/frontend/public/locales/fr/chat.json index f81535a516ee..4d871d7e88e2 100644 --- a/frontend/public/locales/fr/chat.json +++ b/frontend/public/locales/fr/chat.json @@ -21,6 +21,7 @@ "last30Days": "30 derniers jours", "last7Days": "7 derniers jours", "limit_reached": "Vous avez atteint la limite de requêtes, veuillez réessayer plus tard", + "menu": "Menu", "missing_brain": "Veuillez selectionner un cerveau pour discuter", "new_discussion": "Nouvelle discussion", "new_prompt": "Créer un nouveau prompt", diff --git a/frontend/public/locales/pt-br/chat.json b/frontend/public/locales/pt-br/chat.json index 062dc171331a..a50e3155beb1 100644 --- a/frontend/public/locales/pt-br/chat.json +++ b/frontend/public/locales/pt-br/chat.json @@ -21,6 +21,7 @@ "last30Days": "Últimos 30 dias", "last7Days": "Últimos 7 dias", "limit_reached": "Você atingiu o limite de solicitações, por favor, tente novamente mais tarde", + "menu": "Menu", "missing_brain": "Cérebro não encontrado", "new_discussion": "Nova discussão", "new_prompt": "Criar novo prompt", diff --git a/frontend/public/locales/ru/chat.json b/frontend/public/locales/ru/chat.json index 694b42e39885..c40c6896f85a 100644 --- a/frontend/public/locales/ru/chat.json +++ b/frontend/public/locales/ru/chat.json @@ -21,6 +21,7 @@ "last30Days": "Последние 30 дней", "last7Days": "Последние 7 дней", "limit_reached": "Вы достигли лимита запросов, пожалуйста, попробуйте позже", + "menu": "Меню", "missing_brain": "Мозг не найден", "new_discussion": "Новое обсуждение", "new_prompt": "Создать новый запрос", diff --git a/frontend/public/locales/zh-cn/chat.json b/frontend/public/locales/zh-cn/chat.json index 47bdcc601749..4ef9494860dc 100644 --- a/frontend/public/locales/zh-cn/chat.json +++ b/frontend/public/locales/zh-cn/chat.json @@ -22,6 +22,7 @@ "last30Days": "过去30天", "last7Days": "过去7天", "limit_reached": "您已达到请求限制,请稍后再试", + "menu": "菜单", "missing_brain": "请选择一个大脑进行聊天", "new_discussion": "新讨论", "new_prompt": "新提示",