mirror of
https://github.com/immich-app/immich.git
synced 2025-03-25 02:41:37 -05:00
Merge branches 'chore/web-bucketing-by-day' and 'main' of github.com:immich-app/immich into chore/web-bucketing-by-day
This commit is contained in:
commit
8dea3ef74f
21 changed files with 34 additions and 103 deletions
|
@ -1,19 +1,12 @@
|
||||||
import { matchesShortcut } from '$lib/actions/shortcut';
|
import { matchesShortcut } from '$lib/actions/shortcut';
|
||||||
import type { ActionReturn } from 'svelte/action';
|
import type { ActionReturn } from 'svelte/action';
|
||||||
|
|
||||||
interface Attributes {
|
|
||||||
/** @deprecated */
|
|
||||||
'on:outclick'?: (e: CustomEvent) => void;
|
|
||||||
/** @deprecated **/
|
|
||||||
'on:escape'?: (e: CustomEvent) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Options {
|
interface Options {
|
||||||
onOutclick?: () => void;
|
onOutclick?: () => void;
|
||||||
onEscape?: () => void;
|
onEscape?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clickOutside(node: HTMLElement, options: Options = {}): ActionReturn<void, Attributes> {
|
export function clickOutside(node: HTMLElement, options: Options = {}): ActionReturn {
|
||||||
const { onOutclick, onEscape } = options;
|
const { onOutclick, onEscape } = options;
|
||||||
|
|
||||||
const handleClick = (event: MouseEvent) => {
|
const handleClick = (event: MouseEvent) => {
|
||||||
|
@ -22,11 +15,7 @@ export function clickOutside(node: HTMLElement, options: Options = {}): ActionRe
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onOutclick) {
|
onOutclick?.();
|
||||||
onOutclick();
|
|
||||||
} else {
|
|
||||||
node.dispatchEvent(new CustomEvent('outclick'));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleKey = (event: KeyboardEvent) => {
|
const handleKey = (event: KeyboardEvent) => {
|
||||||
|
@ -37,8 +26,6 @@ export function clickOutside(node: HTMLElement, options: Options = {}): ActionRe
|
||||||
if (onEscape) {
|
if (onEscape) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
onEscape();
|
onEscape();
|
||||||
} else {
|
|
||||||
node.dispatchEvent(new CustomEvent('escape'));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if selectedMenuUser === user}
|
{#if selectedMenuUser === user}
|
||||||
<ContextMenu {...position} on:outclick={() => (selectedMenuUser = null)}>
|
<ContextMenu {...position} onClose={() => (selectedMenuUser = null)}>
|
||||||
{#if role === AlbumUserRole.Viewer}
|
{#if role === AlbumUserRole.Viewer}
|
||||||
<MenuOption on:click={() => handleSetReadonly(user, AlbumUserRole.Editor)} text="Allow edits" />
|
<MenuOption on:click={() => handleSetReadonly(user, AlbumUserRole.Editor)} text="Allow edits" />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
|
@ -201,8 +201,7 @@
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="absolute right-6 rounded-xl items-center bg-gray-300 dark:bg-slate-100 py-3 px-6 text-left text-sm font-medium text-immich-fg hover:bg-red-300 focus:outline-none focus:ring-2 focus:ring-inset dark:text-immich-dark-bg dark:hover:bg-red-100 transition-colors"
|
class="absolute right-6 rounded-xl items-center bg-gray-300 dark:bg-slate-100 py-3 px-6 text-left text-sm font-medium text-immich-fg hover:bg-red-300 focus:outline-none focus:ring-2 focus:ring-inset dark:text-immich-dark-bg dark:hover:bg-red-100 transition-colors"
|
||||||
use:clickOutside
|
use:clickOutside={{ onOutclick: () => (showDeleteReaction[index] = false) }}
|
||||||
on:outclick={() => (showDeleteReaction[index] = false)}
|
|
||||||
on:click={() => handleDeleteReaction(reaction, index)}
|
on:click={() => handleDeleteReaction(reaction, index)}
|
||||||
>
|
>
|
||||||
Remove
|
Remove
|
||||||
|
@ -254,8 +253,7 @@
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="absolute right-6 rounded-xl items-center bg-gray-300 dark:bg-slate-100 py-3 px-6 text-left text-sm font-medium text-immich-fg hover:bg-red-300 focus:outline-none focus:ring-2 focus:ring-inset dark:text-immich-dark-bg dark:hover:bg-red-100 transition-colors"
|
class="absolute right-6 rounded-xl items-center bg-gray-300 dark:bg-slate-100 py-3 px-6 text-left text-sm font-medium text-immich-fg hover:bg-red-300 focus:outline-none focus:ring-2 focus:ring-inset dark:text-immich-dark-bg dark:hover:bg-red-100 transition-colors"
|
||||||
use:clickOutside
|
use:clickOutside={{ onOutclick: () => (showDeleteReaction[index] = false) }}
|
||||||
on:outclick={() => (showDeleteReaction[index] = false)}
|
|
||||||
on:click={() => handleDeleteReaction(reaction, index)}
|
on:click={() => handleDeleteReaction(reaction, index)}
|
||||||
>
|
>
|
||||||
Remove
|
Remove
|
||||||
|
|
|
@ -273,10 +273,12 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeViewer = async () => {
|
const closeViewer = async () => {
|
||||||
$slideshowState = SlideshowState.StopSlideshow;
|
if ($slideshowState === SlideshowState.None) {
|
||||||
document.body.style.cursor = '';
|
dispatch('close');
|
||||||
dispatch('close');
|
await navigate({ targetRoute: 'current', assetId: null });
|
||||||
await navigate({ targetRoute: 'current', assetId: null });
|
} else {
|
||||||
|
$slideshowState = SlideshowState.StopSlideshow;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const navigateAssetRandom = async () => {
|
const navigateAssetRandom = async () => {
|
||||||
|
@ -793,7 +795,6 @@
|
||||||
<DeleteAssetDialog
|
<DeleteAssetDialog
|
||||||
size={1}
|
size={1}
|
||||||
on:cancel={() => (isShowDeleteConfirmation = false)}
|
on:cancel={() => (isShowDeleteConfirmation = false)}
|
||||||
on:escape={() => (isShowDeleteConfirmation = false)}
|
|
||||||
on:confirm={() => deleteAsset()}
|
on:confirm={() => deleteAsset()}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
$: renderedSelectedOption = renderOption(selectedOption);
|
$: renderedSelectedOption = renderOption(selectedOption);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div use:clickOutside on:outclick={handleClickOutside} on:escape={handleClickOutside}>
|
<div use:clickOutside={{ onOutclick: handleClickOutside, onEscape: handleClickOutside }}>
|
||||||
<!-- BUTTON TITLE -->
|
<!-- BUTTON TITLE -->
|
||||||
<LinkButton on:click={() => (showMenu = true)} fullwidth {title}>
|
<LinkButton on:click={() => (showMenu = true)} fullwidth {title}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
|
|
|
@ -87,7 +87,7 @@
|
||||||
|
|
||||||
{#if showContextMenu}
|
{#if showContextMenu}
|
||||||
<Portal target="body">
|
<Portal target="body">
|
||||||
<ContextMenu {...contextMenuPosition} on:outclick={() => onMenuExit()}>
|
<ContextMenu {...contextMenuPosition} onClose={() => onMenuExit()}>
|
||||||
<MenuOption on:click={() => onMenuClick('hide-person')} icon={mdiEyeOffOutline} text="Hide person" />
|
<MenuOption on:click={() => onMenuClick('hide-person')} icon={mdiEyeOffOutline} text="Hide person" />
|
||||||
<MenuOption on:click={() => onMenuClick('change-name')} icon={mdiAccountEditOutline} text="Change name" />
|
<MenuOption on:click={() => onMenuClick('change-name')} icon={mdiAccountEditOutline} text="Change name" />
|
||||||
<MenuOption
|
<MenuOption
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
|
||||||
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import { featureFlags } from '$lib/stores/server-config.store';
|
import { featureFlags } from '$lib/stores/server-config.store';
|
||||||
import { mdiTimerSand, mdiDeleteOutline } from '@mdi/js';
|
import { mdiTimerSand, mdiDeleteOutline } from '@mdi/js';
|
||||||
import { type OnDelete, deleteAssets } from '$lib/utils/actions';
|
import { type OnDelete, deleteAssets } from '$lib/utils/actions';
|
||||||
|
@ -14,10 +13,6 @@
|
||||||
|
|
||||||
const { clearSelect, getOwnedAssets } = getAssetControlContext();
|
const { clearSelect, getOwnedAssets } = getAssetControlContext();
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
|
||||||
escape: void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
let isShowConfirmation = false;
|
let isShowConfirmation = false;
|
||||||
let loading = false;
|
let loading = false;
|
||||||
|
|
||||||
|
@ -40,11 +35,6 @@
|
||||||
isShowConfirmation = false;
|
isShowConfirmation = false;
|
||||||
loading = false;
|
loading = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const escape = () => {
|
|
||||||
dispatch('escape');
|
|
||||||
isShowConfirmation = false;
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if menuItem}
|
{#if menuItem}
|
||||||
|
@ -60,6 +50,5 @@
|
||||||
size={getOwnedAssets().size}
|
size={getOwnedAssets().size}
|
||||||
on:confirm={handleDelete}
|
on:confirm={handleDelete}
|
||||||
on:cancel={() => (isShowConfirmation = false)}
|
on:cancel={() => (isShowConfirmation = false)}
|
||||||
on:escape={escape}
|
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
setContext(() => (showContextMenu = false));
|
setContext(() => (showContextMenu = false));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div use:clickOutside on:outclick={() => (showContextMenu = false)}>
|
<div use:clickOutside={{ onOutclick: () => (showContextMenu = false) }}>
|
||||||
<CircleIconButton {title} {icon} on:click={handleShowMenu} />
|
<CircleIconButton {title} {icon} on:click={handleShowMenu} />
|
||||||
{#if showContextMenu}
|
{#if showContextMenu}
|
||||||
<ContextMenu {...contextMenuPosition}>
|
<ContextMenu {...contextMenuPosition}>
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
import { shortcuts } from '$lib/actions/shortcut';
|
import { shortcuts } from '$lib/actions/shortcut';
|
||||||
import { clickOutside } from '$lib/actions/click-outside';
|
import { clickOutside } from '$lib/actions/click-outside';
|
||||||
import { focusOutside } from '$lib/actions/focus-outside';
|
import { focusOutside } from '$lib/actions/focus-outside';
|
||||||
|
import { generateId } from '$lib/utils/generate-id';
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import { uniqueIdStore } from '$lib/stores/unique-id.store';
|
|
||||||
|
|
||||||
export let label: string;
|
export let label: string;
|
||||||
export let hideLabel = false;
|
export let hideLabel = false;
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
/**
|
/**
|
||||||
* Unique identifier for the combobox.
|
* Unique identifier for the combobox.
|
||||||
*/
|
*/
|
||||||
let id: string = uniqueIdStore.generateId();
|
let id: string = generateId();
|
||||||
/**
|
/**
|
||||||
* Indicates whether or not the dropdown autocomplete list should be visible.
|
* Indicates whether or not the dropdown autocomplete list should be visible.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
export let y = 0;
|
export let y = 0;
|
||||||
|
|
||||||
export let menuElement: HTMLDivElement | undefined = undefined;
|
export let menuElement: HTMLDivElement | undefined = undefined;
|
||||||
|
export let onClose: (() => void) | undefined = undefined;
|
||||||
|
|
||||||
let left: number;
|
let left: number;
|
||||||
let top: number;
|
let top: number;
|
||||||
|
@ -36,9 +37,7 @@
|
||||||
style:top="{top}px"
|
style:top="{top}px"
|
||||||
style:left="{left}px"
|
style:left="{left}px"
|
||||||
role="menu"
|
role="menu"
|
||||||
use:clickOutside
|
use:clickOutside={{ onOutclick: onClose, onEscape: onClose }}
|
||||||
on:outclick
|
|
||||||
on:escape
|
|
||||||
>
|
>
|
||||||
<div class="flex flex-col rounded-lg">
|
<div class="flex flex-col rounded-lg">
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
@ -49,14 +49,7 @@
|
||||||
on:contextmenu|preventDefault={reopenContextMenu}
|
on:contextmenu|preventDefault={reopenContextMenu}
|
||||||
role="presentation"
|
role="presentation"
|
||||||
>
|
>
|
||||||
<ContextMenu
|
<ContextMenu {x} {y} {direction} onClose={closeContextMenu} bind:menuElement={contextMenuElement}>
|
||||||
{x}
|
|
||||||
{y}
|
|
||||||
{direction}
|
|
||||||
on:outclick={closeContextMenu}
|
|
||||||
on:escape={closeContextMenu}
|
|
||||||
bind:menuElement={contextMenuElement}
|
|
||||||
>
|
|
||||||
<slot />
|
<slot />
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import FocusTrap from '$lib/components/shared-components/focus-trap.svelte';
|
import FocusTrap from '$lib/components/shared-components/focus-trap.svelte';
|
||||||
import ModalHeader from '$lib/components/shared-components/modal-header.svelte';
|
import ModalHeader from '$lib/components/shared-components/modal-header.svelte';
|
||||||
import { uniqueIdStore } from '$lib/stores/unique-id.store';
|
import { generateId } from '$lib/utils/generate-id';
|
||||||
|
|
||||||
export let onClose: () => void;
|
export let onClose: () => void;
|
||||||
export let title: string;
|
export let title: string;
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
/**
|
/**
|
||||||
* Unique identifier for the modal.
|
* Unique identifier for the modal.
|
||||||
*/
|
*/
|
||||||
let id: string = uniqueIdStore.generateId();
|
let id: string = generateId();
|
||||||
|
|
||||||
$: titleId = `${id}-title`;
|
$: titleId = `${id}-title`;
|
||||||
$: isStickyBottom = !!$$slots['sticky-bottom'];
|
$: isStickyBottom = !!$$slots['sticky-bottom'];
|
||||||
|
|
|
@ -114,9 +114,10 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
use:clickOutside
|
use:clickOutside={{
|
||||||
on:outclick={() => (shouldShowAccountInfoPanel = false)}
|
onOutclick: () => (shouldShowAccountInfoPanel = false),
|
||||||
on:escape={() => (shouldShowAccountInfoPanel = false)}
|
onEscape: () => (shouldShowAccountInfoPanel = false),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Slider from '$lib/components/elements/slider.svelte';
|
import Slider from '$lib/components/elements/slider.svelte';
|
||||||
import { uniqueIdStore } from '$lib/stores/unique-id.store';
|
import { generateId } from '$lib/utils/generate-id';
|
||||||
|
|
||||||
export let title: string;
|
export let title: string;
|
||||||
export let subtitle = '';
|
export let subtitle = '';
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let isEdited = false;
|
export let isEdited = false;
|
||||||
|
|
||||||
let id: string = uniqueIdStore.generateId();
|
let id: string = generateId();
|
||||||
|
|
||||||
$: sliderId = `${id}-slider`;
|
$: sliderId = `${id}-slider`;
|
||||||
$: subtitleId = subtitle ? `${id}-subtitle` : undefined;
|
$: subtitleId = subtitle ? `${id}-subtitle` : undefined;
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { uniqueIdStore } from '$lib/stores/unique-id.store';
|
|
||||||
|
|
||||||
describe('uniqueIdStore', () => {
|
|
||||||
afterEach(() => {
|
|
||||||
uniqueIdStore.update(() => -1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should generate unique ids', () => {
|
|
||||||
const { generateId } = uniqueIdStore;
|
|
||||||
const ids = [generateId(), generateId(), generateId()];
|
|
||||||
|
|
||||||
expect(ids).toEqual(['id-0', 'id-1', 'id-2']);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,16 +0,0 @@
|
||||||
import { get, writable } from 'svelte/store';
|
|
||||||
|
|
||||||
function createIdStore() {
|
|
||||||
const { subscribe, update } = writable(-1);
|
|
||||||
|
|
||||||
return {
|
|
||||||
subscribe,
|
|
||||||
update,
|
|
||||||
generateId: () => {
|
|
||||||
update((value) => value + 1);
|
|
||||||
return `id-${get(uniqueIdStore)}`;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const uniqueIdStore = createIdStore();
|
|
2
web/src/lib/utils/generate-id.ts
Normal file
2
web/src/lib/utils/generate-id.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
let _count = 0;
|
||||||
|
export const generateId = (): string => `id-${_count++}`;
|
|
@ -467,7 +467,7 @@
|
||||||
<CircleIconButton title="Download" on:click={handleDownloadAlbum} icon={mdiFolderDownloadOutline} />
|
<CircleIconButton title="Download" on:click={handleDownloadAlbum} icon={mdiFolderDownloadOutline} />
|
||||||
|
|
||||||
{#if isOwned}
|
{#if isOwned}
|
||||||
<div use:clickOutside on:outclick={() => (viewMode = ViewMode.VIEW)}>
|
<div use:clickOutside={{ onOutclick: () => (viewMode = ViewMode.VIEW) }}>
|
||||||
<CircleIconButton title="Album options" on:click={handleOpenAlbumOptions} icon={mdiDotsVertical} />
|
<CircleIconButton title="Album options" on:click={handleOpenAlbumOptions} icon={mdiDotsVertical} />
|
||||||
{#if viewMode === ViewMode.ALBUM_OPTIONS}
|
{#if viewMode === ViewMode.ALBUM_OPTIONS}
|
||||||
<ContextMenu {...contextMenuPosition}>
|
<ContextMenu {...contextMenuPosition}>
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
import { preferences, user } from '$lib/stores/user.store';
|
import { preferences, user } from '$lib/stores/user.store';
|
||||||
|
|
||||||
let { isViewing: showAssetViewer } = assetViewingStore;
|
let { isViewing: showAssetViewer } = assetViewingStore;
|
||||||
let handleEscapeKey = false;
|
|
||||||
const assetStore = new AssetStore({ isArchived: false, withStacked: true, withPartners: true });
|
const assetStore = new AssetStore({ isArchived: false, withStacked: true, withPartners: true });
|
||||||
const assetInteractionStore = createAssetInteractionStore();
|
const assetInteractionStore = createAssetInteractionStore();
|
||||||
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
|
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
|
||||||
|
@ -43,10 +42,6 @@
|
||||||
if ($showAssetViewer) {
|
if ($showAssetViewer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (handleEscapeKey) {
|
|
||||||
handleEscapeKey = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($isMultiSelectState) {
|
if ($isMultiSelectState) {
|
||||||
assetInteractionStore.clearMultiselect();
|
assetInteractionStore.clearMultiselect();
|
||||||
return;
|
return;
|
||||||
|
@ -79,11 +74,7 @@
|
||||||
<ChangeDate menuItem />
|
<ChangeDate menuItem />
|
||||||
<ChangeLocation menuItem />
|
<ChangeLocation menuItem />
|
||||||
<ArchiveAction menuItem onArchive={(assetIds) => assetStore.removeAssets(assetIds)} />
|
<ArchiveAction menuItem onArchive={(assetIds) => assetStore.removeAssets(assetIds)} />
|
||||||
<DeleteAssets
|
<DeleteAssets menuItem onAssetDelete={(assetIds) => assetStore.removeAssets(assetIds)} />
|
||||||
menuItem
|
|
||||||
on:escape={() => (handleEscapeKey = true)}
|
|
||||||
onAssetDelete={(assetIds) => assetStore.removeAssets(assetIds)}
|
|
||||||
/>
|
|
||||||
<hr />
|
<hr />
|
||||||
<AssetJobActions />
|
<AssetJobActions />
|
||||||
</AssetSelectContextMenu>
|
</AssetSelectContextMenu>
|
||||||
|
|
|
@ -97,13 +97,13 @@
|
||||||
{#if $featureFlags.loaded && $featureFlags.trash}
|
{#if $featureFlags.loaded && $featureFlags.trash}
|
||||||
<UserPageLayout hideNavbar={$isMultiSelectState} title={data.meta.title} scrollbar={false}>
|
<UserPageLayout hideNavbar={$isMultiSelectState} title={data.meta.title} scrollbar={false}>
|
||||||
<div class="flex place-items-center gap-2" slot="buttons">
|
<div class="flex place-items-center gap-2" slot="buttons">
|
||||||
<LinkButton on:click={handleRestoreTrash}>
|
<LinkButton on:click={handleRestoreTrash} disabled={$isMultiSelectState}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<Icon path={mdiHistory} size="18" />
|
<Icon path={mdiHistory} size="18" />
|
||||||
Restore all
|
Restore all
|
||||||
</div>
|
</div>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
<LinkButton on:click={() => handleEmptyTrash()}>
|
<LinkButton on:click={() => handleEmptyTrash()} disabled={$isMultiSelectState}>
|
||||||
<div class="flex place-items-center gap-2 text-sm">
|
<div class="flex place-items-center gap-2 text-sm">
|
||||||
<Icon path={mdiDeleteOutline} size="18" />
|
<Icon path={mdiDeleteOutline} size="18" />
|
||||||
Empty trash
|
Empty trash
|
||||||
|
|
|
@ -397,7 +397,7 @@
|
||||||
|
|
||||||
{#if showContextMenu}
|
{#if showContextMenu}
|
||||||
<Portal target="body">
|
<Portal target="body">
|
||||||
<ContextMenu {...contextMenuPosition} on:outclick={() => onMenuExit()}>
|
<ContextMenu {...contextMenuPosition} onClose={() => onMenuExit()}>
|
||||||
<MenuOption on:click={() => onRenameClicked()} text={`Rename`} />
|
<MenuOption on:click={() => onRenameClicked()} text={`Rename`} />
|
||||||
|
|
||||||
{#if selectedLibrary}
|
{#if selectedLibrary}
|
||||||
|
|
Loading…
Add table
Reference in a new issue