From d664f516dbf177351e89ab396f1e3a54aa6f9685 Mon Sep 17 00:00:00 2001 From: Hiep Le <69354317+hieptl@users.noreply.github.com> Date: Mon, 15 Sep 2025 20:56:38 +0700 Subject: [PATCH] refactor(frontend): conversation tab content component (#10956) --- .../conversation/conversation-main.tsx | 2 +- .../conversation-tab-content.tsx | 104 +++++++----------- .../tab-container.tsx | 13 +++ .../tab-content-area.tsx | 13 +++ .../conversation-tab-content/tab-wrapper.tsx | 15 +++ 5 files changed, 79 insertions(+), 68 deletions(-) rename frontend/src/components/features/conversation/conversation-tabs/{ => conversation-tab-content}/conversation-tab-content.tsx (50%) create mode 100644 frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-container.tsx create mode 100644 frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-content-area.tsx create mode 100644 frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-wrapper.tsx diff --git a/frontend/src/components/features/conversation/conversation-main.tsx b/frontend/src/components/features/conversation/conversation-main.tsx index 8b1f061e20..f6fbf91010 100644 --- a/frontend/src/components/features/conversation/conversation-main.tsx +++ b/frontend/src/components/features/conversation/conversation-main.tsx @@ -2,7 +2,7 @@ import { useSelector } from "react-redux"; import { useWindowSize } from "@uidotdev/usehooks"; import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; import { ChatInterface } from "../chat/chat-interface"; -import { ConversationTabContent } from "./conversation-tabs/conversation-tab-content"; +import { ConversationTabContent } from "./conversation-tabs/conversation-tab-content/conversation-tab-content"; import { cn } from "#/utils/utils"; import { RootState } from "#/store"; diff --git a/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content.tsx b/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/conversation-tab-content.tsx similarity index 50% rename from frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content.tsx rename to frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/conversation-tab-content.tsx index fdffbbe831..6fad4ea286 100644 --- a/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content.tsx +++ b/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/conversation-tab-content.tsx @@ -1,12 +1,14 @@ import { lazy, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { useSelector } from "react-redux"; -import { cn } from "#/utils/utils"; import { RootState } from "#/store"; -import { ConversationLoading } from "../conversation-loading"; -import Terminal from "../../terminal/terminal"; -import { ConversationTabTitle } from "./conversation-tab-title"; +import { ConversationLoading } from "../../conversation-loading"; import { I18nKey } from "#/i18n/declaration"; +import { TabWrapper } from "./tab-wrapper"; +import { TabContainer } from "./tab-container"; +import { TabContentArea } from "./tab-content-area"; +import { ConversationTabTitle } from "../conversation-tab-title"; +import Terminal from "#/components/features/terminal/terminal"; // Lazy load all tab components const EditorTab = lazy(() => import("#/routes/changes-tab")); @@ -33,6 +35,28 @@ export function ConversationTabContent() { const isVSCodeActive = selectedTab === "vscode"; const isTerminalActive = selectedTab === "terminal"; + // Define tab configurations + const tabs = [ + { key: "editor", component: EditorTab, isActive: isEditorActive }, + { + key: "browser", + component: BrowserTab, + isActive: isBrowserActive, + }, + { + key: "jupyter", + component: JupyterTab, + isActive: isJupyterActive, + }, + { key: "served", component: ServedTab, isActive: isServedActive }, + { key: "vscode", component: VSCodeTab, isActive: isVSCodeActive }, + { + key: "terminal", + component: Terminal, + isActive: isTerminalActive, + }, + ]; + const conversationTabTitle = useMemo(() => { if (isEditorActive) { return t(I18nKey.COMMON$CHANGES); @@ -67,69 +91,15 @@ export function ConversationTabContent() { } return ( -
+ - -
-
-
- {/* Each tab content is always loaded but only visible when active */} -
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
+ + {tabs.map(({ key, component: Component, isActive }) => ( + + + + ))} + + ); } diff --git a/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-container.tsx b/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-container.tsx new file mode 100644 index 0000000000..904805a7fd --- /dev/null +++ b/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-container.tsx @@ -0,0 +1,13 @@ +import { ReactNode } from "react"; + +interface TabContainerProps { + children: ReactNode; +} + +export function TabContainer({ children }: TabContainerProps) { + return ( +
+ {children} +
+ ); +} diff --git a/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-content-area.tsx b/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-content-area.tsx new file mode 100644 index 0000000000..555ecf8738 --- /dev/null +++ b/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-content-area.tsx @@ -0,0 +1,13 @@ +import { ReactNode } from "react"; + +interface TabContentAreaProps { + children: ReactNode; +} + +export function TabContentArea({ children }: TabContentAreaProps) { + return ( +
+ {children} +
+ ); +} diff --git a/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-wrapper.tsx b/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-wrapper.tsx new file mode 100644 index 0000000000..4d7044ac3f --- /dev/null +++ b/frontend/src/components/features/conversation/conversation-tabs/conversation-tab-content/tab-wrapper.tsx @@ -0,0 +1,15 @@ +import { ReactNode } from "react"; +import { cn } from "#/utils/utils"; + +interface TabWrapperProps { + isActive: boolean; + children: ReactNode; +} + +export function TabWrapper({ isActive, children }: TabWrapperProps) { + return ( +
+ {children} +
+ ); +}