diff --git a/packages/frontend/core/src/components/affine/share-page-modal/index.tsx b/packages/frontend/core/src/components/affine/share-page-modal/index.tsx index e697661b1a..491370ec9a 100644 --- a/packages/frontend/core/src/components/affine/share-page-modal/index.tsx +++ b/packages/frontend/core/src/components/affine/share-page-modal/index.tsx @@ -7,19 +7,13 @@ import { ShareMenu } from './share-menu'; type SharePageModalProps = { workspace: Workspace; page: Doc; - isJournal?: boolean; }; -export const SharePageButton = ({ - workspace, - page, - isJournal, -}: SharePageModalProps) => { +export const SharePageButton = ({ workspace, page }: SharePageModalProps) => { const confirmEnableCloud = useEnableCloud(); return ( diff --git a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/index.css.ts b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/index.css.ts index 9aa22527ed..f20c829706 100644 --- a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/index.css.ts +++ b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/index.css.ts @@ -138,7 +138,7 @@ globalStyle(`${shareLinkStyle} > span`, { globalStyle(`${shareLinkStyle} > div > svg`, { color: cssVar('linkColor'), }); -export const journalShareButton = style({ +export const shareButton = style({ height: 32, padding: '0px 8px', }); diff --git a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-menu.tsx b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-menu.tsx index d87cac1f1b..feee8cdf55 100644 --- a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-menu.tsx +++ b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-menu.tsx @@ -1,27 +1,24 @@ import { Button } from '@affine/component/ui/button'; import { Divider } from '@affine/component/ui/divider'; import { Menu } from '@affine/component/ui/menu'; -import { useRegisterCopyLinkCommands } from '@affine/core/hooks/affine/use-register-copy-link-commands'; -import { useIsActiveView } from '@affine/core/modules/workbench'; import { WorkspaceFlavour } from '@affine/env/workspace'; import { useI18n } from '@affine/i18n'; import { WebIcon } from '@blocksuite/icons/rc'; import type { Doc } from '@blocksuite/store'; import type { WorkspaceMetadata } from '@toeverything/infra'; -import clsx from 'clsx'; +import { forwardRef, type PropsWithChildren, type Ref } from 'react'; import * as styles from './index.css'; import { ShareExport } from './share-export'; import { SharePage } from './share-page'; -export interface ShareMenuProps { +export interface ShareMenuProps extends PropsWithChildren { workspaceMetadata: WorkspaceMetadata; currentPage: Doc; - isJournal?: boolean; onEnableAffineCloud: () => void; } -const ShareMenuContent = (props: ShareMenuProps) => { +export const ShareMenuContent = (props: ShareMenuProps) => { const t = useI18n(); return (
@@ -40,8 +37,20 @@ const ShareMenuContent = (props: ShareMenuProps) => { ); }; -const LocalShareMenu = (props: ShareMenuProps) => { +const DefaultShareButton = forwardRef(function DefaultShareButton( + _, + ref: Ref +) { const t = useI18n(); + + return ( + + ); +}); + +const LocalShareMenu = (props: ShareMenuProps) => { return ( } @@ -53,27 +62,14 @@ const LocalShareMenu = (props: ShareMenuProps) => { modal: false, }} > - +
+ {props.children || } +
); }; const CloudShareMenu = (props: ShareMenuProps) => { - const t = useI18n(); - - // only enable copy link commands when the view is active and the workspace is cloud - const isActiveView = useIsActiveView(); - useRegisterCopyLinkCommands({ - workspaceId: props.workspaceMetadata.id, - docId: props.currentPage.id, - isActiveView, - }); return ( } @@ -85,13 +81,9 @@ const CloudShareMenu = (props: ShareMenuProps) => { modal: false, }} > - +
+ {props.children || } +
); }; diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx index 76a0c46fa9..29b9ed2a0d 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx @@ -4,14 +4,18 @@ import { MenuIcon, MenuItem, MenuSeparator, + MenuSub, } from '@affine/component/ui/menu'; import { openHistoryTipsModalAtom } from '@affine/core/atoms'; import { PageHistoryModal } from '@affine/core/components/affine/page-history-modal'; +import { ShareMenuContent } from '@affine/core/components/affine/share-page-modal/share-menu'; import { Export, MoveToTrash } from '@affine/core/components/page-list'; import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper'; +import { useEnableCloud } from '@affine/core/hooks/affine/use-enable-cloud'; import { useExportPage } from '@affine/core/hooks/affine/use-export-page'; import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { useDetailPageHeaderResponsive } from '@affine/core/pages/workspace/detail-page/use-header-responsive'; import { mixpanel } from '@affine/core/utils'; import { WorkspaceFlavour } from '@affine/env/workspace'; import { useI18n } from '@affine/i18n'; @@ -24,7 +28,9 @@ import { HistoryIcon, ImportIcon, PageIcon, + ShareIcon, } from '@blocksuite/icons/rc'; +import type { Doc } from '@blocksuite/store'; import { DocService, useLiveData, @@ -40,16 +46,19 @@ import { useFavorite } from '../favorite'; type PageMenuProps = { rename?: () => void; - pageId: string; + page: Doc; isJournal?: boolean; }; // fixme: refactor this file export const PageHeaderMenuButton = ({ rename, - pageId, + page, isJournal, }: PageMenuProps) => { + const pageId = page?.id; const t = useI18n(); + const { hideShare } = useDetailPageHeaderResponsive(); + const confirmEnableCloud = useEnableCloud(); const workspace = useService(WorkspaceService).workspace; const docCollection = workspace.docCollection; @@ -127,8 +136,46 @@ export const PageHeaderMenuButton = ({ } }, [importFile]); + const showResponsiveMenu = hideShare; + const ResponsiveMenuItems = ( + <> + {hideShare ? ( + + + confirmEnableCloud(workspace, { + openPageId: page.id, + }) + } + /> +
+ } + triggerOptions={{ + preFix: ( + + + + ), + }} + > + {t['com.affine.share-menu.shareButton']()} + + ) : null} + + + ); + const EditMenu = ( <> + {showResponsiveMenu ? ResponsiveMenuItems : null} {!isJournal && ( { + const { isPresent, handlePresent } = usePresent(); + + return ( + } + onClick={() => handlePresent(!isPresent)} + > + ); +}; diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-header/present/use-present.ts b/packages/frontend/core/src/components/blocksuite/block-suite-header/present/use-present.ts new file mode 100644 index 0000000000..a7b498f552 --- /dev/null +++ b/packages/frontend/core/src/components/blocksuite/block-suite-header/present/use-present.ts @@ -0,0 +1,59 @@ +import { useActiveBlocksuiteEditor } from '@affine/core/hooks/use-block-suite-editor'; +import type { EdgelessRootService } from '@blocksuite/blocks'; +import { useCallback, useEffect, useState } from 'react'; + +export const usePresent = () => { + const [isPresent, setIsPresent] = useState(false); + const [editor] = useActiveBlocksuiteEditor(); + + const handlePresent = useCallback( + (enable = true) => { + isPresent; + const editorHost = editor?.host; + if (!editorHost) return; + + // TODO: use surfaceService subAtom + const enterOrLeavePresentationMode = () => { + const edgelessRootService = editorHost.spec.getService( + 'affine:page' + ) as EdgelessRootService; + + if (!edgelessRootService) { + return; + } + + const activeTool = edgelessRootService.tool.edgelessTool.type; + const isFrameNavigator = activeTool === 'frameNavigator'; + if ((enable && isFrameNavigator) || (!enable && !isFrameNavigator)) + return; + + edgelessRootService.tool.setEdgelessTool({ + type: enable ? 'frameNavigator' : 'default', + }); + }; + + enterOrLeavePresentationMode(); + setIsPresent(enable); + }, + [editor?.host, isPresent] + ); + + useEffect(() => { + if (!isPresent) return; + + const editorHost = editor?.host; + if (!editorHost) return; + + const edgelessPage = editorHost?.querySelector('affine-edgeless-root'); + if (!edgelessPage) return; + + return edgelessPage.slots.edgelessToolUpdated.on(() => { + setIsPresent(edgelessPage.edgelessTool.type === 'frameNavigator'); + }).dispose; + }, [editor?.host, isPresent]); + + return { + isPresent, + handlePresent, + }; +}; diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/style.ts b/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/style.ts index 75ea1e17c2..03249c43f4 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/style.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/style.ts @@ -11,7 +11,7 @@ export const StyledEditorModeSwitch = styled('div')<{ background: showAlone ? 'transparent' : 'var(--affine-background-secondary-color)', - borderRadius: '12px', + borderRadius: '8px', ...displayFlex('space-between', 'center'), padding: '4px 4px', position: 'relative', @@ -23,7 +23,7 @@ export const StyledEditorModeSwitch = styled('div')<{ height: '24px', background: 'var(--affine-background-primary-color)', boxShadow: 'var(--affine-shadow-1)', - borderRadius: '8px', + borderRadius: '4px', zIndex: 1, position: 'absolute', transform: `translateX(${switchLeft ? '0' : '32px'})`, diff --git a/packages/frontend/core/src/components/cloud/share-header-right-item/present.tsx b/packages/frontend/core/src/components/cloud/share-header-right-item/present.tsx index 4144257df9..0444951f87 100644 --- a/packages/frontend/core/src/components/cloud/share-header-right-item/present.tsx +++ b/packages/frontend/core/src/components/cloud/share-header-right-item/present.tsx @@ -1,60 +1,19 @@ import { Button } from '@affine/component/ui/button'; -import { useActiveBlocksuiteEditor } from '@affine/core/hooks/use-block-suite-editor'; import { useI18n } from '@affine/i18n'; -import type { EdgelessRootService } from '@blocksuite/blocks'; import { PresentationIcon } from '@blocksuite/icons/rc'; -import { useCallback, useEffect, useState } from 'react'; +import { usePresent } from '../../blocksuite/block-suite-header/present/use-present'; import * as styles from './styles.css'; export const PresentButton = () => { const t = useI18n(); - const [isPresent, setIsPresent] = useState(false); - const [editor] = useActiveBlocksuiteEditor(); - - const handlePresent = useCallback(() => { - const editorHost = editor?.host; - if (!editorHost || isPresent) return; - - // TODO: use surfaceService subAtom - const enterPresentationMode = () => { - const edgelessRootService = editorHost.spec.getService( - 'affine:page' - ) as EdgelessRootService; - - if ( - !edgelessRootService || - edgelessRootService.tool.edgelessTool.type === 'frameNavigator' - ) { - return; - } - - edgelessRootService.tool.setEdgelessTool({ type: 'frameNavigator' }); - }; - - enterPresentationMode(); - setIsPresent(true); - }, [editor?.host, isPresent]); - - useEffect(() => { - if (!isPresent) return; - - const editorHost = editor?.host; - if (!editorHost) return; - - const edgelessPage = editorHost?.querySelector('affine-edgeless-root'); - if (!edgelessPage) return; - - return edgelessPage.slots.edgelessToolUpdated.on(() => { - setIsPresent(edgelessPage.edgelessTool.type === 'frameNavigator'); - }).dispose; - }, [editor?.host, isPresent]); + const { isPresent, handlePresent } = usePresent(); return (