mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	chore(web): fade between thumbhash and thumbnail (#2856)
This commit is contained in:
		
							
								
								
									
										131
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										131
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -10,6 +10,7 @@
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"@zoom-image/svelte": "^0.1.0",
 | 
			
		||||
				"axios": "^0.27.2",
 | 
			
		||||
				"buffer": "^6.0.3",
 | 
			
		||||
				"copy-image-clipboard": "^2.1.2",
 | 
			
		||||
				"handlebars": "^4.7.7",
 | 
			
		||||
				"justified-layout": "^4.1.0",
 | 
			
		||||
@@ -21,7 +22,7 @@
 | 
			
		||||
				"socket.io-client": "^4.6.1",
 | 
			
		||||
				"svelte-local-storage-store": "^0.5.0",
 | 
			
		||||
				"svelte-material-icons": "^3.0.4",
 | 
			
		||||
				"unlazy": "^0.8.9"
 | 
			
		||||
				"thumbhash": "^0.1.1"
 | 
			
		||||
			},
 | 
			
		||||
			"devDependencies": {
 | 
			
		||||
				"@babel/preset-env": "^7.20.2",
 | 
			
		||||
@@ -4135,15 +4136,6 @@
 | 
			
		||||
				"url": "https://opencollective.com/typescript-eslint"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@unlazy/core": {
 | 
			
		||||
			"version": "0.8.9",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@unlazy/core/-/core-0.8.9.tgz",
 | 
			
		||||
			"integrity": "sha512-DQ4WB/cuEWTknU/59uRwpSipvMAJzBDmRyaHDUc1RcXi0Z7/Vcl0EE7BpROxEynqd1EI+2oMWQaDLyXffUdUiA==",
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"fast-blurhash": "^1.1.2",
 | 
			
		||||
				"thumbhash": "^0.1.1"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@zoom-image/core": {
 | 
			
		||||
			"version": "0.18.2",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.18.2.tgz",
 | 
			
		||||
@@ -4595,6 +4587,25 @@
 | 
			
		||||
			"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
 | 
			
		||||
			"dev": true
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/base64-js": {
 | 
			
		||||
			"version": "1.5.1",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
 | 
			
		||||
			"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
 | 
			
		||||
			"funding": [
 | 
			
		||||
				{
 | 
			
		||||
					"type": "github",
 | 
			
		||||
					"url": "https://github.com/sponsors/feross"
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					"type": "patreon",
 | 
			
		||||
					"url": "https://www.patreon.com/feross"
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					"type": "consulting",
 | 
			
		||||
					"url": "https://feross.org/support"
 | 
			
		||||
				}
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/binary-extensions": {
 | 
			
		||||
			"version": "2.2.0",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
 | 
			
		||||
@@ -4663,6 +4674,29 @@
 | 
			
		||||
				"node-int64": "^0.4.0"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/buffer": {
 | 
			
		||||
			"version": "6.0.3",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
 | 
			
		||||
			"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
 | 
			
		||||
			"funding": [
 | 
			
		||||
				{
 | 
			
		||||
					"type": "github",
 | 
			
		||||
					"url": "https://github.com/sponsors/feross"
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					"type": "patreon",
 | 
			
		||||
					"url": "https://www.patreon.com/feross"
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					"type": "consulting",
 | 
			
		||||
					"url": "https://feross.org/support"
 | 
			
		||||
				}
 | 
			
		||||
			],
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"base64-js": "^1.3.1",
 | 
			
		||||
				"ieee754": "^1.2.1"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/buffer-crc32": {
 | 
			
		||||
			"version": "0.2.13",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
 | 
			
		||||
@@ -5955,11 +5989,6 @@
 | 
			
		||||
				"node": ">= 14"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/fast-blurhash": {
 | 
			
		||||
			"version": "1.1.2",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/fast-blurhash/-/fast-blurhash-1.1.2.tgz",
 | 
			
		||||
			"integrity": "sha512-lJVOgYSlahqkRhrKumNx/SGB2F/qS0D1z7xjGYjb5EZJRtlzySGMniZjkQ9h9Rv8sPmM/V9orEgRiMwazDNH6A=="
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/fast-deep-equal": {
 | 
			
		||||
			"version": "3.1.3",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 | 
			
		||||
@@ -6518,6 +6547,25 @@
 | 
			
		||||
				"node": ">=4"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/ieee754": {
 | 
			
		||||
			"version": "1.2.1",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
 | 
			
		||||
			"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
 | 
			
		||||
			"funding": [
 | 
			
		||||
				{
 | 
			
		||||
					"type": "github",
 | 
			
		||||
					"url": "https://github.com/sponsors/feross"
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					"type": "patreon",
 | 
			
		||||
					"url": "https://www.patreon.com/feross"
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					"type": "consulting",
 | 
			
		||||
					"url": "https://feross.org/support"
 | 
			
		||||
				}
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/ignore": {
 | 
			
		||||
			"version": "5.2.4",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
 | 
			
		||||
@@ -11461,18 +11509,6 @@
 | 
			
		||||
				"node": ">= 4.0.0"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/unlazy": {
 | 
			
		||||
			"version": "0.8.9",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/unlazy/-/unlazy-0.8.9.tgz",
 | 
			
		||||
			"integrity": "sha512-lRCuXN20N1esqSQqtSVBLAw9GJz0lcBuOBs3UGGw7cFWHQlWJVZZ3OviwOl42f1CnVHjAON1rs2hIdJWgMAUyg==",
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"@unlazy/core": "0.8.9"
 | 
			
		||||
			},
 | 
			
		||||
			"peerDependencies": {
 | 
			
		||||
				"fast-blurhash": "^1.1.2",
 | 
			
		||||
				"thumbhash": "^0.1.1"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/update-browserslist-db": {
 | 
			
		||||
			"version": "1.0.10",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
 | 
			
		||||
@@ -14771,15 +14807,6 @@
 | 
			
		||||
				"eslint-visitor-keys": "^3.3.0"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"@unlazy/core": {
 | 
			
		||||
			"version": "0.8.9",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@unlazy/core/-/core-0.8.9.tgz",
 | 
			
		||||
			"integrity": "sha512-DQ4WB/cuEWTknU/59uRwpSipvMAJzBDmRyaHDUc1RcXi0Z7/Vcl0EE7BpROxEynqd1EI+2oMWQaDLyXffUdUiA==",
 | 
			
		||||
			"requires": {
 | 
			
		||||
				"fast-blurhash": "^1.1.2",
 | 
			
		||||
				"thumbhash": "^0.1.1"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"@zoom-image/core": {
 | 
			
		||||
			"version": "0.18.2",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.18.2.tgz",
 | 
			
		||||
@@ -15110,6 +15137,11 @@
 | 
			
		||||
			"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
 | 
			
		||||
			"dev": true
 | 
			
		||||
		},
 | 
			
		||||
		"base64-js": {
 | 
			
		||||
			"version": "1.5.1",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
 | 
			
		||||
			"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
 | 
			
		||||
		},
 | 
			
		||||
		"binary-extensions": {
 | 
			
		||||
			"version": "2.2.0",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
 | 
			
		||||
@@ -15156,6 +15188,15 @@
 | 
			
		||||
				"node-int64": "^0.4.0"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"buffer": {
 | 
			
		||||
			"version": "6.0.3",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
 | 
			
		||||
			"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
 | 
			
		||||
			"requires": {
 | 
			
		||||
				"base64-js": "^1.3.1",
 | 
			
		||||
				"ieee754": "^1.2.1"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"buffer-crc32": {
 | 
			
		||||
			"version": "0.2.13",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
 | 
			
		||||
@@ -16094,11 +16135,6 @@
 | 
			
		||||
				"source-map-support": "^0.5.21"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"fast-blurhash": {
 | 
			
		||||
			"version": "1.1.2",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/fast-blurhash/-/fast-blurhash-1.1.2.tgz",
 | 
			
		||||
			"integrity": "sha512-lJVOgYSlahqkRhrKumNx/SGB2F/qS0D1z7xjGYjb5EZJRtlzySGMniZjkQ9h9Rv8sPmM/V9orEgRiMwazDNH6A=="
 | 
			
		||||
		},
 | 
			
		||||
		"fast-deep-equal": {
 | 
			
		||||
			"version": "3.1.3",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 | 
			
		||||
@@ -16517,6 +16553,11 @@
 | 
			
		||||
				"harmony-reflect": "^1.4.6"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"ieee754": {
 | 
			
		||||
			"version": "1.2.1",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
 | 
			
		||||
			"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
 | 
			
		||||
		},
 | 
			
		||||
		"ignore": {
 | 
			
		||||
			"version": "5.2.4",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
 | 
			
		||||
@@ -20074,14 +20115,6 @@
 | 
			
		||||
			"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
 | 
			
		||||
			"dev": true
 | 
			
		||||
		},
 | 
			
		||||
		"unlazy": {
 | 
			
		||||
			"version": "0.8.9",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/unlazy/-/unlazy-0.8.9.tgz",
 | 
			
		||||
			"integrity": "sha512-lRCuXN20N1esqSQqtSVBLAw9GJz0lcBuOBs3UGGw7cFWHQlWJVZZ3OviwOl42f1CnVHjAON1rs2hIdJWgMAUyg==",
 | 
			
		||||
			"requires": {
 | 
			
		||||
				"@unlazy/core": "0.8.9"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"update-browserslist-db": {
 | 
			
		||||
			"version": "1.0.10",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
 | 
			
		||||
 
 | 
			
		||||
@@ -60,6 +60,7 @@
 | 
			
		||||
	"dependencies": {
 | 
			
		||||
		"@zoom-image/svelte": "^0.1.0",
 | 
			
		||||
		"axios": "^0.27.2",
 | 
			
		||||
		"buffer": "^6.0.3",
 | 
			
		||||
		"copy-image-clipboard": "^2.1.2",
 | 
			
		||||
		"handlebars": "^4.7.7",
 | 
			
		||||
		"justified-layout": "^4.1.0",
 | 
			
		||||
@@ -71,6 +72,6 @@
 | 
			
		||||
		"socket.io-client": "^4.6.1",
 | 
			
		||||
		"svelte-local-storage-store": "^0.5.0",
 | 
			
		||||
		"svelte-material-icons": "^3.0.4",
 | 
			
		||||
		"unlazy": "^0.8.9"
 | 
			
		||||
		"thumbhash": "^0.1.1"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,8 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
	import { onMount } from 'svelte';
 | 
			
		||||
	import { lazyLoad } from 'unlazy';
 | 
			
		||||
	import { imageLoad } from '$lib/utils/image-load';
 | 
			
		||||
	import { fade } from 'svelte/transition';
 | 
			
		||||
	import { thumbHashToDataURL } from 'thumbhash';
 | 
			
		||||
	import { Buffer } from 'buffer';
 | 
			
		||||
 | 
			
		||||
	export let url: string;
 | 
			
		||||
	export let altText: string;
 | 
			
		||||
@@ -11,37 +12,11 @@
 | 
			
		||||
	export let curve = false;
 | 
			
		||||
	export let shadow = false;
 | 
			
		||||
	export let circle = false;
 | 
			
		||||
	let loading = true;
 | 
			
		||||
 | 
			
		||||
	let imageElement: HTMLImageElement;
 | 
			
		||||
 | 
			
		||||
	onMount(() => {
 | 
			
		||||
		if (thumbhash) {
 | 
			
		||||
			lazyLoad(imageElement, {
 | 
			
		||||
				hash: thumbhash,
 | 
			
		||||
				hashType: 'thumbhash'
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	let complete = false;
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{#if thumbhash}
 | 
			
		||||
	<img
 | 
			
		||||
		style:width={widthStyle}
 | 
			
		||||
		style:height={heightStyle}
 | 
			
		||||
		data-src={url}
 | 
			
		||||
		alt={altText}
 | 
			
		||||
		class="object-cover"
 | 
			
		||||
		class:rounded-lg={curve}
 | 
			
		||||
		class:shadow-lg={shadow}
 | 
			
		||||
		class:rounded-full={circle}
 | 
			
		||||
		draggable="false"
 | 
			
		||||
		bind:this={imageElement}
 | 
			
		||||
	/>
 | 
			
		||||
 | 
			
		||||
	<!-- not everthing yet has thumbhash support so the old method is kept -->
 | 
			
		||||
{:else}
 | 
			
		||||
	<img
 | 
			
		||||
<img
 | 
			
		||||
	style:width={widthStyle}
 | 
			
		||||
	style:height={heightStyle}
 | 
			
		||||
	src={url}
 | 
			
		||||
@@ -50,9 +25,23 @@
 | 
			
		||||
	class:rounded-lg={curve}
 | 
			
		||||
	class:shadow-lg={shadow}
 | 
			
		||||
	class:rounded-full={circle}
 | 
			
		||||
		class:opacity-0={loading}
 | 
			
		||||
	class:opacity-0={!thumbhash && !complete}
 | 
			
		||||
	draggable="false"
 | 
			
		||||
	use:imageLoad
 | 
			
		||||
		on:image-load|once={() => (loading = false)}
 | 
			
		||||
	on:image-load|once={() => (complete = true)}
 | 
			
		||||
/>
 | 
			
		||||
 | 
			
		||||
{#if thumbhash && !complete}
 | 
			
		||||
	<img
 | 
			
		||||
		style:width={widthStyle}
 | 
			
		||||
		style:height={heightStyle}
 | 
			
		||||
		src={thumbHashToDataURL(Buffer.from(thumbhash, 'base64'))}
 | 
			
		||||
		alt={altText}
 | 
			
		||||
		class="absolute object-cover top-0"
 | 
			
		||||
		class:rounded-lg={curve}
 | 
			
		||||
		class:shadow-lg={shadow}
 | 
			
		||||
		class:rounded-full={circle}
 | 
			
		||||
		draggable="false"
 | 
			
		||||
		out:fade={{ duration: 300 }}
 | 
			
		||||
	/>
 | 
			
		||||
{/if}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user