From b7e3b48a4417c9ae92c40ec9dd760b50a5f2243c Mon Sep 17 00:00:00 2001 From: CJPeckover Date: Fri, 22 Aug 2025 17:29:03 -0400 Subject: [PATCH] - pass available album users along to the thumbnail through the asset-date-group - show a small user-avatar in bottom right of thumbnail --- .../assets/thumbnail/thumbnail.svelte | 13 ++++++++++++- .../photos-page/asset-date-group.svelte | 4 ++++ .../components/photos-page/asset-grid.svelte | 18 +++++++++++++++++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/web/src/lib/components/assets/thumbnail/thumbnail.svelte b/web/src/lib/components/assets/thumbnail/thumbnail.svelte index e4b590b8ea..8c9f58b239 100644 --- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte @@ -5,7 +5,7 @@ import { getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils'; import { timeToSeconds } from '$lib/utils/date-time'; import { getAltText } from '$lib/utils/thumbnail-util'; - import { AssetMediaSize, AssetVisibility } from '@immich/sdk'; + import { AssetMediaSize, AssetVisibility, type UserResponseDto } from '@immich/sdk'; import { mdiArchiveArrowDownOutline, mdiCameraBurst, @@ -17,6 +17,7 @@ } from '@mdi/js'; import { thumbhash } from '$lib/actions/thumbhash'; + import UserAvatar from '$lib/components/shared-components/user-avatar.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; import { mobileDevice } from '$lib/stores/mobile-device.svelte'; @@ -45,6 +46,7 @@ imageClass?: ClassValue; brokenAssetClass?: ClassValue; dimmed?: boolean; + albumUsers?: UserResponseDto[]; onClick?: (asset: TimelineAsset) => void; onSelect?: (asset: TimelineAsset) => void; onMouseEvent?: (event: { isMouseOver: boolean; selectedGroupIndex: number }) => void; @@ -63,6 +65,7 @@ readonly = false, showArchiveIcon = false, showStackedIcon = true, + albumUsers = [], onClick = undefined, onSelect = undefined, onMouseEvent = undefined, @@ -84,6 +87,8 @@ let width = $derived(thumbnailSize || thumbnailWidth || 235); let height = $derived(thumbnailSize || thumbnailHeight || 235); + let assetOwner = $derived(albumUsers?.find((user) => user.id === asset.ownerId) ?? null); + const onIconClickedHandler = (e?: MouseEvent) => { e?.stopPropagation(); e?.preventDefault(); @@ -267,6 +272,12 @@ {/if} + {#if !!assetOwner} +
+ +
+ {/if} + {#if !authManager.isSharedLink && showArchiveIcon && asset.visibility === AssetVisibility.Archive}
diff --git a/web/src/lib/components/photos-page/asset-date-group.svelte b/web/src/lib/components/photos-page/asset-date-group.svelte index 6fab96c3ec..61c283e3fe 100644 --- a/web/src/lib/components/photos-page/asset-date-group.svelte +++ b/web/src/lib/components/photos-page/asset-date-group.svelte @@ -9,6 +9,7 @@ import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte'; import { uploadAssetsStore } from '$lib/stores/upload'; import { navigate } from '$lib/utils/navigation'; + import type { UserResponseDto } from '@immich/sdk'; import { mdiCheckCircle, mdiCircleOutline } from '@mdi/js'; @@ -25,6 +26,7 @@ monthGroup: MonthGroup; timelineManager: TimelineManager; assetInteraction: AssetInteraction; + albumUsers?: UserResponseDto[]; onSelect: ({ title, assets }: { title: string; assets: TimelineAsset[] }) => void; onSelectAssets: (asset: TimelineAsset) => void; @@ -40,6 +42,7 @@ monthGroup = $bindable(), assetInteraction, timelineManager, + albumUsers = [], onSelect, onSelectAssets, onSelectAssetCandidates, @@ -189,6 +192,7 @@ showStackedIcon={withStacked} {showArchiveIcon} {asset} + {albumUsers} {groupIndex} onClick={(asset) => onClick(timelineManager, dayGroup.getAssets(), dayGroup.groupTitle, asset)} onSelect={(asset) => assetSelectHandler(timelineManager, asset, dayGroup.getAssets(), dayGroup.groupTitle)} diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte index 69faf8e1e5..d2f44c5257 100644 --- a/web/src/lib/components/photos-page/asset-grid.svelte +++ b/web/src/lib/components/photos-page/asset-grid.svelte @@ -30,7 +30,13 @@ import { archiveAssets, cancelMultiselect, selectAllAssets, stackAssets } from '$lib/utils/asset-utils'; import { navigate } from '$lib/utils/navigation'; import { getTimes, toTimelineAsset, type ScrubberListener, type TimelineYearMonth } from '$lib/utils/timeline-util'; - import { AssetVisibility, getAssetInfo, type AlbumResponseDto, type PersonResponseDto } from '@immich/sdk'; + import { + AssetVisibility, + getAssetInfo, + type AlbumResponseDto, + type PersonResponseDto, + type UserResponseDto, + } from '@immich/sdk'; import { modalManager } from '@immich/ui'; import { DateTime } from 'luxon'; import { onMount, type Snippet } from 'svelte'; @@ -88,6 +94,15 @@ let { isViewing: showAssetViewer, asset: viewingAsset, preloadAssets, gridScrollTarget, mutex } = assetViewingStore; + const isUser = (user: UserResponseDto | undefined): user is UserResponseDto => { + return !!user; + }; + const albumUsers = $derived( + album?.shared && album?.albumUsers.length + ? [album?.owner, ...(album?.albumUsers?.map(({ user }) => user) ?? [])].filter((element) => isUser(element)) + : [], + ); + let element: HTMLElement | undefined = $state(); let timelineElement: HTMLElement | undefined = $state(); @@ -936,6 +951,7 @@ {isSelectionMode} {singleSelect} {monthGroup} + {albumUsers} onSelect={({ title, assets }) => handleGroupSelect(timelineManager, title, assets)} onSelectAssetCandidates={handleSelectAssetCandidates} onSelectAssets={handleSelectAssets}