eqzms-1175: improve copy UX when clipboard is not available (#6657)

Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com>
This commit is contained in:
Alexey Zinoviev 2024-09-20 19:08:22 +04:00 committed by GitHub
parent f2c961c5d5
commit 0b39c4a843
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 24 additions and 4 deletions

View File

@ -562,6 +562,7 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
input: 'focus', input: 'focus',
category: tracker.category.Tracker, category: tracker.category.Tracker,
target: tracker.class.Issue, target: tracker.class.Issue,
visibilityTester: view.function.IsClipboardAvailable,
context: { context: {
mode: ['context', 'browser'], mode: ['context', 'browser'],
application: tracker.app.Tracker, application: tracker.app.Tracker,
@ -582,6 +583,7 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
input: 'focus', input: 'focus',
category: tracker.category.Tracker, category: tracker.category.Tracker,
target: tracker.class.Issue, target: tracker.class.Issue,
visibilityTester: view.function.IsClipboardAvailable,
context: { context: {
mode: ['context', 'browser'], mode: ['context', 'browser'],
application: tracker.app.Tracker, application: tracker.app.Tracker,
@ -602,6 +604,7 @@ export function createActions (builder: Builder, issuesId: string, componentsId:
input: 'focus', input: 'focus',
category: tracker.category.Tracker, category: tracker.category.Tracker,
target: tracker.class.Issue, target: tracker.class.Issue,
visibilityTester: view.function.IsClipboardAvailable,
context: { context: {
mode: ['context', 'browser'], mode: ['context', 'browser'],
application: tracker.app.Tracker, application: tracker.app.Tracker,

View File

@ -140,6 +140,7 @@ export default mergeIds(viewId, view, {
CanDeleteSpace: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>, CanDeleteSpace: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
CanJoinSpace: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>, CanJoinSpace: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
CanLeaveSpace: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>, CanLeaveSpace: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
IsClipboardAvailable: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
BlobImageMetadata: '' as Resource<(file: FileOrBlob, blob: Ref<Blob>) => Promise<BlobMetadata | undefined>>, BlobImageMetadata: '' as Resource<(file: FileOrBlob, blob: Ref<Blob>) => Promise<BlobMetadata | undefined>>,
BlobVideoMetadata: '' as Resource<(file: FileOrBlob, blob: Ref<Blob>) => Promise<BlobMetadata | undefined>> BlobVideoMetadata: '' as Resource<(file: FileOrBlob, blob: Ref<Blob>) => Promise<BlobMetadata | undefined>>
}, },

View File

@ -40,6 +40,7 @@
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const query = createQuery() const query = createQuery()
const isSecureContext = window.isSecureContext
interface InviteParams { interface InviteParams {
expirationTime: number expirationTime: number
@ -87,6 +88,7 @@
} }
} }
function copy (): void { function copy (): void {
if (!isSecureContext) return
if (link === undefined) return if (link === undefined) return
copyTextToClipboard(link) copyTextToClipboard(link)
copied = true copied = true
@ -109,7 +111,7 @@
let loading = false let loading = false
</script> </script>
<div class="antiPopup popup"> <div class="antiPopup popup" class:secure={isSecureContext}>
<div class="flex-between fs-title mb-9"> <div class="flex-between fs-title mb-9">
<Label label={login.string.InviteDescription} /> <Label label={login.string.InviteDescription} />
<InviteWorkspace size={'large'} /> <InviteWorkspace size={'large'} />
@ -154,7 +156,9 @@
<Loading /> <Loading />
{:else if link !== undefined} {:else if link !== undefined}
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="over-underline link" on:click={copy}>{link}</div> <div class="link" class:notSecure={!isSecureContext} class:over-underline={isSecureContext} on:click={copy}>
{link}
</div>
<div class="buttons"> <div class="buttons">
<Button <Button
label={login.string.Close} label={login.string.Close}
@ -164,7 +168,9 @@
dispatch('close') dispatch('close')
}} }}
/> />
<Button label={copied ? login.string.Copied : login.string.Copy} size={'medium'} on:click={copy} /> {#if isSecureContext}
<Button label={copied ? login.string.Copied : login.string.Copy} size={'medium'} on:click={copy} />
{/if}
</div> </div>
{:else} {:else}
<div class="buttons"> <div class="buttons">
@ -195,6 +201,10 @@
.link { .link {
margin: 1.75rem 0 0; margin: 1.75rem 0 0;
overflow-wrap: break-word; overflow-wrap: break-word;
&.notSecure {
user-select: text;
}
} }
.buttons { .buttons {

View File

@ -135,7 +135,8 @@ import {
canDeleteSpace, canDeleteSpace,
canEditSpace, canEditSpace,
canJoinSpace, canJoinSpace,
canLeaveSpace canLeaveSpace,
isClipboardAvailable
} from './visibilityTester' } from './visibilityTester'
export { canArchiveSpace, canDeleteObject, canDeleteSpace, canEditSpace } from './visibilityTester' export { canArchiveSpace, canDeleteObject, canDeleteSpace, canEditSpace } from './visibilityTester'
export { getActions, getContextActions, invokeAction, showMenu } from './actions' export { getActions, getContextActions, invokeAction, showMenu } from './actions'
@ -334,6 +335,7 @@ export default async (): Promise<Resources> => ({
CanDeleteSpace: canDeleteSpace, CanDeleteSpace: canDeleteSpace,
CanJoinSpace: canJoinSpace, CanJoinSpace: canJoinSpace,
CanLeaveSpace: canLeaveSpace, CanLeaveSpace: canLeaveSpace,
IsClipboardAvailable: isClipboardAvailable,
BlobImageMetadata: blobImageMetadata, BlobImageMetadata: blobImageMetadata,
BlobVideoMetadata: blobVideoMetadata BlobVideoMetadata: blobVideoMetadata
} }

View File

@ -143,3 +143,7 @@ export async function canLeaveSpace (doc?: Doc | Doc[]): Promise<boolean> {
return space.members?.includes(getCurrentAccount()._id) return space.members?.includes(getCurrentAccount()._id)
} }
export function isClipboardAvailable (doc?: Doc | Doc[]): boolean {
return isSecureContext && navigator.clipboard !== undefined
}