feat(web): Shared album owner labels (#21171)

* - pass available album users along to the thumbnail through the asset-date-group
- show a small user-avatar in bottom right of thumbnail

* - change owner to their name in white text instead of the avatar

* cleanup

* - cleanup albumUsers creation
- use font-light for the user's name

* fix lint

* format

* - add toggle to show/hide asset owner names

* update new Timeline with albumUsers

* add @idubnori suggestion for the name font

* Don't show 'view owners' button if the album doesn't have editors

* add missing import

* format

* fix(web): #21171 (#24298)

fix: Bind timelineManager to Timeline component

---------

Co-authored-by: idubnori <i.dub.nori@gmail.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Chris Peckover
2025-11-30 13:56:03 -05:00
committed by GitHub
parent e3ab16a5bd
commit 922282b2b4
3 changed files with 36 additions and 2 deletions

View File

@@ -4,7 +4,7 @@
import { getAssetOriginalUrl, 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,
@@ -46,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;
@@ -64,6 +65,7 @@
readonly = false,
showArchiveIcon = false,
showStackedIcon = true,
albumUsers = [],
onClick = undefined,
onSelect = undefined,
onMouseEvent = undefined,
@@ -85,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();
@@ -268,6 +272,14 @@
</div>
{/if}
{#if !!assetOwner}
<div class="absolute bottom-1 end-2 max-w-[50%]">
<p class="text-xs font-medium text-white drop-shadow-lg max-w-[100%] truncate">
{assetOwner.name}
</p>
</div>
{/if}
{#if !authManager.isSharedLink && showArchiveIcon && asset.visibility === AssetVisibility.Archive}
<div class={['absolute start-2', asset.isFavorite ? 'bottom-10' : 'bottom-2']}>
<Icon data-icon-archive icon={mdiArchiveArrowDownOutline} size="24" class="text-white" />