From 9004c45eedb2329e021ffd3b2a51c12fe22e4c75 Mon Sep 17 00:00:00 2001 From: JimmFly Date: Mon, 20 Jan 2025 02:40:10 +0000 Subject: [PATCH] feat(core): add copy link button to local share menu (#9271) close AF-1838 --- .../share-menu/copy-link-button.tsx | 116 +++++++++++++++ .../share-page-modal/share-menu/index.css.ts | 38 +++++ .../share-menu/share-page.tsx | 132 ++++-------------- 3 files changed, 182 insertions(+), 104 deletions(-) create mode 100644 packages/frontend/core/src/components/affine/share-page-modal/share-menu/copy-link-button.tsx diff --git a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/copy-link-button.tsx b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/copy-link-button.tsx new file mode 100644 index 0000000000..787dd1e917 --- /dev/null +++ b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/copy-link-button.tsx @@ -0,0 +1,116 @@ +import { Button, Menu, MenuItem, MenuTrigger } from '@affine/component'; +import { + getSelectedNodes, + useSharingUrl, +} from '@affine/core/components/hooks/affine/use-share-url'; +import { EditorService } from '@affine/core/modules/editor'; +import { useI18n } from '@affine/i18n'; +import type { DocMode } from '@blocksuite/affine/blocks'; +import { BlockIcon, EdgelessIcon, PageIcon } from '@blocksuite/icons/rc'; +import { useLiveData, useService } from '@toeverything/infra'; +import clsx from 'clsx'; +import { useCallback, useMemo } from 'react'; + +import * as styles from './index.css'; + +export const CopyLinkButton = ({ + workspaceId, + secondary, +}: { + secondary?: boolean; + workspaceId: string; +}) => { + const t = useI18n(); + + const editor = useService(EditorService).editor; + const currentMode = useLiveData(editor.mode$); + const editorContainer = useLiveData(editor.editorContainer$); + + const { blockIds, elementIds } = useMemo( + () => getSelectedNodes(editorContainer?.host || null, currentMode), + [editorContainer, currentMode] + ); + const { onClickCopyLink } = useSharingUrl({ + workspaceId, + pageId: editor.doc.id, + }); + + const onCopyPageLink = useCallback(() => { + onClickCopyLink('page' as DocMode); + }, [onClickCopyLink]); + const onCopyEdgelessLink = useCallback(() => { + onClickCopyLink('edgeless' as DocMode); + }, [onClickCopyLink]); + const onCopyBlockLink = useCallback(() => { + onClickCopyLink(currentMode, blockIds, elementIds); + }, [onClickCopyLink, currentMode, blockIds, elementIds]); + return ( +
+ + + } + onSelect={onCopyPageLink} + data-testid="share-link-menu-copy-page" + > + {t['com.affine.share-menu.copy.page']()} + + } + onSelect={onCopyEdgelessLink} + data-testid="share-link-menu-copy-edgeless" + > + {t['com.affine.share-menu.copy.edgeless']()} + + } + onSelect={onCopyBlockLink} + disabled={blockIds.length + elementIds.length === 0} + > + {t['com.affine.share-menu.copy.block']()} + + + } + > + + +
+ ); +}; 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 4d13c287d1..4771c68717 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 @@ -54,6 +54,12 @@ export const copyLinkContainerStyle = style({ alignItems: 'center', width: '100%', position: 'relative', + selectors: { + '&.secondary': { + padding: 0, + marginTop: '12px', + }, + }, }); export const copyLinkButtonStyle = style({ flex: 1, @@ -64,6 +70,14 @@ export const copyLinkButtonStyle = style({ borderBottomRightRadius: '0', color: 'transparent', position: 'initial', + selectors: { + '&.dark': { + backgroundColor: cssVarV2('layer/pureBlack'), + }, + '&.dark::hover': { + backgroundColor: cssVarV2('layer/pureBlack'), + }, + }, }); export const copyLinkLabelContainerStyle = style({ width: '100%', @@ -80,6 +94,11 @@ export const copyLinkLabelStyle = style({ transform: 'translateX(-50%) translateY(-50%)', lineHeight: '20px', color: cssVarV2('text/pureWhite'), + selectors: { + '&.secondary': { + color: cssVarV2('text/primary'), + }, + }, }); export const copyLinkShortcutStyle = style({ position: 'absolute', @@ -90,6 +109,11 @@ export const copyLinkShortcutStyle = style({ opacity: 0.5, lineHeight: '20px', color: cssVarV2('text/pureWhite'), + selectors: { + '&.secondary': { + color: cssVarV2('text/secondary'), + }, + }, }); export const copyLinkTriggerStyle = style({ padding: '4px 12px 4px 8px', @@ -109,11 +133,25 @@ export const copyLinkTriggerStyle = style({ width: '1px', backgroundColor: cssVarV2('button/innerBlackBorder'), }, + selectors: { + '&.secondary': { + backgroundColor: cssVarV2('button/secondary'), + color: cssVarV2('text/secondary'), + }, + '&.secondary:hover': { + backgroundColor: cssVarV2('button/secondary'), + color: cssVarV2('text/secondary'), + }, + }, }); globalStyle(`${copyLinkTriggerStyle} svg`, { color: cssVarV2('button/pureWhiteText'), transform: 'translateX(2px)', }); +globalStyle(`${copyLinkTriggerStyle}.secondary svg`, { + color: cssVarV2('text/secondary'), + transform: 'translateX(2px)', +}); export const copyLinkMenuItemStyle = style({ padding: '4px', transition: 'all 0.3s', diff --git a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx index 44d9acfdee..6bf7c7ba1e 100644 --- a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx +++ b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx @@ -1,62 +1,62 @@ import { notify, Skeleton } from '@affine/component'; import { Button } from '@affine/component/ui/button'; import { Menu, MenuItem, MenuTrigger } from '@affine/component/ui/menu'; -import { - getSelectedNodes, - useSharingUrl, -} from '@affine/core/components/hooks/affine/use-share-url'; import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks'; import { ServerService } from '@affine/core/modules/cloud'; import { WorkspaceDialogService } from '@affine/core/modules/dialogs'; -import { EditorService } from '@affine/core/modules/editor'; import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { ShareInfoService } from '@affine/core/modules/share-doc'; import { PublicPageMode } from '@affine/graphql'; import { useI18n } from '@affine/i18n'; import { track } from '@affine/track'; -import type { DocMode } from '@blocksuite/affine/blocks'; import { - BlockIcon, CollaborationIcon, DoneIcon, - EdgelessIcon, LockIcon, - PageIcon, SingleSelectCheckSolidIcon, ViewIcon, } from '@blocksuite/icons/rc'; import { useLiveData, useService } from '@toeverything/infra'; import { cssVar } from '@toeverything/theme'; -import { Suspense, useCallback, useEffect, useMemo } from 'react'; +import { Suspense, useCallback, useEffect } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; import { CloudSvg } from '../cloud-svg'; +import { CopyLinkButton } from './copy-link-button'; import * as styles from './index.css'; import type { ShareMenuProps } from './share-menu'; export const LocalSharePage = (props: ShareMenuProps) => { const t = useI18n(); - + const { + workspaceMetadata: { id: workspaceId }, + } = props; return ( -
-
-
- {t['com.affine.share-menu.EnableCloudDescription']()} -
-
- + {t['com.affine.share-menu.EnableCloudDescription']()} +
+
+ +
+
+
+
-
- -
- + + ); }; @@ -65,9 +65,6 @@ export const AFFiNESharePage = (props: ShareMenuProps) => { const { workspaceMetadata: { id: workspaceId }, } = props; - const editor = useService(EditorService).editor; - const currentMode = useLiveData(editor.mode$); - const editorContainer = useLiveData(editor.editorContainer$); const shareInfoService = useService(ShareInfoService); const serverService = useService(ServerService); useEffect(() => { @@ -152,25 +149,6 @@ export const AFFiNESharePage = (props: ShareMenuProps) => { } }, [shareInfoService, t]); - const { blockIds, elementIds } = useMemo( - () => getSelectedNodes(editorContainer?.host || null, currentMode), - [editorContainer, currentMode] - ); - const { onClickCopyLink } = useSharingUrl({ - workspaceId, - pageId: editor.doc.id, - }); - - const onCopyPageLink = useCallback(() => { - onClickCopyLink('page' as DocMode); - }, [onClickCopyLink]); - const onCopyEdgelessLink = useCallback(() => { - onClickCopyLink('edgeless' as DocMode); - }, [onClickCopyLink]); - const onCopyBlockLink = useCallback(() => { - onClickCopyLink(currentMode, blockIds, elementIds); - }, [onClickCopyLink, currentMode, blockIds, elementIds]); - if (isLoading) { // TODO(@eyhn): loading and error UI return ( @@ -254,61 +232,7 @@ export const AFFiNESharePage = (props: ShareMenuProps) => { {t['com.affine.share-menu.navigate.workspace']()} )} -
- - - } - onSelect={onCopyPageLink} - data-testid="share-link-menu-copy-page" - > - {t['com.affine.share-menu.copy.page']()} - - } - onSelect={onCopyEdgelessLink} - data-testid="share-link-menu-copy-edgeless" - > - {t['com.affine.share-menu.copy.edgeless']()} - - } - onSelect={onCopyBlockLink} - disabled={blockIds.length + elementIds.length === 0} - > - {t['com.affine.share-menu.copy.block']()} - - - } - > - - -
+ ); };