diff --git a/web/src/lib/components/assets/thumbnail/thumbnail.svelte b/web/src/lib/components/assets/thumbnail/thumbnail.svelte index 1047f4a2dfcf0..ff2e98761f8be 100644 --- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte @@ -45,6 +45,7 @@ imageClass?: ClassValue; brokenAssetClass?: ClassValue; dimmed?: boolean; + ownerName?: string; onClick?: (asset: TimelineAsset) => void; onSelect?: (asset: TimelineAsset) => void; onMouseEvent?: (event: { isMouseOver: boolean; selectedGroupIndex: number }) => void; @@ -69,6 +70,7 @@ imageClass = '', brokenAssetClass = '', dimmed = false, + ownerName = undefined, }: Props = $props(); let { @@ -260,6 +262,15 @@
{/if} + + {#if !authManager.isSharedLink && ownerName} +
+

+ {ownerName} +

+
+ {/if} + {#if !authManager.isSharedLink && asset.isFavorite}
diff --git a/web/src/lib/components/timeline/Timeline.svelte b/web/src/lib/components/timeline/Timeline.svelte index f94926ab2627a..47359f889c8d9 100644 --- a/web/src/lib/components/timeline/Timeline.svelte +++ b/web/src/lib/components/timeline/Timeline.svelte @@ -599,6 +599,7 @@ {isSelectionMode} {singleSelect} {monthGroup} + {album} onSelect={({ title, assets }) => handleGroupSelect(timelineManager, title, assets)} onSelectAssetCandidates={handleSelectAssetCandidates} onSelectAssets={handleSelectAssets} diff --git a/web/src/lib/components/timeline/TimelineDateGroup.svelte b/web/src/lib/components/timeline/TimelineDateGroup.svelte index cd0dc9a212850..eb911fb108579 100644 --- a/web/src/lib/components/timeline/TimelineDateGroup.svelte +++ b/web/src/lib/components/timeline/TimelineDateGroup.svelte @@ -13,6 +13,7 @@ import { mdiCheckCircle, mdiCircleOutline } from '@mdi/js'; import { fromTimelinePlainDate, getDateLocaleString } from '$lib/utils/timeline-util'; + import type { AlbumResponseDto } from '@immich/sdk'; import { Icon } from '@immich/ui'; import { type Snippet } from 'svelte'; import { flip } from 'svelte/animate'; @@ -29,6 +30,7 @@ timelineManager: TimelineManager; assetInteraction: AssetInteraction; customLayout?: Snippet<[TimelineAsset]>; + album?: AlbumResponseDto | null; onSelect: ({ title, assets }: { title: string; assets: TimelineAsset[] }) => void; onSelectAssets: (asset: TimelineAsset) => void; @@ -55,6 +57,7 @@ assetInteraction, timelineManager, customLayout, + album = null, onSelect, onSelectAssets, onSelectAssetCandidates, @@ -133,6 +136,16 @@ }); return getDateLocaleString(date); }; + + const getSharedAssetOwnerName = (album: AlbumResponseDto | null, asset: TimelineAsset): string | undefined => { + if (!album || !album.albumUsers || album.albumUsers.length === 0) { + return undefined; + } + if (album.owner.id === asset.ownerId) { + return album.owner.name; + } + return album.albumUsers.find((user) => user.user.id === asset.ownerId)?.user.name; + }; {#each filterIntersecting(monthGroup.dayGroups) as dayGroup, groupIndex (dayGroup.day)} @@ -210,6 +223,7 @@ {showArchiveIcon} {asset} {groupIndex} + ownerName={getSharedAssetOwnerName(album, asset)} onClick={(asset) => { if (typeof onThumbnailClick === 'function') { onThumbnailClick(asset, timelineManager, dayGroup, _onClick);