diff --git a/web/jest.config.mjs b/web/jest.config.mjs index a411c5b8dc..9ba08b74b1 100644 --- a/web/jest.config.mjs +++ b/web/jest.config.mjs @@ -86,6 +86,8 @@ export default { // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module moduleNameMapper: { + '\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + 'identity-obj-proxy', '^\\$lib(.*)$': '/src/lib$1', '^\\@api(.*)$': '/src/api$1', '^\\@test-data(.*)$': '/src/test-data$1' diff --git a/web/package-lock.json b/web/package-lock.json index ed1f8007e9..6f82cf7cbb 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -45,6 +45,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^4.0.0", "factory.ts": "^1.2.0", + "identity-obj-proxy": "^3.0.0", "jest": "^29.0.2", "jest-environment-jsdom": "^29.0.2", "postcss": "^8.4.13", @@ -6202,6 +6203,12 @@ "uglify-js": "^3.1.4" } }, + "node_modules/harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", + "dev": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -6337,6 +6344,18 @@ "node": ">=0.10.0" } }, + "node_modules/identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "dev": true, + "dependencies": { + "harmony-reflect": "^1.4.6" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/ignore": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", @@ -15822,6 +15841,12 @@ "wordwrap": "^1.0.0" } }, + "harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -15918,6 +15943,15 @@ "safer-buffer": ">= 2.1.2 < 3.0.0" } }, + "identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "dev": true, + "requires": { + "harmony-reflect": "^1.4.6" + } + }, "ignore": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", diff --git a/web/package.json b/web/package.json index 6aa91c117c..bf778f2959 100644 --- a/web/package.json +++ b/web/package.json @@ -43,6 +43,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^4.0.0", "factory.ts": "^1.2.0", + "identity-obj-proxy": "^3.0.0", "jest": "^29.0.2", "jest-environment-jsdom": "^29.0.2", "postcss": "^8.4.13", diff --git a/web/src/app.css b/web/src/app.css index 9324af9ff7..e2f47a1155 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -4,13 +4,13 @@ @font-face { font-family: 'Work Sans'; - src: url('/fonts/WorkSans-VariableFont_wght.ttf') format('truetype-variations'); + src: url('$lib/assets/fonts/WorkSans-VariableFont_wght.ttf') format('truetype-variations'); font-weight: 1 999; } @font-face { font-family: 'Snowburst One'; - src: url('/fonts/SnowburstOne-Regular.ttf') format('truetype'); + src: url('$lib/assets/fonts/SnowburstOne-Regular.ttf') format('truetype'); } :root { diff --git a/web/src/app.html b/web/src/app.html index b5f19dfba5..3838f41f2d 100644 --- a/web/src/app.html +++ b/web/src/app.html @@ -2,7 +2,6 @@ - %sveltekit.head% diff --git a/web/static/empty-1.svg b/web/src/lib/assets/empty-1.svg similarity index 100% rename from web/static/empty-1.svg rename to web/src/lib/assets/empty-1.svg diff --git a/web/static/empty-2.svg b/web/src/lib/assets/empty-2.svg similarity index 100% rename from web/static/empty-2.svg rename to web/src/lib/assets/empty-2.svg diff --git a/web/static/favicon.png b/web/src/lib/assets/favicon.png similarity index 100% rename from web/static/favicon.png rename to web/src/lib/assets/favicon.png diff --git a/web/static/feature-panel.png b/web/src/lib/assets/feature-panel.png similarity index 100% rename from web/static/feature-panel.png rename to web/src/lib/assets/feature-panel.png diff --git a/web/static/fonts/SnowburstOne-Regular.ttf b/web/src/lib/assets/fonts/SnowburstOne-Regular.ttf similarity index 100% rename from web/static/fonts/SnowburstOne-Regular.ttf rename to web/src/lib/assets/fonts/SnowburstOne-Regular.ttf diff --git a/web/static/fonts/WorkSans-Italic-VariableFont_wght.ttf b/web/src/lib/assets/fonts/WorkSans-Italic-VariableFont_wght.ttf similarity index 100% rename from web/static/fonts/WorkSans-Italic-VariableFont_wght.ttf rename to web/src/lib/assets/fonts/WorkSans-Italic-VariableFont_wght.ttf diff --git a/web/static/fonts/WorkSans-VariableFont_wght.ttf b/web/src/lib/assets/fonts/WorkSans-VariableFont_wght.ttf similarity index 100% rename from web/static/fonts/WorkSans-VariableFont_wght.ttf rename to web/src/lib/assets/fonts/WorkSans-VariableFont_wght.ttf diff --git a/web/static/immich-logo-no-outline.png b/web/src/lib/assets/immich-logo-no-outline.png similarity index 100% rename from web/static/immich-logo-no-outline.png rename to web/src/lib/assets/immich-logo-no-outline.png diff --git a/web/static/immich-logo.svg b/web/src/lib/assets/immich-logo.svg similarity index 100% rename from web/static/immich-logo.svg rename to web/src/lib/assets/immich-logo.svg diff --git a/web/static/no-thumbnail.png b/web/src/lib/assets/no-thumbnail.png similarity index 100% rename from web/static/no-thumbnail.png rename to web/src/lib/assets/no-thumbnail.png diff --git a/web/src/lib/components/album-page/__tests__/album-card.spec.ts b/web/src/lib/components/album-page/__tests__/album-card.spec.ts index 30b8521e4f..61706ebf05 100644 --- a/web/src/lib/components/album-page/__tests__/album-card.spec.ts +++ b/web/src/lib/components/album-page/__tests__/album-card.spec.ts @@ -44,10 +44,10 @@ describe('AlbumCard component', () => { const albumDetailsElement = sut.getByTestId('album-details'); const detailsText = `${count} items` + (shared ? ' . Shared' : ''); - expect(albumImgElement).toHaveAttribute('src', 'no-thumbnail.png'); + expect(albumImgElement).toHaveAttribute('src'); expect(albumImgElement).toHaveAttribute('alt', album.id); - await waitFor(() => expect(albumImgElement).toHaveAttribute('src', 'no-thumbnail.png')); + await waitFor(() => expect(albumImgElement).toHaveAttribute('src')); expect(albumImgElement).toHaveAttribute('alt', album.id); expect(apiMock.assetApi.getAssetThumbnail).not.toHaveBeenCalled(); @@ -108,7 +108,7 @@ describe('AlbumCard component', () => { sut = render(AlbumCard, { album }); const albumImgElement = sut.getByTestId('album-image'); - await waitFor(() => expect(albumImgElement).toHaveAttribute('src', 'no-thumbnail.png')); + await waitFor(() => expect(albumImgElement).toHaveAttribute('src')); }); it('dispatches custom "click" event with the album in context', async () => { diff --git a/web/src/lib/components/album-page/album-card.svelte b/web/src/lib/components/album-page/album-card.svelte index f702538ef8..43bb400145 100644 --- a/web/src/lib/components/album-page/album-card.svelte +++ b/web/src/lib/components/album-page/album-card.svelte @@ -16,14 +16,13 @@ import { createEventDispatcher, onMount } from 'svelte'; import DotsVertical from 'svelte-material-icons/DotsVertical.svelte'; import CircleIconButton from '../shared-components/circle-icon-button.svelte'; + import noThumbnailUrl from '$lib/assets/no-thumbnail.png'; export let album: AlbumResponseDto; - const NO_THUMBNAIL = 'no-thumbnail.png'; - let imageData = `/api/asset/thumbnail/${album.albumThumbnailAssetId}?format=${ThumbnailFormat.Webp}`; if (!album.albumThumbnailAssetId) { - imageData = NO_THUMBNAIL; + imageData = noThumbnailUrl; } const dispatchClick = createEventDispatcher(); @@ -51,7 +50,7 @@ }; onMount(async () => { - imageData = (await loadHighQualityThumbnail(album.albumThumbnailAssetId)) || NO_THUMBNAIL; + imageData = (await loadHighQualityThumbnail(album.albumThumbnailAssetId)) || noThumbnailUrl; }); const locale = navigator.language; diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte index f177d4e091..a89204517b 100644 --- a/web/src/lib/components/album-page/album-viewer.svelte +++ b/web/src/lib/components/album-page/album-viewer.svelte @@ -40,6 +40,7 @@ import { openFileUploadDialog } from '$lib/utils/file-uploader'; import { bulkDownload } from '$lib/utils/asset-utils'; import GalleryViewer from '../shared-components/gallery-viewer/gallery-viewer.svelte'; + import ImmichLogo from '../shared-components/immich-logo.svelte'; export let album: AlbumResponseDto; export let sharedLink: SharedLinkResponseDto | undefined = undefined; @@ -419,13 +420,7 @@ class="flex gap-2 place-items-center hover:cursor-pointer ml-6" href="https://immich.app" > - immich logo +

IMMICH

diff --git a/web/src/lib/components/album-page/user-selection-modal.svelte b/web/src/lib/components/album-page/user-selection-modal.svelte index d735f852d7..a2bba9608e 100644 --- a/web/src/lib/components/album-page/user-selection-modal.svelte +++ b/web/src/lib/components/album-page/user-selection-modal.svelte @@ -6,6 +6,7 @@ import Link from 'svelte-material-icons/Link.svelte'; import ShareCircle from 'svelte-material-icons/ShareCircle.svelte'; import { goto } from '$app/navigation'; + import ImmichLogo from '../shared-components/immich-logo.svelte'; export let album: AlbumResponseDto; export let sharedUsersInAlbum: Set; @@ -53,7 +54,7 @@ dispatch('close')}> - Immich +

