mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:17:11 -05:00 
			
		
		
		
	feat(web,a11y): standardize base modal (#8388)
* consistent headings * remove escape key handler * add aria attributes
This commit is contained in:
		
							parent
							
								
									28e8e539f6
								
							
						
					
					
						commit
						f7afc0334e
					
				@ -66,13 +66,7 @@
 | 
				
			|||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{#if !selectedRemoveUser}
 | 
					{#if !selectedRemoveUser}
 | 
				
			||||||
  <BaseModal on:close={() => dispatch('close')}>
 | 
					  <BaseModal id="share-info-modal" title="Options" on:close>
 | 
				
			||||||
    <svelte:fragment slot="title">
 | 
					 | 
				
			||||||
      <span class="flex place-items-center gap-2">
 | 
					 | 
				
			||||||
        <p class="font-medium text-immich-fg dark:text-immich-dark-fg">Options</p>
 | 
					 | 
				
			||||||
      </span>
 | 
					 | 
				
			||||||
    </svelte:fragment>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <section class="immich-scrollbar max-h-[400px] overflow-y-auto pb-4">
 | 
					    <section class="immich-scrollbar max-h-[400px] overflow-y-auto pb-4">
 | 
				
			||||||
      <div class="flex w-full place-items-center justify-between gap-4 p-5">
 | 
					      <div class="flex w-full place-items-center justify-between gap-4 p-5">
 | 
				
			||||||
        <div class="flex place-items-center gap-4">
 | 
					        <div class="flex place-items-center gap-4">
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,6 @@
 | 
				
			|||||||
  import { createEventDispatcher, onMount } from 'svelte';
 | 
					  import { createEventDispatcher, onMount } from 'svelte';
 | 
				
			||||||
  import Button from '../elements/buttons/button.svelte';
 | 
					  import Button from '../elements/buttons/button.svelte';
 | 
				
			||||||
  import BaseModal from '../shared-components/base-modal.svelte';
 | 
					  import BaseModal from '../shared-components/base-modal.svelte';
 | 
				
			||||||
  import ImmichLogo from '../shared-components/immich-logo.svelte';
 | 
					 | 
				
			||||||
  import UserAvatar from '../shared-components/user-avatar.svelte';
 | 
					  import UserAvatar from '../shared-components/user-avatar.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let album: AlbumResponseDto;
 | 
					  export let album: AlbumResponseDto;
 | 
				
			||||||
@ -55,14 +54,7 @@
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<BaseModal on:close={() => dispatch('close')}>
 | 
					<BaseModal id="user-selection-modal" title="Invite to album" showLogo on:close>
 | 
				
			||||||
  <svelte:fragment slot="title">
 | 
					 | 
				
			||||||
    <span class="flex place-items-center gap-2">
 | 
					 | 
				
			||||||
      <ImmichLogo noText={true} width={36} />
 | 
					 | 
				
			||||||
      <p class="font-medium">Invite to album</p>
 | 
					 | 
				
			||||||
    </span>
 | 
					 | 
				
			||||||
  </svelte:fragment>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  {#if selectedUsers.length > 0}
 | 
					  {#if selectedUsers.length > 0}
 | 
				
			||||||
    <div class="mb-2 flex flex-wrap place-items-center gap-4 overflow-x-auto px-5 py-2 sticky">
 | 
					    <div class="mb-2 flex flex-wrap place-items-center gap-4 overflow-x-auto px-5 py-2 sticky">
 | 
				
			||||||
      <p class="font-medium">To</p>
 | 
					      <p class="font-medium">To</p>
 | 
				
			||||||
 | 
				
			|||||||
@ -737,7 +737,6 @@
 | 
				
			|||||||
        on:newAlbum={({ detail }) => handleAddToNewAlbum(detail)}
 | 
					        on:newAlbum={({ detail }) => handleAddToNewAlbum(detail)}
 | 
				
			||||||
        on:album={({ detail }) => handleAddToAlbum(detail)}
 | 
					        on:album={({ detail }) => handleAddToAlbum(detail)}
 | 
				
			||||||
        on:close={() => (isShowAlbumPicker = false)}
 | 
					        on:close={() => (isShowAlbumPicker = false)}
 | 
				
			||||||
        on:escape={() => (isShowAlbumPicker = false)}
 | 
					 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    {/if}
 | 
					    {/if}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -751,19 +750,11 @@
 | 
				
			|||||||
    {/if}
 | 
					    {/if}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {#if isShowProfileImageCrop}
 | 
					    {#if isShowProfileImageCrop}
 | 
				
			||||||
      <ProfileImageCropper
 | 
					      <ProfileImageCropper {asset} on:close={() => (isShowProfileImageCrop = false)} />
 | 
				
			||||||
        {asset}
 | 
					 | 
				
			||||||
        on:close={() => (isShowProfileImageCrop = false)}
 | 
					 | 
				
			||||||
        on:escape={() => (isShowProfileImageCrop = false)}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    {/if}
 | 
					    {/if}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {#if isShowShareModal}
 | 
					    {#if isShowShareModal}
 | 
				
			||||||
      <CreateSharedLinkModal
 | 
					      <CreateSharedLinkModal assetIds={[asset.id]} on:close={() => (isShowShareModal = false)} />
 | 
				
			||||||
        assetIds={[asset.id]}
 | 
					 | 
				
			||||||
        on:close={() => (isShowShareModal = false)}
 | 
					 | 
				
			||||||
        on:escape={() => (isShowShareModal = false)}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    {/if}
 | 
					    {/if}
 | 
				
			||||||
  </section>
 | 
					  </section>
 | 
				
			||||||
</FocusTrap>
 | 
					</FocusTrap>
 | 
				
			||||||
 | 
				
			|||||||
@ -2,26 +2,14 @@
 | 
				
			|||||||
  import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
 | 
					  import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
 | 
				
			||||||
  import CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte';
 | 
					  import CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte';
 | 
				
			||||||
  import { mdiShareVariantOutline } from '@mdi/js';
 | 
					  import { mdiShareVariantOutline } from '@mdi/js';
 | 
				
			||||||
  import { createEventDispatcher } from 'svelte';
 | 
					 | 
				
			||||||
  import { getAssetControlContext } from '../asset-select-control-bar.svelte';
 | 
					  import { getAssetControlContext } from '../asset-select-control-bar.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let showModal = false;
 | 
					  let showModal = false;
 | 
				
			||||||
  const dispatch = createEventDispatcher<{
 | 
					 | 
				
			||||||
    escape: void;
 | 
					 | 
				
			||||||
  }>();
 | 
					 | 
				
			||||||
  const { getAssets } = getAssetControlContext();
 | 
					  const { getAssets } = getAssetControlContext();
 | 
				
			||||||
  const escape = () => {
 | 
					 | 
				
			||||||
    dispatch('escape');
 | 
					 | 
				
			||||||
    showModal = false;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<CircleIconButton title="Share" icon={mdiShareVariantOutline} on:click={() => (showModal = true)} />
 | 
					<CircleIconButton title="Share" icon={mdiShareVariantOutline} on:click={() => (showModal = true)} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{#if showModal}
 | 
					{#if showModal}
 | 
				
			||||||
  <CreateSharedLinkModal
 | 
					  <CreateSharedLinkModal assetIds={[...getAssets()].map(({ id }) => id)} on:close={() => (showModal = false)} />
 | 
				
			||||||
    assetIds={[...getAssets()].map(({ id }) => id)}
 | 
					 | 
				
			||||||
    on:close={() => (showModal = false)}
 | 
					 | 
				
			||||||
    on:escape={escape}
 | 
					 | 
				
			||||||
  />
 | 
					 | 
				
			||||||
{/if}
 | 
					{/if}
 | 
				
			||||||
 | 
				
			|||||||
@ -43,17 +43,16 @@
 | 
				
			|||||||
  const handleNew = () => {
 | 
					  const handleNew = () => {
 | 
				
			||||||
    dispatch('newAlbum', search.length > 0 ? search : '');
 | 
					    dispatch('newAlbum', search.length > 0 ? search : '');
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getTitle = () => {
 | 
				
			||||||
 | 
					    if (shared) {
 | 
				
			||||||
 | 
					      return 'Add to shared album';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 'Add to album';
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<BaseModal on:close on:escape>
 | 
					<BaseModal id="album-selection-modal" title={getTitle()} on:close>
 | 
				
			||||||
  <svelte:fragment slot="title">
 | 
					 | 
				
			||||||
    <span class="flex place-items-center gap-2">
 | 
					 | 
				
			||||||
      <p class="font-medium">
 | 
					 | 
				
			||||||
        Add to {shared ? 'Shared ' : ''}Album
 | 
					 | 
				
			||||||
      </p>
 | 
					 | 
				
			||||||
    </span>
 | 
					 | 
				
			||||||
  </svelte:fragment>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <div class="mb-2 flex max-h-[400px] flex-col">
 | 
					  <div class="mb-2 flex max-h-[400px] flex-col">
 | 
				
			||||||
    {#if loading}
 | 
					    {#if loading}
 | 
				
			||||||
      {#each { length: 3 } as _}
 | 
					      {#each { length: 3 } as _}
 | 
				
			||||||
@ -69,11 +68,9 @@
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      {/each}
 | 
					      {/each}
 | 
				
			||||||
    {:else}
 | 
					    {:else}
 | 
				
			||||||
      <!-- svelte-ignore a11y-autofocus -->
 | 
					 | 
				
			||||||
      <input
 | 
					      <input
 | 
				
			||||||
        class="border-b-4 border-immich-bg bg-immich-bg px-6 py-2 text-2xl focus:border-immich-primary dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:focus:border-immich-dark-primary"
 | 
					        class="border-b-4 border-immich-bg bg-immich-bg px-6 py-2 text-2xl focus:border-immich-primary dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:focus:border-immich-dark-primary"
 | 
				
			||||||
        placeholder="Search"
 | 
					        placeholder="Search"
 | 
				
			||||||
        autofocus
 | 
					 | 
				
			||||||
        bind:value={search}
 | 
					        bind:value={search}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      <div class="immich-scrollbar overflow-y-auto">
 | 
					      <div class="immich-scrollbar overflow-y-auto">
 | 
				
			||||||
 | 
				
			|||||||
@ -7,12 +7,26 @@
 | 
				
			|||||||
  import { clickOutside } from '$lib/utils/click-outside';
 | 
					  import { clickOutside } from '$lib/utils/click-outside';
 | 
				
			||||||
  import { mdiClose } from '@mdi/js';
 | 
					  import { mdiClose } from '@mdi/js';
 | 
				
			||||||
  import FocusTrap from '$lib/components/shared-components/focus-trap.svelte';
 | 
					  import FocusTrap from '$lib/components/shared-components/focus-trap.svelte';
 | 
				
			||||||
 | 
					  import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
 | 
				
			||||||
 | 
					  import Icon from '$lib/components/elements/icon.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const dispatch = createEventDispatcher<{
 | 
					  const dispatch = createEventDispatcher<{
 | 
				
			||||||
    escape: void;
 | 
					 | 
				
			||||||
    close: void;
 | 
					    close: void;
 | 
				
			||||||
  }>();
 | 
					  }>();
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Unique identifier for the modal.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  export let id: string;
 | 
				
			||||||
 | 
					  export let title: string;
 | 
				
			||||||
  export let zIndex = 9999;
 | 
					  export let zIndex = 9999;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * If true, the logo will be displayed next to the modal title.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  export let showLogo = false;
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Optional icon to display next to the modal title, if `showLogo` is false.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  export let icon: string | undefined = undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onMount(() => {
 | 
					  onMount(() => {
 | 
				
			||||||
    if (browser) {
 | 
					    if (browser) {
 | 
				
			||||||
@ -36,7 +50,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<FocusTrap>
 | 
					<FocusTrap>
 | 
				
			||||||
  <div
 | 
					  <div
 | 
				
			||||||
    id="immich-modal"
 | 
					    aria-modal="true"
 | 
				
			||||||
 | 
					    aria-labelledby={`${id}-title`}
 | 
				
			||||||
    style:z-index={zIndex}
 | 
					    style:z-index={zIndex}
 | 
				
			||||||
    transition:fade={{ duration: 100, easing: quintOut }}
 | 
					    transition:fade={{ duration: 100, easing: quintOut }}
 | 
				
			||||||
    class="fixed left-0 top-0 flex h-full w-full place-content-center place-items-center overflow-hidden bg-black/50"
 | 
					    class="fixed left-0 top-0 flex h-full w-full place-content-center place-items-center overflow-hidden bg-black/50"
 | 
				
			||||||
@ -44,16 +59,23 @@
 | 
				
			|||||||
    <div
 | 
					    <div
 | 
				
			||||||
      use:clickOutside={{
 | 
					      use:clickOutside={{
 | 
				
			||||||
        onOutclick: () => dispatch('close'),
 | 
					        onOutclick: () => dispatch('close'),
 | 
				
			||||||
        onEscape: () => dispatch('escape'),
 | 
					        onEscape: () => dispatch('close'),
 | 
				
			||||||
      }}
 | 
					      }}
 | 
				
			||||||
      class="max-h-[800px] min-h-[200px] w-[450px] overflow-y-auto rounded-lg bg-immich-bg shadow-md dark:bg-immich-dark-gray dark:text-immich-dark-fg immich-scrollbar"
 | 
					      class="max-h-[800px] min-h-[200px] w-[450px] overflow-y-auto rounded-lg bg-immich-bg shadow-md dark:bg-immich-dark-gray dark:text-immich-dark-fg immich-scrollbar"
 | 
				
			||||||
      tabindex="-1"
 | 
					      tabindex="-1"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <div class="flex place-items-center justify-between px-5 py-3">
 | 
					      <div class="flex place-items-center justify-between px-5 py-3">
 | 
				
			||||||
        <div>
 | 
					        <div class="flex items-center">
 | 
				
			||||||
          <slot name="title">
 | 
					          {#if showLogo}
 | 
				
			||||||
            <p>Modal Title</p>
 | 
					            <ImmichLogo noText={true} width={24} />
 | 
				
			||||||
          </slot>
 | 
					            <div class="w-2" />
 | 
				
			||||||
 | 
					          {:else if icon}
 | 
				
			||||||
 | 
					            <Icon path={icon} size={24} ariaHidden={true} class="text-immich-primary dark:text-immich-dark-primary" />
 | 
				
			||||||
 | 
					            <div class="w-2" />
 | 
				
			||||||
 | 
					          {/if}
 | 
				
			||||||
 | 
					          <h1 id={`${id}-title`} class="text-xl font-medium text-immich-primary dark:text-immich-dark-primary mt-1">
 | 
				
			||||||
 | 
					            {title}
 | 
				
			||||||
 | 
					          </h1>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <CircleIconButton on:click={() => dispatch('close')} icon={mdiClose} size={'20'} title="Close" />
 | 
					        <CircleIconButton on:click={() => dispatch('close')} icon={mdiClose} size={'20'} title="Close" />
 | 
				
			||||||
 | 
				
			|||||||
@ -143,20 +143,16 @@
 | 
				
			|||||||
      handleError(error, 'Failed to edit shared link');
 | 
					      handleError(error, 'Failed to edit shared link');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getTitle = () => {
 | 
				
			||||||
 | 
					    if (editingLink) {
 | 
				
			||||||
 | 
					      return 'Edit link';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 'Create link to share';
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<BaseModal on:close={() => dispatch('close')} on:escape={() => dispatch('escape')}>
 | 
					<BaseModal id="create-shared-link-modal" title={getTitle()} icon={mdiLink} on:close>
 | 
				
			||||||
  <svelte:fragment slot="title">
 | 
					 | 
				
			||||||
    <span class="flex place-items-center gap-2">
 | 
					 | 
				
			||||||
      <Icon path={mdiLink} size={24} />
 | 
					 | 
				
			||||||
      {#if editingLink}
 | 
					 | 
				
			||||||
        <p class="font-medium text-immich-fg dark:text-immich-dark-fg">Edit link</p>
 | 
					 | 
				
			||||||
      {:else}
 | 
					 | 
				
			||||||
        <p class="font-medium text-immich-fg dark:text-immich-dark-fg">Create link to share</p>
 | 
					 | 
				
			||||||
      {/if}
 | 
					 | 
				
			||||||
    </span>
 | 
					 | 
				
			||||||
  </svelte:fragment>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <section class="mx-6 mb-6">
 | 
					  <section class="mx-6 mb-6">
 | 
				
			||||||
    {#if shareType === SharedLinkType.Album}
 | 
					    {#if shareType === SharedLinkType.Album}
 | 
				
			||||||
      {#if !editingLink}
 | 
					      {#if !editingLink}
 | 
				
			||||||
 | 
				
			|||||||
@ -71,12 +71,7 @@
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<BaseModal on:close on:escape>
 | 
					<BaseModal id="profile-image-cropper" title="Set profile picture" on:close>
 | 
				
			||||||
  <svelte:fragment slot="title">
 | 
					 | 
				
			||||||
    <span class="flex place-items-center gap-2">
 | 
					 | 
				
			||||||
      <p class="font-medium">Set profile picture</p>
 | 
					 | 
				
			||||||
    </span>
 | 
					 | 
				
			||||||
  </svelte:fragment>
 | 
					 | 
				
			||||||
  <div class="flex place-items-center items-center justify-center">
 | 
					  <div class="flex place-items-center items-center justify-center">
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
      class="relative flex aspect-square w-1/2 overflow-hidden rounded-full border-4 border-immich-primary bg-immich-dark-primary dark:border-immich-dark-primary dark:bg-immich-primary"
 | 
					      class="relative flex aspect-square w-1/2 overflow-hidden rounded-full border-4 border-immich-primary bg-immich-dark-primary dark:border-immich-dark-primary dark:bg-immich-primary"
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,6 @@
 | 
				
			|||||||
  import { createEventDispatcher, onMount } from 'svelte';
 | 
					  import { createEventDispatcher, onMount } from 'svelte';
 | 
				
			||||||
  import Button from '../elements/buttons/button.svelte';
 | 
					  import Button from '../elements/buttons/button.svelte';
 | 
				
			||||||
  import BaseModal from '../shared-components/base-modal.svelte';
 | 
					  import BaseModal from '../shared-components/base-modal.svelte';
 | 
				
			||||||
  import ImmichLogo from '../shared-components/immich-logo.svelte';
 | 
					 | 
				
			||||||
  import UserAvatar from '../shared-components/user-avatar.svelte';
 | 
					  import UserAvatar from '../shared-components/user-avatar.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let user: UserResponseDto;
 | 
					  export let user: UserResponseDto;
 | 
				
			||||||
@ -33,14 +32,7 @@
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<BaseModal on:close={() => dispatch('close')}>
 | 
					<BaseModal id="partner-selection-modal" title="Add partner" showLogo on:close>
 | 
				
			||||||
  <svelte:fragment slot="title">
 | 
					 | 
				
			||||||
    <span class="flex place-items-center gap-2">
 | 
					 | 
				
			||||||
      <ImmichLogo noText width={36} />
 | 
					 | 
				
			||||||
      <p class="font-medium">Add partner</p>
 | 
					 | 
				
			||||||
    </span>
 | 
					 | 
				
			||||||
  </svelte:fragment>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <div class="immich-scrollbar max-h-[300px] overflow-y-auto">
 | 
					  <div class="immich-scrollbar max-h-[300px] overflow-y-auto">
 | 
				
			||||||
    {#if availableUsers.length > 0}
 | 
					    {#if availableUsers.length > 0}
 | 
				
			||||||
      {#each availableUsers as user}
 | 
					      {#each availableUsers as user}
 | 
				
			||||||
 | 
				
			|||||||
@ -53,7 +53,7 @@
 | 
				
			|||||||
    assets={$selectedAssets}
 | 
					    assets={$selectedAssets}
 | 
				
			||||||
    clearSelect={() => assetInteractionStore.clearMultiselect()}
 | 
					    clearSelect={() => assetInteractionStore.clearMultiselect()}
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <CreateSharedLink on:escape={() => (handleEscapeKey = true)} />
 | 
					    <CreateSharedLink />
 | 
				
			||||||
    <SelectAllAssets {assetStore} {assetInteractionStore} />
 | 
					    <SelectAllAssets {assetStore} {assetInteractionStore} />
 | 
				
			||||||
    <AssetSelectContextMenu icon={mdiPlus} title="Add to...">
 | 
					    <AssetSelectContextMenu icon={mdiPlus} title="Add to...">
 | 
				
			||||||
      <AddToAlbum />
 | 
					      <AddToAlbum />
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user