feat(mobile): add journal conflict block to the top of detail page (#9042)

This commit is contained in:
CatsJuice
2024-12-06 06:57:46 +00:00
parent e83617a556
commit dd94fb3450
5 changed files with 157 additions and 2 deletions

View File

@@ -0,0 +1,74 @@
import {
bodyRegular,
subHeadlineEmphasized,
} from '@toeverything/theme/typography';
import { cssVarV2 } from '@toeverything/theme/v2';
import { style } from '@vanilla-extract/css';
export const body = style({
paddingTop: 8,
});
export const header = style([
subHeadlineEmphasized,
{
height: 42,
padding: '11px 20px',
display: 'flex',
alignItems: 'center',
color: cssVarV2.button.error,
},
]);
export const separator = style({
width: '100%',
height: 16,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
':before': {
content: '',
width: '100%',
height: 0,
borderTop: '0.5px solid ' + cssVarV2.layer.insideBorder.border,
},
});
export const docItem = style({
padding: '11px 20px',
height: 44,
display: 'flex',
gap: 8,
alignItems: 'center',
});
export const icon = style({
fontSize: 20,
color: cssVarV2.icon.primary,
});
export const content = style({
width: 0,
flex: 1,
display: 'flex',
alignItems: 'center',
gap: 8,
});
export const title = style([
bodyRegular,
{
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
},
]);
export const duplicatedTag = style({
fontSize: 12,
lineHeight: '20px',
height: 20,
padding: '0 8px',
borderRadius: 4,
color: cssVarV2.toast.iconState.error,
backgroundColor: cssVarV2.layer.background.error,
border: `1px solid ${cssVarV2.database.border}`,
});
export const edit = style({
fontSize: 20,
color: cssVarV2.icon.primary,
});

View File

@@ -0,0 +1,74 @@
import { IconButton, Menu } from '@affine/component';
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
import { JournalService } from '@affine/core/modules/journal';
import { useI18n } from '@affine/i18n';
import { EditIcon, TodayIcon } from '@blocksuite/icons/rc';
import type { DocRecord } from '@toeverything/infra';
import { DocsService, useLiveData, useService } from '@toeverything/infra';
import { useMemo } from 'react';
import * as styles from './journal-conflict-block.css';
import { ResolveConflictOperations } from './menu/journal-conflicts';
export const JournalConflictBlock = ({ date }: { date?: string }) => {
return date ? <JournalConflictChecker date={date} /> : null;
};
const JournalConflictChecker = ({ date }: { date: string }) => {
const docRecordList = useService(DocsService).list;
const journalService = useService(JournalService);
const docs = useLiveData(
useMemo(() => journalService.journalsByDate$(date), [journalService, date])
);
const docRecords = useLiveData(
docRecordList.docs$.map(records =>
records.filter(v => {
return docs.some(doc => doc.id === v.id);
})
)
);
if (docRecords.length <= 1) return null;
return <JournalConflictList docRecords={docRecords} />;
};
const JournalConflictList = ({ docRecords }: { docRecords: DocRecord[] }) => {
const t = useI18n();
return (
<>
<div className={styles.body}>
<div className={styles.header}>
{t['com.affine.editor.journal-conflict.title']()}
</div>
{docRecords.map(docRecord => (
<ConflictItem docRecord={docRecord} key={docRecord.id} />
))}
</div>
<div className={styles.separator} />
</>
);
};
const ConflictItem = ({ docRecord }: { docRecord: DocRecord }) => {
const docId = docRecord.id;
const i18n = useI18n();
const docDisplayMetaService = useService(DocDisplayMetaService);
const titleMeta = useLiveData(docDisplayMetaService.title$(docId));
const title = i18n.t(titleMeta);
return (
<div className={styles.docItem}>
<TodayIcon className={styles.icon} />
<div className={styles.content}>
<div className={styles.title}>{title}</div>
<div className={styles.duplicatedTag}>
{i18n['com.affine.page-properties.property.journal-duplicated']()}
</div>
</div>
<Menu items={<ResolveConflictOperations docRecord={docRecord} />}>
<IconButton className={styles.edit} icon={<EditIcon />} />
</Menu>
</div>
);
};

View File

@@ -22,7 +22,11 @@ import { type MouseEvent, useCallback, useMemo } from 'react';
import * as styles from './journal-conflicts.css';
const ResolveConflictOperations = ({ docRecord }: { docRecord: DocRecord }) => {
export const ResolveConflictOperations = ({
docRecord,
}: {
docRecord: DocRecord;
}) => {
const t = useI18n();
const journalService = useService(JournalService);
const { openConfirmModal } = useConfirmModal();
@@ -106,7 +110,7 @@ const DocItem = ({ docRecord }: { docRecord: DocRecord }) => {
);
};
const ConflictList = ({ docRecords }: { docRecords: DocRecord[] }) => {
export const ConflictList = ({ docRecords }: { docRecords: DocRecord[] }) => {
return docRecords.map(docRecord => (
<DocItem key={docRecord.id} docRecord={docRecord} />
));

View File

@@ -45,6 +45,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import { AppTabs } from '../../../components';
import { JournalConflictBlock } from './journal-conflict-block';
import { JournalDatePicker } from './journal-date-picker';
import * as styles from './mobile-detail-page.css';
import { PageHeaderMenuButton } from './page-header-more-button';
@@ -288,6 +289,7 @@ const MobileDetailPage = ({
: title}
</span>
</PageHeader>
<JournalConflictBlock date={date} />
<DetailPageImpl />
<AppTabs background={cssVarV2('layer/background/primary')} />
</DetailPageWrapper>

View File

@@ -1491,6 +1491,7 @@
"com.affine.attachment.preview.error.title": "Unable to preview this file",
"com.affine.attachment.preview.error.subtitle": "file type not supported.",
"com.affine.pdf.page.render.error": "Failed to render page.",
"com.affine.editor.journal-conflict.title": "Duplicate Entries in Today's Journal",
"com.affine.editor.at-menu.link-to-doc": "Link to Doc",
"com.affine.editor.at-menu.new-doc": "New Doc",
"com.affine.editor.at-menu.create-doc": "Create \"{{name}}\" Doc",