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",