1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-16 00:36:47 +01:00

perf(web): optimize images and modules (#7088)

* perf: optimize images and modules

* fix: tests

* fix: missing font

* fix: delay showing the loading spinner

* simplify

* simplify

* pr feedback

* chore: merge main

* fix: enum

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
martin 2024-02-18 20:18:40 +01:00 committed by GitHub
parent 3480fe5326
commit 36e5d298db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 796 additions and 59 deletions

675
web/package-lock.json generated
View file

@ -31,6 +31,7 @@
"@floating-ui/dom": "^1.5.1",
"@socket.io/component-emitter": "^3.1.0",
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/enhanced-img": "^0.1.8",
"@sveltejs/kit": "^2.5.0",
"@sveltejs/vite-plugin-svelte": "^3.0.2",
"@testing-library/jest-dom": "^6.1.5",
@ -456,6 +457,16 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
"node_modules/@emnapi/runtime": {
"version": "0.45.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.45.0.tgz",
"integrity": "sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==",
"dev": true,
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz",
@ -969,6 +980,456 @@
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
"dev": true
},
"node_modules/@img/sharp-darwin-arm64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.2.tgz",
"integrity": "sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"glibc": ">=2.26",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-arm64": "1.0.1"
}
},
"node_modules/@img/sharp-darwin-x64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.2.tgz",
"integrity": "sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"glibc": ">=2.26",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-x64": "1.0.1"
}
},
"node_modules/@img/sharp-libvips-darwin-arm64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.1.tgz",
"integrity": "sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"macos": ">=11",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-darwin-x64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.1.tgz",
"integrity": "sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"macos": ">=10.13",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.1.tgz",
"integrity": "sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.28",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.1.tgz",
"integrity": "sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.26",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-s390x": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.1.tgz",
"integrity": "sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.28",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-x64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.1.tgz",
"integrity": "sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.26",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.1.tgz",
"integrity": "sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"musl": ">=1.2.2",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.1.tgz",
"integrity": "sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"musl": ">=1.2.2",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-linux-arm": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.2.tgz",
"integrity": "sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.28",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm": "1.0.1"
}
},
"node_modules/@img/sharp-linux-arm64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.2.tgz",
"integrity": "sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.26",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm64": "1.0.1"
}
},
"node_modules/@img/sharp-linux-s390x": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.2.tgz",
"integrity": "sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.28",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-s390x": "1.0.1"
}
},
"node_modules/@img/sharp-linux-x64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.2.tgz",
"integrity": "sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"glibc": ">=2.26",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-x64": "1.0.1"
}
},
"node_modules/@img/sharp-linuxmusl-arm64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.2.tgz",
"integrity": "sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"musl": ">=1.2.2",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-arm64": "1.0.1"
}
},
"node_modules/@img/sharp-linuxmusl-x64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.2.tgz",
"integrity": "sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"musl": ">=1.2.2",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-x64": "1.0.1"
}
},
"node_modules/@img/sharp-wasm32": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.2.tgz",
"integrity": "sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==",
"cpu": [
"wasm32"
],
"dev": true,
"optional": true,
"dependencies": {
"@emnapi/runtime": "^0.45.0"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-ia32": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.2.tgz",
"integrity": "sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-x64": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.2.tgz",
"integrity": "sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=9.6.5",
"pnpm": ">=7.1.0",
"yarn": ">=3.2.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@immich/sdk": {
"resolved": "../open-api/typescript-sdk",
"link": true
@ -1169,6 +1630,34 @@
"integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==",
"dev": true
},
"node_modules/@rollup/pluginutils": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
"integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^2.0.2",
"picomatch": "^2.3.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/pluginutils/node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.5.tgz",
@ -1358,6 +1847,17 @@
"@sveltejs/kit": "^2.0.0"
}
},
"node_modules/@sveltejs/enhanced-img": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/@sveltejs/enhanced-img/-/enhanced-img-0.1.8.tgz",
"integrity": "sha512-0cLVR9KiO0/t3VVm64OM7bPHTkdaT2aaz1rwoAhao+EBXR3vMvLoYXLHvz8o9/552PSV8G844RkH7qkGc3YAiQ==",
"dev": true,
"dependencies": {
"magic-string": "^0.30.5",
"svelte-parse-markup": "^0.1.2",
"vite-imagetools": "^6.2.8"
}
},
"node_modules/@sveltejs/kit": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.0.tgz",
@ -2966,6 +3466,19 @@
"periscopic": "^3.1.0"
}
},
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
},
"engines": {
"node": ">=12.5.0"
}
},
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@ -2981,6 +3494,34 @@
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
"node_modules/color-string": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
"dev": true,
"dependencies": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"node_modules/color/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -3280,6 +3821,15 @@
"node": ">=8"
}
},
"node_modules/detect-libc": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz",
"integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/devalue": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz",
@ -4617,6 +5167,18 @@
"node": ">= 4"
}
},
"node_modules/imagetools-core": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/imagetools-core/-/imagetools-core-6.0.4.tgz",
"integrity": "sha512-N1qs5qn7u9nR3kboISkYuvJm8MohiphCfBa+wx1UOropVaFis9/mh6wuDPLHJNhl6/64C7q2Pch5NASVKAaSrg==",
"dev": true,
"dependencies": {
"sharp": "^0.33.1"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@ -7013,6 +7575,79 @@
"node": ">=8"
}
},
"node_modules/sharp": {
"version": "0.33.2",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.2.tgz",
"integrity": "sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
"color": "^4.2.3",
"detect-libc": "^2.0.2",
"semver": "^7.5.4"
},
"engines": {
"libvips": ">=8.15.1",
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-darwin-arm64": "0.33.2",
"@img/sharp-darwin-x64": "0.33.2",
"@img/sharp-libvips-darwin-arm64": "1.0.1",
"@img/sharp-libvips-darwin-x64": "1.0.1",
"@img/sharp-libvips-linux-arm": "1.0.1",
"@img/sharp-libvips-linux-arm64": "1.0.1",
"@img/sharp-libvips-linux-s390x": "1.0.1",
"@img/sharp-libvips-linux-x64": "1.0.1",
"@img/sharp-libvips-linuxmusl-arm64": "1.0.1",
"@img/sharp-libvips-linuxmusl-x64": "1.0.1",
"@img/sharp-linux-arm": "0.33.2",
"@img/sharp-linux-arm64": "0.33.2",
"@img/sharp-linux-s390x": "0.33.2",
"@img/sharp-linux-x64": "0.33.2",
"@img/sharp-linuxmusl-arm64": "0.33.2",
"@img/sharp-linuxmusl-x64": "0.33.2",
"@img/sharp-wasm32": "0.33.2",
"@img/sharp-win32-ia32": "0.33.2",
"@img/sharp-win32-x64": "0.33.2"
}
},
"node_modules/sharp/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/sharp/node_modules/semver": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/sharp/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -7066,6 +7701,21 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
"dev": true,
"dependencies": {
"is-arrayish": "^0.3.1"
}
},
"node_modules/simple-swizzle/node_modules/is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"dev": true
},
"node_modules/sirv": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
@ -7551,6 +8201,18 @@
}
}
},
"node_modules/svelte-parse-markup": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/svelte-parse-markup/-/svelte-parse-markup-0.1.2.tgz",
"integrity": "sha512-DycY7DJr7VqofiJ63ut1/NEG92HrWWL56VWITn/cJCu+LlZhMoBkBXT4opUitPEEwbq1nMQbv4vTKUfbOqIW1g==",
"dev": true,
"funding": {
"url": "https://bjornlu.com/sponsor"
},
"peerDependencies": {
"svelte": "^3.0.0 || ^4.0.0"
}
},
"node_modules/svelte-preprocess": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz",
@ -8125,6 +8787,19 @@
}
}
},
"node_modules/vite-imagetools": {
"version": "6.2.9",
"resolved": "https://registry.npmjs.org/vite-imagetools/-/vite-imagetools-6.2.9.tgz",
"integrity": "sha512-C4ZYhgj2vAj43/TpZ06XlDNP0p/7LIeYbgUYr+xG44nM++4HGX6YZBKAYpiBNgiCFUTJ6eXkRppWBrfPMevgmg==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^5.0.5",
"imagetools-core": "^6.0.4"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/vite-node": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.2.2.tgz",

View file

@ -26,6 +26,7 @@
"@floating-ui/dom": "^1.5.1",
"@socket.io/component-emitter": "^3.1.0",
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/enhanced-img": "^0.1.8",
"@sveltejs/kit": "^2.5.0",
"@sveltejs/vite-plugin-svelte": "^3.0.2",
"@testing-library/jest-dom": "^6.1.5",

View file

@ -1,6 +1,5 @@
<script lang="ts">
import { api } from '$lib/api';
import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
import Icon from '$lib/components/elements/icon.svelte';
import { locale } from '$lib/stores/preferences.store';
import { user } from '$lib/stores/user.store';
@ -21,7 +20,7 @@
$: imageData = album.albumThumbnailAssetId
? getAssetThumbnailUrl(album.albumThumbnailAssetId, ThumbnailFormat.Webp)
: noThumbnailUrl;
: null;
const dispatchClick = createEventDispatcher<OnClick>();
const dispatchShowContextMenu = createEventDispatcher<OnShowContextMenu>();
@ -50,7 +49,7 @@
dispatchShowContextMenu('showalbumcontextmenu', getContextMenuPosition(e));
onMount(async () => {
imageData = (await loadHighQualityThumbnail(album.albumThumbnailAssetId)) || noThumbnailUrl;
imageData = (await loadHighQualityThumbnail(album.albumThumbnailAssetId)) || null;
});
const getAlbumOwnerInfo = () => getUserById({ id: album.ownerId });
@ -81,15 +80,26 @@
{/if}
<div class={`relative aspect-square`}>
<img
loading={preload ? 'eager' : 'lazy'}
src={imageData}
alt={album.id}
class={`z-0 h-full w-full rounded-xl object-cover transition-all duration-300 hover:shadow-lg`}
data-testid="album-image"
draggable="false"
/>
<div class="absolute top-0 h-full w-full rounded-3xl" />
{#if album.albumThumbnailAssetId}
<img
loading={preload ? 'eager' : 'lazy'}
src={imageData}
alt={album.id}
class="z-0 h-full w-full rounded-xl object-cover transition-all duration-300 hover:shadow-lg"
data-testid="album-image"
draggable="false"
/>
{:else}
<enhanced:img
loading={preload ? 'eager' : 'lazy'}
src="$lib/assets/no-thumbnail.png"
sizes="min(271px,186px)"
alt={album.id}
class="z-0 h-full w-full rounded-xl object-cover transition-all duration-300 hover:shadow-lg"
data-testid="album-image"
draggable="false"
/>
{/if}
</div>
<div class="mt-4">

View file

@ -1,14 +1,14 @@
<script lang="ts">
import Icon from '$lib/components/elements/icon.svelte';
import ChangeDate from '$lib/components/shared-components/change-date.svelte';
import { AppRoute, QueryParameter } from '$lib/constants';
import { AppRoute, QueryParameter, timeToLoadTheMap } from '$lib/constants';
import { boundingBoxesArray } from '$lib/stores/people.store';
import { locale } from '$lib/stores/preferences.store';
import { featureFlags } from '$lib/stores/server-config.store';
import { user } from '$lib/stores/user.store';
import { websocketEvents } from '$lib/stores/websocket';
import { getAssetThumbnailUrl, getPeopleThumbnailUrl, isSharedLink } from '$lib/utils';
import { getAssetFilename } from '$lib/utils/asset-utils';
import { delay, getAssetFilename } from '$lib/utils/asset-utils';
import { autoGrowHeight } from '$lib/utils/autogrow';
import { clickOutside } from '$lib/utils/click-outside';
import {
@ -38,8 +38,8 @@
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import PersonSidePanel from '../faces-page/person-side-panel.svelte';
import ChangeLocation from '../shared-components/change-location.svelte';
import Map from '../shared-components/map/map.svelte';
import UserAvatar from '../shared-components/user-avatar.svelte';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
export let asset: AssetResponseDto;
export let albums: AlbumResponseDto[] = [];
@ -609,27 +609,37 @@
{#if latlng && $featureFlags.loaded && $featureFlags.map}
<div class="h-[360px]">
<Map
mapMarkers={[{ lat: latlng.lat, lon: latlng.lng, id: asset.id }]}
center={latlng}
zoom={15}
simplified
useLocationPin
>
<svelte:fragment slot="popup" let:marker>
{@const { lat, lon } = marker}
<div class="flex flex-col items-center gap-1">
<p class="font-bold">{lat.toPrecision(6)}, {lon.toPrecision(6)}</p>
<a
href="https://www.openstreetmap.org/?mlat={lat}&mlon={lon}&zoom=15#map=15/{lat}/{lon}"
target="_blank"
class="font-medium text-immich-primary"
>
Open in OpenStreetMap
</a>
{#await import('../shared-components/map/map.svelte')}
{#await delay(timeToLoadTheMap) then}
<!-- show the loading spinner only if loading the map takes too much time -->
<div class="flex items-center justify-center h-full w-full">
<LoadingSpinner />
</div>
</svelte:fragment>
</Map>
{/await}
{:then component}
<svelte:component
this={component.default}
mapMarkers={[{ lat: latlng.lat, lon: latlng.lng, id: asset.id }]}
center={latlng}
zoom={15}
simplified
useLocationPin
>
<svelte:fragment slot="popup" let:marker>
{@const { lat, lon } = marker}
<div class="flex flex-col items-center gap-1">
<p class="font-bold">{lat.toPrecision(6)}, {lon.toPrecision(6)}</p>
<a
href="https://www.openstreetmap.org/?mlat={lat}&mlon={lon}&zoom=15#map=15/{lat}/{lon}"
target="_blank"
class="font-medium text-immich-primary"
>
Open in OpenStreetMap
</a>
</div>
</svelte:fragment>
</svelte:component>
{/await}
</div>
{/if}

View file

@ -168,14 +168,22 @@
class:hover:opacity-70={previousMemory}
>
<button class="relative h-full w-full rounded-2xl" disabled={!previousMemory} on:click={toPreviousMemory}>
<img
class="h-full w-full rounded-2xl object-cover"
src={previousMemory
? getAssetThumbnailUrl(previousMemory.assets[0].id, ThumbnailFormat.Jpeg)
: noThumbnailUrl}
alt=""
draggable="false"
/>
{#if previousMemory}
<img
class="h-full w-full rounded-2xl object-cover"
src={getAssetThumbnailUrl(previousMemory.assets[0].id, ThumbnailFormat.Jpeg)}
alt=""
draggable="false"
/>
{:else}
<enhanced:img
class="h-full w-full rounded-2xl object-cover"
src={noThumbnailUrl}
sizes="min(271px,186px)"
alt=""
draggable="false"
/>
{/if}
{#if previousMemory}
<div class="absolute bottom-4 right-4 text-left text-white">
@ -233,12 +241,22 @@
class:hover:opacity-70={nextMemory}
>
<button class="relative h-full w-full rounded-2xl" on:click={toNextMemory} disabled={!nextMemory}>
<img
class="h-full w-full rounded-2xl object-cover"
src={nextMemory ? getAssetThumbnailUrl(nextMemory.assets[0].id, ThumbnailFormat.Jpeg) : noThumbnailUrl}
alt=""
draggable="false"
/>
{#if nextMemory}
<img
class="h-full w-full rounded-2xl object-cover"
src={getAssetThumbnailUrl(nextMemory.assets[0].id, ThumbnailFormat.Jpeg)}
alt=""
draggable="false"
/>
{:else}
<enhanced:img
class="h-full w-full rounded-2xl object-cover"
src={noThumbnailUrl}
sizes="min(271px,186px)"
alt=""
draggable="false"
/>
{/if}
{#if nextMemory}
<div class="absolute bottom-4 left-4 text-left text-white">

View file

@ -2,7 +2,10 @@
import type { AssetResponseDto } from '@immich/sdk';
import { createEventDispatcher } from 'svelte';
import ConfirmDialogue from './confirm-dialogue.svelte';
import Map from './map/map.svelte';
import LoadingSpinner from './loading-spinner.svelte';
import { delay } from '$lib/utils/asset-utils';
import { timeToLoadTheMap } from '$lib/constants';
export const title = 'Change Location';
export let asset: AssetResponseDto | undefined = undefined;
@ -48,14 +51,24 @@
<div slot="prompt" class="flex flex-col w-full h-full gap-2">
<label for="datetime">Pick a location</label>
<div class="h-[500px] min-h-[300px] w-full">
<Map
mapMarkers={lat && lng && asset ? [{ id: asset.id, lat, lon: lng }] : []}
{zoom}
center={lat && lng ? { lat, lng } : undefined}
simplified={true}
clickable={true}
on:clickedPoint={({ detail: point }) => handleSelect(point)}
/>
{#await import('../shared-components/map/map.svelte')}
{#await delay(timeToLoadTheMap) then}
<!-- show the loading spinner only if loading the map takes too much time -->
<div class="flex items-center justify-center h-full w-full">
<LoadingSpinner />
</div>
{/await}
{:then component}
<svelte:component
this={component.default}
mapMarkers={lat && lng && asset ? [{ id: asset.id, lat, lon: lng }] : []}
{zoom}
center={lat && lng ? { lat, lng } : undefined}
simplified={true}
clickable={true}
on:clickedPoint={({ detail: point }) => handleSelect(point)}
/>
{/await}
</div>
</div>
</ConfirmDialogue>

View file

@ -85,7 +85,7 @@
/>
{/await}
{:else}
<img
<enhanced:img
src={noThumbnailUrl}
alt={'Album without assets'}
class="h-[100px] w-[100px] rounded-lg object-cover"

View file

@ -86,7 +86,11 @@ export enum ActionQueryParameterValue {
export const maximumLengthSearchPeople: number = 20;
// time to load the map before displaying the loading spinner
export const timeToLoadTheMap: number = 100;
export const timeBeforeShowLoadingSpinner: number = 100;
// should be the same values as the ones in the app.html
export enum Theme {
LIGHT = 'light',

View file

@ -226,3 +226,7 @@ export const getSelectedAssets = (assets: Set<AssetResponseDto>, user: UserRespo
}
return ids;
};
export const delay = async (ms: number) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};

View file

@ -1,3 +1,4 @@
import { enhancedImages } from '@sveltejs/enhanced-img';
import { sveltekit } from '@sveltejs/kit/vite';
import path from 'node:path';
import { visualizer } from 'rollup-plugin-visualizer';
@ -33,6 +34,7 @@ export default defineConfig({
emitFile: true,
filename: 'stats.html',
}),
enhancedImages(),
],
optimizeDeps: {
entries: ['src/**/*.{svelte,ts,html}'],