feat(core): responsive detail page header (#7263)

This commit is contained in:
CatsJuice
2024-06-20 05:47:43 +00:00
parent 78429166da
commit 1fdfa834a0
15 changed files with 264 additions and 108 deletions
@@ -1,12 +1,14 @@
import type { InlineEditHandle } from '@affine/component';
import { Divider, type InlineEditHandle } from '@affine/component';
import { FavoriteButton } from '@affine/core/components/blocksuite/block-suite-header/favorite';
import { JournalWeekDatePicker } from '@affine/core/components/blocksuite/block-suite-header/journal/date-picker';
import { JournalTodayButton } from '@affine/core/components/blocksuite/block-suite-header/journal/today-button';
import { PageHeaderMenuButton } from '@affine/core/components/blocksuite/block-suite-header/menu';
import { DetailPageHeaderPresentButton } from '@affine/core/components/blocksuite/block-suite-header/present/detail-header-present-button';
import { EditorModeSwitch } from '@affine/core/components/blocksuite/block-suite-mode-switch';
import { useRegisterCopyLinkCommands } from '@affine/core/hooks/affine/use-register-copy-link-commands';
import { useJournalInfoHelper } from '@affine/core/hooks/use-journal';
import type { Doc } from '@blocksuite/store';
import type { Workspace } from '@toeverything/infra';
import { type Workspace } from '@toeverything/infra';
import { useAtomValue } from 'jotai';
import { useCallback, useRef } from 'react';
@@ -15,6 +17,7 @@ import { appSidebarFloatingAtom } from '../../../components/app-sidebar';
import { BlocksuiteHeaderTitle } from '../../../components/blocksuite/block-suite-header/title/index';
import { HeaderDivider } from '../../../components/pure/header';
import * as styles from './detail-page-header.css';
import { useDetailPageHeaderResponsive } from './use-header-responsive';
function Header({
children,
@@ -43,6 +46,7 @@ interface PageHeaderProps {
workspace: Workspace;
}
export function JournalPageHeader({ page, workspace }: PageHeaderProps) {
const { hideShare, hideToday } = useDetailPageHeaderResponsive();
return (
<Header className={styles.header}>
<EditorModeSwitch
@@ -55,11 +59,13 @@ export function JournalPageHeader({ page, workspace }: PageHeaderProps) {
page={page}
/>
</div>
<JournalTodayButton docCollection={workspace.docCollection} />
{hideToday ? null : (
<JournalTodayButton docCollection={workspace.docCollection} />
)}
<HeaderDivider />
<PageHeaderMenuButton isJournal pageId={page?.id} />
{page ? (
<SharePageButton isJournal workspace={workspace} page={page} />
<PageHeaderMenuButton isJournal page={page} />
{page && !hideShare ? (
<SharePageButton workspace={workspace} page={page} />
) : null}
</Header>
);
@@ -67,6 +73,8 @@ export function JournalPageHeader({ page, workspace }: PageHeaderProps) {
export function NormalPageHeader({ page, workspace }: PageHeaderProps) {
const titleInputHandleRef = useRef<InlineEditHandle>(null);
const { hideCollect, hideShare, hidePresent, showDivider } =
useDetailPageHeaderResponsive();
const onRename = useCallback(() => {
setTimeout(() => titleInputHandleRef.current?.triggerEdit());
@@ -82,19 +90,33 @@ export function NormalPageHeader({ page, workspace }: PageHeaderProps) {
pageId={page?.id}
docCollection={workspace.docCollection}
/>
<PageHeaderMenuButton rename={onRename} pageId={page?.id} />
<FavoriteButton pageId={page?.id} />
{hideCollect ? null : <FavoriteButton pageId={page?.id} />}
<PageHeaderMenuButton rename={onRename} page={page} />
<div className={styles.spacer} />
{page ? <SharePageButton workspace={workspace} page={page} /> : null}
{!hidePresent ? <DetailPageHeaderPresentButton /> : null}
{page && !hideShare ? (
<SharePageButton workspace={workspace} page={page} />
) : null}
{showDivider ? (
<Divider orientation="vertical" style={{ height: 20, marginLeft: 4 }} />
) : null}
</Header>
);
}
export function DetailPageHeader(props: PageHeaderProps) {
const { page } = props;
const { page, workspace } = props;
const { isJournal } = useJournalInfoHelper(page.collection, page.id);
const isInTrash = page.meta?.trash;
useRegisterCopyLinkCommands({
workspaceMeta: workspace.meta,
docId: page.id,
});
return isJournal && !isInTrash ? (
<JournalPageHeader {...props} />
) : (
@@ -0,0 +1,36 @@
import { RightSidebarService } from '@affine/core/modules/right-sidebar';
import { WorkbenchService } from '@affine/core/modules/workbench';
import { ViewService } from '@affine/core/modules/workbench/services/view';
import { useViewPosition } from '@affine/core/modules/workbench/view/use-view-position';
import { DocService, useLiveData, useService } from '@toeverything/infra';
export const useDetailPageHeaderResponsive = () => {
const mode = useLiveData(useService(DocService).doc.mode$);
const view = useService(ViewService).view;
const workbench = useService(WorkbenchService).workbench;
const availableWidth = useLiveData(view.headerContentWidth$);
const viewPosition = useViewPosition();
const workbenchViewsCount = useLiveData(
workbench.views$.map(views => views.length)
);
const rightSidebar = useService(RightSidebarService).rightSidebar;
const rightSidebarOpen = useLiveData(rightSidebar.isOpen$);
// share button should be hidden once split-view is enabled
const hideShare = availableWidth < 500 || workbenchViewsCount > 1;
const hidePresent = availableWidth < 400 || mode !== 'edgeless';
const hideCollect = availableWidth < 300;
const hideToday = availableWidth < 300;
const showDivider =
viewPosition.isLast && !rightSidebarOpen && !(hidePresent && hideShare);
return {
hideShare,
hidePresent,
hideCollect,
hideToday,
showDivider,
};
};