mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
fix(web): escape shortcut (#3753)
* fix: escape shortcut * feat: more escape scenarios * feat: more escape shortcuts --------- Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
parent
8873c9a02f
commit
f63d6d5b67
21 changed files with 140 additions and 27 deletions
|
|
@ -6,18 +6,17 @@
|
|||
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
updated: string;
|
||||
save: string;
|
||||
}>();
|
||||
export let album: AlbumResponseDto;
|
||||
|
||||
let description = album.description;
|
||||
|
||||
const handleSave = () => {
|
||||
dispatch('updated', description);
|
||||
};
|
||||
const handleCancel = () => dispatch('close');
|
||||
const handleSubmit = () => dispatch('save', description);
|
||||
</script>
|
||||
|
||||
<FullScreenModal on:clickOutside={() => dispatch('close')}>
|
||||
<FullScreenModal on:clickOutside={handleCancel} on:escape={handleCancel}>
|
||||
<div
|
||||
class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
||||
>
|
||||
|
|
@ -27,7 +26,7 @@
|
|||
<h1 class="text-2xl font-medium text-immich-primary dark:text-immich-dark-primary">Edit description</h1>
|
||||
</div>
|
||||
|
||||
<form on:submit|preventDefault={handleSave} autocomplete="off">
|
||||
<form on:submit|preventDefault={handleSubmit} autocomplete="off">
|
||||
<div class="m-4 flex flex-col gap-2">
|
||||
<label class="immich-form-label" for="name">Description</label>
|
||||
<!-- svelte-ignore a11y-autofocus -->
|
||||
|
|
@ -42,7 +41,7 @@
|
|||
</div>
|
||||
|
||||
<div class="mt-8 flex w-full gap-4 px-4">
|
||||
<Button color="gray" fullwidth on:click={() => dispatch('close')}>Cancel</Button>
|
||||
<Button color="gray" fullwidth on:click={handleCancel}>Cancel</Button>
|
||||
<Button type="submit" fullwidth>Ok</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -120,6 +120,10 @@
|
|||
isShowDeleteConfirmation = true;
|
||||
return;
|
||||
case 'Escape':
|
||||
if (isShowDeleteConfirmation) {
|
||||
isShowDeleteConfirmation = false;
|
||||
return;
|
||||
}
|
||||
closeViewer();
|
||||
return;
|
||||
case 'f':
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
$: icon = icons?.[index];
|
||||
</script>
|
||||
|
||||
<div id="dropdown-button" use:clickOutside on:outclick={handleClickOutside}>
|
||||
<div id="dropdown-button" use:clickOutside on:outclick={handleClickOutside} on:escape={handleClickOutside}>
|
||||
<!-- BUTTON TITLE -->
|
||||
<LinkButton on:click={() => (showMenu = true)}>
|
||||
<div class="flex place-items-center gap-2 text-sm">
|
||||
|
|
|
|||
|
|
@ -16,9 +16,11 @@
|
|||
close: void;
|
||||
save: MapSettings;
|
||||
}>();
|
||||
|
||||
const handleClose = () => dispatch('close');
|
||||
</script>
|
||||
|
||||
<FullScreenModal on:clickOutside={() => dispatch('close')}>
|
||||
<FullScreenModal on:clickOutside={handleClose} on:escape={handleClose}>
|
||||
<div
|
||||
class="flex w-96 max-w-lg flex-col gap-8 rounded-3xl border bg-white p-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray"
|
||||
>
|
||||
|
|
@ -105,7 +107,7 @@
|
|||
{/if}
|
||||
|
||||
<div class="mt-4 flex w-full gap-4">
|
||||
<Button color="gray" size="sm" fullwidth on:click={() => dispatch('close')}>Cancel</Button>
|
||||
<Button color="gray" size="sm" fullwidth on:click={handleClose}>Cancel</Button>
|
||||
<Button type="submit" size="sm" fullwidth>Save</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -3,13 +3,23 @@
|
|||
import CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte';
|
||||
import ShareVariantOutline from 'svelte-material-icons/ShareVariantOutline.svelte';
|
||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
let showModal = false;
|
||||
const dispatch = createEventDispatcher();
|
||||
const { getAssets } = getAssetControlContext();
|
||||
const escape = () => {
|
||||
dispatch('escape');
|
||||
showModal = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<CircleIconButton title="Share" logo={ShareVariantOutline} on:click={() => (showModal = true)} />
|
||||
|
||||
{#if showModal}
|
||||
<CreateSharedLinkModal assetIds={Array.from(getAssets()).map(({ id }) => id)} on:close={() => (showModal = false)} />
|
||||
<CreateSharedLinkModal
|
||||
assetIds={Array.from(getAssets()).map(({ id }) => id)}
|
||||
on:close={() => (showModal = false)}
|
||||
on:escape={escape}
|
||||
/>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,14 @@
|
|||
import TimerSand from 'svelte-material-icons/TimerSand.svelte';
|
||||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||
import { OnAssetDelete, getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
export let onAssetDelete: OnAssetDelete;
|
||||
export let menuItem = false;
|
||||
const { getAssets, clearSelect } = getAssetControlContext();
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let isShowConfirmation = false;
|
||||
let loading = false;
|
||||
|
||||
|
|
@ -51,6 +54,11 @@
|
|||
loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
const escape = () => {
|
||||
dispatch('escape');
|
||||
isShowConfirmation = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if menuItem}
|
||||
|
|
@ -71,6 +79,7 @@
|
|||
confirmText="Delete"
|
||||
on:confirm={handleDelete}
|
||||
on:cancel={() => (isShowConfirmation = false)}
|
||||
on:escape={escape}
|
||||
>
|
||||
<svelte:fragment slot="prompt">
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
$: timelineY = element?.scrollTop || 0;
|
||||
|
||||
const onKeyboardPress = (event: KeyboardEvent) => handleKeyboardPress(event);
|
||||
const dispatch = createEventDispatcher<{ select: AssetResponseDto }>();
|
||||
const dispatch = createEventDispatcher<{ select: AssetResponseDto; escape: void }>();
|
||||
|
||||
onMount(async () => {
|
||||
showSkeleton = false;
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
if (!$showAssetViewer) {
|
||||
switch (event.key) {
|
||||
case 'Escape':
|
||||
assetInteractionStore.clearMultiselect();
|
||||
dispatch('escape');
|
||||
return;
|
||||
case '?':
|
||||
if (event.shiftKey) {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
<div
|
||||
use:clickOutside
|
||||
on:outclick={() => dispatch('close')}
|
||||
on:escape={() => dispatch('escape')}
|
||||
class="max-h-[600px] min-h-[200px] w-[450px] rounded-lg bg-immich-bg shadow-md dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
||||
>
|
||||
<div class="flex place-items-center justify-between px-5 py-3">
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@
|
|||
let isConfirmButtonDisabled = false;
|
||||
|
||||
const handleCancel = () => dispatch('cancel');
|
||||
const handleEscape = () => {
|
||||
if (!isConfirmButtonDisabled) {
|
||||
dispatch('cancel');
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
isConfirmButtonDisabled = true;
|
||||
|
|
@ -24,7 +29,7 @@
|
|||
};
|
||||
</script>
|
||||
|
||||
<FullScreenModal on:clickOutside={handleCancel}>
|
||||
<FullScreenModal on:clickOutside={handleCancel} on:escape={() => handleEscape()}>
|
||||
<div
|
||||
class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
role="menu"
|
||||
use:clickOutside
|
||||
on:outclick
|
||||
on:escape
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@
|
|||
};
|
||||
</script>
|
||||
|
||||
<BaseModal on:close={() => dispatch('close')}>
|
||||
<BaseModal on:close={() => dispatch('close')} on:escape={() => dispatch('escape')}>
|
||||
<svelte:fragment slot="title">
|
||||
<span class="flex place-items-center gap-2">
|
||||
<Link size={24} />
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@
|
|||
import { createEventDispatcher } from 'svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
const dispatch = createEventDispatcher<{ clickOutside: void }>();
|
||||
const dispatch = createEventDispatcher<{
|
||||
clickOutside: void;
|
||||
escape: void;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<section
|
||||
|
|
@ -11,7 +14,12 @@
|
|||
out:fade={{ duration: 100 }}
|
||||
class="fixed left-0 top-0 z-[990] flex h-screen w-screen place-content-center place-items-center bg-black/40"
|
||||
>
|
||||
<div class="z-[9999]" use:clickOutside on:outclick={() => dispatch('clickOutside')}>
|
||||
<div
|
||||
class="z-[9999]"
|
||||
use:clickOutside
|
||||
on:outclick={() => dispatch('clickOutside')}
|
||||
on:escape={() => dispatch('escape')}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -106,7 +106,11 @@
|
|||
</a>
|
||||
{/if}
|
||||
|
||||
<div use:clickOutside on:outclick={() => (shouldShowAccountInfoPanel = false)}>
|
||||
<div
|
||||
use:clickOutside
|
||||
on:outclick={() => (shouldShowAccountInfoPanel = false)}
|
||||
on:escape={() => (shouldShowAccountInfoPanel = false)}
|
||||
>
|
||||
<button
|
||||
class="flex"
|
||||
on:mouseover={() => (shouldShowAccountInfo = true)}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
});
|
||||
|
||||
showBigSearchBar = false;
|
||||
$isSearchEnabled = false;
|
||||
goto(`${AppRoute.SEARCH}?${params}`);
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +69,7 @@
|
|||
};
|
||||
</script>
|
||||
|
||||
<div role="button" class="w-full" use:clickOutside on:outclick={onFocusOut}>
|
||||
<div role="button" class="w-full" use:clickOutside on:outclick={onFocusOut} on:escape={onFocusOut}>
|
||||
<form
|
||||
draggable="false"
|
||||
autocomplete="off"
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
const dispatch = createEventDispatcher();
|
||||
</script>
|
||||
|
||||
<FullScreenModal on:clickOutside={() => dispatch('close')}>
|
||||
<FullScreenModal on:clickOutside={() => dispatch('close')} on:escape={() => dispatch('close')}>
|
||||
<div class="flex h-full w-full place-content-center place-items-center overflow-hidden">
|
||||
<div
|
||||
class="w-[400px] max-w-[125vw] rounded-3xl border bg-immich-bg shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg md:w-[650px]"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue