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 de1df39f2..dcc37b61c 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 000000000..a85ad2e20
--- /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 b8663cbe5..088294aa6 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 cab6c9a00..17f888f58 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 ? (
+
+ ) : (
+
+ );
+};