Invite to album

diff --git a/web/src/lib/components/forms/admin-registration-form.svelte b/web/src/lib/components/forms/admin-registration-form.svelte index 0e9cc1f665..b4e706d5fe 100644 --- a/web/src/lib/components/forms/admin-registration-form.svelte +++ b/web/src/lib/components/forms/admin-registration-form.svelte @@ -1,7 +1,8 @@ + +Immich Logo diff --git a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte index 378bb1cae9..5d219c7f4c 100644 --- a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte +++ b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte @@ -8,6 +8,7 @@ import ThemeButton from '../theme-button.svelte'; import { AppRoute } from '../../../constants'; import AccountInfoPanel from './account-info-panel.svelte'; + import ImmichLogo from '../immich-logo.svelte'; export let user: UserResponseDto; export let shouldShowUploadButton = true; @@ -50,7 +51,7 @@ class="flex gap-2 place-items-center hover:cursor-pointer" href="/photos" > - immich logo +

IMMICH

diff --git a/web/src/lib/components/shared-components/upload-asset-preview.svelte b/web/src/lib/components/shared-components/upload-asset-preview.svelte index 21dfd304bf..5c891e1792 100644 --- a/web/src/lib/components/shared-components/upload-asset-preview.svelte +++ b/web/src/lib/components/shared-components/upload-asset-preview.svelte @@ -2,6 +2,7 @@ import { fade } from 'svelte/transition'; import { asByteUnitString } from '$lib/utils/byte-units'; import { UploadAsset } from '$lib/models/upload-asset'; + import ImmichLogo from './immich-logo.svelte'; export let uploadAsset: UploadAsset; @@ -16,13 +17,9 @@ >
{#if showFallbackImage} - Immich Logo +
+ +
{:else} import { AlbumResponseDto, api, ThumbnailFormat, UserResponseDto } from '@api'; import { fade } from 'svelte/transition'; + import noThumbnailUrl from '$lib/assets/no-thumbnail.png'; export let album: AlbumResponseDto; export let user: UserResponseDto; const loadImageData = async (thubmnailId: string | null) => { if (thubmnailId == null) { - return '/no-thumbnail.png'; + return noThumbnailUrl; } const { data } = await api.assetApi.getAssetThumbnail(thubmnailId, ThumbnailFormat.Webp, { diff --git a/web/src/routes/+error.svelte b/web/src/routes/+error.svelte index ad9625e197..3f0329a146 100644 --- a/web/src/routes/+error.svelte +++ b/web/src/routes/+error.svelte @@ -9,6 +9,7 @@ NotificationType } from '$lib/components/shared-components/notification/notification'; import { handleError } from '$lib/utils/handle-error'; + import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte'; const handleCopy = async () => { // @@ -33,7 +34,7 @@
- immich logo +

IMMICH

diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index c9c1300a2d..f37f0f6bf7 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -13,6 +13,7 @@ import NavigationLoadingBar from '$lib/components/shared-components/navigation-loading-bar.svelte'; import NotificationList from '$lib/components/shared-components/notification/notification-list.svelte'; import { fileUploadHandler } from '$lib/utils/file-uploader'; + import faviconUrl from '$lib/assets/favicon.png'; let shouldShowAnnouncement: boolean; let localVersion: string; @@ -80,6 +81,7 @@ {$page.data.meta?.title || 'Web'} - Immich {#if $page.data.meta} + diff --git a/web/src/routes/+page.svelte b/web/src/routes/+page.svelte index b1f3e2e440..1cd6e0ab6e 100644 --- a/web/src/routes/+page.svelte +++ b/web/src/routes/+page.svelte @@ -1,18 +1,12 @@
- immich-logo +

- Empty shared album + Empty shared album

Create an album to organize your photos and videos diff --git a/web/src/routes/favorites/+page.svelte b/web/src/routes/favorites/+page.svelte index a02315a77e..00a175a556 100644 --- a/web/src/routes/favorites/+page.svelte +++ b/web/src/routes/favorites/+page.svelte @@ -13,6 +13,7 @@ import StarMinusOutline from 'svelte-material-icons/StarMinusOutline.svelte'; import Error from '../+error.svelte'; import type { PageData } from './$types'; + import empty1Url from '$lib/assets/empty-1.svg'; export let data: PageData; @@ -126,7 +127,7 @@

- Empty shared album + Empty shared album

Add favorites to quickly find your best pictures and videos diff --git a/web/src/routes/share/[key]/+page.server.ts b/web/src/routes/share/[key]/+page.server.ts index 50d0cf0163..35c20d1b54 100644 --- a/web/src/routes/share/[key]/+page.server.ts +++ b/web/src/routes/share/[key]/+page.server.ts @@ -4,6 +4,7 @@ import { error } from '@sveltejs/kit'; import { getThumbnailUrl } from '$lib/utils/asset-utils'; import { serverApi, ThumbnailFormat } from '@api'; import type { PageServerLoad } from './$types'; +import featurePanelUrl from '$lib/assets/feature-panel.png'; export const load: PageServerLoad = async ({ params, parent }) => { const { user } = await parent(); @@ -23,7 +24,7 @@ export const load: PageServerLoad = async ({ params, parent }) => { description: sharedLink.description || `${assetCount} shared photos & videos.`, imageUrl: assetId ? getThumbnailUrl(assetId, ThumbnailFormat.Webp, sharedLink.key) - : 'feature-panel.png' + : featurePanelUrl }, user }; diff --git a/web/src/routes/sharing/+page.svelte b/web/src/routes/sharing/+page.svelte index 3bbdc3db4f..f4c4a3c0f0 100644 --- a/web/src/routes/sharing/+page.svelte +++ b/web/src/routes/sharing/+page.svelte @@ -12,6 +12,7 @@ notificationController, NotificationType } from '$lib/components/shared-components/notification/notification'; + import empty2Url from '$lib/assets/empty-2.svg'; export let data: PageData; @@ -94,7 +95,7 @@

- Empty shared album + Empty shared album

Create a shared album to share photos and videos with people in your network

diff --git a/web/static/svelte-welcome.png b/web/static/svelte-welcome.png deleted file mode 100644 index fe7d2d6b50..0000000000 Binary files a/web/static/svelte-welcome.png and /dev/null differ diff --git a/web/static/svelte-welcome.webp b/web/static/svelte-welcome.webp deleted file mode 100644 index 6ec1a28d63..0000000000 Binary files a/web/static/svelte-welcome.webp and /dev/null differ