mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-16 17:46:18 +08:00
feat(core): make some tabs in sidebar persistent for all docs page (#10014)
close AF-2164 
This commit is contained in:
@@ -49,7 +49,11 @@ export const DatePicker = (props: DatePickerProps) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={styles.calendarRoot} style={variables}>
|
||||
<div
|
||||
className={styles.calendarRoot}
|
||||
style={variables}
|
||||
data-testid="date-picker-calendar"
|
||||
>
|
||||
<Component
|
||||
cursor={cursor}
|
||||
{...finalProps}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { CollectionService } from '../../../../modules/collection';
|
||||
import { ViewBody, ViewHeader } from '../../../../modules/workbench';
|
||||
import { AllDocSidebarTabs } from '../layouts/all-doc-sidebar-tabs';
|
||||
import { EmptyCollectionList } from '../page-list-empty';
|
||||
import { AllCollectionHeader } from './header';
|
||||
import * as styles from './index.css';
|
||||
@@ -102,6 +103,7 @@ export const AllCollection = () => {
|
||||
)}
|
||||
</div>
|
||||
</ViewBody>
|
||||
<AllDocSidebarTabs />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
ViewIcon,
|
||||
ViewTitle,
|
||||
} from '../../../../modules/workbench';
|
||||
import { AllDocSidebarTabs } from '../layouts/all-doc-sidebar-tabs';
|
||||
import { EmptyPageList } from '../page-list-empty';
|
||||
import * as styles from './all-page.css';
|
||||
import { FilterContainer } from './all-page-filter';
|
||||
@@ -78,6 +79,7 @@ export const AllPage = () => {
|
||||
)}
|
||||
</div>
|
||||
</ViewBody>
|
||||
<AllDocSidebarTabs />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
ViewIcon,
|
||||
ViewTitle,
|
||||
} from '../../../../modules/workbench';
|
||||
import { AllDocSidebarTabs } from '../layouts/all-doc-sidebar-tabs';
|
||||
import { EmptyTagList } from '../page-list-empty';
|
||||
import * as styles from './all-tag.css';
|
||||
import { AllTagHeader } from './header';
|
||||
@@ -72,6 +73,7 @@ export const AllTag = () => {
|
||||
)}
|
||||
</div>
|
||||
</ViewBody>
|
||||
<AllDocSidebarTabs />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
ViewIcon,
|
||||
ViewTitle,
|
||||
} from '../../../../modules/workbench';
|
||||
import { AllDocSidebarTabs } from '../layouts/all-doc-sidebar-tabs';
|
||||
import { CollectionDetailHeader } from './header';
|
||||
|
||||
export const CollectionDetail = ({
|
||||
@@ -123,6 +124,7 @@ export const Component = function CollectionPage() {
|
||||
<>
|
||||
<ViewIcon icon="collection" />
|
||||
<ViewTitle title={collection.name} />
|
||||
<AllDocSidebarTabs />
|
||||
{inner}
|
||||
</>
|
||||
);
|
||||
|
||||
+9
-3
@@ -21,7 +21,11 @@ import { JournalService } from '@affine/core/modules/journal';
|
||||
import { WorkbenchLink } from '@affine/core/modules/workbench';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { CalendarXmarkIcon, EditIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import {
|
||||
useLiveData,
|
||||
useService,
|
||||
useServiceOptional,
|
||||
} from '@toeverything/infra';
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||
import clsx from 'clsx';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -99,9 +103,11 @@ interface JournalBlockProps {
|
||||
const mobile = environment.isMobile;
|
||||
export const EditorJournalPanel = () => {
|
||||
const t = useI18n();
|
||||
const doc = useService(DocService).doc;
|
||||
const doc = useServiceOptional(DocService)?.doc;
|
||||
const journalService = useService(JournalService);
|
||||
const journalDateStr = useLiveData(journalService.journalDate$(doc.id));
|
||||
const journalDateStr = useLiveData(
|
||||
doc ? journalService.journalDate$(doc.id) : null
|
||||
);
|
||||
const journalDate = journalDateStr ? dayjs(journalDateStr) : null;
|
||||
const isJournal = !!journalDate;
|
||||
const { openJournal } = useJournalRouteHelper();
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Scrollable } from '@affine/component';
|
||||
import { ViewSidebarTab } from '@affine/core/modules/workbench';
|
||||
import { TodayIcon } from '@blocksuite/icons/rc';
|
||||
|
||||
import { sidebarScrollArea } from '../detail-page/detail-page.css';
|
||||
import { EditorJournalPanel } from '../detail-page/tabs/journal';
|
||||
|
||||
export const AllDocSidebarTabs = () => {
|
||||
return (
|
||||
<ViewSidebarTab tabId="all-docs-journal" icon={<TodayIcon />}>
|
||||
<Scrollable.Root className={sidebarScrollArea}>
|
||||
<Scrollable.Viewport>
|
||||
<EditorJournalPanel />
|
||||
</Scrollable.Viewport>
|
||||
<Scrollable.Scrollbar />
|
||||
</Scrollable.Root>
|
||||
</ViewSidebarTab>
|
||||
);
|
||||
};
|
||||
@@ -19,6 +19,7 @@ import { useEffect, useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { PageNotFound } from '../../404';
|
||||
import { AllDocSidebarTabs } from '../layouts/all-doc-sidebar-tabs';
|
||||
import { EmptyPageList } from '../page-list-empty';
|
||||
import { TagDetailHeader } from './header';
|
||||
import * as styles from './index.css';
|
||||
@@ -99,5 +100,10 @@ export const TagDetail = ({ tagId }: { tagId?: string }) => {
|
||||
export const Component = () => {
|
||||
const params = useParams();
|
||||
|
||||
return <TagDetail tagId={params.tagId} />;
|
||||
return (
|
||||
<>
|
||||
<AllDocSidebarTabs />
|
||||
<TagDetail tagId={params.tagId} />;
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -73,7 +73,7 @@ const ViewIsland = ({
|
||||
);
|
||||
}
|
||||
|
||||
const [island] = useState<Island>(createIsland());
|
||||
const [island] = useState<Island>(createIsland);
|
||||
|
||||
useEffect(() => {
|
||||
setter(prev => ({ ...prev, [id]: island }));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable unicorn/prefer-dom-node-dataset */
|
||||
/* oxlint-disable unicorn/prefer-dom-node-dataset */
|
||||
import { test } from '@affine-test/kit/playwright';
|
||||
import {
|
||||
changeFilter,
|
||||
@@ -80,13 +80,16 @@ test('use monthpicker to modify the month of datepicker', async ({ page }) => {
|
||||
await clickDatePicker(page);
|
||||
const lastMonth = new Date();
|
||||
lastMonth.setMonth(lastMonth.getMonth() - 1);
|
||||
await selectMonthFromMonthPicker(page, lastMonth);
|
||||
await checkDatePickerMonth(page, lastMonth);
|
||||
const datePicker = page.locator(
|
||||
'[role="dialog"] [data-testid="date-picker-calendar"]'
|
||||
);
|
||||
await selectMonthFromMonthPicker(datePicker, lastMonth);
|
||||
await checkDatePickerMonth(datePicker, lastMonth);
|
||||
// change month
|
||||
const nextMonth = new Date();
|
||||
nextMonth.setMonth(nextMonth.getMonth() + 1);
|
||||
await selectMonthFromMonthPicker(page, nextMonth);
|
||||
await checkDatePickerMonth(page, nextMonth);
|
||||
await selectMonthFromMonthPicker(datePicker, nextMonth);
|
||||
await checkDatePickerMonth(datePicker, nextMonth);
|
||||
});
|
||||
|
||||
test('allow creation of filters by tags', async ({ page }) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
import { clickNewPageButton, getBlockSuiteEditorTitle } from './page-logic';
|
||||
@@ -49,7 +49,7 @@ export const getPagesCount = async (page: Page) => {
|
||||
}
|
||||
|
||||
// locator is not a HTMLElement, so we can't use dataset
|
||||
// eslint-disable-next-line unicorn/prefer-dom-node-dataset
|
||||
// oxlint-disable-next-line unicorn/prefer-dom-node-dataset
|
||||
const count = await locator.getAttribute('data-total-count');
|
||||
return count ? parseInt(count) : 0;
|
||||
};
|
||||
@@ -67,7 +67,7 @@ export const clickDatePicker = async (page: Page) => {
|
||||
await page.locator('[data-testid="filter-arg"]').locator('input').click();
|
||||
};
|
||||
|
||||
const clickMonthPicker = async (page: Page) => {
|
||||
const clickMonthPicker = async (page: Page | Locator) => {
|
||||
await page.locator('[data-testid="month-picker-button"]').click();
|
||||
};
|
||||
|
||||
@@ -78,7 +78,10 @@ export const fillDatePicker = async (page: Page, date: Date) => {
|
||||
.fill(dateFormat(date));
|
||||
};
|
||||
|
||||
export const selectMonthFromMonthPicker = async (page: Page, date: Date) => {
|
||||
export const selectMonthFromMonthPicker = async (
|
||||
page: Page | Locator,
|
||||
date: Date
|
||||
) => {
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const year = date.getFullYear();
|
||||
// Open the month picker popup
|
||||
@@ -103,7 +106,10 @@ export const selectMonthFromMonthPicker = async (page: Page, date: Date) => {
|
||||
await selectMonth();
|
||||
};
|
||||
|
||||
export const checkDatePickerMonth = async (page: Page, date: Date) => {
|
||||
export const checkDatePickerMonth = async (
|
||||
page: Page | Locator,
|
||||
date: Date
|
||||
) => {
|
||||
expect(
|
||||
await page.getByTestId('month-picker-button').evaluate(e => e.dataset.month)
|
||||
).toBe(date.getMonth().toString());
|
||||
|
||||
Reference in New Issue
Block a user