mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-15 17:16:16 +08:00
@@ -0,0 +1,42 @@
|
||||
import { useSharingUrl } from '@affine/core/hooks/affine/use-share-url';
|
||||
import { registerAffineCommand } from '@toeverything/infra';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export function useRegisterCopyLinkCommands({
|
||||
workspaceId,
|
||||
docId,
|
||||
isActiveView,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
docId: string;
|
||||
isActiveView: boolean;
|
||||
}) {
|
||||
const { onClickCopyLink } = useSharingUrl({
|
||||
workspaceId,
|
||||
pageId: docId,
|
||||
urlType: 'workspace',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const unsubs: Array<() => void> = [];
|
||||
|
||||
unsubs.push(
|
||||
registerAffineCommand({
|
||||
id: `affine:share-private-link:${docId}`,
|
||||
category: 'affine:general',
|
||||
preconditionStrategy: () => isActiveView,
|
||||
keyBinding: {
|
||||
binding: '$mod+Shift+c',
|
||||
},
|
||||
label: '',
|
||||
icon: null,
|
||||
run() {
|
||||
isActiveView && onClickCopyLink();
|
||||
},
|
||||
})
|
||||
);
|
||||
return () => {
|
||||
unsubs.forEach(unsub => unsub());
|
||||
};
|
||||
}, [docId, isActiveView, onClickCopyLink]);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { getAffineCloudBaseUrl } from '@affine/core/modules/cloud/services/fetch';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
type UrlType = 'share' | 'workspace';
|
||||
|
||||
type UseSharingUrl = {
|
||||
workspaceId: string;
|
||||
pageId: string;
|
||||
urlType: UrlType;
|
||||
};
|
||||
|
||||
const useGenerateUrl = ({ workspaceId, pageId, urlType }: UseSharingUrl) => {
|
||||
// to generate a private url like https://app.affine.app/workspace/123/456
|
||||
// or https://app.affine.app/workspace/123/456#block-123
|
||||
|
||||
// to generate a public url like https://app.affine.app/share/123/456
|
||||
// or https://app.affine.app/share/123/456?mode=edgeless
|
||||
|
||||
const [hash, setHash] = useState(window.location.hash);
|
||||
|
||||
useEffect(() => {
|
||||
const handleLocationChange = () => {
|
||||
setHash(window.location.hash);
|
||||
};
|
||||
window.addEventListener('hashchange-custom', handleLocationChange);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('hashchange-custom', handleLocationChange);
|
||||
};
|
||||
}, [setHash]);
|
||||
|
||||
const baseUrl = getAffineCloudBaseUrl();
|
||||
|
||||
const url = useMemo(() => {
|
||||
// baseUrl is null when running in electron and without network
|
||||
if (!baseUrl) return null;
|
||||
|
||||
try {
|
||||
return new URL(
|
||||
`${baseUrl}/${urlType}/${workspaceId}/${pageId}${urlType === 'workspace' ? `${hash}` : ''}`
|
||||
).toString();
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}, [baseUrl, hash, pageId, urlType, workspaceId]);
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
export const useSharingUrl = ({
|
||||
workspaceId,
|
||||
pageId,
|
||||
urlType,
|
||||
}: UseSharingUrl) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const sharingUrl = useGenerateUrl({ workspaceId, pageId, urlType });
|
||||
|
||||
const onClickCopyLink = useCallback(() => {
|
||||
if (sharingUrl) {
|
||||
navigator.clipboard
|
||||
.writeText(sharingUrl)
|
||||
.then(() => {
|
||||
toast(t['Copied link to clipboard']());
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
mixpanel.track('ShareLinkCopied', {
|
||||
module: urlType === 'share' ? 'public share' : 'private share',
|
||||
type: 'link',
|
||||
});
|
||||
} else {
|
||||
toast('Network not available');
|
||||
}
|
||||
}, [sharingUrl, t, urlType]);
|
||||
|
||||
return {
|
||||
sharingUrl,
|
||||
onClickCopyLink,
|
||||
};
|
||||
};
|
||||
@@ -42,7 +42,8 @@ type KeyboardShortcutsI18NKeys =
|
||||
| 'groupDatabase'
|
||||
| 'moveUp'
|
||||
| 'moveDown'
|
||||
| 'divider';
|
||||
| 'divider'
|
||||
| 'copy-private-link';
|
||||
|
||||
// TODO(550): remove this hook after 'useAFFiNEI18N' support scoped i18n
|
||||
const useKeyboardShortcutsI18N = () => {
|
||||
@@ -81,8 +82,9 @@ export const useWinGeneralKeyboardShortcuts = (): ShortcutMap => {
|
||||
// not implement yet
|
||||
// [t('appendDailyNote')]: 'Ctrl + Alt + A',
|
||||
[t('expandOrCollapseSidebar')]: ['Ctrl', '/'],
|
||||
[t('goBack')]: ['Ctrl + ['],
|
||||
[t('goForward')]: ['Ctrl + ]'],
|
||||
[t('goBack')]: ['Ctrl', '['],
|
||||
[t('goForward')]: ['Ctrl', ']'],
|
||||
[t('copy-private-link')]: ['⌘', '⇧', 'C'],
|
||||
}),
|
||||
[t]
|
||||
);
|
||||
@@ -97,8 +99,9 @@ export const useMacGeneralKeyboardShortcuts = (): ShortcutMap => {
|
||||
// not implement yet
|
||||
// [t('appendDailyNote')]: '⌘ + ⌥ + A',
|
||||
[t('expandOrCollapseSidebar')]: ['⌘', '/'],
|
||||
[t('goBack')]: ['⌘ + ['],
|
||||
[t('goForward')]: ['⌘ + ]'],
|
||||
[t('goBack')]: ['⌘ ', '['],
|
||||
[t('goForward')]: ['⌘ ', ']'],
|
||||
[t('copy-private-link')]: ['⌘', '⇧', 'C'],
|
||||
}),
|
||||
[t]
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user