diff --git a/i18n/en.json b/i18n/en.json index e86b56be85..bd59c37fac 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -33,6 +33,7 @@ "add_to_albums": "Add to albums", "add_to_albums_count": "Add to albums ({count})", "add_to_shared_album": "Add to shared album", + "add_upload_to_stack": "Add upload to stack", "add_url": "Add URL", "added_to_archive": "Added to archive", "added_to_favorites": "Added to favorites", diff --git a/web/src/lib/components/asset-viewer/actions/action.ts b/web/src/lib/components/asset-viewer/actions/action.ts index 680dced7ca..6a807d2766 100644 --- a/web/src/lib/components/asset-viewer/actions/action.ts +++ b/web/src/lib/components/asset-viewer/actions/action.ts @@ -12,6 +12,7 @@ type ActionMap = { [AssetAction.RESTORE]: { asset: TimelineAsset }; [AssetAction.ADD]: { asset: TimelineAsset }; [AssetAction.ADD_TO_ALBUM]: { asset: TimelineAsset; album: AlbumResponseDto }; + [AssetAction.STACK]: { stack: StackResponseDto }; [AssetAction.UNSTACK]: { assets: TimelineAsset[] }; [AssetAction.KEEP_THIS_DELETE_OTHERS]: { asset: TimelineAsset }; [AssetAction.SET_STACK_PRIMARY_ASSET]: { stack: StackResponseDto }; diff --git a/web/src/lib/components/asset-viewer/actions/add-to-stack-action.svelte b/web/src/lib/components/asset-viewer/actions/add-to-stack-action.svelte new file mode 100644 index 0000000000..5b30beff6e --- /dev/null +++ b/web/src/lib/components/asset-viewer/actions/add-to-stack-action.svelte @@ -0,0 +1,37 @@ + + + diff --git a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte index bbdd0dcd5f..d61af04db6 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte @@ -4,6 +4,7 @@ import CastButton from '$lib/cast/cast-button.svelte'; import type { OnAction, PreAction } from '$lib/components/asset-viewer/actions/action'; import AddToAlbumAction from '$lib/components/asset-viewer/actions/add-to-album-action.svelte'; + import AddToStackAction from '$lib/components/asset-viewer/actions/add-to-stack-action.svelte'; import ArchiveAction from '$lib/components/asset-viewer/actions/archive-action.svelte'; import CloseAction from '$lib/components/asset-viewer/actions/close-action.svelte'; import DeleteAction from '$lib/components/asset-viewer/actions/delete-action.svelte'; @@ -196,6 +197,7 @@ {/if} {#if isOwner} + {#if stack} diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index 5484cd2c08..3dd7741af5 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -336,6 +336,7 @@ } break; } + case AssetAction.STACK: case AssetAction.SET_STACK_PRIMARY_ASSET: { stack = action.stack; break; diff --git a/web/src/lib/components/timeline/TimelineAssetViewer.svelte b/web/src/lib/components/timeline/TimelineAssetViewer.svelte index 17e3ed06f3..60b839d7e1 100644 --- a/web/src/lib/components/timeline/TimelineAssetViewer.svelte +++ b/web/src/lib/components/timeline/TimelineAssetViewer.svelte @@ -120,6 +120,16 @@ break; } + case AssetAction.STACK: { + updateStackedAssetInTimeline(timelineManager, { + stack: action.stack, + toDeleteIds: action.stack.assets + .filter((asset) => asset.id !== action.stack.primaryAssetId) + .map((asset) => asset.id), + }); + break; + } + case AssetAction.UNSTACK: { updateUnstackedAssetInTimeline(timelineManager, action.assets); break; diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts index da638bb41d..8d2b706ead 100644 --- a/web/src/lib/constants.ts +++ b/web/src/lib/constants.ts @@ -8,6 +8,7 @@ export enum AssetAction { RESTORE = 'restore', ADD = 'add', ADD_TO_ALBUM = 'add-to-album', + STACK = 'stack', UNSTACK = 'unstack', KEEP_THIS_DELETE_OTHERS = 'keep-this-delete-others', SET_STACK_PRIMARY_ASSET = 'set-stack-primary-asset', diff --git a/web/src/lib/utils/file-uploader.ts b/web/src/lib/utils/file-uploader.ts index c572ec1760..3f602bdb29 100644 --- a/web/src/lib/utils/file-uploader.ts +++ b/web/src/lib/utils/file-uploader.ts @@ -52,7 +52,7 @@ export const openFileUploadDialog = async (options: FileUploadParam = {}) => { const { albumId, multiple = true, assetId } = options; const extensions = uploadManager.getExtensions(); - return new Promise<(string | undefined)[]>((resolve, reject) => { + return new Promise((resolve, reject) => { try { const fileSelector = document.createElement('input');