feat(core): add private anchor link for sharing (#6966)

close AFF-1085
This commit is contained in:
JimmFly
2024-05-16 13:35:01 +00:00
parent 3799b65f73
commit 10015c59b7
9 changed files with 162 additions and 41 deletions
@@ -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]
);