Repository: OneKeyHQ/app-monorepo
Pull request #6849: refactor: Discovery & Browser, OK-36161, OK-36275
Author: login: limichange
Created: 2025-03-10T13:14:11Z | Merged: 2025-03-13T13:59:14Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced a dedicated home tab for browser navigation that adapts header displays.
  - The add tab action now instantly creates a home tab, streamlining how users manage tabs.
  - The desktop browser view shows dashboard content when no website is available.
  - Added a new `addBrowserHomeTab` method for enhanced tab management.
  - New optional property `type` added to web tab categorization.
  - Enhanced website handling through a new `useWebSiteHandler` hook.

- **Refactor**
  - Unified and simplified website navigation handling across various views for improved consistency.
  - Transitioned to a hook-based approach for handling website navigation in several components.

- **Chores**
  - Enhanced development tooling by enforcing stricter React hooks usage and updating dependency versions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/.eslintrc.js b/.eslintrc.js
index 6bd5d5be089b..c6f6db532fe4 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -23,6 +23,7 @@ const jsRules = {
   'react/jsx-key': 'error',
   'react/jsx-no-useless-fragment': 'off',
   'use-effect-no-deps/use-effect-no-deps': 'error',
+  'react-hooks/rules-of-hooks': 'error',
   'react-hooks/exhaustive-deps': [
     'error',
     {
diff --git a/package.json b/package.json
index f959ebd1ca83..8b86f64e9536 100644
--- a/package.json
+++ b/package.json
@@ -209,7 +209,7 @@
     "eslint-plugin-prettier": "^4.2.1",
     "eslint-plugin-props-checker": "^1.1.0",
     "eslint-plugin-react": "^7.31.11",
-    "eslint-plugin-react-hooks": "^4.6.0",
+    "eslint-plugin-react-hooks": "4.6.2",
     "eslint-plugin-spellcheck": "^0.0.20",
     "eslint-plugin-unicorn": "^56.0.0",
     "eslint-plugin-use-effect-no-deps": "^1.1.2",
diff --git a/packages/components/src/layouts/Navigation/Tab/TabBar/MobileTabItem.tsx b/packages/components/src/layouts/Navigation/Tab/TabBar/MobileTabItem.tsx
index 7ba2f66f8234..bad13a10162d 100644
--- a/packages/components/src/layouts/Navigation/Tab/TabBar/MobileTabItem.tsx
+++ b/packages/components/src/layouts/Navigation/Tab/TabBar/MobileTabItem.tsx
@@ -15,7 +15,7 @@ interface IMobileTabItemProps {
 export function MobileTabItem(
   props: IMobileTabItemProps & GetProps<typeof YStack>,
 ) {
-  const { icon, label, selected, tabBarStyle, ...rest } = props;
+  const { icon, label, selected, ...rest } = props;
   return (
     <YStack alignItems="center" py="$1.5" userSelect="none" {...rest}>
       {icon ? (
diff --git a/packages/kit/src/hooks/useReplaceTx.ts b/packages/kit/src/hooks/useReplaceTx.ts
index f98a402453a2..f5079281e11b 100644
--- a/packages/kit/src/hooks/useReplaceTx.ts
+++ b/packages/kit/src/hooks/useReplaceTx.ts
@@ -161,13 +161,13 @@ function useReplaceTx({
       }
     },
     [
-      canReplaceTx,
       historyTx,
+      canReplaceTx,
       intl,
-      navigation,
-      onSuccess,
       handleOpenWebSite,
+      navigation,
       gtMd,
+      onSuccess,
     ],
   );
 
diff --git a/packages/kit/src/states/jotai/contexts/discovery/actions.ts b/packages/kit/src/states/jotai/contexts/discovery/actions.ts
index f7f96f416d40..c64436821835 100644
--- a/packages/kit/src/states/jotai/contexts/discovery/actions.ts
+++ b/packages/kit/src/states/jotai/contexts/discovery/actions.ts
@@ -230,7 +230,23 @@ class ContextJotaiActionsDiscovery extends ContextJotaiActionsBase {
   });
 
   addBlankWebTab = contextAtomMethod((_, set) => {
-    this.addWebTab.call(set, { ...homeTab, isActive: true });
+    this.addWebTab.call(set, { ...homeTab, isActive: true, type: 'normal' });
+  });
+
+  addBrowserHomeTab = contextAtomMethod((_, set) => {
+    this.addWebTab.call(set, {
+      id: generateUUID(),
+      url: '',
+      title: appLocale.intl.formatMessage({
+        id: ETranslations.browser_start_tab,
+      }),
+      canGoBack: false,
+      loading: false,
+      favicon: '',
+      isActive: true,
+      type: 'home',
+    });
+    this.setDisplayHomePage.call(set, true);
   });
 
   setWebTabData = contextAtomMethod((get, set, payload: Partial<IWebTab>) => {
@@ -737,16 +753,16 @@ class ContextJotaiActionsDiscovery extends ContextJotaiActionsBase {
         navigation,
         webSite,
         dApp,
-        switchToMultiTabBrowser = false,
         shouldPopNavigation = true,
+        switchToMultiTabBrowser = false,
       }: {
         navigation: ReturnType<typeof useAppNavigation>;
         useCurrentWindow?: boolean;
-        switchToMultiTabBrowser?: boolean;
         tabId?: string;
         webSite?: IMatchDAppItemType['webSite'];
         dApp?: IMatchDAppItemType['dApp'];
         shouldPopNavigation?: boolean;
+        switchToMultiTabBrowser?: boolean;
       },
     ) => {
       if (webSite?.url) {
@@ -779,6 +795,7 @@ class ContextJotaiActionsDiscovery extends ContextJotaiActionsBase {
           tabId,
         });
       }, delayTime);
+
       if (switchToMultiTabBrowser || platformEnv.isDesktop) {
         navigation.switchTab(ETabRoutes.MultiTabBrowser);
       } else if (shouldPopNavigation) {
@@ -967,6 +984,7 @@ export function useBrowserTabActions() {
   const actions = createActions();
   const addWebTab = actions.addWebTab.use();
   const addBlankWebTab = actions.addBlankWebTab.use();
+  const addBrowserHomeTab = actions.addBrowserHomeTab.use();
   const buildWebTabs = actions.buildWebTabs.use();
   const setTabs = actions.setTabs.use();
   const setTabsByIds = actions.setTabsByIds.use();
@@ -983,6 +1001,7 @@ export function useBrowserTabActions() {
   return useRef({
     addWebTab,
     addBlankWebTab,
+    addBrowserHomeTab,
     buildWebTabs,
     setTabs,
     setTabsByIds,
diff --git a/packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.native.tsx b/packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.native.tsx
index e967248439f2..47bd8942f2f4 100644
--- a/packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.native.tsx
+++ b/packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.native.tsx
@@ -136,13 +136,8 @@ function MobileBrowserBottomBar({
     }, [origin]);
 
   const { displayHomePage } = useDisplayHomePageFlag();
-  const {
-    setWebTabData,
-    setPinnedTab,
-    setCurrentWebTab,
-    closeWebTab,
-    setSiteMode,
-  } = useBrowserTabActions().current;
+  const { setPinnedTab, setCurrentWebTab, closeWebTab, setSiteMode } =
+    useBrowserTabActions().current;
   const { disabledAddedNewTab } = useDisabledAddedNewTab();
   const { addBrowserBookmark, removeBrowserBookmark } =
     useBrowserBookmarkAction().current;
diff --git a/packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.tsx b/packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.tsx
index bf31422e983f..a8110f3301a6 100644
--- a/packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.tsx
+++ b/packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.tsx
@@ -1,10 +1,10 @@
 import type { IMobileBrowserBottomBarProps } from './MobileBrowserBottomBar.native';
 
-function MobileBrowserBottomBar(props: IMobileBrowserBottomBarProps) {
+function MobileBrowserBottomBar(_props: IMobileBrowserBottomBarProps) {
   return null;
 }
 
-export const useTakeScreenshot = (id?: string | null) => () =>
+export const useTakeScreenshot = (_id?: string | null) => () =>
   Promise.resolve(true);
 
 export default MobileBrowserBottomBar;
diff --git a/packages/kit/src/views/Discovery/hooks/useDesktopNewWindow.ts b/packages/kit/src/views/Discovery/hooks/useDesktopNewWindow.ts
index e057d146bd34..c5eb312e8430 100644
--- a/packages/kit/src/views/Discovery/hooks/useDesktopNewWindow.ts
+++ b/packages/kit/src/views/Discovery/hooks/useDesktopNewWindow.ts
@@ -14,17 +14,17 @@ export function useDesktopNewWindow() {
     (_: any, data: { url: string }) => {
       if (data.url) {
         handleOpenWebSite({
-          switchToMultiTabBrowser: gtMd,
           useCurrentWindow: false,
           webSite: {
             url: data.url,
             title: data.url,
           },
+          gtMd,
           navigation,
         });
       }
     },
-    [gtMd, handleOpenWebSite, navigation],
+    [handleOpenWebSite, navigation, gtMd],
   );
   useEffect(() => {
     globalThis.desktopApi?.addIpcEventListener(
diff --git a/packages/kit/src/views/Discovery/pages/BookmarkListModal/index.tsx b/packages/kit/src/views/Discovery/pages/BookmarkListModal/index.tsx
index 4a438bb104df..1a68ddd7af3d 100644
--- a/packages/kit/src/views/Discovery/pages/BookmarkListModal/index.tsx
+++ b/packages/kit/src/views/Discovery/pages/BookmarkListModal/index.tsx
@@ -6,24 +6,18 @@ import {
   Button,
   Dialog,
   Empty,
-  Input,
   Page,
   SortableListView,
   Toast,
   XStack,
-  useMedia,
 } from '@onekeyhq/components';
 import backgroundApiProxy from '@onekeyhq/kit/src/background/instance/backgroundApiProxy';
 import { ListItem } from '@onekeyhq/kit/src/components/ListItem';
 import { RenameInputWithNameSelector } from '@onekeyhq/kit/src/components/RenameDialog';
 import useAppNavigation from '@onekeyhq/kit/src/hooks/useAppNavigation';
 import { usePromiseResult } from '@onekeyhq/kit/src/hooks/usePromiseResult';
-import {
-  useBrowserAction,
-  useBrowserBookmarkAction,
-} from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
+import { useBrowserBookmarkAction } from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
 import { ETranslations } from '@onekeyhq/shared/src/locale';
-import { defaultLogger } from '@onekeyhq/shared/src/logger/logger';
 import { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
 import {
   EChangeHistoryContentType,
@@ -31,6 +25,7 @@ import {
 } from '@onekeyhq/shared/src/types/changeHistory';
 
 import { DiscoveryIcon } from '../../components/DiscoveryIcon';
+import { useWebSiteHandler } from '../../utils/useWebSiteHandler';
 import { withBrowserProvider } from '../Browser/WithBrowserProvider';
 
 import type { IBrowserBookmark } from '../../types';
@@ -40,7 +35,7 @@ function BookmarkListModal() {
   const intl = useIntl();
   const { buildBookmarkData, removeBrowserBookmark, modifyBrowserBookmark } =
     useBrowserBookmarkAction().current;
-  const { handleOpenWebSite } = useBrowserAction().current;
+  const handleWebSite = useWebSiteHandler();
 
   const [dataSource, setDataSource] = useState<IBrowserBookmark[]>([]);
   const { run, result } = usePromiseResult(
@@ -144,6 +139,19 @@ function BookmarkListModal() {
     [buildBookmarkData],
   );
 
+  const handleItemPress = useCallback(
+    (item: IBrowserBookmark) => {
+      handleWebSite({
+        webSite: {
+          url: item.url,
+          title: item.title,
+        },
+        enterMethod: EEnterMethod.bookmark,
+      });
+    },
+    [handleWebSite],
+  );
+
   const CELL_HEIGHT = 60;
 
   const headerRight = useCallback(
@@ -165,7 +173,6 @@ function BookmarkListModal() {
     ),
     [isEditing, intl],
   );
-  const { gtMd } = useMedia();
 
   return (
     <Page>
@@ -201,21 +208,7 @@ function BookmarkListModal() {
               h={CELL_HEIGHT}
               testID={`search-modal-${item.url.toLowerCase()}`}
               {...(!isEditing && {
-                onPress: () => {
-                  handleOpenWebSite({
-                    navigation,
-                    switchToMultiTabBrowser: gtMd,
-                    webSite: {
-                      url: item.url,
-                      title: item.title,
-                    },
-                  });
-                  defaultLogger.discovery.dapp.enterDapp({
-                    dappDomain: item.url,
-                    dappName: item.title,
-                    enterMethod: EEnterMethod.bookmark,
-                  });
-                },
+                onPress: () => handleItemPress(item),
               })}
             >
               {isEditing ? (
diff --git a/packages/kit/src/views/Discovery/pages/Browser/Browser.desktop.tsx b/packages/kit/src/views/Discovery/pages/Browser/Browser.desktop.tsx
index 12e9f1387190..937d1f47f166 100644
--- a/packages/kit/src/views/Discovery/pages/Browser/Browser.desktop.tsx
+++ b/packages/kit/src/views/Discovery/pages/Browser/Browser.desktop.tsx
@@ -6,7 +6,12 @@ import { ETabRoutes } from '@onekeyhq/shared/src/routes';
 
 import HeaderRightToolBar from '../../components/HeaderRightToolBar';
 import { useDAppNotifyChanges } from '../../hooks/useDAppNotifyChanges';
-import { useActiveTabId, useWebTabs } from '../../hooks/useWebTabs';
+import {
+  useActiveTabId,
+  useWebTabDataById,
+  useWebTabs,
+} from '../../hooks/useWebTabs';
+import { HistoryIconButton } from '../components/HistoryIconButton';
 
 import DesktopBrowserContent from './DesktopBrowserContent';
 import DesktopBrowserNavigationContainer from './DesktopBrowserNavigationContainer';
@@ -15,6 +20,8 @@ import { withBrowserProvider } from './WithBrowserProvider';
 function DesktopBrowser() {
   const { tabs } = useWebTabs();
   const { activeTabId } = useActiveTabId();
+  const { tab: activeTab } = useWebTabDataById(activeTabId ?? '');
+  const isHomeType = activeTab?.type === 'home';
 
   const navigation = useAppNavigation();
   const firstRender = useRef(true);
@@ -45,9 +52,11 @@ function DesktopBrowser() {
     <Page>
       <Page.Header
         // @ts-expect-error
-        headerTitle={DesktopBrowserNavigationContainer}
+        headerTitle={
+          !isHomeType ? DesktopBrowserNavigationContainer : undefined
+        }
         // @ts-expect-error
-        headerRight={HeaderRightToolBar}
+        headerRight={!isHomeType ? HeaderRightToolBar : HistoryIconButton}
         headerRightContainerStyle={{
           flexBasis: 'auto',
           flexGrow: 0,
diff --git a/packages/kit/src/views/Discovery/pages/Browser/DesktopBrowserContent.tsx b/packages/kit/src/views/Discovery/pages/Browser/DesktopBrowserContent.tsx
index f3cd4f265d8b..711fb0457f6f 100644
--- a/packages/kit/src/views/Discovery/pages/Browser/DesktopBrowserContent.tsx
+++ b/packages/kit/src/views/Discovery/pages/Browser/DesktopBrowserContent.tsx
@@ -20,6 +20,7 @@ import platformEnv from '@onekeyhq/shared/src/platformEnv';
 import WebContent from '../../components/WebContent/WebContent';
 import { useWebTabDataById } from '../../hooks/useWebTabs';
 import { webviewRefs } from '../../utils/explorerUtils';
+import DashboardContent from '../Dashboard/DashboardContent';
 
 interface IElectronWebView {
   stopFindInPage: (text: string) => void;
@@ -234,7 +235,9 @@ function BasicDesktopBrowserContent({
       {platformEnv.isDesktop ? <Find id={id} /> : null}
       {tab?.url ? (
         <WebContent id={id} url={tab.url} isCurrent={isActive} />
-      ) : null}
+      ) : (
+        <DashboardContent />
+      )}
     </Freeze>
   );
 }
diff --git a/packages/kit/src/views/Discovery/pages/Dashboard/Banner.tsx b/packages/kit/src/views/Discovery/pages/Dashboard/Banner.tsx
index 6ead76f910ee..56e554a1bae3 100644
--- a/packages/kit/src/views/Discovery/pages/Dashboard/Banner.tsx
+++ b/packages/kit/src/views/Discovery/pages/Dashboard/Banner.tsx
@@ -1,26 +1,23 @@
 import { useMemo } from 'react';
 
 import { Banner, Skeleton, Stack } from '@onekeyhq/components';
+import { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
 import type { IDiscoveryBanner } from '@onekeyhq/shared/types/discovery';
 
 import { useBannerData } from '../../hooks/useBannerData';
+import { useWebSiteHandler } from '../../utils/useWebSiteHandler';
 
 import type { IMatchDAppItemType } from '../../types';
 
 export function DashboardBanner({
   banners,
-  handleOpenWebSite,
   isLoading,
 }: {
   banners: IDiscoveryBanner[];
-  handleOpenWebSite: ({
-    dApp,
-    webSite,
-    useSystemBrowser,
-  }: IMatchDAppItemType & { useSystemBrowser: boolean }) => void;
   isLoading: boolean | undefined;
 }) {
   const { data, closeAllBanners } = useBannerData(banners);
+  const handleWebSite = useWebSiteHandler();
 
   const emptyComponent = useMemo(
     () =>
@@ -62,12 +59,14 @@ export function DashboardBanner({
         itemTitleContainerStyle={{ display: 'none' }}
         emptyComponent={emptyComponent}
         onItemPress={(item) => {
-          handleOpenWebSite({
+          handleWebSite({
             webSite: {
               url: item.href,
               title: item.href,
             },
             useSystemBrowser: item.useSystemBrowser,
+            shouldPopNavigation: false,
+            enterMethod: EEnterMethod.banner,
           });
         }}
       />
diff --git a/packages/kit/src/views/Discovery/pages/Dashboard/BookmarksSection.tsx b/packages/kit/src/views/Discovery/pages/Dashboard/BookmarksSection.tsx
index f818f3b020ec..7e9006402d69 100644
--- a/packages/kit/src/views/Discovery/pages/Dashboard/BookmarksSection.tsx
+++ b/packages/kit/src/views/Discovery/pages/Dashboard/BookmarksSection.tsx
@@ -12,24 +12,24 @@ import {
   appEventBus,
 } from '@onekeyhq/shared/src/eventBus/appEventBus';
 import { ETranslations } from '@onekeyhq/shared/src/locale';
+import { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
 import {
   EDiscoveryModalRoutes,
   EModalRoutes,
   ETabRoutes,
 } from '@onekeyhq/shared/src/routes';
 
+import { useWebSiteHandler } from '../../utils/useWebSiteHandler';
+
 import { BookmarksSectionItems } from './BookmarksSectionItems';
 import { DashboardSectionHeader } from './DashboardSectionHeader';
 
 import type { IBrowserBookmark, IMatchDAppItemType } from '../../types';
 
-export function BookmarksSection({
-  handleOpenWebSite,
-}: {
-  handleOpenWebSite: ({ dApp, webSite }: IMatchDAppItemType) => void;
-}) {
+export function BookmarksSection() {
   const intl = useIntl();
   const navigation = useAppNavigation();
+  const handleWebSite = useWebSiteHandler();
 
   const {
     result: bookmarksData,
@@ -91,6 +91,18 @@ export function BookmarksSection({
   );
   const hasBookmarks = dataSource.length > 0;
 
+  const handleOpenWebSite = useCallback(
+    ({ dApp, webSite }: IMatchDAppItemType) => {
+      handleWebSite({
+        webSite,
+        dApp,
+        shouldPopNavigation: false,
+        enterMethod: EEnterMethod.bookmark,
+      });
+    },
+    [handleWebSite],
+  );
+
   if (!hasBookmarks) {
     return null;
   }
diff --git a/packages/kit/src/views/Discovery/pages/Dashboard/DashboardContent.tsx b/packages/kit/src/views/Discovery/pages/Dashboard/DashboardContent.tsx
index 63812e2c5c28..44733aa1c178 100644
--- a/packages/kit/src/views/Discovery/pages/Dashboard/DashboardContent.tsx
+++ b/packages/kit/src/views/Discovery/pages/Dashboard/DashboardContent.tsx
@@ -2,21 +2,11 @@ import { memo, useCallback, useMemo, useState } from 'react';
 
 import { useWindowDimensions } from 'react-native';
 
-import {
-  RefreshControl,
-  ScrollView,
-  Stack,
-  useMedia,
-} from '@onekeyhq/components';
+import { RefreshControl, ScrollView, Stack } from '@onekeyhq/components';
 import backgroundApiProxy from '@onekeyhq/kit/src/background/instance/backgroundApiProxy';
-import useAppNavigation from '@onekeyhq/kit/src/hooks/useAppNavigation';
 import { usePromiseResult } from '@onekeyhq/kit/src/hooks/usePromiseResult';
 import { useRouteIsFocused as useIsFocused } from '@onekeyhq/kit/src/hooks/useRouteIsFocused';
-import { useBrowserAction } from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
-import { defaultLogger } from '@onekeyhq/shared/src/logger/logger';
-import { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
 import platformEnv from '@onekeyhq/shared/src/platformEnv';
-import { openUrlExternal } from '@onekeyhq/shared/src/utils/openUrlUtils';
 
 import { useBannerData } from '../../hooks/useBannerData';
 
@@ -33,11 +23,8 @@ function DashboardContent({
 }: {
   onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
 }) {
-  const navigation = useAppNavigation();
   const isFocused = useIsFocused();
-  const { gtMd } = useMedia();
   const { height: screenHeight } = useWindowDimensions();
-  const { handleOpenWebSite } = useBrowserAction().current;
 
   const [isRefreshing, setIsRefreshing] = useState(false);
 
@@ -111,23 +98,6 @@ function DashboardContent({
               <DashboardBanner
                 key="Banner"
                 banners={homePageData?.banners || []}
-                handleOpenWebSite={({ webSite, useSystemBrowser }) => {
-                  if (useSystemBrowser && webSite?.url) {
-                    openUrlExternal(webSite.url);
-                  } else if (webSite?.url) {
-                    handleOpenWebSite({
-                      switchToMultiTabBrowser: gtMd,
-                      webSite,
-                      navigation,
-                      shouldPopNavigation: false,
-                    });
-                  }
-                  defaultLogger.discovery.dapp.enterDapp({
-                    dappDomain: webSite?.url || '',
-                    dappName: webSite?.title || '',
-                    enterMethod: EEnterMethod.banner,
-                  });
-                }}
                 isLoading={isLoading}
               />
             ) : null
@@ -140,56 +110,19 @@ function DashboardContent({
           ) : (
             <>
               <Stack px="$5" width="100%" $gtXl={{ width: 960 }}>
-                <BookmarksSection
-                  key="BookmarksSection"
-                  handleOpenWebSite={({ webSite }) => {
-                    handleOpenWebSite({
-                      switchToMultiTabBrowser: gtMd,
-                      webSite,
-                      navigation,
-                      shouldPopNavigation: false,
-                    });
-                    defaultLogger.discovery.dapp.enterDapp({
-                      dappDomain: webSite?.url || '',
-                      dappName: webSite?.title || '',
-                      enterMethod: EEnterMethod.dashboard,
-                    });
-                  }}
-                />
+                <BookmarksSection key="BookmarksSection" />
               </Stack>
 
               {/* here is trending */}
               <Stack px="$5" width="100%" $gtXl={{ width: 960 }} mt="$6">
-                <TrendingSection
-                  handleOpenWebSite={({ webSite }) => {
-                    handleOpenWebSite({
-                      switchToMultiTabBrowser: gtMd,
-                      webSite,
-                      navigation,
-                      shouldPopNavigation: false,
-                    });
-                    defaultLogger.discovery.dapp.enterDapp({
-                      dappDomain: webSite?.url || '',
-                      dappName: webSite?.title || '',
-                      enterMethod: EEnterMethod.dashboard,
-                    });
-                  }}
-                />
+                <TrendingSection />
               </Stack>
             </>
           )}
         </Stack>
       </>
     ),
-    [
-      homePageData?.banners,
-      hasActiveBanners,
-      isLoading,
-      handleOpenWebSite,
-      gtMd,
-      navigation,
-      showDiveInDescription,
-    ],
+    [homePageData?.banners, hasActiveBanners, isLoading, showDiveInDescription],
   );
 
   if (platformEnv.isNative) {
diff --git a/packages/kit/src/views/Discovery/pages/Dashboard/TrendingSection.tsx b/packages/kit/src/views/Discovery/pages/Dashboard/TrendingSection.tsx
index 420045a1266b..71076d6a9e7d 100644
--- a/packages/kit/src/views/Discovery/pages/Dashboard/TrendingSection.tsx
+++ b/packages/kit/src/views/Discovery/pages/Dashboard/TrendingSection.tsx
@@ -1,4 +1,4 @@
-import { useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
 
 import { isNil } from 'lodash';
 import { useIntl } from 'react-intl';
@@ -7,18 +7,17 @@ import { SizableText, Skeleton, Stack } from '@onekeyhq/components';
 import backgroundApiProxy from '@onekeyhq/kit/src/background/instance/backgroundApiProxy';
 import { usePromiseResult } from '@onekeyhq/kit/src/hooks/usePromiseResult';
 import { ETranslations } from '@onekeyhq/shared/src/locale';
+import { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
 import type { IDApp } from '@onekeyhq/shared/types/discovery';
 
+import { useWebSiteHandler } from '../../utils/useWebSiteHandler';
+
 import { DashboardSectionHeader } from './DashboardSectionHeader';
 import { TrendingSectionItems } from './TrendingSectionItems';
 
 import type { IMatchDAppItemType } from '../../types';
 
-export function TrendingSection({
-  handleOpenWebSite,
-}: {
-  handleOpenWebSite: ({ dApp, webSite }: IMatchDAppItemType) => void;
-}) {
+export function TrendingSection() {
   const { result: trendingData } = usePromiseResult<IDApp[]>(
     async () => {
       const data =
@@ -31,11 +30,24 @@ export function TrendingSection({
     },
   );
   const intl = useIntl();
+  const handleWebSite = useWebSiteHandler();
   const dataSource = useMemo<IDApp[]>(() => trendingData ?? [], [trendingData]);
 
   const isLoadingTrending = isNil(trendingData);
   const hasTrendingItems = dataSource.length > 0;
 
+  const handleOpenWebSite = useCallback(
+    ({ dApp, webSite }: IMatchDAppItemType) => {
+      handleWebSite({
+        webSite,
+        dApp,
+        shouldPopNavigation: false,
+        enterMethod: EEnterMethod.trending,
+      });
+    },
+    [handleWebSite],
+  );
+
   return (
     <Stack minHeight="$40">
       <DashboardSectionHeader>
diff --git a/packages/kit/src/views/Discovery/pages/Dashboard/Welcome/Welcome.tsx b/packages/kit/src/views/Discovery/pages/Dashboard/Welcome/Welcome.tsx
index c265172249c0..23970681e0eb 100644
--- a/packages/kit/src/views/Discovery/pages/Dashboard/Welcome/Welcome.tsx
+++ b/packages/kit/src/views/Discovery/pages/Dashboard/Welcome/Welcome.tsx
@@ -1,4 +1,4 @@
-import { useMemo, useState } from 'react';
+import { useMemo } from 'react';
 
 import { Skeleton, Stack, XStack, useMedia } from '@onekeyhq/components';
 import backgroundApiProxy from '@onekeyhq/kit/src/background/instance/backgroundApiProxy';
diff --git a/packages/kit/src/views/Discovery/pages/Dashboard/Welcome/WelcomeItem.tsx b/packages/kit/src/views/Discovery/pages/Dashboard/Welcome/WelcomeItem.tsx
index 18201066f824..f43fbced4c4a 100644
--- a/packages/kit/src/views/Discovery/pages/Dashboard/Welcome/WelcomeItem.tsx
+++ b/packages/kit/src/views/Discovery/pages/Dashboard/Welcome/WelcomeItem.tsx
@@ -10,10 +10,9 @@ import Animated, {
   withTiming,
 } from 'react-native-reanimated';
 
-import { Image, Stack, useMedia } from '@onekeyhq/components';
-import useAppNavigation from '@onekeyhq/kit/src/hooks/useAppNavigation';
-import { useBrowserAction } from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
-import platformEnv from '@onekeyhq/shared/src/platformEnv';
+import { Image, Stack } from '@onekeyhq/components';
+import { useWebSiteHandler } from '@onekeyhq/kit/src/views/Discovery/utils/useWebSiteHandler';
+import { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
 
 import type { ImageSourcePropType, ImageURISource } from 'react-native';
 
@@ -105,9 +104,7 @@ export const WelcomeItem = memo(
     const rotate = useSharedValue(0);
     const scale = useSharedValue(1);
     const shadowOpacity = useSharedValue(DEFAULT_SHADOW_OPACITY);
-    const navigation = useAppNavigation();
-    const { gtMd } = useMedia();
-    const { handleOpenWebSite } = useBrowserAction().current;
+    const handleWebSite = useWebSiteHandler();
 
     useEffect(() => {
       setTimeout(
@@ -216,14 +213,13 @@ export const WelcomeItem = memo(
 
     const handlePress = () => {
       if (url) {
-        handleOpenWebSite({
-          switchToMultiTabBrowser: gtMd,
+        handleWebSite({
           webSite: {
             url,
             title: url,
           },
-          navigation,
           shouldPopNavigation: false,
+          enterMethod: EEnterMethod.dashboard,
         });
       }
     };
diff --git a/packages/kit/src/views/Discovery/pages/DesktopCustomTabBar/index.tsx b/packages/kit/src/views/Discovery/pages/DesktopCustomTabBar/index.tsx
index 90f3ce902e6a..4810cfeac3a8 100644
--- a/packages/kit/src/views/Discovery/pages/DesktopCustomTabBar/index.tsx
+++ b/packages/kit/src/views/Discovery/pages/DesktopCustomTabBar/index.tsx
@@ -66,6 +66,7 @@ function DesktopCustomTabBar() {
     setPinnedTab,
     closeAllWebTabs,
     setTabsByIds,
+    addBrowserHomeTab,
     reOpenLastClosedTab,
   } = useBrowserTabActions().current;
   const { addBrowserBookmark, removeBrowserBookmark } =
@@ -384,9 +385,14 @@ function DesktopCustomTabBar() {
                 testID="browser-bar-add"
                 onPress={(e) => {
                   e.stopPropagation();
-                  navigation.pushModal(EModalRoutes.DiscoveryModal, {
-                    screen: EDiscoveryModalRoutes.SearchModal,
-                  });
+
+                  if (platformEnv.isDesktop) {
+                    addBrowserHomeTab();
+                  } else {
+                    navigation.pushModal(EModalRoutes.DiscoveryModal, {
+                      screen: EDiscoveryModalRoutes.SearchModal,
+                    });
+                  }
                 }}
               />
             </>
diff --git a/packages/kit/src/views/Discovery/pages/HistoryListModal/index.tsx b/packages/kit/src/views/Discovery/pages/HistoryListModal/index.tsx
index bf342ace632d..534ac4e61e12 100644
--- a/packages/kit/src/views/Discovery/pages/HistoryListModal/index.tsx
+++ b/packages/kit/src/views/Discovery/pages/HistoryListModal/index.tsx
@@ -13,22 +13,18 @@ import {
   SectionList,
   Toast,
   XStack,
-  useMedia,
 } from '@onekeyhq/components';
 import backgroundApiProxy from '@onekeyhq/kit/src/background/instance/backgroundApiProxy';
 import { ListItem } from '@onekeyhq/kit/src/components/ListItem';
 import useAppNavigation from '@onekeyhq/kit/src/hooks/useAppNavigation';
 import { usePromiseResult } from '@onekeyhq/kit/src/hooks/usePromiseResult';
-import {
-  useBrowserAction,
-  useBrowserHistoryAction,
-} from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
+import { useBrowserHistoryAction } from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
 import { ETranslations } from '@onekeyhq/shared/src/locale';
-import { defaultLogger } from '@onekeyhq/shared/src/logger/logger';
 import { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
 import { formatRelativeDate } from '@onekeyhq/shared/src/utils/dateUtils';
 
 import { DiscoveryIcon } from '../../components/DiscoveryIcon';
+import { useWebSiteHandler } from '../../utils/useWebSiteHandler';
 import { withBrowserProvider } from '../Browser/WithBrowserProvider';
 
 import type { IBrowserHistory } from '../../types';
@@ -57,8 +53,7 @@ function HistoryListModal() {
   const { removeBrowserHistory, removeAllBrowserHistory } =
     useBrowserHistoryAction().current;
 
-  const { gtMd } = useMedia();
-  const { handleOpenWebSite } = useBrowserAction().current;
+  const handleWebSite = useWebSiteHandler();
 
   const [page, setPage] = useState(1);
   const { result: dataSource, run } = usePromiseResult(
@@ -183,18 +178,12 @@ function HistoryListModal() {
               testID={`search-modal-${item.url.toLowerCase()}`}
               {...(!isEditing && {
                 onPress: () => {
-                  handleOpenWebSite({
-                    switchToMultiTabBrowser: gtMd,
-                    navigation,
+                  handleWebSite({
                     webSite: {
                       url: item.url,
                       title: item.title,
                     },
-                  });
-
-                  defaultLogger.discovery.dapp.enterDapp({
-                    dappDomain: item.url,
-                    dappName: item.title,
+                    shouldPopNavigation: true,
                     enterMethod: EEnterMethod.history,
                   });
                 },
diff --git a/packages/kit/src/views/Discovery/pages/SearchModal/index.tsx b/packages/kit/src/views/Discovery/pages/SearchModal/index.tsx
index a7febb02918d..a7474332dc08 100644
--- a/packages/kit/src/views/Discovery/pages/SearchModal/index.tsx
+++ b/packages/kit/src/views/Discovery/pages/SearchModal/index.tsx
@@ -21,9 +21,7 @@ import backgroundApiProxy from '@onekeyhq/kit/src/background/instance/background
 import { ListItem } from '@onekeyhq/kit/src/components/ListItem';
 import useAppNavigation from '@onekeyhq/kit/src/hooks/useAppNavigation';
 import { usePromiseResult } from '@onekeyhq/kit/src/hooks/usePromiseResult';
-import { useBrowserAction } from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
 import { ETranslations } from '@onekeyhq/shared/src/locale';
-import { defaultLogger } from '@onekeyhq/shared/src/logger/logger';
 import { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
 import type { IDiscoveryModalParamList } from '@onekeyhq/shared/src/routes';
 import {
@@ -33,6 +31,7 @@ import {
 import type { IDApp } from '@onekeyhq/shared/types/discovery';
 
 import { DiscoveryIcon } from '../../components/DiscoveryIcon';
+import { useWebSiteHandler } from '../../utils/useWebSiteHandler';
 import { withBrowserProvider } from '../Browser/WithBrowserProvider';
 
 import { DappSearchModalSectionHeader } from './DappSearchModalSectionHeader';
@@ -58,7 +57,7 @@ function SearchModal() {
 
   const [searchValue, setSearchValue] = useState(url);
   const { gtMd } = useMedia();
-  const { handleOpenWebSite } = useBrowserAction().current;
+  const handleWebSite = useWebSiteHandler();
 
   const { serviceDiscovery } = backgroundApiProxy;
   const { result: localData, run: refreshLocalData } =
@@ -163,32 +162,20 @@ function SearchModal() {
           }}
           onPress={() => {
             if (item.dappId === SEARCH_ITEM_ID) {
-              handleOpenWebSite({
-                switchToMultiTabBrowser: gtMd,
-                navigation,
-                useCurrentWindow,
-                tabId,
+              handleWebSite({
                 webSite: {
                   url: searchValue,
                   title: searchValue,
                 },
-              });
-              defaultLogger.discovery.dapp.enterDapp({
-                dappDomain: searchValue,
-                dappName: searchValue,
+                useCurrentWindow,
+                tabId,
                 enterMethod: EEnterMethod.search,
               });
             } else {
-              handleOpenWebSite({
-                switchToMultiTabBrowser: gtMd,
-                navigation,
+              handleWebSite({
+                dApp: item,
                 useCurrentWindow,
                 tabId,
-                dApp: item,
-              });
-              defaultLogger.discovery.dapp.enterDapp({
-                dappDomain: item.name,
-                dappName: item.url,
                 enterMethod: EEnterMethod.search,
               });
             }
@@ -196,7 +183,7 @@ function SearchModal() {
           testID={`dapp-search${index}`}
         />
       )),
-    [gtMd, handleOpenWebSite, navigation, searchValue, tabId, useCurrentWindow],
+    [handleWebSite, searchValue, tabId, useCurrentWindow],
   );
 
   return (
@@ -221,20 +208,13 @@ function SearchModal() {
               if (!searchValue) {
                 navigation.pop();
               } else {
-                handleOpenWebSite({
-                  switchToMultiTabBrowser: gtMd,
-                  navigation,
-                  useCurrentWindow,
-                  tabId,
+                handleWebSite({
                   webSite: {
                     url: searchValue,
                     title: searchValue,
                   },
-                });
-
-                defaultLogger.discovery.dapp.enterDapp({
-                  dappDomain: searchValue,
-                  dappName: searchValue,
+                  useCurrentWindow,
+                  tabId,
                   enterMethod: EEnterMethod.addressBar,
                 });
               }
@@ -274,20 +254,13 @@ function SearchModal() {
                       flexBasis: '16.66666667%',
                     }}
                     onPress={() => {
-                      handleOpenWebSite({
-                        switchToMultiTabBrowser: gtMd,
-                        navigation,
-                        useCurrentWindow,
-                        tabId,
+                      handleWebSite({
                         webSite: {
                           url: item.url,
                           title: item.title,
                         },
-                      });
-
-                      defaultLogger.discovery.dapp.enterDapp({
-                        dappDomain: item.url,
-                        dappName: item.title,
+                        useCurrentWindow,
+                        tabId,
                         enterMethod: EEnterMethod.bookmarkInSearch,
                       });
                     }}
@@ -354,20 +327,13 @@ function SearchModal() {
                   }}
                   testID={`search-modal-${item.title.toLowerCase()}`}
                   onPress={() => {
-                    handleOpenWebSite({
-                      switchToMultiTabBrowser: gtMd,
-                      navigation,
-                      useCurrentWindow,
-                      tabId,
+                    handleWebSite({
                       webSite: {
                         url: item.url,
                         title: item.title,
                       },
-                    });
-
-                    defaultLogger.discovery.dapp.enterDapp({
-                      dappDomain: item.url,
-                      dappName: item.title,
+                      useCurrentWindow,
+                      tabId,
                       enterMethod: EEnterMethod.historyInSearch,
                     });
                   }}
diff --git a/packages/kit/src/views/Discovery/types.ts b/packages/kit/src/views/Discovery/types.ts
index 3e2b15c69465..33b59f05b215 100644
--- a/packages/kit/src/views/Discovery/types.ts
+++ b/packages/kit/src/views/Discovery/types.ts
@@ -90,6 +90,7 @@ export interface IWebTab {
   refReady?: boolean;
   timestamp?: number;
   siteMode?: ESiteMode;
+  type?: 'normal' | 'home';
 }
 
 export interface IWebTabsAtom {
diff --git a/packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts b/packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts
new file mode 100644
index 000000000000..6729b01113f0
--- /dev/null
+++ b/packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts
@@ -0,0 +1,93 @@
+import { useCallback } from 'react';
+
+import { useMedia } from '@onekeyhq/components';
+import useAppNavigation from '@onekeyhq/kit/src/hooks/useAppNavigation';
+import {
+  useBrowserAction,
+  useBrowserTabActions,
+} from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
+import { defaultLogger } from '@onekeyhq/shared/src/logger/logger';
+import type { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
+import { openUrlExternal } from '@onekeyhq/shared/src/utils/openUrlUtils';
+import type { IDApp } from '@onekeyhq/shared/types/discovery';
+
+import { useActiveTabId, useWebTabDataById } from '../hooks/useWebTabs';
+
+import type { IBrowserBookmark, IBrowserHistory } from '../types';
+
+interface IHandleWebSiteParams {
+  webSite?: IBrowserBookmark | IBrowserHistory;
+  dApp?: IDApp;
+  useSystemBrowser?: boolean;
+  shouldPopNavigation?: boolean;
+  useCurrentWindow?: boolean;
+  tabId?: string;
+  enterMethod: EEnterMethod;
+}
+
+export const useWebSiteHandler = () => {
+  const { handleOpenWebSite } = useBrowserAction().current;
+  const { setWebTabData } = useBrowserTabActions().current;
+  const navigation = useAppNavigation();
+  const { activeTabId } = useActiveTabId();
+  const { tab: activeTab } = useWebTabDataById(activeTabId ?? '');
+  const { gtMd } = useMedia();
+
+  return useCallback(
+    ({
+      webSite,
+      dApp,
+      useSystemBrowser,
+      shouldPopNavigation,
+      enterMethod,
+      useCurrentWindow,
+      tabId,
+    }: IHandleWebSiteParams) => {
+      if (!webSite?.url) {
+        return;
+      }
+
+      // If current active tab is of type 'home', change it to 'normal' and update its URL
+      if (activeTab?.type === 'home' && !useSystemBrowser) {
+        setWebTabData({
+          id: activeTab.id,
+          url: webSite.url,
+          title: webSite.title || dApp?.name || '',
+          type: 'normal',
+          isPinned: activeTab.isPinned,
+        });
+
+        if (shouldPopNavigation) {
+          navigation.pop();
+        }
+      } else if (useSystemBrowser) {
+        openUrlExternal(webSite.url);
+      } else {
+        handleOpenWebSite({
+          webSite,
+          dApp,
+          navigation,
+          shouldPopNavigation,
+          switchToMultiTabBrowser: gtMd,
+          useCurrentWindow,
+          tabId,
+        });
+      }
+
+      defaultLogger.discovery.dapp.enterDapp({
+        dappDomain: webSite.url,
+        dappName: webSite.title || dApp?.name || '',
+        enterMethod,
+      });
+    },
+    [
+      activeTab?.type,
+      activeTab?.id,
+      activeTab?.isPinned,
+      setWebTabData,
+      navigation,
+      handleOpenWebSite,
+      gtMd,
+    ],
+  );
+};
diff --git a/packages/kit/src/views/Discovery/utils/webSiteHandler.ts b/packages/kit/src/views/Discovery/utils/webSiteHandler.ts
deleted file mode 100644
index b7c9784ac18a..000000000000
--- a/packages/kit/src/views/Discovery/utils/webSiteHandler.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { useCallback } from 'react';
-
-import { useBrowserAction } from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
-import { defaultLogger } from '@onekeyhq/shared/src/logger/logger';
-import type { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
-import { openUrlExternal } from '@onekeyhq/shared/src/utils/openUrlUtils';
-import type { IDApp } from '@onekeyhq/shared/types/discovery';
-
-import type { IBrowserBookmark, IBrowserHistory } from '../types';
-
-interface IHandleWebSiteParams {
-  webSite?: IBrowserBookmark | IBrowserHistory;
-  dApp?: IDApp;
-  useSystemBrowser?: boolean;
-  switchToMultiTabBrowser?: boolean;
-  navigation?: any;
-  shouldPopNavigation?: boolean;
-  enterMethod: EEnterMethod;
-}
-
-export const useWebSiteHandler = () => {
-  const { handleOpenWebSite } = useBrowserAction().current;
-
-  return useCallback(
-    async ({
-      webSite,
-      dApp,
-      useSystemBrowser,
-      switchToMultiTabBrowser,
-      navigation,
-      shouldPopNavigation = true,
-      enterMethod,
-    }: IHandleWebSiteParams) => {
-      if (!webSite?.url) {
-        return;
-      }
-
-      if (useSystemBrowser) {
-        openUrlExternal(webSite.url);
-      } else {
-        handleOpenWebSite({
-          webSite,
-          dApp,
-          switchToMultiTabBrowser,
-          navigation,
-          shouldPopNavigation,
-        });
-      }
-
-      defaultLogger.discovery.dapp.enterDapp({
-        dappDomain: webSite.url,
-        dappName: webSite.title || dApp?.name || '',
-        enterMethod,
-      });
-    },
-    [handleOpenWebSite],
-  );
-};
diff --git a/packages/shared/src/logger/scopes/discovery/scenes/dapp.ts b/packages/shared/src/logger/scopes/discovery/scenes/dapp.ts
index a63f44feaca1..45b01ff12ef3 100644
--- a/packages/shared/src/logger/scopes/discovery/scenes/dapp.ts
+++ b/packages/shared/src/logger/scopes/discovery/scenes/dapp.ts
@@ -7,6 +7,7 @@ import type { IJsBridgeMessagePayload } from '@onekeyfe/cross-inpage-provider-ty
 
 export enum EEnterMethod {
   banner = 'banner',
+  trending = 'trending',
   dashboard = 'dashboard',
   search = 'search',
   addressBar = 'addressBar',
diff --git a/yarn.lock b/yarn.lock
index ae9040523269..2cb6420b0bab 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6970,7 +6970,7 @@ __metadata:
     eslint-plugin-prettier: "npm:^4.2.1"
     eslint-plugin-props-checker: "npm:^1.1.0"
     eslint-plugin-react: "npm:^7.31.11"
-    eslint-plugin-react-hooks: "npm:^4.6.0"
+    eslint-plugin-react-hooks: "npm:4.6.2"
     eslint-plugin-spellcheck: "npm:^0.0.20"
     eslint-plugin-unicorn: "npm:^56.0.0"
     eslint-plugin-use-effect-no-deps: "npm:^1.1.2"
@@ -23607,6 +23607,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"eslint-plugin-react-hooks@npm:4.6.2":
+  version: 4.6.2
+  resolution: "eslint-plugin-react-hooks@npm:4.6.2"
+  peerDependencies:
+    eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
+  checksum: 10/5a0680941f34e70cf505bcb6082df31a3e445d193ee95a88ff3483041eb944f4cefdaf7e81b0eb1feb4eeceee8c7c6ddb8a2a6e8c4c0388514a42e16ac7b7a69
+  languageName: node
+  linkType: hard
+
 "eslint-plugin-react-hooks@npm:^4.6.0":
   version: 4.6.0
   resolution: "eslint-plugin-react-hooks@npm:4.6.0"


Reviews:
user: login: originalix
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-03-13T09:47:59Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.native.tsx (1)</summary><blockquote>

`85-88`: _🧹 Nitpick (assertive)_

**Consider creating a standalone function for thumbnail updates**

This thumbnail setting logic is tied directly to the actions API. This creates coupling that makes testing harder.


Extract this into a standalone function that takes the action and parameters:

```diff
- actionsRef.current.setWebTabData({
-   id,
-   thumbnail: path,
- });
+ updateTabThumbnail(actionsRef.current, id, path);

// Add this helper function elsewhere in the file
+ function updateTabThumbnail(actions, id, thumbnailPath) {
+   actions.setWebTabData({
+     id,
+     thumbnail: thumbnailPath,
+   });
+ }
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro (Legacy)**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 77ef8d1e3eed9601137a977b0ce01299341c59c8 and 014c4cd6f05be8ccbde2932320ddef1fd1e10c1a.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.native.tsx` (1 hunks)
* `packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.tsx` (1 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: lint (20.x)
* GitHub Check: unittest (20.x)
* GitHub Check: Analyze (javascript-typescript)

</details>

<details>
<summary>🔇 Additional comments (3)</summary><blockquote>

<details>
<summary>packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.tsx (2)</summary>

`3-5`: **Clear Unused Parameter Indication**: Renaming `props` to `_props` clearly signals that the parameter is unused. This improves readability and prevents linting warnings.

---

`7-8`: **Consistent Naming for Unused Parameters**: Changing `id` to `_id` in `useTakeScreenshot` follows the same convention, making it evident that the identifier is not used within the function.

</details>
<details>
<summary>packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.native.tsx (1)</summary>

`60-101`: <details>
<summary>✅ Verification successful</summary>

**Verify functionality of screenshot feature**

This hook relies on `actionsRef.current.setWebTabData`, but `setWebTabData` was removed from the destructuring in the component. Make sure this function still exists in the API.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if setWebTabData is still defined in the actions file
rg "setWebTabData" --type ts packages/kit/src/states/jotai/contexts/discovery/
```

Length of output: 1011

---



</details>

**Verified: The screenshot hook still relies on a valid API**  
Our check confirms that `setWebTabData` remains in the codebase (see `packages/kit/src/states/jotai/contexts/discovery/actions.ts`). The hook's dependency on `actionsRef.current.setWebTabData` is valid. No further action is needed on this part of the code.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T10:05:02Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro (Legacy)**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 014c4cd6f05be8ccbde2932320ddef1fd1e10c1a and bd15a6af76223c8239f0bcac39a99a62fcadba40.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `packages/kit/src/hooks/useReplaceTx.ts` (1 hunks)
* `packages/kit/src/states/jotai/contexts/discovery/actions.ts` (5 hunks)
* `packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts` (2 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: unittest (20.x)
* GitHub Check: lint (20.x)
* GitHub Check: Analyze (javascript-typescript)

</details>

<details>
<summary>🔇 Additional comments (8)</summary><blockquote>

<details>
<summary>packages/kit/src/states/jotai/contexts/discovery/actions.ts (3)</summary>

`233-234`: **Keep it consistent with homeTab or about:blank?**

You're using an object spread of `homeTab` but forcing `type: 'normal'`. This looks correct for a blank tab, but confirm that `homeTab`'s default values (like `'about:blank'`) won't conflict with a normal tab's requirements.

---

`757-799`: **Clarify desktop auto-switch behavior.**

Defaulting `switchToMultiTabBrowser` to false but still switching on desktop might catch users off guard. If you want a single route for desktop, that’s fine—just confirm you expect no single-tab scenario on desktop.

---

`987-1004`: **Expose addBrowserHomeTab nicely.**

Exporting `addBrowserHomeTab` improves clarity and reusability. The naming is straightforward. All good here!

</details>
<details>
<summary>packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts (4)</summary>

`3-8`: **Imports look good.**

You added essential hooks for tab actions and media queries. Straightforward and consistent with usage.

---

`14-15`: **Active tab retrieval is well-integrated.**

Using `useActiveTabId` and `useWebTabDataById` is a neat approach for pulling the correct tab info. Nice job.

---

`28-33`: **Smart approach for hooking references.**

You're pulling in `setWebTabData`, `navigation`, `activeTab`, and media breakpoints. This is well-structured and easy to follow.

---

`68-68`: **Good synergy with multi-tab triggers.**

Passing `gtMd` as `switchToMultiTabBrowser` lines up with your responsive design choice. This helps unify big-screen usage.

</details>
<details>
<summary>packages/kit/src/hooks/useReplaceTx.ts (1)</summary>

`165-171`: **Reordered dependency array is fine.**

Rearranging references in the `useCallback` doesn’t appear harmful. Keep an eye on unexpected re-renders.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T10:38:31Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro (Legacy)**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 9ba561b63a31556706b83bbf7df5ab12b85c510f and 7608eabc4c7995c40e89da39addc92abc46d76f2.

</details>

<details>
<summary>📒 Files selected for processing (5)</summary>

* `packages/kit/src/views/Discovery/pages/Dashboard/BookmarksSection.tsx` (2 hunks)
* `packages/kit/src/views/Discovery/pages/Dashboard/TrendingSection.tsx` (3 hunks)
* `packages/kit/src/views/Discovery/pages/SearchModal/index.tsx` (6 hunks)
* `packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts` (1 hunks)
* `packages/shared/src/logger/scopes/discovery/scenes/dapp.ts` (1 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: unittest (20.x)
* GitHub Check: lint (20.x)
* GitHub Check: Analyze (javascript-typescript)

</details>

<details>
<summary>🔇 Additional comments (18)</summary><blockquote>

<details>
<summary>packages/shared/src/logger/scopes/discovery/scenes/dapp.ts (1)</summary>

`10-10`: **Clean addition to the enum**

New `trending` value fits seamlessly with existing enum pattern. This enables tracking when users enter DApps from trending lists.

</details>
<details>
<summary>packages/kit/src/views/Discovery/pages/SearchModal/index.tsx (7)</summary>

`34-34`: **Good simplification with useWebSiteHandler**

The switch from `useBrowserAction` to `useWebSiteHandler` streamlines the website handling logic throughout the component.



Also applies to: 60-61

---

`165-173`: **API simplification looks good**

Removed multi-tab browser parameter and simplified the interface. The code now provides a cleaner, more consistent way to handle website navigation.

---

`175-181`: **Consistent parameter structure**

The parameter structure matches other calls to `handleWebSite` in this file, maintaining consistency in the refactored approach.

---

`186-186`: **Dependency array properly updated**

Dependencies correctly updated to reflect new function name and removed parameters. This prevents potential stale closure issues.

---

`211-219`: **Consistent implementation for address bar entry**

The same pattern used for handling website navigation from the address bar. Good consistency in the implementation.

---

`257-266`: **Bookmark handling follows the pattern**

The bookmark navigation handling follows the same clean pattern as other navigation paths in this component.

---

`330-338`: **History handling maintains consistency**

The history navigation handling matches the pattern used elsewhere in the component, completing a consistent refactoring approach.

</details>
<details>
<summary>packages/kit/src/views/Discovery/pages/Dashboard/BookmarksSection.tsx (3)</summary>

`15-15`: **Good imports for new functionality**

Added necessary imports to support the refactored website handling approach.



Also applies to: 22-22

---

`29-33`: **Clean signature simplification**

Removed the `handleOpenWebSite` prop requirement, making the component more self-contained. The hook initialization looks good.

---

`94-104`: **Good encapsulation of website handling**

Created an internal implementation that wraps the `handleWebSite` function. The callback properly sets tracking parameters and maintains the component's functionality while simplifying its interface.

</details>
<details>
<summary>packages/kit/src/views/Discovery/pages/Dashboard/TrendingSection.tsx (3)</summary>

`1-1`: **Imports updated for new functionality**

Added necessary imports to support website handling and the new trending entry method.



Also applies to: 10-11, 13-13

---

`20-33`: **Simplified function signature**

Removed external dependency on `handleOpenWebSite` prop, making the component self-contained with its own website handling logic.

---

`39-49`: **Correctly implements trending navigation**

The new `handleOpenWebSite` function properly uses the trending entry method for analytics tracking. Good use of `useCallback` to optimize performance.

</details>
<details>
<summary>packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts (4)</summary>

`18-26`: **Good clarity in interface.**

The interface captures essential parameters well. It’s easy to read and ensures type safety.

---

`50-59`: **Reuse pinned status properly.**

Replacing 'home' type with 'normal' while keeping pinned status looks good. Continue testing edge cases to ensure pinned states remain correct.

---

`64-65`: **Validate external URL usage.**

Opening external URLs is risky if they come from untrusted sources. Confirm the URL is safe or sanitized before calling `openUrlExternal`.

---

`77-82`: **Review logged details for sensitive data.**

This logs domain and title. Ensure no sensitive user info is exposed in logs.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T11:22:42Z
user: login: originalix
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-13T11:49:32Z
user: login: sidmorizon
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T13:59:12Z

Review comments:
diff_hunk: @@ -136,7 +136,6 @@ function useReplaceTx({
           onConfirm: async () => {
             // https://www.f2pool.com/user/tx-acc?from=onekey&txid={txid}
             handleOpenWebSite({
-              switchToMultiTabBrowser: gtMd,
path: packages/kit/src/hooks/useReplaceTx.ts
user: login: originalix
body: 这里不应该改变交易加速的跳转逻辑，否则在桌面端就只会跳转到发现页首页，而不是鱼池的 dapp
created_at: 2025-03-13T09:47:55Z
author_association: COLLABORATOR
diff_hunk: @@ -136,13 +136,8 @@ function MobileBrowserBottomBar({
     }, [origin]);
 
   const { displayHomePage } = useDisplayHomePageFlag();
-  const {
-    setWebTabData,
-    setPinnedTab,
-    setCurrentWebTab,
-    closeWebTab,
-    setSiteMode,
-  } = useBrowserTabActions().current;
+  const { setPinnedTab, setCurrentWebTab, closeWebTab, setSiteMode } =
+    useBrowserTabActions().current;
path: packages/kit/src/views/Discovery/components/MobileBrowser/MobileBrowserBottomBar.native.tsx
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Consider consistent access patterns for browser tab actions**

There's an inconsistency between how browser tab actions are accessed. Lines 85-88 use `actionsRef.current.setWebTabData` directly while here you're destructuring specific functions. This could lead to confusion.


Either:
1. Add `setWebTabData` back to the destructuring if it's used in this component
2. Or refactor the `useTakeScreenshot` hook to use the same access pattern

```diff
- const { setPinnedTab, setCurrentWebTab, closeWebTab, setSiteMode } =
+ const { setPinnedTab, setCurrentWebTab, closeWebTab, setSiteMode, setWebTabData } =
  useBrowserTabActions().current;
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  const { setPinnedTab, setCurrentWebTab, closeWebTab, setSiteMode, setWebTabData } =
    useBrowserTabActions().current;
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-13T10:05:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -230,7 +230,23 @@ class ContextJotaiActionsDiscovery extends ContextJotaiActionsBase {
   });
 
   addBlankWebTab = contextAtomMethod((_, set) => {
-    this.addWebTab.call(set, { ...homeTab, isActive: true });
+    this.addWebTab.call(set, { ...homeTab, isActive: true, type: 'normal' });
+  });
+
+  addBrowserHomeTab = contextAtomMethod((_, set) => {
+    this.addWebTab.call(set, {
+      id: generateUUID(),
+      url: '',
+      title: appLocale.intl.formatMessage({
+        id: ETranslations.browser_start_tab,
+      }),
+      canGoBack: false,
+      loading: false,
+      favicon: '',
+      isActive: true,
+      type: 'home',
+    });
+    this.setDisplayHomePage.call(set, true);
path: packages/kit/src/states/jotai/contexts/discovery/actions.ts
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Double-check empty string vs. `about:blank`.**

Here, you're creating a “home” tab with `url: ''`. Elsewhere, `homeTab` uses `'about:blank'`. Confirm there's no undesired discrepancy in empty URL vs. `'about:blank'`.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-13T10:38:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,49 +1,70 @@
 import { useCallback } from 'react';
 
-import { useBrowserAction } from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
+import { useMedia } from '@onekeyhq/components';
+import useAppNavigation from '@onekeyhq/kit/src/hooks/useAppNavigation';
+import {
+  useBrowserAction,
+  useBrowserTabActions,
+} from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
 import { defaultLogger } from '@onekeyhq/shared/src/logger/logger';
 import type { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
 import { openUrlExternal } from '@onekeyhq/shared/src/utils/openUrlUtils';
 import type { IDApp } from '@onekeyhq/shared/types/discovery';
 
+import { useActiveTabId, useWebTabDataById } from '../hooks/useWebTabs';
+
 import type { IBrowserBookmark, IBrowserHistory } from '../types';
 
 interface IHandleWebSiteParams {
   webSite?: IBrowserBookmark | IBrowserHistory;
   dApp?: IDApp;
   useSystemBrowser?: boolean;
-  switchToMultiTabBrowser?: boolean;
-  navigation?: any;
   shouldPopNavigation?: boolean;
   enterMethod: EEnterMethod;
 }
 
 export const useWebSiteHandler = () => {
   const { handleOpenWebSite } = useBrowserAction().current;
+  const { setWebTabData } = useBrowserTabActions().current;
+  const navigation = useAppNavigation();
+  const { activeTabId } = useActiveTabId();
+  const { tab: activeTab } = useWebTabDataById(activeTabId ?? '');
+  const { gtMd } = useMedia();
 
   return useCallback(
     async ({
       webSite,
       dApp,
       useSystemBrowser,
-      switchToMultiTabBrowser,
-      navigation,
       shouldPopNavigation = true,
       enterMethod,
     }: IHandleWebSiteParams) => {
       if (!webSite?.url) {
         return;
       }
 
-      if (useSystemBrowser) {
+      // If current active tab is of type 'home', change it to 'normal' and update its URL
+      if (activeTab?.type === 'home' && !useSystemBrowser) {
+        setWebTabData({
+          id: activeTab.id,
+          url: webSite.url,
+          title: webSite.title || dApp?.name || '',
+          type: 'normal',
+          isPinned: activeTab.isPinned,
+        });
+
+        if (shouldPopNavigation) {
+          navigation.pop();
+        }
+      } else if (useSystemBrowser) {
path: packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Overwrite ‘home’ tab seamlessly.**

Replacing 'home' tab with a 'normal' one and reusing pinned status looks logical. Keep verifying that pinned states remain correct across edge cases.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-13T10:38:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,93 @@
+import { useCallback } from 'react';
+
+import { useMedia } from '@onekeyhq/components';
+import useAppNavigation from '@onekeyhq/kit/src/hooks/useAppNavigation';
+import {
+  useBrowserAction,
+  useBrowserTabActions,
+} from '@onekeyhq/kit/src/states/jotai/contexts/discovery';
+import { defaultLogger } from '@onekeyhq/shared/src/logger/logger';
+import type { EEnterMethod } from '@onekeyhq/shared/src/logger/scopes/discovery/scenes/dapp';
+import { openUrlExternal } from '@onekeyhq/shared/src/utils/openUrlUtils';
+import type { IDApp } from '@onekeyhq/shared/types/discovery';
+
+import { useActiveTabId, useWebTabDataById } from '../hooks/useWebTabs';
+
+import type { IBrowserBookmark, IBrowserHistory } from '../types';
+
+interface IHandleWebSiteParams {
+  webSite?: IBrowserBookmark | IBrowserHistory;
+  dApp?: IDApp;
+  useSystemBrowser?: boolean;
+  shouldPopNavigation?: boolean;
+  useCurrentWindow?: boolean;
+  tabId?: string;
+  enterMethod: EEnterMethod;
+}
+
+export const useWebSiteHandler = () => {
+  const { handleOpenWebSite } = useBrowserAction().current;
+  const { setWebTabData } = useBrowserTabActions().current;
+  const navigation = useAppNavigation();
+  const { activeTabId } = useActiveTabId();
+  const { tab: activeTab } = useWebTabDataById(activeTabId ?? '');
+  const { gtMd } = useMedia();
+
+  return useCallback(
+    async ({
+      webSite,
+      dApp,
+      useSystemBrowser,
+      shouldPopNavigation,
+      enterMethod,
+      useCurrentWindow,
+      tabId,
+    }: IHandleWebSiteParams) => {
path: packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Remove async or use await.**

The function is marked “async” but has no “await” usage. Remove “async” or add “await” if needed.

```diff
-    async ({
+    ({
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    ({
      webSite,
      dApp,
      useSystemBrowser,
      shouldPopNavigation,
      enterMethod,
      useCurrentWindow,
      tabId,
    }: IHandleWebSiteParams) => {
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-13T11:22:41Z
author_association: CONTRIBUTOR

PR comments:
user: login: codesandbox[bot]
created_at: 2025-03-10T13:14:13Z
body: #### Review or Edit in CodeSandbox

Open the branch in <a href="https://codesandbox.io/p/github/OneKeyHQ/app-monorepo/OK-36161?mode=review&utm_source=gh_app">Web Editor</a> &bull; <a href="https://codesandbox.io/p/vscode?owner=OneKeyHQ&repo=app-monorepo&branch=OK-36161&utm_source=gh_app">VS Code</a> &bull; <a href="https://codesandbox.io/p/vscode?owner=OneKeyHQ&repo=app-monorepo&branch=OK-36161&insiders=true&utm_source=gh_app">Insiders</a><br>
Open <a href="https://codesandbox.io/p/devtool/preview/OneKeyHQ/app-monorepo/OK-36161?task=preview&port=51423&redirect=true&utm_source=gh_app">Preview</a>

<!-- open-in-codesandbox:complete -->

author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-03-10T13:14:19Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
The changes introduce a new ESLint rule for React hooks and update the version of the `eslint-plugin-react-hooks` dependency. Multiple files simplify website navigation logic by removing the multi-tab browser parameter and unused dependencies. Components transition from prop-based to hook-based website handling, updating their signatures accordingly. New tab management features are added, including methods for managing browser tabs. Type definitions and utility functions are refined to support new tab categorization.

## Changes

| File(s) | Change Summary |
|---------|----------------|
| `.eslintrc.js`, `package.json` | Added `'react-hooks/rules-of-hooks': 'error'` rule; updated `eslint-plugin-react-hooks` version from `^4.6.0` to `4.6.2`. |
| `packages/kit/src/hooks/useReplaceTx.ts`, `packages/kit/src/views/Discovery/hooks/useDesktopNewWindow.ts`, `packages/kit/src/views/Discovery/pages/BookmarkListModal/index.tsx`, `packages/kit/src/views/Discovery/pages/SearchModal/index.tsx` | Removed `gtMd` variable and `switchToMultiTabBrowser` parameter from function calls and dependency arrays. |
| `packages/kit/src/views/Discovery/pages/Dashboard/Banner.tsx`, `packages/kit/src/views/Discovery/pages/Dashboard/BookmarksSection.tsx`, `packages/kit/src/views/Discovery/pages/Dashboard/TrendingSection.tsx`, `packages/kit/src/views/Discovery/pages/Dashboard/Welcome/WelcomeItem.tsx`, `packages/kit/src/views/Discovery/pages/HistoryListModal/index.tsx` | Replaced prop-based `handleOpenWebSite` with hook-based `handleWebSite` and updated parameters (e.g., added `enterMethod` flags). |
| `packages/kit/src/states/jotai/contexts/discovery/actions.ts`, `packages/kit/src/views/Discovery/pages/Browser/Browser.desktop.tsx`, `packages/kit/src/views/Discovery/pages/Browser/DesktopBrowserContent.tsx`, `packages/kit/src/views/Discovery/pages/DesktopCustomTabBar/index.tsx` | Added new UI features for tab management including `addBrowserHomeTab`, conditional header rendering based on tab type, and changed button event behavior. |
| `packages/kit/src/views/Discovery/pages/Dashboard/Welcome/Welcome.tsx`, `packages/kit/src/views/Discovery/pages/Dashboard/DashboardContent.tsx`, `packages/kit/src/views/Discovery/types.ts`, `packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts` | Removed unused imports and logic; simplified component signatures; updated `IWebTab` with an optional `type` property; refined website handler interface and control flow. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
  participant U as User
  participant C as Dashboard Component
  participant H as useWebSiteHandler Hook
  participant B as Browser/Tab Manager
  participant N as Navigation System

  U->>C: Click website/bookmark item
  C->>H: Call handleWebSite({ dApp, webSite, options })
  alt Active tab is "home" and system browser is not used
    H->>B: Update active tab (set URL, title, change type to "normal")
    H->>N: Pop navigation (if shouldPopNavigation true)
  else Using system browser
    H->>B: Open URL externally
  end
  B-->>C: Return updated tab data/UI state
```

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro (Legacy)**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 7608eabc4c7995c40e89da39addc92abc46d76f2 and 5cd937c0a6f41473b6748c3d658e4b582dc65eb3.

</details>

<details>
<summary>📒 Files selected for processing (8)</summary>

* `packages/kit/src/views/Discovery/pages/BookmarkListModal/index.tsx` (4 hunks)
* `packages/kit/src/views/Discovery/pages/Dashboard/Banner.tsx` (2 hunks)
* `packages/kit/src/views/Discovery/pages/Dashboard/BookmarksSection.tsx` (2 hunks)
* `packages/kit/src/views/Discovery/pages/Dashboard/TrendingSection.tsx` (3 hunks)
* `packages/kit/src/views/Discovery/pages/Dashboard/Welcome/WelcomeItem.tsx` (3 hunks)
* `packages/kit/src/views/Discovery/pages/HistoryListModal/index.tsx` (3 hunks)
* `packages/kit/src/views/Discovery/pages/SearchModal/index.tsx` (6 hunks)
* `packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts` (1 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: unittest (20.x)
* GitHub Check: lint (20.x)
* GitHub Check: Analyze (javascript-typescript)

</details>

<details>
<summary>🔇 Additional comments (37)</summary><blockquote>

<details>
<summary>packages/kit/src/views/Discovery/pages/SearchModal/index.tsx (8)</summary>

`34-34`: **Good addition of the useWebSiteHandler hook.**

This import supports the refactoring from prop-based to hook-based website navigation.

---

`60-60`: **Clean implementation of useWebSiteHandler.**

The hook replaces the previous handleOpenWebSite function, centralizing website navigation logic.

---

`165-173`: **Improved website handling implementation.**

The code now uses a more structured approach with explicit parameters for website navigation.

---

`175-180`: **Consistent API usage for dApp handling.**

Follows the same pattern as other website navigation code, improving consistency.

---

`186-186`: **Correctly updated dependency array.**

The dependencies now properly match the functions used in the callback.

---

`211-219`: **Streamlined website navigation.**

Uses the same structured approach for address bar navigation, maintaining consistency.

---

`257-265`: **Consistent bookmark navigation handling.**

Maintains the same pattern for bookmark navigation as other entry points.

---

`330-338`: **Consistent history item navigation.**

Uses the same pattern for history items, creating a uniform approach across the app.

</details>
<details>
<summary>packages/kit/src/views/Discovery/pages/Dashboard/Banner.tsx (3)</summary>

`4-4`: **Good addition of necessary imports.**

Added imports for EEnterMethod and useWebSiteHandler support the new implementation.



Also applies to: 8-8

---

`20-20`: **Clean hook implementation.**

Replaces prop-based website handling with hook-based approach, improving modularity.

---

`62-70`: **Enhanced website navigation with additional params.**

Added shouldPopNavigation and enterMethod parameters improve tracking and navigation behavior.

</details>
<details>
<summary>packages/kit/src/views/Discovery/pages/BookmarkListModal/index.tsx (4)</summary>

`19-19`: **Good update to imports.**

Imports now align with the new hook-based implementation strategy.



Also applies to: 28-28

---

`38-38`: **Clean implementation of useWebSiteHandler.**

Replaces useBrowserAction's handleOpenWebSite with the centralized hook implementation.

---

`142-153`: **Well-structured handleItemPress function.**

Creates a clean callback that encapsulates the website navigation logic with proper parameter structure.

---

`211-211`: **Updated ListItem to use new handler.**

Correctly uses the new handleItemPress function for consistent behavior.

</details>
<details>
<summary>packages/kit/src/views/Discovery/pages/Dashboard/BookmarksSection.tsx (3)</summary>

`15-15`: **Good addition of necessary imports.**

Added imports for EEnterMethod and useWebSiteHandler support the new implementation.



Also applies to: 22-22

---

`29-29`: **Clean component signature update.**

Removed external dependency on handleOpenWebSite prop and switched to internal hook usage.



Also applies to: 32-32

---

`94-104`: **Well-structured handleOpenWebSite implementation.**

Created an internal function that uses the new hook, maintaining backward compatibility while adopting the new pattern.

</details>
<details>
<summary>packages/kit/src/views/Discovery/pages/HistoryListModal/index.tsx (4)</summary>

`21-21`: **Looks fine.**
Imports appear valid. No issues spotted.

---

`27-27`: **Imports looks good.**
The `useWebSiteHandler` is used consistently with the new pattern.

---

`56-56`: **Implementation is clear.**
`handleWebSite` set here makes the code more readable and consistent across the app.

---

`181-189`: **Logic is cohesive.**
Your call to `handleWebSite` with `shouldPopNavigation` and `enterMethod` maintains a neat flow. No functional issues noticed.

</details>
<details>
<summary>packages/kit/src/views/Discovery/pages/Dashboard/TrendingSection.tsx (6)</summary>

`1-1`: **Import usage is straightforward.**
No concerns. Good move using `useCallback`, `useMemo`.

---

`10-10`: **Enum import is fine.**
No red flags here.

---

`13-13`: **New hook usage is consistent.**
Brings uniform handling of site navigation.

---

`20-20`: **Refactored function signature.**
Clear name simplification. Good approach.

---

`33-33`: **Handler assignment is fine.**
No major concerns on hooking logic.

---

`39-49`: **Function logic is clear.**
You're merging `handleOpenWebSite` with the new `handleWebSite` approach elegantly. No flaws found.

</details>
<details>
<summary>packages/kit/src/views/Discovery/pages/Dashboard/Welcome/WelcomeItem.tsx (3)</summary>

`13-15`: **Imports updated correctly.**
Switching to `useWebSiteHandler` aligns with the new design. No concerns.

---

`107-107`: **Well placed hook call.**
Keeps the logic simple.

---

`216-224`: **Implementation looks correct.**
`handleWebSite` usage is consistent, with `enterMethod` set to `dashboard`. Good detail.

</details>
<details>
<summary>packages/kit/src/views/Discovery/utils/useWebSiteHandler.ts (6)</summary>

`1-11`: **Module imports look suitable.**
Dependencies are well structured. No immediate issues.

---

`14-17`: **Proper synergy with tab data hooks.**
This helps unify tab logic. Fine as is.

---

`18-26`: **Interface is clear.**
Defines all parameters well. Easy to extend if needed.

---

`28-35`: **Function scaffolding is straightforward.**
Neat layout with no glaring problems.

---

`36-75`: **Nicely organized logic.**
You handle active 'home' tabs, system browser calls, or a normal scenario. Clean approach. Looks stable.

---

`77-82`: **Log statement is precise.**
Entering DApp logging is done correctly.

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=OneKeyHQ/app-monorepo&utm_content=6849):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` or `Summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: limichange
created_at: 2025-03-10T13:14:26Z
body: @rabbitcode pause
author_association: CONTRIBUTOR
user: login: limichange
created_at: 2025-03-13T09:38:56Z
body: @rabbitcode resume
author_association: CONTRIBUTOR