mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
feat(component): add private copy link button (#4508)
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { style } from '@vanilla-extract/css';
|
import { globalStyle, style } from '@vanilla-extract/css';
|
||||||
|
|
||||||
export const menuItemStyle = style({
|
export const menuItemStyle = style({
|
||||||
padding: '4px',
|
padding: '4px',
|
||||||
@@ -12,6 +12,7 @@ export const descriptionStyle = style({
|
|||||||
lineHeight: '20px',
|
lineHeight: '20px',
|
||||||
color: 'var(--affine-text-secondary-color)',
|
color: 'var(--affine-text-secondary-color)',
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
|
padding: '0 2px',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const buttonStyle = style({
|
export const buttonStyle = style({
|
||||||
@@ -66,7 +67,7 @@ export const columnContainerStyle = style({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
padding: '0 4px',
|
padding: '0 4px',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
gap: '12px',
|
gap: '8px',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const rowContainerStyle = style({
|
export const rowContainerStyle = style({
|
||||||
@@ -131,3 +132,18 @@ export const shareIconStyle = style({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const shareLinkStyle = style({
|
||||||
|
padding: '4px',
|
||||||
|
fontSize: 'var(--affine-font-xs)',
|
||||||
|
fontWeight: 500,
|
||||||
|
lineHeight: '20px',
|
||||||
|
transform: 'translateX(-4px)',
|
||||||
|
gap: '4px',
|
||||||
|
});
|
||||||
|
globalStyle(`${shareLinkStyle} > span`, {
|
||||||
|
color: 'var(--affine-link-color)',
|
||||||
|
});
|
||||||
|
globalStyle(`${shareLinkStyle} > div > svg`, {
|
||||||
|
color: 'var(--affine-link-color)',
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
|
import { LinkIcon } from '@blocksuite/icons';
|
||||||
|
import { Button } from '@toeverything/components/button';
|
||||||
|
import { Divider } from '@toeverything/components/divider';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ExportToHtmlMenuItem,
|
ExportToHtmlMenuItem,
|
||||||
@@ -7,9 +10,19 @@ import {
|
|||||||
ExportToPngMenuItem,
|
ExportToPngMenuItem,
|
||||||
} from '../page-list/operation-menu-items/export';
|
} from '../page-list/operation-menu-items/export';
|
||||||
import * as styles from './index.css';
|
import * as styles from './index.css';
|
||||||
|
import type { ShareMenuProps } from './share-menu';
|
||||||
|
import { useSharingUrl } from './use-share-url';
|
||||||
|
|
||||||
export const ShareExport = () => {
|
export const ShareExport = (props: ShareMenuProps) => {
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
|
const workspaceId = props.workspace.id;
|
||||||
|
const pageId = props.currentPage.id;
|
||||||
|
const { onClickCopyLink } = useSharingUrl({
|
||||||
|
workspaceId,
|
||||||
|
pageId,
|
||||||
|
urlType: 'workspace',
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={styles.titleContainerStyle} style={{ fontWeight: '500' }}>
|
<div className={styles.titleContainerStyle} style={{ fontWeight: '500' }}>
|
||||||
@@ -25,6 +38,17 @@ export const ShareExport = () => {
|
|||||||
<div className={styles.descriptionStyle}>
|
<div className={styles.descriptionStyle}>
|
||||||
{t['com.affine.share-menu.ShareViaExportDescription']()}
|
{t['com.affine.share-menu.ShareViaExportDescription']()}
|
||||||
</div>
|
</div>
|
||||||
|
<Divider size="thinner" />
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
className={styles.shareLinkStyle}
|
||||||
|
onClick={onClickCopyLink}
|
||||||
|
icon={<LinkIcon />}
|
||||||
|
type="plain"
|
||||||
|
>
|
||||||
|
{t['Copy Link']()}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { Menu } from '@toeverything/components/menu';
|
|||||||
import * as styles from './index.css';
|
import * as styles from './index.css';
|
||||||
import { ShareExport } from './share-export';
|
import { ShareExport } from './share-export';
|
||||||
import { SharePage } from './share-page';
|
import { SharePage } from './share-page';
|
||||||
|
|
||||||
export interface ShareMenuProps<
|
export interface ShareMenuProps<
|
||||||
Workspace extends AffineOfficialWorkspace =
|
Workspace extends AffineOfficialWorkspace =
|
||||||
| AffineCloudWorkspace
|
| AffineCloudWorkspace
|
||||||
@@ -43,7 +42,7 @@ export const ShareMenu = (props: ShareMenuProps) => {
|
|||||||
<div className={styles.columnContainerStyle}>
|
<div className={styles.columnContainerStyle}>
|
||||||
<Divider size="thinner" />
|
<Divider size="thinner" />
|
||||||
</div>
|
</div>
|
||||||
<ShareExport />
|
<ShareExport {...props} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import { ArrowRightSmallIcon, WebIcon } from '@blocksuite/icons';
|
|||||||
import { Button } from '@toeverything/components/button';
|
import { Button } from '@toeverything/components/button';
|
||||||
import { Menu, MenuItem, MenuTrigger } from '@toeverything/components/menu';
|
import { Menu, MenuItem, MenuTrigger } from '@toeverything/components/menu';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import Input from '../../ui/input';
|
import Input from '../../ui/input';
|
||||||
import { toast } from '../../ui/toast';
|
import { toast } from '../../ui/toast';
|
||||||
import { PublicLinkDisableModal } from './disable-public-link';
|
import { PublicLinkDisableModal } from './disable-public-link';
|
||||||
import * as styles from './index.css';
|
import * as styles from './index.css';
|
||||||
import type { ShareMenuProps } from './share-menu';
|
import type { ShareMenuProps } from './share-menu';
|
||||||
|
import { useSharingUrl } from './use-share-url';
|
||||||
|
|
||||||
const CloudSvg = () => (
|
const CloudSvg = () => (
|
||||||
<svg
|
<svg
|
||||||
@@ -74,32 +75,19 @@ export const AffineSharePage = (props: ShareMenuProps) => {
|
|||||||
workspace: { id: workspaceId },
|
workspace: { id: workspaceId },
|
||||||
currentPage: { id: pageId },
|
currentPage: { id: pageId },
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [isPublic, setIsPublic] = props.useIsSharedPage(workspaceId, pageId);
|
const [isPublic, setIsPublic] = props.useIsSharedPage(workspaceId, pageId);
|
||||||
|
|
||||||
const [showDisable, setShowDisable] = useState(false);
|
const [showDisable, setShowDisable] = useState(false);
|
||||||
|
const { sharingUrl, onClickCopyLink } = useSharingUrl({
|
||||||
|
workspaceId,
|
||||||
|
pageId,
|
||||||
|
urlType: 'share',
|
||||||
|
});
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
|
|
||||||
const sharingUrl = useMemo(() => {
|
|
||||||
return `${runtimeConfig.serverUrlPrefix}/share/${workspaceId}/${pageId}`;
|
|
||||||
}, [workspaceId, pageId]);
|
|
||||||
|
|
||||||
const onClickCreateLink = useCallback(() => {
|
const onClickCreateLink = useCallback(() => {
|
||||||
setIsPublic(true);
|
setIsPublic(true);
|
||||||
}, [setIsPublic]);
|
}, [setIsPublic]);
|
||||||
|
|
||||||
const onClickCopyLink = useCallback(() => {
|
|
||||||
navigator.clipboard
|
|
||||||
.writeText(sharingUrl)
|
|
||||||
.then(() => {
|
|
||||||
toast(t['Copied link to clipboard']());
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}, [sharingUrl, t]);
|
|
||||||
|
|
||||||
const onDisablePublic = useCallback(() => {
|
const onDisablePublic = useCallback(() => {
|
||||||
setIsPublic(false);
|
setIsPublic(false);
|
||||||
toast('Successfully disabled', {
|
toast('Successfully disabled', {
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { toast } from '../../ui/toast';
|
||||||
|
|
||||||
|
type UrlType = 'share' | 'workspace';
|
||||||
|
|
||||||
|
type UseSharingUrl = {
|
||||||
|
workspaceId: string;
|
||||||
|
pageId: string;
|
||||||
|
urlType: UrlType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const generateUrl = ({
|
||||||
|
workspaceId,
|
||||||
|
pageId,
|
||||||
|
urlType,
|
||||||
|
}: UseSharingUrl) => {
|
||||||
|
return `${runtimeConfig.serverUrlPrefix}/${urlType}/${workspaceId}/${pageId}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSharingUrl = ({
|
||||||
|
workspaceId,
|
||||||
|
pageId,
|
||||||
|
urlType,
|
||||||
|
}: UseSharingUrl) => {
|
||||||
|
const t = useAFFiNEI18N();
|
||||||
|
const sharingUrl = useMemo(
|
||||||
|
() => generateUrl({ workspaceId, pageId, urlType }),
|
||||||
|
[urlType, workspaceId, pageId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onClickCopyLink = useCallback(() => {
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(sharingUrl)
|
||||||
|
.then(() => {
|
||||||
|
toast(t['Copied link to clipboard']());
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}, [sharingUrl, t]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
sharingUrl,
|
||||||
|
onClickCopyLink,
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user