From 7bdad2dc4b0981fad6b833c6f870f6158e96461a Mon Sep 17 00:00:00 2001 From: CatsJuice Date: Mon, 11 Nov 2024 04:26:02 +0000 Subject: [PATCH] feat(mobile): new journal tab, show App tab for journal page (#8738) close AF-1648 --- .../src/mobile/components/app-tabs/index.tsx | 88 +++++++++++++------ .../mobile/components/app-tabs/journal.tsx | 39 ++++++++ .../mobile/components/app-tabs/styles.css.ts | 9 +- .../workspace/detail/mobile-detail-page.tsx | 71 ++++++++++++--- 4 files changed, 168 insertions(+), 39 deletions(-) create mode 100644 packages/frontend/core/src/mobile/components/app-tabs/journal.tsx 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 de1df39f23f30..dcc37b61cd120 100644 --- a/packages/frontend/core/src/mobile/components/app-tabs/index.tsx +++ b/packages/frontend/core/src/mobile/components/app-tabs/index.tsx @@ -5,23 +5,36 @@ import { } from '@affine/core/modules/workbench'; import { AllDocsIcon, MobileHomeIcon, SearchIcon } from '@blocksuite/icons/rc'; import { useLiveData, useService } from '@toeverything/infra'; +import { assignInlineVars } from '@vanilla-extract/dynamic'; +import React from 'react'; import type { Location } from 'react-router-dom'; +import { AppTabJournal } from './journal'; import * as styles from './styles.css'; -interface Route { - to: string; +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 => @@ -30,41 +43,62 @@ const routes: Route[] = [ location.pathname.startsWith('/tag'), }, { + key: 'journal', + node: , + }, + { + key: 'search', to: '/search', Icon: SearchIcon, }, ]; -export const AppTabs = () => { - const workbench = useService(WorkbenchService).workbench; - const location = useLiveData(workbench.location$); - +export const AppTabs = ({ background }: { background?: string }) => { return ( - +
    {routes.map(route => { - const Link = route.LinkComponent || WorkbenchLink; - - const isActive = route.isActive - ? route.isActive(location) - : location.pathname === route.to; - return ( - -
  • - -
  • - - ); + if ('to' in route) { + return ; + } else { + return ( + {route.node} + ); + } })}
); }; + +const AppTabLink = ({ route }: { route: AppTabLinkProps }) => { + const workbench = useService(WorkbenchService).workbench; + const location = useLiveData(workbench.location$); + 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 new file mode 100644 index 0000000000000..a85ad2e208fb0 --- /dev/null +++ b/packages/frontend/core/src/mobile/components/app-tabs/journal.tsx @@ -0,0 +1,39 @@ +import { useJournalRouteHelper } from '@affine/core/components/hooks/use-journal'; +import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta'; +import { JournalService } from '@affine/core/modules/journal'; +import { WorkbenchService } from '@affine/core/modules/workbench'; +import { TodayIcon } from '@blocksuite/icons/rc'; +import { useLiveData, useService } from '@toeverything/infra'; +import { useCallback } from 'react'; + +import { tabItem } from './styles.css'; + +export const AppTabJournal = () => { + const workbench = useService(WorkbenchService).workbench; + const location = useLiveData(workbench.location$); + const journalService = useService(JournalService); + const docDisplayMetaService = useService(DocDisplayMetaService); + + const maybeDocId = location.pathname.split('/')[1]; + const journalDate = useLiveData(journalService.journalDate$(maybeDocId)); + const JournalIcon = useLiveData( + docDisplayMetaService.icon$(maybeDocId, { compareDate: new Date() }) + ); + + const { openToday } = useJournalRouteHelper(); + const handleOpenToday = useCallback(() => openToday(false), [openToday]); + + const Icon = journalDate ? JournalIcon : TodayIcon; + + return ( +
    + +
    + ); +}; diff --git a/packages/frontend/core/src/mobile/components/app-tabs/styles.css.ts b/packages/frontend/core/src/mobile/components/app-tabs/styles.css.ts index b8663cbe579e1..088294aa68c97 100644 --- a/packages/frontend/core/src/mobile/components/app-tabs/styles.css.ts +++ b/packages/frontend/core/src/mobile/components/app-tabs/styles.css.ts @@ -1,10 +1,15 @@ import { cssVarV2 } from '@toeverything/theme/v2'; -import { style } from '@vanilla-extract/css'; +import { createVar, style } from '@vanilla-extract/css'; import { globalVars } from '../../styles/mobile.css'; +export const appTabsBackground = createVar('appTabsBackground'); + export const appTabs = style({ - backgroundColor: cssVarV2('layer/background/secondary'), + vars: { + [appTabsBackground]: cssVarV2('layer/background/secondary'), + }, + backgroundColor: appTabsBackground, borderTop: `1px solid ${cssVarV2('layer/insideBorder/border')}`, width: '100dvw', diff --git a/packages/frontend/core/src/mobile/pages/workspace/detail/mobile-detail-page.tsx b/packages/frontend/core/src/mobile/pages/workspace/detail/mobile-detail-page.tsx index cab6c9a00d8ec..17f888f580d1f 100644 --- a/packages/frontend/core/src/mobile/pages/workspace/detail/mobile-detail-page.tsx +++ b/packages/frontend/core/src/mobile/pages/workspace/detail/mobile-detail-page.tsx @@ -9,8 +9,10 @@ import { useNavigateHelper } from '@affine/core/components/hooks/use-navigate-he import { PageDetailEditor } from '@affine/core/components/page-detail-editor'; import { DetailPageWrapper } from '@affine/core/desktop/pages/workspace/detail-page/detail-page-wrapper'; import { EditorService } from '@affine/core/modules/editor'; +import { JournalService } from '@affine/core/modules/journal'; import { WorkbenchService } from '@affine/core/modules/workbench'; import { ViewService } from '@affine/core/modules/workbench/services/view'; +import { i18nTime } from '@affine/i18n'; import { BookmarkBlockService, customImageProxyMiddleware, @@ -28,14 +30,18 @@ import { FrameworkScope, GlobalContextService, useLiveData, + useService, useServices, WorkspaceService, } from '@toeverything/infra'; +import { bodyEmphasized } from '@toeverything/theme/typography'; +import { cssVarV2 } from '@toeverything/theme/v2'; import clsx from 'clsx'; +import dayjs from 'dayjs'; import { useCallback, useEffect, useRef } from 'react'; import { useParams } from 'react-router-dom'; -import { PageHeader } from '../../../components'; +import { AppTabs, PageHeader } from '../../../components'; import { JournalIconButton } from './journal-icon-button'; import * as styles from './mobile-detail-page.css'; import { PageHeaderMenuButton } from './page-header-more-button'; @@ -214,15 +220,42 @@ const notFound = ( ); -export const Component = () => { - useThemeColorV2('layer/background/primary'); - const params = useParams(); - const pageId = params.pageId; - - if (!pageId) { - return null; - } - +const JournalDetailPage = ({ + pageId, + date, +}: { + pageId: string; + date: string; +}) => { + return ( +
    + + + + + + } + > + + {i18nTime(dayjs(date), { absolute: { accuracy: 'month' } })} + + + {/* TODO(@CatsJuice): */} + + + +
    + ); +}; +const NormalDetailPage = ({ pageId }: { pageId: string }) => { return (
    {
    ); }; + +export const Component = () => { + useThemeColorV2('layer/background/primary'); + const journalService = useService(JournalService); + const params = useParams(); + const pageId = params.pageId; + const journalDate = useLiveData(journalService.journalDate$(pageId ?? '')); + + if (!pageId) { + return null; + } + + return journalDate ? ( + + ) : ( + + ); +};