diff --git a/web/src/lib/components/album-page/__tests__/album-cover.spec.ts b/web/src/lib/components/album-page/__tests__/album-cover.spec.ts new file mode 100644 index 0000000000..4f5fb7e571 --- /dev/null +++ b/web/src/lib/components/album-page/__tests__/album-cover.spec.ts @@ -0,0 +1,42 @@ +import AlbumCover from '$lib/components/album-page/album-cover.svelte'; +import { getAssetThumbnailUrl } from '$lib/utils'; +import { albumFactory } from '@test-data'; +import { render } from '@testing-library/svelte'; + +vi.mock('$lib/utils'); + +describe('AlbumCover component', () => { + it('renders an image when the album has a thumbnail', () => { + vi.mocked(getAssetThumbnailUrl).mockReturnValue('/asdf'); + const component = render(AlbumCover, { + album: albumFactory.build({ + albumName: 'someName', + albumThumbnailAssetId: '123', + }), + preload: false, + class: 'text', + }); + const img = component.getByTestId('album-image') as HTMLImageElement; + expect(img.alt).toBe('someName'); + expect(img.getAttribute('loading')).toBe('lazy'); + expect(img.className).toBe('z-0 rounded-xl object-cover text'); + expect(img.getAttribute('src')).toBe('/asdf'); + expect(getAssetThumbnailUrl).toHaveBeenCalledWith({ id: '123' }); + }); + + it('renders an image when the album has no thumbnail', () => { + const component = render(AlbumCover, { + album: albumFactory.build({ + albumName: '', + albumThumbnailAssetId: null, + }), + preload: true, + class: 'asdf', + }); + const img = component.getByTestId('album-image') as HTMLImageElement; + expect(img.alt).toBe('unnamed_album'); + expect(img.getAttribute('loading')).toBe('eager'); + expect(img.className).toBe('z-0 rounded-xl object-cover asdf'); + expect(img.getAttribute('src')).toStrictEqual(expect.any(String)); + }); +}); diff --git a/web/src/lib/components/album-page/album-card.svelte b/web/src/lib/components/album-page/album-card.svelte index dc32846642..6ff723d3bb 100644 --- a/web/src/lib/components/album-page/album-card.svelte +++ b/web/src/lib/components/album-page/album-card.svelte @@ -46,7 +46,7 @@ {/if} - +

import { getAssetThumbnailUrl } from '$lib/utils'; import { type AlbumResponseDto } from '@immich/sdk'; + import NoCover from '$lib/components/sharedlinks-page/covers/no-cover.svelte'; + import AssetCover from '$lib/components/sharedlinks-page/covers/asset-cover.svelte'; import { t } from 'svelte-i18n'; - export let album: AlbumResponseDto | undefined; + export let album: AlbumResponseDto; export let preload = false; - export let css = ''; + let className = ''; + export { className as class }; - $: thumbnailUrl = - album && album.albumThumbnailAssetId ? getAssetThumbnailUrl({ id: album.albumThumbnailAssetId }) : null; + $: alt = album.albumName || $t('unnamed_album'); + $: thumbnailUrl = album.albumThumbnailAssetId ? getAssetThumbnailUrl({ id: album.albumThumbnailAssetId }) : null;

