individual-shared-viewer.svelte 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <script lang="ts">
  2. import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
  3. import { api, AssetResponseDto, SharedLinkResponseDto } from '@api';
  4. import ControlAppBar from '../shared-components/control-app-bar.svelte';
  5. import { goto } from '$app/navigation';
  6. import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
  7. import FileImagePlusOutline from 'svelte-material-icons/FileImagePlusOutline.svelte';
  8. import FolderDownloadOutline from 'svelte-material-icons/FolderDownloadOutline.svelte';
  9. import { openFileUploadDialog } from '$lib/utils/file-uploader';
  10. import { bulkDownload } from '$lib/utils/asset-utils';
  11. import Close from 'svelte-material-icons/Close.svelte';
  12. import CloudDownloadOutline from 'svelte-material-icons/CloudDownloadOutline.svelte';
  13. import GalleryViewer from '../shared-components/gallery-viewer/gallery-viewer.svelte';
  14. import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
  15. import ImmichLogo from '../shared-components/immich-logo.svelte';
  16. import {
  17. notificationController,
  18. NotificationType
  19. } from '../shared-components/notification/notification';
  20. import { locale } from '$lib/stores/preferences.store';
  21. export let sharedLink: SharedLinkResponseDto;
  22. export let isOwned: boolean;
  23. let assets = sharedLink.assets;
  24. let selectedAssets: Set<AssetResponseDto> = new Set();
  25. $: isMultiSelectionMode = selectedAssets.size > 0;
  26. const clearMultiSelectAssetAssetHandler = () => {
  27. selectedAssets = new Set();
  28. };
  29. const downloadAssets = async (isAll: boolean) => {
  30. await bulkDownload(
  31. 'immich-shared',
  32. isAll ? assets : Array.from(selectedAssets),
  33. () => {
  34. isMultiSelectionMode = false;
  35. clearMultiSelectAssetAssetHandler();
  36. },
  37. sharedLink?.key
  38. );
  39. };
  40. const handleUploadAssets = async () => {
  41. try {
  42. const results = await openFileUploadDialog(undefined, sharedLink?.key);
  43. const assetIds = results.filter((id) => !!id) as string[];
  44. await api.assetApi.addAssetsToSharedLink(
  45. {
  46. assetIds
  47. },
  48. sharedLink?.key
  49. );
  50. notificationController.show({
  51. message: `Successfully add ${assetIds.length} to the shared link`,
  52. type: NotificationType.Info
  53. });
  54. } catch (e) {
  55. console.error('handleUploadAssets', e);
  56. }
  57. };
  58. const handleRemoveAssetsFromSharedLink = async () => {
  59. if (window.confirm('Do you want to remove selected assets from the shared link?')) {
  60. await api.assetApi.removeAssetsFromSharedLink(
  61. {
  62. assetIds: assets.filter((a) => !selectedAssets.has(a)).map((a) => a.id)
  63. },
  64. sharedLink?.key
  65. );
  66. assets = assets.filter((a) => !selectedAssets.has(a));
  67. clearMultiSelectAssetAssetHandler();
  68. }
  69. };
  70. </script>
  71. <section class="bg-immich-bg dark:bg-immich-dark-bg">
  72. {#if isMultiSelectionMode}
  73. <ControlAppBar
  74. on:close-button-click={clearMultiSelectAssetAssetHandler}
  75. backIcon={Close}
  76. tailwindClasses={'bg-white shadow-md'}
  77. >
  78. <svelte:fragment slot="leading">
  79. <p class="font-medium text-immich-primary dark:text-immich-dark-primary">
  80. Selected {selectedAssets.size.toLocaleString($locale)}
  81. </p>
  82. </svelte:fragment>
  83. <svelte:fragment slot="trailing">
  84. <CircleIconButton
  85. title="Download"
  86. on:click={() => downloadAssets(false)}
  87. logo={CloudDownloadOutline}
  88. />
  89. {#if isOwned}
  90. <CircleIconButton
  91. title="Remove from album"
  92. on:click={handleRemoveAssetsFromSharedLink}
  93. logo={DeleteOutline}
  94. />
  95. {/if}
  96. </svelte:fragment>
  97. </ControlAppBar>
  98. {:else}
  99. <ControlAppBar
  100. on:close-button-click={() => goto('/photos')}
  101. backIcon={ArrowLeft}
  102. showBackButton={false}
  103. >
  104. <svelte:fragment slot="leading">
  105. <a
  106. data-sveltekit-preload-data="hover"
  107. class="flex gap-2 place-items-center hover:cursor-pointer ml-6"
  108. href="https://immich.app"
  109. >
  110. <ImmichLogo height="30" width="30" />
  111. <h1 class="font-immich-title text-lg text-immich-primary dark:text-immich-dark-primary">
  112. IMMICH
  113. </h1>
  114. </a>
  115. </svelte:fragment>
  116. <svelte:fragment slot="trailing">
  117. {#if sharedLink?.allowUpload}
  118. <CircleIconButton
  119. title="Add Photos"
  120. on:click={handleUploadAssets}
  121. logo={FileImagePlusOutline}
  122. />
  123. {/if}
  124. {#if sharedLink?.allowDownload}
  125. <CircleIconButton
  126. title="Download"
  127. on:click={() => downloadAssets(true)}
  128. logo={FolderDownloadOutline}
  129. />
  130. {/if}
  131. </svelte:fragment>
  132. </ControlAppBar>
  133. {/if}
  134. <section class="flex flex-col my-[160px] px-6 sm:px-12 md:px-24 lg:px-40">
  135. <GalleryViewer {assets} {sharedLink} bind:selectedAssets viewFrom="shared-link-page" />
  136. </section>
  137. </section>