Skip to content

Commit

Permalink
feat(core): add copy link button to local share menu
Browse files Browse the repository at this point in the history
  • Loading branch information
JimmFly committed Dec 24, 2024
1 parent bbd61c9 commit 44fd81b
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 104 deletions.
Original file line number Diff line number Diff line change
@@ -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 (
<div
className={clsx(styles.copyLinkContainerStyle, { secondary: secondary })}
>
<Button
className={styles.copyLinkButtonStyle}
onClick={onCopyBlockLink}
withoutHover
variant={secondary ? 'secondary' : 'primary'}
>
<span
className={clsx(styles.copyLinkLabelStyle, {
secondary: secondary,
})}
>
{t['com.affine.share-menu.copy']()}
</span>
{BUILD_CONFIG.isDesktopEdition && (
<span
className={clsx(styles.copyLinkShortcutStyle, {
secondary: secondary,
})}
>
{environment.isMacOs ? '⌘ + ⌥ + C' : 'Ctrl + Shift + C'}
</span>
)}
</Button>
<Menu
contentOptions={{
align: 'end',
}}
items={
<>
<MenuItem
prefixIcon={<PageIcon />}
onSelect={onCopyPageLink}
data-testid="share-link-menu-copy-page"
>
{t['com.affine.share-menu.copy.page']()}
</MenuItem>
<MenuItem
prefixIcon={<EdgelessIcon />}
onSelect={onCopyEdgelessLink}
data-testid="share-link-menu-copy-edgeless"
>
{t['com.affine.share-menu.copy.edgeless']()}
</MenuItem>
<MenuItem
prefixIcon={<BlockIcon />}
onSelect={onCopyBlockLink}
disabled={blockIds.length + elementIds.length === 0}
>
{t['com.affine.share-menu.copy.block']()}
</MenuItem>
</>
}
>
<MenuTrigger
variant={secondary ? 'secondary' : 'primary'}
className={clsx(styles.copyLinkTriggerStyle, {
secondary: secondary,
})}
data-testid="share-menu-copy-link-button"
suffixStyle={{ width: 20, height: 20 }}
withoutHover
/>
</Menu>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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%',
Expand All @@ -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',
Expand All @@ -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',
Expand All @@ -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',
Expand Down
Original file line number Diff line number Diff line change
@@ -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 { GlobalDialogService } 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,
SingleSelectSelectSolidIcon,
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 (
<div className={styles.localSharePage}>
<div className={styles.columnContainerStyle} style={{ gap: '12px' }}>
<div className={styles.descriptionStyle} style={{ maxWidth: '230px' }}>
{t['com.affine.share-menu.EnableCloudDescription']()}
</div>
<div>
<Button
onClick={props.onEnableAffineCloud}
variant="primary"
data-testid="share-menu-enable-affine-cloud-button"
<>
<div className={styles.localSharePage}>
<div className={styles.columnContainerStyle} style={{ gap: '12px' }}>
<div
className={styles.descriptionStyle}
style={{ maxWidth: '230px' }}
>
{t['Enable AFFiNE Cloud']()}
</Button>
{t['com.affine.share-menu.EnableCloudDescription']()}
</div>
<div>
<Button
onClick={props.onEnableAffineCloud}
variant="primary"
data-testid="share-menu-enable-affine-cloud-button"
>
{t['Enable AFFiNE Cloud']()}
</Button>
</div>
</div>
<div className={styles.cloudSvgContainer}>
<CloudSvg />
</div>
</div>
<div className={styles.cloudSvgContainer}>
<CloudSvg />
</div>
</div>
<CopyLinkButton workspaceId={workspaceId} secondary />
</>
);
};

Expand All @@ -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(() => {
Expand Down Expand Up @@ -153,25 +150,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 (
Expand Down Expand Up @@ -255,61 +233,7 @@ export const AFFiNESharePage = (props: ShareMenuProps) => {
{t['com.affine.share-menu.navigate.workspace']()}
</div>
)}
<div className={styles.copyLinkContainerStyle}>
<Button
className={styles.copyLinkButtonStyle}
onClick={onCopyBlockLink}
variant="primary"
withoutHover
>
<span className={styles.copyLinkLabelStyle}>
{t['com.affine.share-menu.copy']()}
</span>
{BUILD_CONFIG.isDesktopEdition && (
<span className={styles.copyLinkShortcutStyle}>
{environment.isMacOs ? '⌘ + ⌥ + C' : 'Ctrl + Shift + C'}
</span>
)}
</Button>
<Menu
contentOptions={{
align: 'end',
}}
items={
<>
<MenuItem
prefixIcon={<PageIcon />}
onSelect={onCopyPageLink}
data-testid="share-link-menu-copy-page"
>
{t['com.affine.share-menu.copy.page']()}
</MenuItem>
<MenuItem
prefixIcon={<EdgelessIcon />}
onSelect={onCopyEdgelessLink}
data-testid="share-link-menu-copy-edgeless"
>
{t['com.affine.share-menu.copy.edgeless']()}
</MenuItem>
<MenuItem
prefixIcon={<BlockIcon />}
onSelect={onCopyBlockLink}
disabled={blockIds.length + elementIds.length === 0}
>
{t['com.affine.share-menu.copy.block']()}
</MenuItem>
</>
}
>
<MenuTrigger
variant="primary"
className={styles.copyLinkTriggerStyle}
data-testid="share-menu-copy-link-button"
suffixStyle={{ width: 20, height: 20 }}
withoutHover
/>
</Menu>
</div>
<CopyLinkButton workspaceId={workspaceId} />
</div>
);
};
Expand Down

0 comments on commit 44fd81b

Please sign in to comment.