From 8fe188e773ed2c8c0c7ed47d2ff87487c11060d3 Mon Sep 17 00:00:00 2001 From: CatsJuice Date: Mon, 9 Dec 2024 04:07:05 +0000 Subject: [PATCH] refactor(mobile): determine the currently active tab through a persistent state (#9018) close AF-1868 Only tap on specific tab can change active tab --- .../src/mobile/components/app-tabs/create.tsx | 52 ++++--------- .../src/mobile/components/app-tabs/data.tsx | 46 +++++++++++ .../src/mobile/components/app-tabs/index.tsx | 77 ++++--------------- .../mobile/components/app-tabs/journal.tsx | 15 ++-- .../mobile/components/app-tabs/tab-item.tsx | 44 +++++++++++ 5 files changed, 123 insertions(+), 111 deletions(-) create mode 100644 packages/frontend/core/src/mobile/components/app-tabs/data.tsx create mode 100644 packages/frontend/core/src/mobile/components/app-tabs/tab-item.tsx diff --git a/packages/frontend/core/src/mobile/components/app-tabs/create.tsx b/packages/frontend/core/src/mobile/components/app-tabs/create.tsx index 6575413637..900bfacdde 100644 --- a/packages/frontend/core/src/mobile/components/app-tabs/create.tsx +++ b/packages/frontend/core/src/mobile/components/app-tabs/create.tsx @@ -1,51 +1,29 @@ import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-page-list/utils'; -import { JournalService } from '@affine/core/modules/journal'; -import { WorkbenchService } from '@affine/core/modules/workbench'; import track from '@affine/track'; import { EditIcon } from '@blocksuite/icons/rc'; -import { - DocsService, - useLiveData, - useServices, - WorkspaceService, -} from '@toeverything/infra'; +import { useService, WorkspaceService } from '@toeverything/infra'; import { useCallback } from 'react'; -import { tabItem } from './styles.css'; +import type { AppTabCustomFCProps } from './data'; +import { TabItem } from './tab-item'; -export const AppTabCreate = () => { - const { docsService, workbenchService, workspaceService, journalService } = - useServices({ - DocsService, - WorkbenchService, - WorkspaceService, - JournalService, - }); - const workbench = workbenchService.workbench; +export const AppTabCreate = ({ tab }: AppTabCustomFCProps) => { + const workspaceService = useService(WorkspaceService); const currentWorkspace = workspaceService.workspace; - const location = useLiveData(workbench.location$); const pageHelper = usePageHelper(currentWorkspace.docCollection); - const maybeDocId = location.pathname.split('/')[1].split('?')[0]; - const doc = useLiveData(docsService.list.doc$(maybeDocId)); - const journalDate = useLiveData(journalService.journalDate$(maybeDocId)); - const isActive = !!doc && !journalDate; - - const createPage = useCallback(() => { - if (isActive) return; - pageHelper.createPage(undefined, true); - track.$.navigationPanel.$.createDoc(); - }, [isActive, pageHelper]); + const createPage = useCallback( + (isActive: boolean) => { + if (isActive) return; + pageHelper.createPage(undefined, true); + track.$.navigationPanel.$.createDoc(); + }, + [pageHelper] + ); return ( -
+ -
+ ); }; diff --git a/packages/frontend/core/src/mobile/components/app-tabs/data.tsx b/packages/frontend/core/src/mobile/components/app-tabs/data.tsx new file mode 100644 index 0000000000..9260228c62 --- /dev/null +++ b/packages/frontend/core/src/mobile/components/app-tabs/data.tsx @@ -0,0 +1,46 @@ +import { AllDocsIcon, MobileHomeIcon } from '@blocksuite/icons/rc'; +import type { Framework } from '@toeverything/infra'; + +import { AppTabCreate } from './create'; +import { AppTabJournal } from './journal'; + +interface AppTabBase { + key: string; + onClick?: (framework: Framework, isActive: boolean) => void; +} +export interface AppTabLink extends AppTabBase { + Icon: React.FC; + to: string; + LinkComponent?: React.FC; +} + +export interface AppTabCustom extends AppTabBase { + custom: (props: AppTabCustomFCProps) => React.ReactNode; +} + +export type Tab = AppTabLink | AppTabCustom; + +export interface AppTabCustomFCProps { + tab: Tab; +} + +export const tabs: Tab[] = [ + { + key: 'home', + to: '/home', + Icon: MobileHomeIcon, + }, + { + key: 'all', + to: '/all', + Icon: AllDocsIcon, + }, + { + key: 'journal', + custom: AppTabJournal, + }, + { + key: 'new', + custom: AppTabCreate, + }, +]; diff --git a/packages/frontend/core/src/mobile/components/app-tabs/index.tsx b/packages/frontend/core/src/mobile/components/app-tabs/index.tsx index 55e54dd69b..1a5de84202 100644 --- a/packages/frontend/core/src/mobile/components/app-tabs/index.tsx +++ b/packages/frontend/core/src/mobile/components/app-tabs/index.tsx @@ -1,59 +1,14 @@ import { SafeArea } from '@affine/component'; -import { - WorkbenchLink, - WorkbenchService, -} from '@affine/core/modules/workbench'; -import { AllDocsIcon, MobileHomeIcon } from '@blocksuite/icons/rc'; +import { WorkbenchLink } from '@affine/core/modules/workbench'; import { useLiveData, useService } from '@toeverything/infra'; import { assignInlineVars } from '@vanilla-extract/dynamic'; import React from 'react'; import { createPortal } from 'react-dom'; -import type { Location } from 'react-router-dom'; import { VirtualKeyboardService } from '../../modules/virtual-keyboard/services/virtual-keyboard'; -import { AppTabCreate } from './create'; -import { AppTabJournal } from './journal'; +import { type AppTabLink, tabs } from './data'; import * as styles from './styles.css'; - -interface AppTabBaseProps { - key: string; -} -interface AppTabLinkProps extends AppTabBaseProps { - Icon: React.FC; - to: string; - LinkComponent?: React.FC; - isActive?: (location: Location) => boolean; -} -interface AppTabCustomProps extends AppTabBaseProps { - node: React.ReactNode; -} - -type Route = AppTabLinkProps | AppTabCustomProps; - -const routes: Route[] = [ - { - key: 'home', - to: '/home', - Icon: MobileHomeIcon, - }, - { - key: 'all', - to: '/all', - Icon: AllDocsIcon, - isActive: location => - location.pathname === '/all' || - location.pathname.startsWith('/collection') || - location.pathname.startsWith('/tag'), - }, - { - key: 'journal', - node: , - }, - { - key: 'new', - node: , - }, -]; +import { TabItem } from './tab-item'; export const AppTabs = ({ background }: { background?: string }) => { const virtualKeyboardService = useService(VirtualKeyboardService); @@ -72,12 +27,14 @@ export const AppTabs = ({ background }: { background?: string }) => { }} >
    - {routes.map(route => { - if ('to' in route) { - return ; + {tabs.map(tab => { + if ('to' in tab) { + return ; } else { return ( - {route.node} + + {} + ); } })} @@ -87,27 +44,19 @@ export const AppTabs = ({ background }: { background?: string }) => { ); }; -const AppTabLink = ({ route }: { route: AppTabLinkProps }) => { - const workbench = useService(WorkbenchService).workbench; - const location = useLiveData(workbench.location$); +const AppTabLink = ({ route }: { route: AppTabLink }) => { const Link = route.LinkComponent || WorkbenchLink; - const isActive = route.isActive - ? route.isActive(location) - : location.pathname === route.to; return ( -
  • + -
  • + ); }; diff --git a/packages/frontend/core/src/mobile/components/app-tabs/journal.tsx b/packages/frontend/core/src/mobile/components/app-tabs/journal.tsx index a85ad2e208..53b731b246 100644 --- a/packages/frontend/core/src/mobile/components/app-tabs/journal.tsx +++ b/packages/frontend/core/src/mobile/components/app-tabs/journal.tsx @@ -6,9 +6,10 @@ import { TodayIcon } from '@blocksuite/icons/rc'; import { useLiveData, useService } from '@toeverything/infra'; import { useCallback } from 'react'; -import { tabItem } from './styles.css'; +import type { AppTabCustomFCProps } from './data'; +import { TabItem } from './tab-item'; -export const AppTabJournal = () => { +export const AppTabJournal = ({ tab }: AppTabCustomFCProps) => { const workbench = useService(WorkbenchService).workbench; const location = useLiveData(workbench.location$); const journalService = useService(JournalService); @@ -26,14 +27,8 @@ export const AppTabJournal = () => { const Icon = journalDate ? JournalIcon : TodayIcon; return ( -
    + -
    + ); }; diff --git a/packages/frontend/core/src/mobile/components/app-tabs/tab-item.tsx b/packages/frontend/core/src/mobile/components/app-tabs/tab-item.tsx new file mode 100644 index 0000000000..f5194ddd2a --- /dev/null +++ b/packages/frontend/core/src/mobile/components/app-tabs/tab-item.tsx @@ -0,0 +1,44 @@ +import { + GlobalCacheService, + LiveData, + useLiveData, + useService, +} from '@toeverything/infra'; +import { type PropsWithChildren, useCallback, useMemo } from 'react'; + +import { tabItem } from './styles.css'; + +export interface TabItemProps extends PropsWithChildren { + id: string; + label: string; + onClick?: (isActive: boolean) => void; +} + +const cacheKey = 'activeAppTabId'; +export const TabItem = ({ id, label, children, onClick }: TabItemProps) => { + const globalCache = useService(GlobalCacheService).globalCache; + const activeTabId$ = useMemo( + () => LiveData.from(globalCache.watch(cacheKey), 'home'), + [globalCache] + ); + const activeTabId = useLiveData(activeTabId$) ?? 'home'; + + const isActive = id === activeTabId; + + const handleClick = useCallback(() => { + globalCache.set(cacheKey, id); + onClick?.(isActive); + }, [globalCache, id, isActive, onClick]); + + return ( +
  • + {children} +
  • + ); +};