mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-23 21:38:44 +08:00
@@ -1,6 +1,8 @@
|
||||
import { useEnableCloud } from '@affine/core/hooks/affine/use-enable-cloud';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import type { Doc } from '@blocksuite/store';
|
||||
import type { Workspace } from '@toeverything/infra';
|
||||
import { type Workspace } from '@toeverything/infra';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { ShareMenu } from './share-menu';
|
||||
|
||||
@@ -11,6 +13,11 @@ type SharePageModalProps = {
|
||||
|
||||
export const SharePageButton = ({ workspace, page }: SharePageModalProps) => {
|
||||
const confirmEnableCloud = useEnableCloud();
|
||||
const handleOpenShareModal = useCallback((open: boolean) => {
|
||||
if (open) {
|
||||
track.$.sharePanel.$.open();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ShareMenu
|
||||
@@ -21,6 +28,7 @@ export const SharePageButton = ({ workspace, page }: SharePageModalProps) => {
|
||||
openPageId: page.id,
|
||||
})
|
||||
}
|
||||
onOpenShareModal={handleOpenShareModal}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
+3
@@ -21,6 +21,7 @@ export interface ShareMenuProps extends PropsWithChildren {
|
||||
workspaceMetadata: WorkspaceMetadata;
|
||||
currentPage: Doc;
|
||||
onEnableAffineCloud: () => void;
|
||||
onOpenShareModal?: (open: boolean) => void;
|
||||
}
|
||||
|
||||
export const ShareMenuContent = (props: ShareMenuProps) => {
|
||||
@@ -73,6 +74,7 @@ const LocalShareMenu = (props: ShareMenuProps) => {
|
||||
}}
|
||||
rootOptions={{
|
||||
modal: false,
|
||||
onOpenChange: props.onOpenShareModal,
|
||||
}}
|
||||
>
|
||||
<div data-testid="local-share-menu-button">
|
||||
@@ -92,6 +94,7 @@ const CloudShareMenu = (props: ShareMenuProps) => {
|
||||
}}
|
||||
rootOptions={{
|
||||
modal: false,
|
||||
onOpenChange: props.onOpenShareModal,
|
||||
}}
|
||||
>
|
||||
<div data-testid="cloud-share-menu-button">
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@ export const AffineSharePage = (props: ShareMenuProps) => {
|
||||
await shareService.share.enableShare(
|
||||
mode === 'edgeless' ? PublicPageMode.Edgeless : PublicPageMode.Page
|
||||
);
|
||||
track.$.header.share.createShareLink({
|
||||
track.$.sharePanel.$.createShareLink({
|
||||
mode,
|
||||
});
|
||||
notify.success({
|
||||
|
||||
+7
-1
@@ -1,4 +1,5 @@
|
||||
import { FavoriteTag } from '@affine/core/components/page-list';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { toast } from '@affine/core/utils';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -30,11 +31,16 @@ export const useFavorite = (pageId: string) => {
|
||||
export const FavoriteButton = ({ pageId }: FavoriteButtonProps) => {
|
||||
const { favorite, toggleFavorite } = useFavorite(pageId);
|
||||
|
||||
const handleFavorite = useCallback(() => {
|
||||
track.$.header.actions.toggleFavorite();
|
||||
toggleFavorite();
|
||||
}, [toggleFavorite]);
|
||||
|
||||
return (
|
||||
<FavoriteTag
|
||||
data-testid="pin-button"
|
||||
active={!!favorite}
|
||||
onClick={toggleFavorite}
|
||||
onClick={handleFavorite}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
import { IconButton } from '@affine/component';
|
||||
import { openInfoModalAtom } from '@affine/core/atoms';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { InformationIcon } from '@blocksuite/icons/rc';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const InfoButton = () => {
|
||||
const setOpenInfoModal = useSetAtom(openInfoModalAtom);
|
||||
const t = useI18n();
|
||||
const onOpenInfoModal = () => {
|
||||
|
||||
const onOpenInfoModal = useCallback(() => {
|
||||
track.$.header.actions.openDocInfo();
|
||||
setOpenInfoModal(true);
|
||||
};
|
||||
}, [setOpenInfoModal]);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
size="20"
|
||||
|
||||
@@ -109,6 +109,7 @@ export const PageHeaderMenuButton = ({
|
||||
const setOpenHistoryTipsModal = useSetAtom(openHistoryTipsModalAtom);
|
||||
|
||||
const openHistoryModal = useCallback(() => {
|
||||
track.$.header.history.open();
|
||||
if (workspace.flavour === WorkspaceFlavour.AFFINE_CLOUD) {
|
||||
return setHistoryModalOpen(true);
|
||||
}
|
||||
@@ -116,9 +117,10 @@ export const PageHeaderMenuButton = ({
|
||||
}, [setOpenHistoryTipsModal, workspace.flavour]);
|
||||
|
||||
const setOpenInfoModal = useSetAtom(openInfoModalAtom);
|
||||
const openInfoModal = () => {
|
||||
const openInfoModal = useCallback(() => {
|
||||
track.$.header.pageInfo.open();
|
||||
setOpenInfoModal(true);
|
||||
};
|
||||
}, [setOpenInfoModal]);
|
||||
|
||||
const handleOpenInNewTab = useCallback(() => {
|
||||
workbench.openDoc(pageId, {
|
||||
@@ -133,6 +135,7 @@ export const PageHeaderMenuButton = ({
|
||||
}, [pageId, workbench]);
|
||||
|
||||
const handleOpenTrashModal = useCallback(() => {
|
||||
track.$.header.docOptions.deleteDoc();
|
||||
setTrashModal({
|
||||
open: true,
|
||||
pageIds: [pageId],
|
||||
@@ -140,8 +143,14 @@ export const PageHeaderMenuButton = ({
|
||||
});
|
||||
}, [doc.meta$.value.title, pageId, setTrashModal]);
|
||||
|
||||
const handleRename = useCallback(() => {
|
||||
rename?.();
|
||||
track.$.header.docOptions.renameDoc();
|
||||
}, [rename]);
|
||||
|
||||
const handleSwitchMode = useCallback(() => {
|
||||
doc.toggleMode();
|
||||
track.$.header.docOptions.switchPageMode();
|
||||
toast(
|
||||
currentMode === 'page'
|
||||
? t['com.affine.toastMessage.edgelessMode']()
|
||||
@@ -153,17 +162,24 @@ export const PageHeaderMenuButton = ({
|
||||
transition: 'all 0.3s',
|
||||
};
|
||||
|
||||
const handleMenuOpenChange = useCallback((open: boolean) => {
|
||||
if (open) {
|
||||
track.$.header.docOptions.open();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const exportHandler = useExportPage(doc.blockSuiteDoc);
|
||||
|
||||
const handleDuplicate = useCallback(() => {
|
||||
duplicate(pageId);
|
||||
track.$.header.actions.createDoc({
|
||||
track.$.header.docOptions.createDoc({
|
||||
control: 'duplicate',
|
||||
});
|
||||
}, [duplicate, pageId]);
|
||||
|
||||
const onImportFile = useAsyncCallback(async () => {
|
||||
const options = await importFile();
|
||||
track.$.header.docOptions.import();
|
||||
if (options.isWorkspaceFile) {
|
||||
track.$.header.actions.createWorkspace({
|
||||
control: 'import',
|
||||
@@ -175,6 +191,17 @@ export const PageHeaderMenuButton = ({
|
||||
}
|
||||
}, [importFile]);
|
||||
|
||||
const handleShareMenuOpenChange = useCallback((open: boolean) => {
|
||||
if (open) {
|
||||
track.$.sharePanel.$.open();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleToggleFavorite = useCallback(() => {
|
||||
track.$.header.docOptions.toggleFavorite();
|
||||
toggleFavorite();
|
||||
}, [toggleFavorite]);
|
||||
|
||||
const showResponsiveMenu = hideShare;
|
||||
const ResponsiveMenuItems = (
|
||||
<>
|
||||
@@ -204,6 +231,9 @@ export const PageHeaderMenuButton = ({
|
||||
</MenuIcon>
|
||||
),
|
||||
}}
|
||||
subOptions={{
|
||||
onOpenChange: handleShareMenuOpenChange,
|
||||
}}
|
||||
>
|
||||
{t['com.affine.share-menu.shareButton']()}
|
||||
</MenuSub>
|
||||
@@ -223,7 +253,7 @@ export const PageHeaderMenuButton = ({
|
||||
</MenuIcon>
|
||||
}
|
||||
data-testid="editor-option-menu-rename"
|
||||
onSelect={rename}
|
||||
onSelect={handleRename}
|
||||
style={menuItemStyle}
|
||||
>
|
||||
{t['Rename']()}
|
||||
@@ -246,7 +276,7 @@ export const PageHeaderMenuButton = ({
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
data-testid="editor-option-menu-favorite"
|
||||
onSelect={toggleFavorite}
|
||||
onSelect={handleToggleFavorite}
|
||||
style={menuItemStyle}
|
||||
preFix={
|
||||
<MenuIcon>
|
||||
@@ -389,6 +419,9 @@ export const PageHeaderMenuButton = ({
|
||||
contentOptions={{
|
||||
align: 'center',
|
||||
}}
|
||||
rootOptions={{
|
||||
onOpenChange: handleMenuOpenChange,
|
||||
}}
|
||||
>
|
||||
<HeaderDropDownButton />
|
||||
</Menu>
|
||||
|
||||
@@ -18,13 +18,14 @@ export interface BlockSuiteHeaderTitleProps {
|
||||
isPublic?: boolean;
|
||||
inputHandleRef?: InlineEditProps['handleRef'];
|
||||
className?: string;
|
||||
onEditSave?: () => void;
|
||||
}
|
||||
|
||||
const inputAttrs = {
|
||||
'data-testid': 'title-content',
|
||||
} as HTMLAttributes<HTMLInputElement>;
|
||||
export const BlocksuiteHeaderTitle = (props: BlockSuiteHeaderTitleProps) => {
|
||||
const { docCollection, pageId, isPublic, inputHandleRef } = props;
|
||||
const { docCollection, pageId, isPublic, inputHandleRef, onEditSave } = props;
|
||||
const currentPage = docCollection.getDoc(pageId);
|
||||
const pageMeta = useBlockSuiteDocMeta(docCollection).find(
|
||||
meta => meta.id === currentPage?.id
|
||||
@@ -34,9 +35,10 @@ export const BlocksuiteHeaderTitle = (props: BlockSuiteHeaderTitleProps) => {
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: string) => {
|
||||
onEditSave?.();
|
||||
setDocTitle(currentPage?.id || '', v);
|
||||
},
|
||||
[currentPage?.id, setDocTitle]
|
||||
[currentPage?.id, onEditSave, setDocTitle]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { MenuIcon, MenuItem, MenuSub } from '@affine/component';
|
||||
import { track } from '@affine/core/mixpanel';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import {
|
||||
ExportIcon,
|
||||
@@ -8,7 +9,7 @@ import {
|
||||
ExportToPngIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
import { transitionStyle } from './index.css';
|
||||
|
||||
@@ -115,6 +116,12 @@ export const Export = ({ exportHandler, className, pageMode }: ExportProps) => {
|
||||
pageMode={pageMode}
|
||||
/>
|
||||
);
|
||||
const handleExportMenuOpenChange = useCallback((open: boolean) => {
|
||||
if (open) {
|
||||
track.$.header.docOptions.export();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<MenuSub
|
||||
items={items}
|
||||
@@ -127,6 +134,9 @@ export const Export = ({ exportHandler, className, pageMode }: ExportProps) => {
|
||||
),
|
||||
['data-testid' as string]: 'export-menu',
|
||||
}}
|
||||
subOptions={{
|
||||
onOpenChange: handleExportMenuOpenChange,
|
||||
}}
|
||||
>
|
||||
{t.Export()}
|
||||
</MenuSub>
|
||||
|
||||
Reference in New Issue
Block a user