{#if thumbnailUrl} - {album?.albumName + {:else} - + {/if}
diff --git a/web/src/lib/components/forms/edit-album-form.svelte b/web/src/lib/components/forms/edit-album-form.svelte index 32e82dab4d..0c3b8e1044 100644 --- a/web/src/lib/components/forms/edit-album-form.svelte +++ b/web/src/lib/components/forms/edit-album-form.svelte @@ -41,7 +41,7 @@
diff --git a/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte b/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte index 3df849e187..1c1c757df0 100644 --- a/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte +++ b/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte @@ -193,9 +193,8 @@
Let anyone with the link see the selected photo(s)
{:else}
- Individual shared | {editingLink.description || ''} + {$t('individual_share')} | + {editingLink.description || ''}
{/if} {/if} diff --git a/web/src/lib/components/sharedlinks-page/covers/__tests__/asset-cover.spec.ts b/web/src/lib/components/sharedlinks-page/covers/__tests__/asset-cover.spec.ts new file mode 100644 index 0000000000..a7a2c85f8a --- /dev/null +++ b/web/src/lib/components/sharedlinks-page/covers/__tests__/asset-cover.spec.ts @@ -0,0 +1,18 @@ +import AssetCover from '$lib/components/sharedlinks-page/covers/asset-cover.svelte'; +import { render } from '@testing-library/svelte'; + +describe('AssetCover component', () => { + it('renders correctly', () => { + const component = render(AssetCover, { + alt: '123', + preload: true, + src: 'wee', + class: 'asdf', + }); + const img = component.getByTestId('album-image') as HTMLImageElement; + expect(img.alt).toBe('123'); + expect(img.getAttribute('src')).toBe('wee'); + expect(img.getAttribute('loading')).toBe('eager'); + expect(img.className).toBe('z-0 rounded-xl object-cover asdf'); + }); +}); diff --git a/web/src/lib/components/sharedlinks-page/covers/__tests__/no-cover.spec.ts b/web/src/lib/components/sharedlinks-page/covers/__tests__/no-cover.spec.ts new file mode 100644 index 0000000000..3dc7d56791 --- /dev/null +++ b/web/src/lib/components/sharedlinks-page/covers/__tests__/no-cover.spec.ts @@ -0,0 +1,17 @@ +import NoCover from '$lib/components/sharedlinks-page/covers/no-cover.svelte'; +import { render } from '@testing-library/svelte'; + +describe('NoCover component', () => { + it('renders correctly', () => { + const component = render(NoCover, { + alt: '123', + preload: true, + class: 'asdf', + }); + const img = component.getByTestId('album-image') as HTMLImageElement; + expect(img.alt).toBe('123'); + expect(img.className).toBe('z-0 rounded-xl object-cover asdf'); + expect(img.getAttribute('loading')).toBe('eager'); + expect(img.src).toStrictEqual(expect.any(String)); + }); +}); diff --git a/web/src/lib/components/sharedlinks-page/covers/__tests__/share-cover.spec.ts b/web/src/lib/components/sharedlinks-page/covers/__tests__/share-cover.spec.ts new file mode 100644 index 0000000000..774c433562 --- /dev/null +++ b/web/src/lib/components/sharedlinks-page/covers/__tests__/share-cover.spec.ts @@ -0,0 +1,60 @@ +import ShareCover from '$lib/components/sharedlinks-page/covers/share-cover.svelte'; +import { getAssetThumbnailUrl } from '$lib/utils'; +import type { SharedLinkResponseDto } from '@immich/sdk'; +import { albumFactory } from '@test-data'; +import { render } from '@testing-library/svelte'; + +vi.mock('$lib/utils'); + +describe('ShareCover component', () => { + it('renders an image when the shared link is an album', () => { + const component = render(ShareCover, { + link: { + album: albumFactory.build({ + albumName: '123', + }), + } as SharedLinkResponseDto, + preload: false, + class: 'text', + }); + const img = component.getByTestId('album-image') as HTMLImageElement; + expect(img.alt).toBe('123'); + expect(img.getAttribute('loading')).toBe('lazy'); + expect(img.className).toBe('z-0 rounded-xl object-cover text'); + }); + + it('renders an image when the shared link is an individual share', () => { + vi.mocked(getAssetThumbnailUrl).mockReturnValue('/asdf'); + const component = render(ShareCover, { + link: { + assets: [ + { + id: 'someId', + }, + ], + } as SharedLinkResponseDto, + preload: false, + class: 'text', + }); + const img = component.getByTestId('album-image') as HTMLImageElement; + expect(img.alt).toBe('individual_share'); + expect(img.getAttribute('loading')).toBe('lazy'); + expect(img.className).toBe('z-0 rounded-xl object-cover text'); + expect(img.getAttribute('src')).toBe('/asdf'); + expect(getAssetThumbnailUrl).toHaveBeenCalledWith('someId'); + }); + + it('renders an image when the shared link has no album or assets', () => { + const component = render(ShareCover, { + link: { + assets: [], + } as unknown as SharedLinkResponseDto, + preload: false, + class: 'text', + }); + const img = component.getByTestId('album-image') as HTMLImageElement; + expect(img.alt).toBe('unnamed_share'); + expect(img.getAttribute('loading')).toBe('lazy'); + expect(img.className).toBe('z-0 rounded-xl object-cover text'); + }); +}); diff --git a/web/src/lib/components/sharedlinks-page/covers/asset-cover.svelte b/web/src/lib/components/sharedlinks-page/covers/asset-cover.svelte new file mode 100644 index 0000000000..b0cd2dfdd5 --- /dev/null +++ b/web/src/lib/components/sharedlinks-page/covers/asset-cover.svelte @@ -0,0 +1,16 @@ + + + diff --git a/web/src/lib/components/sharedlinks-page/covers/no-cover.svelte b/web/src/lib/components/sharedlinks-page/covers/no-cover.svelte new file mode 100644 index 0000000000..47c377f01c --- /dev/null +++ b/web/src/lib/components/sharedlinks-page/covers/no-cover.svelte @@ -0,0 +1,16 @@ + + + diff --git a/web/src/lib/components/sharedlinks-page/covers/share-cover.svelte b/web/src/lib/components/sharedlinks-page/covers/share-cover.svelte new file mode 100644 index 0000000000..a82db72b77 --- /dev/null +++ b/web/src/lib/components/sharedlinks-page/covers/share-cover.svelte @@ -0,0 +1,28 @@ + + +
+ {#if link?.album} + + {:else if link.assets[0]} + + {:else} + + {/if} +
diff --git a/web/src/lib/components/sharedlinks-page/shared-link-card.svelte b/web/src/lib/components/sharedlinks-page/shared-link-card.svelte index 5c3b908a4c..3d75df4259 100644 --- a/web/src/lib/components/sharedlinks-page/shared-link-card.svelte +++ b/web/src/lib/components/sharedlinks-page/shared-link-card.svelte @@ -7,7 +7,7 @@ import { createEventDispatcher } from 'svelte'; import CircleIconButton from '../elements/buttons/circle-icon-button.svelte'; import { locale } from '$lib/stores/preferences.store'; - import AlbumCover from '$lib/components/album-page/album-cover.svelte'; + import ShareCover from '$lib/components/sharedlinks-page/covers/share-cover.svelte'; import { t } from 'svelte-i18n'; export let link: SharedLinkResponseDto; @@ -52,7 +52,7 @@ class="flex w-full gap-4 border-b border-gray-200 py-4 transition-all hover:border-immich-primary dark:border-gray-600 dark:text-immich-gray dark:hover:border-immich-dark-primary" >
- +
diff --git a/web/src/lib/i18n/en.json b/web/src/lib/i18n/en.json index 95bad059d1..d4cb319a36 100644 --- a/web/src/lib/i18n/en.json +++ b/web/src/lib/i18n/en.json @@ -445,7 +445,6 @@ "edited": "Edited", "editor": "Editor", "email": "Email", - "empty_album": "Empty Album", "empty_trash": "Empty trash", "end_date": "End date", "error": "Error", @@ -868,11 +867,12 @@ "unfavorite": "Unfavorite", "unhide_person": "Unhide person", "unknown": "Unknown", - "unknown_album": "Unknown Album", "unknown_year": "Unknown Year", "unlimited": "Unlimited", "unlink_oauth": "Unlink Oauth", "unlinked_oauth_account": "Unlinked OAuth account", + "unnamed_album": "Unnamed Album", + "unnamed_share": "Unnamed Share", "unselect_all": "Unselect all", "unstack": "Un-stack", "untracked_files": "Untracked files",