diff --git a/packages/frontend/core/src/desktop/pages/workspace/journals/index.css.ts b/packages/frontend/core/src/desktop/pages/workspace/journals/index.css.ts index 615c981ad5..91cd112c39 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/journals/index.css.ts +++ b/packages/frontend/core/src/desktop/pages/workspace/journals/index.css.ts @@ -20,12 +20,22 @@ export const body = style({ width: '100%', height: '100%', borderTop: `0.5px solid ${cssVarV2.layer.insideBorder.border}`, + selectors: { + '&[data-mobile]': { + borderTop: 'none', + }, + }, }); export const content = style({ maxWidth: 944, padding: '0px 50px', margin: '0 auto', + selectors: { + '[data-mobile] &': { + padding: '0 24px', + }, + }, }); export const docTitleContainer = style({ diff --git a/packages/frontend/core/src/desktop/pages/workspace/journals/index.tsx b/packages/frontend/core/src/desktop/pages/workspace/journals/index.tsx index 46ca14bcb2..c57ba39d5e 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/journals/index.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/journals/index.tsx @@ -33,7 +33,7 @@ import { import { AllDocSidebarTabs } from '../layouts/all-doc-sidebar-tabs'; import * as styles from './index.css'; -function getDateFromUrl(location: Location) { +export function getDateFromUrl(location: Location) { const searchParams = new URLSearchParams(location.search); const date = searchParams.get('date') ? dayjs(searchParams.get('date')) @@ -41,6 +41,49 @@ function getDateFromUrl(location: Location) { return date.format(JOURNAL_DATE_FORMAT); } +export const JournalPlaceholder = ({ dateString }: { dateString: string }) => { + const t = useI18n(); + const [redirecting, setRedirecting] = useState(false); + const workbench = useService(WorkbenchService).workbench; + const journalService = useService(JournalService); + + const createJournal = useCallback(() => { + if (redirecting) return; + setRedirecting(true); + const doc = journalService.ensureJournalByDate(dateString); + workbench.openDoc(doc.id, { + replaceHistory: true, + at: 'active', + }); + }, [dateString, journalService, redirecting, workbench]); + + return ( +
+
+ +
+
+ +
+
+ {t['com.affine.journal.placeholder.title']()} +
+ +
+
+
+ ); +}; + const weekStyle = { maxWidth: 800, width: '100%' }; // this route page acts as a redirector to today's journal export const JournalsPageWithConfirmation = () => { @@ -55,19 +98,8 @@ export const JournalsPageWithConfirmation = () => { const todayString = dayjs().format(JOURNAL_DATE_FORMAT); const isToday = dateString === todayString; - const [redirecting, setRedirecting] = useState(false); const [ready, setReady] = useState(false); - const createJournal = useCallback(() => { - if (redirecting) return; - setRedirecting(true); - const doc = journalService.ensureJournalByDate(dateString); - workbench.openDoc(doc.id, { - replaceHistory: true, - at: 'active', - }); - }, [dateString, journalService, redirecting, workbench]); - const openJournal = useCallback( (date: string) => { workbench.open(`/journals?date=${date}`, { at: 'active' }); @@ -118,29 +150,7 @@ export const JournalsPageWithConfirmation = () => { -
-
- -
-
- -
-
- {t['com.affine.journal.placeholder.title']()} -
- -
-
-
+
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 5e65fe4f32..5abeb3a044 100644 --- a/packages/frontend/core/src/mobile/components/app-tabs/journal.tsx +++ b/packages/frontend/core/src/mobile/components/app-tabs/journal.tsx @@ -1,4 +1,5 @@ import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta'; +import { FeatureFlagService } from '@affine/core/modules/feature-flag'; import { JournalService } from '@affine/core/modules/journal'; import { WorkbenchService } from '@affine/core/modules/workbench'; import { TodayIcon } from '@blocksuite/icons/rc'; @@ -13,15 +14,23 @@ export const AppTabJournal = ({ tab }: AppTabCustomFCProps) => { const location = useLiveData(workbench.location$); const journalService = useService(JournalService); const docDisplayMetaService = useService(DocDisplayMetaService); + const featureFlagService = useService(FeatureFlagService); + const isTwoStepJournalConfirmationEnabled = useLiveData( + featureFlagService.flags.enable_two_step_journal_confirmation.$ + ); const maybeDocId = location.pathname.split('/')[1]; const journalDate = useLiveData(journalService.journalDate$(maybeDocId)); const JournalIcon = useLiveData(docDisplayMetaService.icon$(maybeDocId)); const handleOpenToday = useCallback(() => { - const docId = journalService.ensureJournalByDate(new Date()).id; - workbench.openDoc({ docId, fromTab: 'true' }, { at: 'active' }); - }, [journalService, workbench]); + if (isTwoStepJournalConfirmationEnabled) { + workbench.open('/journals', { at: 'active' }); + } else { + const docId = journalService.ensureJournalByDate(new Date()).id; + workbench.openDoc({ docId, fromTab: 'true' }, { at: 'active' }); + } + }, [workbench, journalService, isTwoStepJournalConfirmationEnabled]); const Icon = journalDate ? JournalIcon : TodayIcon; 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 46f1449d85..8990f06570 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 @@ -242,6 +242,10 @@ const MobileDetailPage = ({ const workbench = useService(WorkbenchService).workbench; const [showTitle, setShowTitle] = useState(checkShowTitle); const title = useLiveData(docDisplayMetaService.title$(pageId)); + const featureFlagService = useService(FeatureFlagService); + const isTwoStepJournalConfirmationEnabled = useLiveData( + featureFlagService.flags.enable_two_step_journal_confirmation.$ + ); const canAccess = useGuard('Doc_Read', pageId); @@ -252,13 +256,25 @@ const MobileDetailPage = ({ const handleDateChange = useCallback( (date: string) => { - const docId = journalService.ensureJournalByDate(date).id; - workbench.openDoc( - { docId, fromTab: fromTab ? 'true' : undefined }, - { replaceHistory: true } - ); + if (isTwoStepJournalConfirmationEnabled) { + const docs = journalService.journalsByDate$(date).value; + if (docs.length > 0) { + workbench.openDoc( + { docId: docs[0].id, fromTab: fromTab ? 'true' : undefined }, + { replaceHistory: true } + ); + } else { + workbench.open(`/journals?date=${date}`); + } + } else { + const docId = journalService.ensureJournalByDate(date).id; + workbench.openDoc( + { docId, fromTab: fromTab ? 'true' : undefined }, + { replaceHistory: true } + ); + } }, - [fromTab, journalService, workbench] + [fromTab, isTwoStepJournalConfirmationEnabled, journalService, workbench] ); useGlobalEvent( diff --git a/packages/frontend/core/src/mobile/pages/workspace/journals.css.ts b/packages/frontend/core/src/mobile/pages/workspace/journals.css.ts new file mode 100644 index 0000000000..8655989402 --- /dev/null +++ b/packages/frontend/core/src/mobile/pages/workspace/journals.css.ts @@ -0,0 +1,26 @@ +import { cssVarV2 } from '@toeverything/theme/v2'; +import { style } from '@vanilla-extract/css'; + +export const container = style({ + display: 'flex', + flexDirection: 'column', + height: '100dvh', + overflow: 'hidden', + backgroundColor: cssVarV2('layer/background/primary'), +}); + +export const header = style({ + backgroundColor: cssVarV2('layer/background/primary'), +}); + +export const headerTitle = style({ + color: cssVarV2('text/primary'), + fontSize: 17, + lineHeight: '22px', + fontWeight: 600, + letterSpacing: -0.43, +}); + +export const journalDatePicker = style({ + backgroundColor: cssVarV2('layer/background/primary'), +}); diff --git a/packages/frontend/core/src/mobile/pages/workspace/journals.tsx b/packages/frontend/core/src/mobile/pages/workspace/journals.tsx new file mode 100644 index 0000000000..840134bd76 --- /dev/null +++ b/packages/frontend/core/src/mobile/pages/workspace/journals.tsx @@ -0,0 +1,107 @@ +import { + getDateFromUrl, + JournalPlaceholder, +} from '@affine/core/desktop/pages/workspace/journals'; +import { FeatureFlagService } from '@affine/core/modules/feature-flag'; +import { + JOURNAL_DATE_FORMAT, + JournalService, +} from '@affine/core/modules/journal'; +import { ViewService, WorkbenchService } from '@affine/core/modules/workbench'; +import { i18nTime } from '@affine/i18n'; +import { useLiveData, useService } from '@toeverything/infra'; +import { cssVarV2 } from '@toeverything/theme/v2'; +import dayjs from 'dayjs'; +import { useCallback, useEffect, useLayoutEffect, useState } from 'react'; + +import { AppTabs, PageHeader } from '../../components'; +import { JournalDatePicker } from './detail/journal-date-picker'; +import * as styles from './journals.css'; + +export const JournalsPageWithConfirmation = () => { + const journalService = useService(JournalService); + const workbench = useService(WorkbenchService).workbench; + const view = useService(ViewService).view; + const location = useLiveData(view.location$); + const dateString = getDateFromUrl(location); + const [ready, setReady] = useState(false); + const allJournalDates = useLiveData(journalService.allJournalDates$); + + const handleDateChange = useCallback( + (date: string) => { + workbench.open(`/journals?date=${date}`, { at: 'active' }); + }, + [workbench] + ); + + useLayoutEffect(() => { + // only handle current route + if (!location.pathname.startsWith('/journals')) return; + + // check if the journal is created + const docs = journalService.journalsByDate$(dateString).value; + if (docs.length === 0) { + setReady(true); + return; + } + + // if created, redirect to the journal + const journal = docs[0]; + workbench.openDoc(journal.id, { replaceHistory: true, at: 'active' }); + }, [dateString, journalService, location.pathname, view, workbench]); + + if (!ready) return null; + + return ( + <> +
+ + } + contentClassName={styles.headerTitle} + bottomSpacer={94} + > + {i18nTime(dayjs(dateString), { absolute: { accuracy: 'month' } })} + + +
+ + + ); +}; + +export const JournalsPageWithoutConfirmation = () => { + const journalService = useService(JournalService); + const workbench = useService(WorkbenchService).workbench; + + useEffect(() => { + const today = dayjs().format(JOURNAL_DATE_FORMAT); + const doc = journalService.ensureJournalByDate(today); + workbench.openDoc(doc.id, { + replaceHistory: true, + at: 'active', + }); + }, [journalService, workbench]); + + return null; +}; + +export const Component = () => { + const featureFlagService = useService(FeatureFlagService); + const isTwoStepJournalConfirmationEnabled = useLiveData( + featureFlagService.flags.enable_two_step_journal_confirmation.$ + ); + + if (isTwoStepJournalConfirmationEnabled) { + return ; + } + + return ; +}; diff --git a/packages/frontend/core/src/mobile/workbench-router.ts b/packages/frontend/core/src/mobile/workbench-router.ts index 03de0f009c..accee5c1ce 100644 --- a/packages/frontend/core/src/mobile/workbench-router.ts +++ b/packages/frontend/core/src/mobile/workbench-router.ts @@ -4,6 +4,7 @@ import { Component as All } from './pages/workspace/all'; import { Component as Collection } from './pages/workspace/collection'; import { Component as CollectionDetail } from './pages/workspace/collection/detail'; import { Component as Home } from './pages/workspace/home'; +import { Component as Journals } from './pages/workspace/journals'; import { Component as Search } from './pages/workspace/search'; import { Component as Tag } from './pages/workspace/tag'; import { Component as TagDetail } from './pages/workspace/tag/detail'; @@ -41,6 +42,11 @@ export const workbenchRoutes = [ // lazy: () => import('./pages/workspace/tag/detail'), Component: TagDetail, }, + { + path: '/journals', + // lazy: () => import('./pages/workspace/journals'), + Component: Journals, + }, { path: '/trash', lazy: () => import('./pages/workspace/trash'),