mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	feat(web): improved action bar actions (#2553)
* feat(web): improved action bar actions * Update web/src/lib/components/photos-page/actions/delete-assets.svelte Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> * update archive and favorite actions * feat: add un archive/favorite on associated pages * fix favorite action + use isAllArchived for photos * remove unneeded unarchive check --------- Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com>
This commit is contained in:
		| @@ -24,7 +24,7 @@ | ||||
| 	import ShareVariantOutline from 'svelte-material-icons/ShareVariantOutline.svelte'; | ||||
| 	import Button from '../elements/buttons/button.svelte'; | ||||
| 	import CircleIconButton from '../elements/buttons/circle-icon-button.svelte'; | ||||
| 	import DownloadFiles from '../photos-page/actions/download-files.svelte'; | ||||
| 	import DownloadAction from '../photos-page/actions/download-action.svelte'; | ||||
| 	import RemoveFromAlbum from '../photos-page/actions/remove-from-album.svelte'; | ||||
| 	import AssetSelectControlBar from '../photos-page/asset-select-control-bar.svelte'; | ||||
| 	import CircleAvatar from '../shared-components/circle-avatar.svelte'; | ||||
| @@ -338,7 +338,7 @@ | ||||
| 			assets={multiSelectAsset} | ||||
| 			clearSelect={() => (multiSelectAsset = new Set())} | ||||
| 		> | ||||
| 			<DownloadFiles filename={album.albumName} sharedLinkKey={sharedLink?.key} /> | ||||
| 			<DownloadAction filename={album.albumName} sharedLinkKey={sharedLink?.key} /> | ||||
| 			{#if isOwned} | ||||
| 				<RemoveFromAlbum bind:album /> | ||||
| 			{/if} | ||||
|   | ||||
| @@ -15,8 +15,6 @@ | ||||
| 	import ContentCopy from 'svelte-material-icons/ContentCopy.svelte'; | ||||
| 	import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte'; | ||||
| 	import MotionPauseOutline from 'svelte-material-icons/MotionPauseOutline.svelte'; | ||||
| 	import ArchiveArrowDownOutline from 'svelte-material-icons/ArchiveArrowDownOutline.svelte'; | ||||
| 	import ArchiveArrowUpOutline from 'svelte-material-icons/ArchiveArrowUpOutline.svelte'; | ||||
|  | ||||
| 	import { page } from '$app/stores'; | ||||
| 	import { AssetResponseDto } from '../../../api'; | ||||
| @@ -52,15 +50,6 @@ | ||||
| 		<CircleIconButton isOpacity={true} logo={ArrowLeft} on:click={() => dispatch('goBack')} /> | ||||
| 	</div> | ||||
| 	<div class="text-white flex gap-2 justify-end w-[calc(100%-3rem)] overflow-hidden"> | ||||
| 		{#if isOwner} | ||||
| 			<CircleIconButton | ||||
| 				isOpacity={true} | ||||
| 				logo={asset.isArchived ? ArchiveArrowUpOutline : ArchiveArrowDownOutline} | ||||
| 				title={asset.isArchived ? 'Unarchive' : 'Archive'} | ||||
| 				on:click={() => dispatch('toggleArchive')} | ||||
| 			/> | ||||
| 		{/if} | ||||
|  | ||||
| 		{#if showMotionPlayButton} | ||||
| 			{#if isMotionPhotoPlaying} | ||||
| 				<CircleIconButton | ||||
| @@ -134,6 +123,13 @@ | ||||
| 								on:click={() => onMenuClick('addToSharedAlbum')} | ||||
| 								text="Add to Shared Album" | ||||
| 							/> | ||||
|  | ||||
| 							{#if isOwner} | ||||
| 								<MenuOption | ||||
| 									on:click={() => dispatch('toggleArchive')} | ||||
| 									text={asset.isArchived ? 'Unarchive' : 'Archive'} | ||||
| 								/> | ||||
| 							{/if} | ||||
| 						</ContextMenu> | ||||
| 					{/if} | ||||
| 				</CircleIconButton> | ||||
|   | ||||
| @@ -0,0 +1,51 @@ | ||||
| <script lang="ts"> | ||||
| 	import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; | ||||
| 	import { | ||||
| 		NotificationType, | ||||
| 		notificationController | ||||
| 	} from '$lib/components/shared-components/notification/notification'; | ||||
| 	import { api } from '@api'; | ||||
| 	import ArchiveArrowDownOutline from 'svelte-material-icons/ArchiveArrowDownOutline.svelte'; | ||||
| 	import ArchiveArrowUpOutline from 'svelte-material-icons/ArchiveArrowUpOutline.svelte'; | ||||
| 	import MenuOption from '../../shared-components/context-menu/menu-option.svelte'; | ||||
| 	import { OnAssetArchive, getAssetControlContext } from '../asset-select-control-bar.svelte'; | ||||
|  | ||||
| 	export let onAssetArchive: OnAssetArchive = (asset, isArchived) => { | ||||
| 		asset.isArchived = isArchived; | ||||
| 	}; | ||||
|  | ||||
| 	export let menuItem = false; | ||||
| 	export let unarchive = false; | ||||
|  | ||||
| 	$: text = unarchive ? 'Unarchive' : 'Archive'; | ||||
| 	$: logo = unarchive ? ArchiveArrowUpOutline : ArchiveArrowDownOutline; | ||||
|  | ||||
| 	const { getAssets, clearSelect } = getAssetControlContext(); | ||||
|  | ||||
| 	const handleArchive = async () => { | ||||
| 		const isArchived = !unarchive; | ||||
| 		let cnt = 0; | ||||
|  | ||||
| 		for (const asset of getAssets()) { | ||||
| 			if (asset.isArchived !== isArchived) { | ||||
| 				api.assetApi.updateAsset(asset.id, { isArchived }); | ||||
|  | ||||
| 				onAssetArchive(asset, isArchived); | ||||
| 				cnt = cnt + 1; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		notificationController.show({ | ||||
| 			message: `${isArchived ? 'Archived' : 'Unarchived'} ${cnt}`, | ||||
| 			type: NotificationType.Info | ||||
| 		}); | ||||
|  | ||||
| 		clearSelect(); | ||||
| 	}; | ||||
| </script> | ||||
|  | ||||
| {#if menuItem} | ||||
| 	<MenuOption {text} on:click={handleArchive} /> | ||||
| {:else} | ||||
| 	<CircleIconButton title={text} {logo} on:click={handleArchive} /> | ||||
| {/if} | ||||
| @@ -7,39 +7,47 @@ | ||||
| 	import { api } from '@api'; | ||||
| 	import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte'; | ||||
| 	import { OnAssetDelete, getAssetControlContext } from '../asset-select-control-bar.svelte'; | ||||
| 	import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte'; | ||||
| 	import { handleError } from '../../../utils/handle-error'; | ||||
|  | ||||
| 	export let onAssetDelete: OnAssetDelete; | ||||
| 	const { getAssets, clearSelect } = getAssetControlContext(); | ||||
|  | ||||
| 	const deleteSelectedAssetHandler = async () => { | ||||
| 	let confirm = false; | ||||
|  | ||||
| 	const handleDelete = async () => { | ||||
| 		try { | ||||
| 			if ( | ||||
| 				window.confirm( | ||||
| 					`Caution! Are you sure you want to delete ${ | ||||
| 						getAssets().size | ||||
| 					} assets? This step also deletes assets in the album(s) to which they belong. You can not undo this action!` | ||||
| 				) | ||||
| 			) { | ||||
| 				const { data: deletedAssets } = await api.assetApi.deleteAsset({ | ||||
| 					ids: Array.from(getAssets()).map((a) => a.id) | ||||
| 				}); | ||||
| 			let count = 0; | ||||
|  | ||||
| 				for (const asset of deletedAssets) { | ||||
| 					if (asset.status === 'SUCCESS') { | ||||
| 						onAssetDelete(asset.id); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				clearSelect(); | ||||
| 			} | ||||
| 		} catch (e) { | ||||
| 			notificationController.show({ | ||||
| 				type: NotificationType.Error, | ||||
| 				message: 'Error deleting assets, check console for more details' | ||||
| 			const { data: deletedAssets } = await api.assetApi.deleteAsset({ | ||||
| 				ids: Array.from(getAssets()).map((a) => a.id) | ||||
| 			}); | ||||
| 			console.error('Error deleteSelectedAssetHandler', e); | ||||
|  | ||||
| 			for (const asset of deletedAssets) { | ||||
| 				if (asset.status === 'SUCCESS') { | ||||
| 					onAssetDelete(asset.id); | ||||
| 					count++; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			notificationController.show({ message: `Deleted ${count}`, type: NotificationType.Info }); | ||||
|  | ||||
| 			clearSelect(); | ||||
| 		} catch (e) { | ||||
| 			handleError(e, 'Error deleting assets'); | ||||
| 		} | ||||
| 	}; | ||||
| </script> | ||||
|  | ||||
| <CircleIconButton title="Delete" logo={DeleteOutline} on:click={deleteSelectedAssetHandler} /> | ||||
| <CircleIconButton title="Delete" logo={DeleteOutline} on:click={() => (confirm = true)} /> | ||||
|  | ||||
| {#if confirm} | ||||
| 	<ConfirmDialogue | ||||
| 		prompt="Are you sure you want to delete {getAssets() | ||||
| 			.size} assets? This step also deletes assets in the album(s) to which they belong. You can not undo this action!" | ||||
| 		title="Delete assets?" | ||||
| 		confirmText="Delete" | ||||
| 		on:confirm={handleDelete} | ||||
| 		on:cancel={() => (confirm = false)} | ||||
| 	/> | ||||
| {/if} | ||||
|   | ||||
| @@ -2,10 +2,12 @@ | ||||
| 	import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; | ||||
| 	import { bulkDownload } from '$lib/utils/asset-utils'; | ||||
| 	import CloudDownloadOutline from 'svelte-material-icons/CloudDownloadOutline.svelte'; | ||||
| 	import MenuOption from '../../shared-components/context-menu/menu-option.svelte'; | ||||
| 	import { getAssetControlContext } from '../asset-select-control-bar.svelte'; | ||||
| 
 | ||||
| 	export let filename = 'immich'; | ||||
| 	export let sharedLinkKey: string | undefined = undefined; | ||||
| 	export let menuItem = false; | ||||
| 
 | ||||
| 	const { getAssets, clearSelect } = getAssetControlContext(); | ||||
| 
 | ||||
| @@ -14,4 +16,8 @@ | ||||
| 	}; | ||||
| </script> | ||||
| 
 | ||||
| <CircleIconButton title="Download" logo={CloudDownloadOutline} on:click={handleDownloadFiles} /> | ||||
| {#if menuItem} | ||||
| 	<MenuOption text="Download" on:click={handleDownloadFiles} /> | ||||
| {:else} | ||||
| 	<CircleIconButton title="Download" logo={CloudDownloadOutline} on:click={handleDownloadFiles} /> | ||||
| {/if} | ||||
| @@ -0,0 +1,50 @@ | ||||
| <script lang="ts"> | ||||
| 	import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; | ||||
| 	import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte'; | ||||
| 	import { | ||||
| 		NotificationType, | ||||
| 		notificationController | ||||
| 	} from '$lib/components/shared-components/notification/notification'; | ||||
| 	import { api } from '@api'; | ||||
| 	import HeartMinusOutline from 'svelte-material-icons/HeartMinusOutline.svelte'; | ||||
| 	import HeartOutline from 'svelte-material-icons/HeartOutline.svelte'; | ||||
| 	import { OnAssetFavorite, getAssetControlContext } from '../asset-select-control-bar.svelte'; | ||||
|  | ||||
| 	export let onAssetFavorite: OnAssetFavorite = (asset, isFavorite) => { | ||||
| 		asset.isFavorite = isFavorite; | ||||
| 	}; | ||||
|  | ||||
| 	export let menuItem = false; | ||||
| 	export let removeFavorite: boolean; | ||||
|  | ||||
| 	$: text = removeFavorite ? 'Remove from Favorites' : 'Favorite'; | ||||
| 	$: logo = removeFavorite ? HeartMinusOutline : HeartOutline; | ||||
|  | ||||
| 	const { getAssets, clearSelect } = getAssetControlContext(); | ||||
|  | ||||
| 	const handleFavorite = () => { | ||||
| 		const isFavorite = !removeFavorite; | ||||
|  | ||||
| 		let cnt = 0; | ||||
| 		for (const asset of getAssets()) { | ||||
| 			if (asset.isFavorite !== isFavorite) { | ||||
| 				api.assetApi.updateAsset(asset.id, { isFavorite }); | ||||
| 				onAssetFavorite(asset, isFavorite); | ||||
| 				cnt = cnt + 1; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		notificationController.show({ | ||||
| 			message: isFavorite ? `Added ${cnt} to favorites` : `Removed ${cnt} from favorites`, | ||||
| 			type: NotificationType.Info | ||||
| 		}); | ||||
|  | ||||
| 		clearSelect(); | ||||
| 	}; | ||||
| </script> | ||||
|  | ||||
| {#if menuItem} | ||||
| 	<MenuOption {text} on:click={handleFavorite} /> | ||||
| {:else} | ||||
| 	<CircleIconButton title={text} {logo} on:click={handleFavorite} /> | ||||
| {/if} | ||||
| @@ -1,40 +0,0 @@ | ||||
| <script lang="ts"> | ||||
| 	import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; | ||||
| 	import { | ||||
| 		NotificationType, | ||||
| 		notificationController | ||||
| 	} from '$lib/components/shared-components/notification/notification'; | ||||
| 	import { api } from '@api'; | ||||
| 	import ArchiveArrowDownOutline from 'svelte-material-icons/ArchiveArrowDownOutline.svelte'; | ||||
| 	import { OnAssetArchive, getAssetControlContext } from '../asset-select-control-bar.svelte'; | ||||
|  | ||||
| 	export let onAssetArchive: OnAssetArchive = (asset, archive) => { | ||||
| 		asset.isArchived = archive; | ||||
| 	}; | ||||
|  | ||||
| 	const { getAssets, clearSelect } = getAssetControlContext(); | ||||
|  | ||||
| 	const handleArchive = async () => { | ||||
| 		let cnt = 0; | ||||
|  | ||||
| 		for (const asset of getAssets()) { | ||||
| 			if (!asset.isArchived) { | ||||
| 				api.assetApi.updateAsset(asset.id, { | ||||
| 					isArchived: true | ||||
| 				}); | ||||
|  | ||||
| 				onAssetArchive(asset, true); | ||||
| 				cnt = cnt + 1; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		notificationController.show({ | ||||
| 			message: `Archived ${cnt}`, | ||||
| 			type: NotificationType.Info | ||||
| 		}); | ||||
|  | ||||
| 		clearSelect(); | ||||
| 	}; | ||||
| </script> | ||||
|  | ||||
| <CircleIconButton title="Archive" logo={ArchiveArrowDownOutline} on:click={handleArchive} /> | ||||
| @@ -1,36 +0,0 @@ | ||||
| <script lang="ts"> | ||||
| 	import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; | ||||
| 	import { handleError } from '$lib/utils/handle-error'; | ||||
| 	import { api } from '@api'; | ||||
| 	import HeartMinusOutline from 'svelte-material-icons/HeartMinusOutline.svelte'; | ||||
| 	import { getAssetControlContext, OnAssetFavorite } from '../asset-select-control-bar.svelte'; | ||||
|  | ||||
| 	export let onAssetFavorite: OnAssetFavorite = (asset, favorite) => { | ||||
| 		asset.isFavorite = favorite; | ||||
| 	}; | ||||
|  | ||||
| 	const { getAssets, clearSelect } = getAssetControlContext(); | ||||
|  | ||||
| 	const handleRemoveFavorite = async () => { | ||||
| 		for (const asset of getAssets()) { | ||||
| 			try { | ||||
| 				await api.assetApi.updateAsset(asset.id, { | ||||
| 					isFavorite: false | ||||
| 				}); | ||||
| 				onAssetFavorite(asset, false); | ||||
| 			} catch { | ||||
| 				handleError(Error, 'Error updating asset favorite state'); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		clearSelect(); | ||||
| 	}; | ||||
| </script> | ||||
|  | ||||
| <slot {handleRemoveFavorite}> | ||||
| 	<CircleIconButton | ||||
| 		title="Remove Favorite" | ||||
| 		logo={HeartMinusOutline} | ||||
| 		on:click={handleRemoveFavorite} | ||||
| 	/> | ||||
| </slot> | ||||
| @@ -1,39 +0,0 @@ | ||||
| <script lang="ts"> | ||||
| 	import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; | ||||
| 	import { | ||||
| 		NotificationType, | ||||
| 		notificationController | ||||
| 	} from '$lib/components/shared-components/notification/notification'; | ||||
| 	import { api } from '@api'; | ||||
| 	import ArchiveArrowUpOutline from 'svelte-material-icons/ArchiveArrowUpOutline.svelte'; | ||||
| 	import { OnAssetArchive, getAssetControlContext } from '../asset-select-control-bar.svelte'; | ||||
|  | ||||
| 	export let onAssetArchive: OnAssetArchive = (asset, archived) => { | ||||
| 		asset.isArchived = archived; | ||||
| 	}; | ||||
|  | ||||
| 	const { getAssets, clearSelect } = getAssetControlContext(); | ||||
|  | ||||
| 	const handleUnarchive = async () => { | ||||
| 		let cnt = 0; | ||||
| 		for (const asset of getAssets()) { | ||||
| 			if (asset.isArchived) { | ||||
| 				api.assetApi.updateAsset(asset.id, { | ||||
| 					isArchived: false | ||||
| 				}); | ||||
|  | ||||
| 				onAssetArchive(asset, false); | ||||
| 				cnt = cnt + 1; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		notificationController.show({ | ||||
| 			message: `Removed ${cnt} from archive`, | ||||
| 			type: NotificationType.Info | ||||
| 		}); | ||||
|  | ||||
| 		clearSelect(); | ||||
| 	}; | ||||
| </script> | ||||
|  | ||||
| <CircleIconButton title="Unarchive" logo={ArchiveArrowUpOutline} on:click={handleUnarchive} /> | ||||
| @@ -1,41 +0,0 @@ | ||||
| <script lang="ts"> | ||||
| 	import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte'; | ||||
| 	import { | ||||
| 		NotificationType, | ||||
| 		notificationController | ||||
| 	} from '$lib/components/shared-components/notification/notification'; | ||||
| 	import { api } from '@api'; | ||||
| 	import { getMenuContext } from '../asset-select-context-menu.svelte'; | ||||
| 	import { OnAssetFavorite, getAssetControlContext } from '../asset-select-control-bar.svelte'; | ||||
|  | ||||
| 	export let onAssetFavorite: OnAssetFavorite = (asset, favorite) => { | ||||
| 		asset.isFavorite = favorite; | ||||
| 	}; | ||||
|  | ||||
| 	const { getAssets, clearSelect } = getAssetControlContext(); | ||||
| 	const closeMenu = getMenuContext(); | ||||
|  | ||||
| 	const handleAddToFavorites = () => { | ||||
| 		closeMenu(); | ||||
|  | ||||
| 		let cnt = 0; | ||||
| 		for (const asset of getAssets()) { | ||||
| 			if (!asset.isFavorite) { | ||||
| 				api.assetApi.updateAsset(asset.id, { | ||||
| 					isFavorite: true | ||||
| 				}); | ||||
| 				onAssetFavorite(asset, true); | ||||
| 				cnt = cnt + 1; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		notificationController.show({ | ||||
| 			message: `Added ${cnt} to favorites`, | ||||
| 			type: NotificationType.Info | ||||
| 		}); | ||||
|  | ||||
| 		clearSelect(); | ||||
| 	}; | ||||
| </script> | ||||
|  | ||||
| <MenuOption on:click={handleAddToFavorites} text="Add to Favorites" /> | ||||
| @@ -1,19 +0,0 @@ | ||||
| <script lang="ts"> | ||||
| 	import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte'; | ||||
| 	import RemoveFavorite from '../actions/remove-favorite.svelte'; | ||||
| 	import { getMenuContext } from '../asset-select-context-menu.svelte'; | ||||
| 	import { OnAssetFavorite } from '../asset-select-control-bar.svelte'; | ||||
|  | ||||
| 	export let onAssetFavorite: OnAssetFavorite | undefined = undefined; | ||||
| 	const closeMenu = getMenuContext(); | ||||
| </script> | ||||
|  | ||||
| <RemoveFavorite let:handleRemoveFavorite {onAssetFavorite}> | ||||
| 	<MenuOption | ||||
| 		on:click={() => { | ||||
| 			closeMenu(); | ||||
| 			handleRemoveFavorite(); | ||||
| 		}} | ||||
| 		text="Remove from favorites" | ||||
| 	/> | ||||
| </RemoveFavorite> | ||||
| @@ -7,7 +7,7 @@ | ||||
| 	import FileImagePlusOutline from 'svelte-material-icons/FileImagePlusOutline.svelte'; | ||||
| 	import FolderDownloadOutline from 'svelte-material-icons/FolderDownloadOutline.svelte'; | ||||
| 	import CircleIconButton from '../elements/buttons/circle-icon-button.svelte'; | ||||
| 	import DownloadFiles from '../photos-page/actions/download-files.svelte'; | ||||
| 	import DownloadAction from '../photos-page/actions/download-action.svelte'; | ||||
| 	import RemoveFromSharedLink from '../photos-page/actions/remove-from-shared-link.svelte'; | ||||
| 	import AssetSelectControlBar from '../photos-page/asset-select-control-bar.svelte'; | ||||
| 	import ControlAppBar from '../shared-components/control-app-bar.svelte'; | ||||
| @@ -60,7 +60,7 @@ | ||||
| <section class="bg-immich-bg dark:bg-immich-dark-bg"> | ||||
| 	{#if isMultiSelectionMode} | ||||
| 		<AssetSelectControlBar assets={selectedAssets} clearSelect={clearMultiSelectAssetAssetHandler}> | ||||
| 			<DownloadFiles filename="immich-shared" sharedLinkKey={sharedLink.key} /> | ||||
| 			<DownloadAction filename="immich-shared" sharedLinkKey={sharedLink.key} /> | ||||
| 			{#if isOwned} | ||||
| 				<RemoveFromSharedLink bind:sharedLink allAssets={assets} /> | ||||
| 			{/if} | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
| <section | ||||
| 	in:fade={{ duration: 100 }} | ||||
| 	out:fade={{ duration: 100 }} | ||||
| 	class="absolute left-0 top-0 w-full h-full bg-black/40 z-[990] flex place-items-center place-content-center" | ||||
| 	class="fixed left-0 top-0 w-screen h-screen bg-black/40 z-[990] flex place-items-center place-content-center" | ||||
| > | ||||
| 	<div class="z-[9999]" use:clickOutside on:outclick={() => dispatch('clickOutside')}> | ||||
| 		<slot /> | ||||
|   | ||||
| @@ -1,19 +1,20 @@ | ||||
| <script lang="ts"> | ||||
| 	import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte'; | ||||
| 	import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte'; | ||||
| 	import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte'; | ||||
| 	import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte'; | ||||
| 	import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte'; | ||||
| 	import DownloadFiles from '$lib/components/photos-page/actions/download-files.svelte'; | ||||
| 	import RemoveFromArchive from '$lib/components/photos-page/actions/remove-from-archive.svelte'; | ||||
| 	import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte'; | ||||
| 	import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte'; | ||||
| 	import AssetSelectContextMenu from '$lib/components/photos-page/asset-select-context-menu.svelte'; | ||||
| 	import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte'; | ||||
| 	import OptionAddToAlbum from '$lib/components/photos-page/menu-options/option-add-to-album.svelte'; | ||||
| 	import OptionAddToFavorites from '$lib/components/photos-page/menu-options/option-add-to-favorites.svelte'; | ||||
| 	import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte'; | ||||
| 	import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte'; | ||||
| 	import { archivedAsset } from '$lib/stores/archived-asset.store'; | ||||
| 	import { handleError } from '$lib/utils/handle-error'; | ||||
| 	import { api, AssetResponseDto } from '@api'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import DotsVertical from 'svelte-material-icons/DotsVertical.svelte'; | ||||
| 	import Plus from 'svelte-material-icons/Plus.svelte'; | ||||
| 	import type { PageData } from './$types'; | ||||
|  | ||||
| @@ -21,6 +22,7 @@ | ||||
|  | ||||
| 	let selectedAssets: Set<AssetResponseDto> = new Set(); | ||||
| 	$: isMultiSelectionMode = selectedAssets.size > 0; | ||||
| 	$: isAllFavorite = Array.from(selectedAssets).every((asset) => asset.isFavorite); | ||||
|  | ||||
| 	onMount(async () => { | ||||
| 		try { | ||||
| @@ -51,15 +53,17 @@ | ||||
| 				assets={selectedAssets} | ||||
| 				clearSelect={() => (selectedAssets = new Set())} | ||||
| 			> | ||||
| 				<ArchiveAction unarchive onAssetArchive={(asset) => onAssetDelete(asset.id)} /> | ||||
| 				<CreateSharedLink /> | ||||
| 				<RemoveFromArchive onAssetArchive={(asset) => onAssetDelete(asset.id)} /> | ||||
| 				<DownloadFiles /> | ||||
| 				<AssetSelectContextMenu icon={Plus} title="Add"> | ||||
| 					<OptionAddToFavorites /> | ||||
| 					<OptionAddToAlbum /> | ||||
| 					<OptionAddToAlbum shared /> | ||||
| 					<AddToAlbum /> | ||||
| 					<AddToAlbum shared /> | ||||
| 				</AssetSelectContextMenu> | ||||
| 				<DeleteAssets {onAssetDelete} /> | ||||
| 				<AssetSelectContextMenu icon={DotsVertical} title="Add"> | ||||
| 					<DownloadAction menuItem /> | ||||
| 					<FavoriteAction menuItem removeFavorite={isAllFavorite} /> | ||||
| 				</AssetSelectContextMenu> | ||||
| 			</AssetSelectControlBar> | ||||
| 		{/if} | ||||
| 	</svelte:fragment> | ||||
|   | ||||
| @@ -1,13 +1,20 @@ | ||||
| <script lang="ts"> | ||||
| 	import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte'; | ||||
| 	import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte'; | ||||
| 	import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte'; | ||||
| 	import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte'; | ||||
| 	import RemoveFavorite from '$lib/components/photos-page/actions/remove-favorite.svelte'; | ||||
| 	import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte'; | ||||
| 	import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte'; | ||||
| 	import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte'; | ||||
| 	import AssetSelectContextMenu from '$lib/components/photos-page/asset-select-context-menu.svelte'; | ||||
| 	import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte'; | ||||
| 	import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte'; | ||||
| 	import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte'; | ||||
| 	import { handleError } from '$lib/utils/handle-error'; | ||||
| 	import { api, AssetResponseDto } from '@api'; | ||||
| 	import { onMount } from 'svelte'; | ||||
| 	import DotsVertical from 'svelte-material-icons/DotsVertical.svelte'; | ||||
| 	import Plus from 'svelte-material-icons/Plus.svelte'; | ||||
| 	import Error from '../../+error.svelte'; | ||||
| 	import type { PageData } from './$types'; | ||||
|  | ||||
| @@ -17,6 +24,7 @@ | ||||
| 	export let data: PageData; | ||||
|  | ||||
| 	$: isMultiSelectionMode = selectedAssets.size > 0; | ||||
| 	$: isAllArchive = Array.from(selectedAssets).every((asset) => asset.isArchived); | ||||
|  | ||||
| 	onMount(async () => { | ||||
| 		try { | ||||
| @@ -35,8 +43,17 @@ | ||||
| <!-- Multiselection mode app bar --> | ||||
| {#if isMultiSelectionMode} | ||||
| 	<AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}> | ||||
| 		<FavoriteAction removeFavorite onAssetFavorite={(asset) => onAssetDelete(asset.id)} /> | ||||
| 		<CreateSharedLink /> | ||||
| 		<RemoveFavorite onAssetFavorite={(asset) => onAssetDelete(asset.id)} /> | ||||
| 		<AssetSelectContextMenu icon={Plus} title="Add"> | ||||
| 			<AddToAlbum /> | ||||
| 			<AddToAlbum shared /> | ||||
| 		</AssetSelectContextMenu> | ||||
| 		<DeleteAssets {onAssetDelete} /> | ||||
| 		<AssetSelectContextMenu icon={DotsVertical} title="Menu"> | ||||
| 			<DownloadAction menuItem /> | ||||
| 			<ArchiveAction menuItem unarchive={isAllArchive} /> | ||||
| 		</AssetSelectContextMenu> | ||||
| 	</AssetSelectControlBar> | ||||
| {/if} | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,10 @@ | ||||
| <script lang="ts"> | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 	import DownloadFiles from '$lib/components/photos-page/actions/download-files.svelte'; | ||||
| 	import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte'; | ||||
| 	import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte'; | ||||
| 	import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte'; | ||||
| 	import AssetGrid from '$lib/components/photos-page/asset-grid.svelte'; | ||||
| 	import AssetSelectContextMenu from '$lib/components/photos-page/asset-select-context-menu.svelte'; | ||||
| 	import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte'; | ||||
| 	import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte'; | ||||
| 	import { AppRoute } from '$lib/constants'; | ||||
| @@ -12,6 +15,7 @@ | ||||
| 	} from '$lib/stores/asset-interaction.store'; | ||||
| 	import { onDestroy } from 'svelte'; | ||||
| 	import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte'; | ||||
| 	import Plus from 'svelte-material-icons/Plus.svelte'; | ||||
| 	import type { PageData } from './$types'; | ||||
|  | ||||
| 	export let data: PageData; | ||||
| @@ -27,7 +31,18 @@ | ||||
| 			assets={$selectedAssets} | ||||
| 			clearSelect={assetInteractionStore.clearMultiselect} | ||||
| 		> | ||||
| 			<DownloadFiles /> | ||||
| 			<DownloadAction /> | ||||
| 		</AssetSelectControlBar> | ||||
| 		<AssetSelectControlBar | ||||
| 			assets={$selectedAssets} | ||||
| 			clearSelect={assetInteractionStore.clearMultiselect} | ||||
| 		> | ||||
| 			<CreateSharedLink /> | ||||
| 			<AssetSelectContextMenu icon={Plus} title="Add"> | ||||
| 				<AddToAlbum /> | ||||
| 				<AddToAlbum shared /> | ||||
| 			</AssetSelectContextMenu> | ||||
| 			<DownloadAction /> | ||||
| 		</AssetSelectControlBar> | ||||
| 	{:else} | ||||
| 		<ControlAppBar | ||||
|   | ||||
| @@ -3,29 +3,32 @@ | ||||
| 	import { page } from '$app/stores'; | ||||
| 	import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte'; | ||||
| 	import EditNameInput from '$lib/components/faces-page/edit-name-input.svelte'; | ||||
| 	import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte'; | ||||
| 	import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte'; | ||||
| 	import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte'; | ||||
| 	import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte'; | ||||
| 	import DownloadFiles from '$lib/components/photos-page/actions/download-files.svelte'; | ||||
| 	import MoveToArchive from '$lib/components/photos-page/actions/move-to-archive.svelte'; | ||||
| 	import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte'; | ||||
| 	import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte'; | ||||
| 	import AssetSelectContextMenu from '$lib/components/photos-page/asset-select-context-menu.svelte'; | ||||
| 	import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte'; | ||||
| 	import OptionAddToAlbum from '$lib/components/photos-page/menu-options/option-add-to-album.svelte'; | ||||
| 	import OptionAddToFavorites from '$lib/components/photos-page/menu-options/option-add-to-favorites.svelte'; | ||||
| 	import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte'; | ||||
| 	import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte'; | ||||
| 	import { AppRoute } from '$lib/constants'; | ||||
| 	import { handleError } from '$lib/utils/handle-error'; | ||||
| 	import { AssetResponseDto, api } from '@api'; | ||||
| 	import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte'; | ||||
| 	import DotsVertical from 'svelte-material-icons/DotsVertical.svelte'; | ||||
| 	import Plus from 'svelte-material-icons/Plus.svelte'; | ||||
| 	import type { PageData } from './$types'; | ||||
|  | ||||
| 	export let data: PageData; | ||||
|  | ||||
| 	let isEditName = false; | ||||
| 	let multiSelectAsset: Set<AssetResponseDto> = new Set(); | ||||
| 	let previousRoute: string = AppRoute.EXPLORE; | ||||
| 	$: isMultiSelectionMode = multiSelectAsset.size > 0; | ||||
| 	let selectedAssets: Set<AssetResponseDto> = new Set(); | ||||
| 	$: isMultiSelectionMode = selectedAssets.size > 0; | ||||
| 	$: isAllArchive = Array.from(selectedAssets).every((asset) => asset.isArchived); | ||||
| 	$: isAllFavorite = Array.from(selectedAssets).every((asset) => asset.isFavorite); | ||||
|  | ||||
| 	afterNavigate(({ from }) => { | ||||
| 		// Prevent setting previousRoute to the current page. | ||||
| @@ -44,25 +47,28 @@ | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	const handleAssetDelete = (assetId: string) => { | ||||
| 	const onAssetDelete = (assetId: string) => { | ||||
| 		data.assets = data.assets.filter((asset: AssetResponseDto) => asset.id !== assetId); | ||||
| 	}; | ||||
| </script> | ||||
|  | ||||
| {#if isMultiSelectionMode} | ||||
| 	<AssetSelectControlBar | ||||
| 		assets={multiSelectAsset} | ||||
| 		clearSelect={() => (multiSelectAsset = new Set())} | ||||
| 	> | ||||
| 	<AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}> | ||||
| 		<CreateSharedLink /> | ||||
| 		<MoveToArchive /> | ||||
| 		<DownloadFiles filename={data.person.name} /> | ||||
| 		<AssetSelectContextMenu icon={Plus} title="Add"> | ||||
| 			<OptionAddToFavorites /> | ||||
| 			<OptionAddToAlbum /> | ||||
| 			<OptionAddToAlbum shared /> | ||||
| 			<AddToAlbum /> | ||||
| 			<AddToAlbum shared /> | ||||
| 		</AssetSelectContextMenu> | ||||
| 		<DeleteAssets {onAssetDelete} /> | ||||
| 		<AssetSelectContextMenu icon={DotsVertical} title="Add"> | ||||
| 			<DownloadAction menuItem /> | ||||
| 			<FavoriteAction menuItem removeFavorite={isAllFavorite} /> | ||||
| 			<ArchiveAction | ||||
| 				menuItem | ||||
| 				unarchive={isAllArchive} | ||||
| 				onAssetArchive={(asset) => onAssetDelete(asset.id)} | ||||
| 			/> | ||||
| 		</AssetSelectContextMenu> | ||||
| 		<DeleteAssets onAssetDelete={handleAssetDelete} /> | ||||
| 	</AssetSelectControlBar> | ||||
| {:else} | ||||
| 	<ControlAppBar | ||||
| @@ -114,7 +120,7 @@ | ||||
| 				assets={data.assets} | ||||
| 				viewFrom="search-page" | ||||
| 				showArchiveIcon={true} | ||||
| 				bind:selectedAssets={multiSelectAsset} | ||||
| 				bind:selectedAssets | ||||
| 			/> | ||||
| 		</section> | ||||
| 	</section> | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| <script lang="ts"> | ||||
| 	import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte'; | ||||
| 	import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte'; | ||||
| 	import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte'; | ||||
| 	import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte'; | ||||
| 	import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte'; | ||||
| 	import DownloadFiles from '$lib/components/photos-page/actions/download-files.svelte'; | ||||
| 	import MoveToArchive from '$lib/components/photos-page/actions/move-to-archive.svelte'; | ||||
| 	import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte'; | ||||
| 	import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte'; | ||||
| 	import AssetGrid from '$lib/components/photos-page/asset-grid.svelte'; | ||||
| 	import AssetSelectContextMenu from '$lib/components/photos-page/asset-select-context-menu.svelte'; | ||||
| 	import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte'; | ||||
| 	import OptionAddToAlbum from '$lib/components/photos-page/menu-options/option-add-to-album.svelte'; | ||||
| 	import OptionAddToFavorites from '$lib/components/photos-page/menu-options/option-add-to-favorites.svelte'; | ||||
| 	import { | ||||
| 		assetInteractionStore, | ||||
| 		isMultiSelectStoreState, | ||||
| @@ -16,6 +16,7 @@ | ||||
| 	} from '$lib/stores/asset-interaction.store'; | ||||
| 	import { assetStore } from '$lib/stores/assets.store'; | ||||
| 	import { onDestroy } from 'svelte'; | ||||
| 	import DotsVertical from 'svelte-material-icons/DotsVertical.svelte'; | ||||
| 	import Plus from 'svelte-material-icons/Plus.svelte'; | ||||
| 	import type { PageData } from './$types'; | ||||
|  | ||||
| @@ -24,6 +25,8 @@ | ||||
| 	onDestroy(() => { | ||||
| 		assetInteractionStore.clearMultiselect(); | ||||
| 	}); | ||||
|  | ||||
| 	$: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite); | ||||
| </script> | ||||
|  | ||||
| <UserPageLayout user={data.user} hideNavbar={$isMultiSelectStoreState} showUploadButton> | ||||
| @@ -34,14 +37,16 @@ | ||||
| 				clearSelect={assetInteractionStore.clearMultiselect} | ||||
| 			> | ||||
| 				<CreateSharedLink /> | ||||
| 				<MoveToArchive onAssetArchive={(asset) => assetStore.removeAsset(asset.id)} /> | ||||
| 				<DownloadFiles /> | ||||
| 				<AssetSelectContextMenu icon={Plus} title="Add"> | ||||
| 					<OptionAddToFavorites /> | ||||
| 					<OptionAddToAlbum /> | ||||
| 					<OptionAddToAlbum shared /> | ||||
| 					<AddToAlbum /> | ||||
| 					<AddToAlbum shared /> | ||||
| 				</AssetSelectContextMenu> | ||||
| 				<DeleteAssets onAssetDelete={assetStore.removeAsset} /> | ||||
| 				<AssetSelectContextMenu icon={DotsVertical} title="Menu"> | ||||
| 					<FavoriteAction menuItem removeFavorite={isAllFavorite} /> | ||||
| 					<DownloadAction menuItem /> | ||||
| 					<ArchiveAction menuItem onAssetArchive={(asset) => assetStore.removeAsset(asset.id)} /> | ||||
| 				</AssetSelectContextMenu> | ||||
| 			</AssetSelectControlBar> | ||||
| 		{/if} | ||||
| 	</svelte:fragment> | ||||
|   | ||||
| @@ -1,21 +1,20 @@ | ||||
| <script lang="ts"> | ||||
| 	import { afterNavigate, goto } from '$app/navigation'; | ||||
| 	import { page } from '$app/stores'; | ||||
| 	import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte'; | ||||
| 	import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte'; | ||||
| 	import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte'; | ||||
| 	import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte'; | ||||
| 	import DownloadFiles from '$lib/components/photos-page/actions/download-files.svelte'; | ||||
| 	import MoveToArchive from '$lib/components/photos-page/actions/move-to-archive.svelte'; | ||||
| 	import RemoveFromArchive from '$lib/components/photos-page/actions/remove-from-archive.svelte'; | ||||
| 	import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte'; | ||||
| 	import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte'; | ||||
| 	import AssetSelectContextMenu from '$lib/components/photos-page/asset-select-context-menu.svelte'; | ||||
| 	import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte'; | ||||
| 	import OptionAddToAlbum from '$lib/components/photos-page/menu-options/option-add-to-album.svelte'; | ||||
| 	import OptionAddToFavorites from '$lib/components/photos-page/menu-options/option-add-to-favorites.svelte'; | ||||
| 	import OptionRemoveFromFavorites from '$lib/components/photos-page/menu-options/option-remove-from-favorites.svelte'; | ||||
| 	import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte'; | ||||
| 	import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte'; | ||||
| 	import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte'; | ||||
| 	import { AssetResponseDto } from '@api'; | ||||
| 	import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte'; | ||||
| 	import DotsVertical from 'svelte-material-icons/DotsVertical.svelte'; | ||||
| 	import ImageOffOutline from 'svelte-material-icons/ImageOffOutline.svelte'; | ||||
| 	import Plus from 'svelte-material-icons/Plus.svelte'; | ||||
| 	import type { PageData } from './$types'; | ||||
| @@ -51,22 +50,17 @@ | ||||
| 	{#if isMultiSelectionMode} | ||||
| 		<AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}> | ||||
| 			<CreateSharedLink /> | ||||
| 			{#if isAllArchived} | ||||
| 				<RemoveFromArchive /> | ||||
| 			{:else} | ||||
| 				<MoveToArchive /> | ||||
| 			{/if} | ||||
| 			<DownloadFiles /> | ||||
| 			<AssetSelectContextMenu icon={Plus} title="Add"> | ||||
| 				{#if isAllFavorite} | ||||
| 					<OptionRemoveFromFavorites /> | ||||
| 				{:else} | ||||
| 					<OptionAddToFavorites /> | ||||
| 				{/if} | ||||
| 				<OptionAddToAlbum /> | ||||
| 				<OptionAddToAlbum shared /> | ||||
| 				<AddToAlbum /> | ||||
| 				<AddToAlbum shared /> | ||||
| 			</AssetSelectContextMenu> | ||||
| 			<DeleteAssets {onAssetDelete} /> | ||||
|  | ||||
| 			<AssetSelectContextMenu icon={DotsVertical} title="Add"> | ||||
| 				<DownloadAction menuItem /> | ||||
| 				<FavoriteAction menuItem removeFavorite={isAllFavorite} /> | ||||
| 				<ArchiveAction menuItem unarchive={isAllArchived} /> | ||||
| 			</AssetSelectContextMenu> | ||||
| 		</AssetSelectControlBar> | ||||
| 	{:else} | ||||
| 		<ControlAppBar on:close-button-click={() => goto(previousRoute)} backIcon={ArrowLeft}> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user