mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	feat(web): set asset as profile picture (#3106)
* add profile-image-cropper component
* add dom-to-image library
* add store to update user profile picture when set
* dom-to-image
* remove console.logs, add svelte binding
* fix format, unused vars
* change caching of profile image
* set hash after profile image change
* remove unnecessary store
* remove unecesarry changes
* set types/dom-to-image as devDependency
* remove unecessary type declarations
use handleError
* remove error notification
which is already handled by handleError
* Revert "set types/dom-to-image as devDependency"
This reverts commit ca8b3ed1bbe728de8bc5890e32ae76324a95a6ca.
* add types do dev dependencies
* use on:close instead of on:close={()=>...}
* add newline
* sort imports
* bind photo-viewer imgElement directly, not working
* remove console.log, fix binding
* make imgElement optional
* fix element as optional prop
* fix type
* check for transparency
* small changes
* fix img.decode
* add bg, remove publicsharedkey
* fix omit publicSharedKey
---------
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
			
			
This commit is contained in:
		| @@ -94,7 +94,7 @@ export class UserController { | ||||
|   } | ||||
|  | ||||
|   @Get('/profile-image/:userId') | ||||
|   @Header('Cache-Control', 'private, max-age=86400, no-transform') | ||||
|   @Header('Cache-Control', 'private, no-cache, no-transform') | ||||
|   async getProfileImage(@Param() { userId }: UserIdDto, @Response({ passthrough: true }) res: Res): Promise<any> { | ||||
|     const readableStream = await this.service.getUserProfileImage(userId); | ||||
|     res.header('Content-Type', 'image/jpeg'); | ||||
|   | ||||
							
								
								
									
										217
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										217
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -12,6 +12,7 @@ | ||||
|         "axios": "^0.27.2", | ||||
|         "buffer": "^6.0.3", | ||||
|         "copy-image-clipboard": "^2.1.2", | ||||
|         "dom-to-image": "^2.6.0", | ||||
|         "handlebars": "^4.7.7", | ||||
|         "justified-layout": "^4.1.0", | ||||
|         "leaflet": "^1.9.4", | ||||
| @@ -33,6 +34,7 @@ | ||||
|         "@testing-library/jest-dom": "^5.16.5", | ||||
|         "@testing-library/svelte": "^4.0.3", | ||||
|         "@types/cookie": "^0.5.1", | ||||
|         "@types/dom-to-image": "^2.6.4", | ||||
|         "@types/justified-layout": "^4.1.0", | ||||
|         "@types/leaflet": "^1.9.1", | ||||
|         "@types/leaflet.markercluster": "^1.5.1", | ||||
| @@ -3266,9 +3268,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@sveltejs/kit": { | ||||
|       "version": "1.22.1", | ||||
|       "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.22.1.tgz", | ||||
|       "integrity": "sha512-idFhKVEHuCKbTETvuo3V7UShqSYX9JMKVJXP546dOTkh5ZRejo5XtKtsB5TCSwNBa0TH8hIV44/bnylaFhM1Vg==", | ||||
|       "version": "1.22.3", | ||||
|       "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.22.3.tgz", | ||||
|       "integrity": "sha512-IpHD5wvuoOIHYaHQUBJ1zERD2Iz+fB/rBXhXjl8InKw6X4VKE9BSus+ttHhE7Ke+Ie9ecfilzX8BnWE3FeQyng==", | ||||
|       "dev": true, | ||||
|       "hasInstallScript": true, | ||||
|       "dependencies": { | ||||
| @@ -3393,15 +3395,6 @@ | ||||
|         "url": "https://github.com/chalk/ansi-styles?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@testing-library/dom/node_modules/aria-query": { | ||||
|       "version": "5.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", | ||||
|       "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "deep-equal": "^2.0.5" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@testing-library/dom/node_modules/chalk": { | ||||
|       "version": "4.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", | ||||
| @@ -3623,6 +3616,12 @@ | ||||
|       "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/@types/dom-to-image": { | ||||
|       "version": "2.6.4", | ||||
|       "resolved": "https://registry.npmjs.org/@types/dom-to-image/-/dom-to-image-2.6.4.tgz", | ||||
|       "integrity": "sha512-UddUdGF1qulrSDulkz3K2Ypq527MR6ixlgAzqLbxSiQ0icx0XDlIV+h4+edmjq/1dqn0KgN0xGSe1kI9t+vGuw==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/@types/estree": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", | ||||
| @@ -4125,20 +4124,20 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@zoom-image/core": { | ||||
|       "version": "0.19.0", | ||||
|       "resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.19.0.tgz", | ||||
|       "integrity": "sha512-eiN4ZX/lpBMpDoJh1QoKzWBuEIwdjdiEMgEXAjltS0G3f8jfS85uXq2hCF9JcbdjuM9b2JeydOqPi5aZ5TGGxw==", | ||||
|       "version": "0.20.0", | ||||
|       "resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.20.0.tgz", | ||||
|       "integrity": "sha512-QJOGDaHCCkGCAaytWanf0YypOd2gKvn5trn1sHgEFB8T76jgk6RMhuplRJvmKJOitHcr2DKZEwYFurwd9nZ3+w==", | ||||
|       "funding": { | ||||
|         "type": "github", | ||||
|         "url": "https://github.com/sponsors/willnguyen1312" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@zoom-image/svelte": { | ||||
|       "version": "0.1.9", | ||||
|       "resolved": "https://registry.npmjs.org/@zoom-image/svelte/-/svelte-0.1.9.tgz", | ||||
|       "integrity": "sha512-nrWyapOKrNZtApTA6etECpivkR8FIktbO+56U8FQrUX6rU7DlSxTavX10fDsP0rhUuun0GCN1jIGFJ3nm2dOmw==", | ||||
|       "version": "0.1.10", | ||||
|       "resolved": "https://registry.npmjs.org/@zoom-image/svelte/-/svelte-0.1.10.tgz", | ||||
|       "integrity": "sha512-OXeZWWG1W479KpBW8j/8B1R7JyNoZfhoe3IW/ebffyQcbvCAB3UP6HiF5QueU58RvDLMKO+cjvjIaLmJ+w3YCQ==", | ||||
|       "dependencies": { | ||||
|         "@zoom-image/core": "0.19.0" | ||||
|         "@zoom-image/core": "0.20.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "github", | ||||
| @@ -4292,24 +4291,12 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/aria-query": { | ||||
|       "version": "5.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", | ||||
|       "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", | ||||
|       "dependencies": { | ||||
|         "dequal": "^2.0.3" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/array-buffer-byte-length": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", | ||||
|       "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", | ||||
|       "version": "5.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", | ||||
|       "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "call-bind": "^1.0.2", | ||||
|         "is-array-buffer": "^3.0.1" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/ljharb" | ||||
|         "deep-equal": "^2.0.5" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/array-union": { | ||||
| @@ -5141,17 +5128,16 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/deep-equal": { | ||||
|       "version": "2.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", | ||||
|       "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", | ||||
|       "version": "2.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", | ||||
|       "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "array-buffer-byte-length": "^1.0.0", | ||||
|         "call-bind": "^1.0.2", | ||||
|         "es-get-iterator": "^1.1.3", | ||||
|         "get-intrinsic": "^1.2.0", | ||||
|         "es-get-iterator": "^1.1.2", | ||||
|         "get-intrinsic": "^1.1.3", | ||||
|         "is-arguments": "^1.1.1", | ||||
|         "is-array-buffer": "^3.0.2", | ||||
|         "is-array-buffer": "^3.0.1", | ||||
|         "is-date-object": "^1.0.5", | ||||
|         "is-regex": "^1.1.4", | ||||
|         "is-shared-array-buffer": "^1.0.2", | ||||
| @@ -5159,7 +5145,7 @@ | ||||
|         "object-is": "^1.1.5", | ||||
|         "object-keys": "^1.1.1", | ||||
|         "object.assign": "^4.1.4", | ||||
|         "regexp.prototype.flags": "^1.5.0", | ||||
|         "regexp.prototype.flags": "^1.4.3", | ||||
|         "side-channel": "^1.0.4", | ||||
|         "which-boxed-primitive": "^1.0.2", | ||||
|         "which-collection": "^1.0.1", | ||||
| @@ -5291,6 +5277,11 @@ | ||||
|       "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/dom-to-image": { | ||||
|       "version": "2.6.0", | ||||
|       "resolved": "https://registry.npmjs.org/dom-to-image/-/dom-to-image-2.6.0.tgz", | ||||
|       "integrity": "sha512-Dt0QdaHmLpjURjU7Tnu3AgYSF2LuOmksSGsUcE6ItvJoCWTBEmiMXcqBdNSAm9+QbbwD7JMoVsuuKX6ZVQv1qA==" | ||||
|     }, | ||||
|     "node_modules/domexception": { | ||||
|       "version": "4.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", | ||||
| @@ -6265,14 +6256,13 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/get-intrinsic": { | ||||
|       "version": "1.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", | ||||
|       "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", | ||||
|       "version": "1.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", | ||||
|       "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "function-bind": "^1.1.1", | ||||
|         "has": "^1.0.3", | ||||
|         "has-proto": "^1.0.1", | ||||
|         "has-symbols": "^1.0.3" | ||||
|       }, | ||||
|       "funding": { | ||||
| @@ -6479,18 +6469,6 @@ | ||||
|         "url": "https://github.com/sponsors/ljharb" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/has-proto": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", | ||||
|       "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", | ||||
|       "dev": true, | ||||
|       "engines": { | ||||
|         "node": ">= 0.4" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "url": "https://github.com/sponsors/ljharb" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/has-symbols": { | ||||
|       "version": "1.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", | ||||
| @@ -10348,14 +10326,14 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/regexp.prototype.flags": { | ||||
|       "version": "1.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", | ||||
|       "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", | ||||
|       "version": "1.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", | ||||
|       "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "call-bind": "^1.0.2", | ||||
|         "define-properties": "^1.2.0", | ||||
|         "functions-have-names": "^1.2.3" | ||||
|         "define-properties": "^1.1.3", | ||||
|         "functions-have-names": "^1.2.2" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">= 0.4" | ||||
| @@ -11214,6 +11192,14 @@ | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", | ||||
|       "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" | ||||
|     }, | ||||
|     "node_modules/svelte/node_modules/aria-query": { | ||||
|       "version": "5.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", | ||||
|       "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", | ||||
|       "dependencies": { | ||||
|         "dequal": "^2.0.3" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/svelte/node_modules/estree-walker": { | ||||
|       "version": "3.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", | ||||
| @@ -14229,9 +14215,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@sveltejs/kit": { | ||||
|       "version": "1.22.1", | ||||
|       "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.22.1.tgz", | ||||
|       "integrity": "sha512-idFhKVEHuCKbTETvuo3V7UShqSYX9JMKVJXP546dOTkh5ZRejo5XtKtsB5TCSwNBa0TH8hIV44/bnylaFhM1Vg==", | ||||
|       "version": "1.22.3", | ||||
|       "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.22.3.tgz", | ||||
|       "integrity": "sha512-IpHD5wvuoOIHYaHQUBJ1zERD2Iz+fB/rBXhXjl8InKw6X4VKE9BSus+ttHhE7Ke+Ie9ecfilzX8BnWE3FeQyng==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@sveltejs/vite-plugin-svelte": "^2.4.1", | ||||
| @@ -14319,15 +14305,6 @@ | ||||
|             "color-convert": "^2.0.1" | ||||
|           } | ||||
|         }, | ||||
|         "aria-query": { | ||||
|           "version": "5.1.3", | ||||
|           "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", | ||||
|           "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "deep-equal": "^2.0.5" | ||||
|           } | ||||
|         }, | ||||
|         "chalk": { | ||||
|           "version": "4.1.2", | ||||
|           "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", | ||||
| @@ -14506,6 +14483,12 @@ | ||||
|       "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "@types/dom-to-image": { | ||||
|       "version": "2.6.4", | ||||
|       "resolved": "https://registry.npmjs.org/@types/dom-to-image/-/dom-to-image-2.6.4.tgz", | ||||
|       "integrity": "sha512-UddUdGF1qulrSDulkz3K2Ypq527MR6ixlgAzqLbxSiQ0icx0XDlIV+h4+edmjq/1dqn0KgN0xGSe1kI9t+vGuw==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "@types/estree": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", | ||||
| @@ -14891,16 +14874,16 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@zoom-image/core": { | ||||
|       "version": "0.19.0", | ||||
|       "resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.19.0.tgz", | ||||
|       "integrity": "sha512-eiN4ZX/lpBMpDoJh1QoKzWBuEIwdjdiEMgEXAjltS0G3f8jfS85uXq2hCF9JcbdjuM9b2JeydOqPi5aZ5TGGxw==" | ||||
|       "version": "0.20.0", | ||||
|       "resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.20.0.tgz", | ||||
|       "integrity": "sha512-QJOGDaHCCkGCAaytWanf0YypOd2gKvn5trn1sHgEFB8T76jgk6RMhuplRJvmKJOitHcr2DKZEwYFurwd9nZ3+w==" | ||||
|     }, | ||||
|     "@zoom-image/svelte": { | ||||
|       "version": "0.1.9", | ||||
|       "resolved": "https://registry.npmjs.org/@zoom-image/svelte/-/svelte-0.1.9.tgz", | ||||
|       "integrity": "sha512-nrWyapOKrNZtApTA6etECpivkR8FIktbO+56U8FQrUX6rU7DlSxTavX10fDsP0rhUuun0GCN1jIGFJ3nm2dOmw==", | ||||
|       "version": "0.1.10", | ||||
|       "resolved": "https://registry.npmjs.org/@zoom-image/svelte/-/svelte-0.1.10.tgz", | ||||
|       "integrity": "sha512-OXeZWWG1W479KpBW8j/8B1R7JyNoZfhoe3IW/ebffyQcbvCAB3UP6HiF5QueU58RvDLMKO+cjvjIaLmJ+w3YCQ==", | ||||
|       "requires": { | ||||
|         "@zoom-image/core": "0.19.0" | ||||
|         "@zoom-image/core": "0.20.0" | ||||
|       } | ||||
|     }, | ||||
|     "abab": { | ||||
| @@ -15014,21 +14997,12 @@ | ||||
|       } | ||||
|     }, | ||||
|     "aria-query": { | ||||
|       "version": "5.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", | ||||
|       "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", | ||||
|       "requires": { | ||||
|         "dequal": "^2.0.3" | ||||
|       } | ||||
|     }, | ||||
|     "array-buffer-byte-length": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", | ||||
|       "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", | ||||
|       "version": "5.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", | ||||
|       "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "call-bind": "^1.0.2", | ||||
|         "is-array-buffer": "^3.0.1" | ||||
|         "deep-equal": "^2.0.5" | ||||
|       } | ||||
|     }, | ||||
|     "array-union": { | ||||
| @@ -15623,17 +15597,16 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "deep-equal": { | ||||
|       "version": "2.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", | ||||
|       "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", | ||||
|       "version": "2.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", | ||||
|       "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "array-buffer-byte-length": "^1.0.0", | ||||
|         "call-bind": "^1.0.2", | ||||
|         "es-get-iterator": "^1.1.3", | ||||
|         "get-intrinsic": "^1.2.0", | ||||
|         "es-get-iterator": "^1.1.2", | ||||
|         "get-intrinsic": "^1.1.3", | ||||
|         "is-arguments": "^1.1.1", | ||||
|         "is-array-buffer": "^3.0.2", | ||||
|         "is-array-buffer": "^3.0.1", | ||||
|         "is-date-object": "^1.0.5", | ||||
|         "is-regex": "^1.1.4", | ||||
|         "is-shared-array-buffer": "^1.0.2", | ||||
| @@ -15641,7 +15614,7 @@ | ||||
|         "object-is": "^1.1.5", | ||||
|         "object-keys": "^1.1.1", | ||||
|         "object.assign": "^4.1.4", | ||||
|         "regexp.prototype.flags": "^1.5.0", | ||||
|         "regexp.prototype.flags": "^1.4.3", | ||||
|         "side-channel": "^1.0.4", | ||||
|         "which-boxed-primitive": "^1.0.2", | ||||
|         "which-collection": "^1.0.1", | ||||
| @@ -15740,6 +15713,11 @@ | ||||
|       "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "dom-to-image": { | ||||
|       "version": "2.6.0", | ||||
|       "resolved": "https://registry.npmjs.org/dom-to-image/-/dom-to-image-2.6.0.tgz", | ||||
|       "integrity": "sha512-Dt0QdaHmLpjURjU7Tnu3AgYSF2LuOmksSGsUcE6ItvJoCWTBEmiMXcqBdNSAm9+QbbwD7JMoVsuuKX6ZVQv1qA==" | ||||
|     }, | ||||
|     "domexception": { | ||||
|       "version": "4.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", | ||||
| @@ -16443,14 +16421,13 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "get-intrinsic": { | ||||
|       "version": "1.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", | ||||
|       "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", | ||||
|       "version": "1.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", | ||||
|       "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "function-bind": "^1.1.1", | ||||
|         "has": "^1.0.3", | ||||
|         "has-proto": "^1.0.1", | ||||
|         "has-symbols": "^1.0.3" | ||||
|       } | ||||
|     }, | ||||
| @@ -16603,12 +16580,6 @@ | ||||
|         "get-intrinsic": "^1.1.1" | ||||
|       } | ||||
|     }, | ||||
|     "has-proto": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", | ||||
|       "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "has-symbols": { | ||||
|       "version": "1.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", | ||||
| @@ -19417,14 +19388,14 @@ | ||||
|       } | ||||
|     }, | ||||
|     "regexp.prototype.flags": { | ||||
|       "version": "1.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", | ||||
|       "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", | ||||
|       "version": "1.4.3", | ||||
|       "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", | ||||
|       "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "call-bind": "^1.0.2", | ||||
|         "define-properties": "^1.2.0", | ||||
|         "functions-have-names": "^1.2.3" | ||||
|         "define-properties": "^1.1.3", | ||||
|         "functions-have-names": "^1.2.2" | ||||
|       } | ||||
|     }, | ||||
|     "regexpu-core": { | ||||
| @@ -19927,6 +19898,14 @@ | ||||
|           "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", | ||||
|           "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" | ||||
|         }, | ||||
|         "aria-query": { | ||||
|           "version": "5.3.0", | ||||
|           "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", | ||||
|           "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", | ||||
|           "requires": { | ||||
|             "dequal": "^2.0.3" | ||||
|           } | ||||
|         }, | ||||
|         "estree-walker": { | ||||
|           "version": "3.0.3", | ||||
|           "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", | ||||
|   | ||||
| @@ -28,6 +28,7 @@ | ||||
|     "@testing-library/jest-dom": "^5.16.5", | ||||
|     "@testing-library/svelte": "^4.0.3", | ||||
|     "@types/cookie": "^0.5.1", | ||||
|     "@types/dom-to-image": "^2.6.4", | ||||
|     "@types/justified-layout": "^4.1.0", | ||||
|     "@types/leaflet": "^1.9.1", | ||||
|     "@types/leaflet.markercluster": "^1.5.1", | ||||
| @@ -62,6 +63,7 @@ | ||||
|     "axios": "^0.27.2", | ||||
|     "buffer": "^6.0.3", | ||||
|     "copy-image-clipboard": "^2.1.2", | ||||
|     "dom-to-image": "^2.6.0", | ||||
|     "handlebars": "^4.7.7", | ||||
|     "justified-layout": "^4.1.0", | ||||
|     "leaflet": "^1.9.4", | ||||
|   | ||||
| @@ -126,6 +126,7 @@ | ||||
|                   text={asset.isArchived ? 'Unarchive' : 'Archive'} | ||||
|                 /> | ||||
|               {/if} | ||||
|               <MenuOption on:click={() => onMenuClick('asProfileImage')} text="As profile picture" /> | ||||
|             </ContextMenu> | ||||
|           {/if} | ||||
|         </CircleIconButton> | ||||
|   | ||||
| @@ -13,6 +13,7 @@ | ||||
|   import PhotoViewer from './photo-viewer.svelte'; | ||||
|   import VideoViewer from './video-viewer.svelte'; | ||||
|   import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte'; | ||||
|   import ProfileImageCropper from '../shared-components/profile-image-cropper.svelte'; | ||||
|  | ||||
|   import { assetStore } from '$lib/stores/assets.store'; | ||||
|   import { isShowDetail } from '$lib/stores/preferences.store'; | ||||
| @@ -31,6 +32,7 @@ | ||||
|   let isShowDeleteConfirmation = false; | ||||
|   let addToSharedAlbum = true; | ||||
|   let shouldPlayMotionPhoto = false; | ||||
|   let isShowProfileImageCrop = false; | ||||
|   let shouldShowDownloadButton = sharedLink ? sharedLink.allowDownload : true; | ||||
|   let canCopyImagesToClipboard: boolean; | ||||
|   const onKeyboardPress = (keyInfo: KeyboardEvent) => handleKeyboardPress(keyInfo.key); | ||||
| @@ -246,6 +248,7 @@ | ||||
|       on:playMotionPhoto={() => (shouldPlayMotionPhoto = true)} | ||||
|       on:stopMotionPhoto={() => (shouldPlayMotionPhoto = false)} | ||||
|       on:toggleArchive={toggleArchive} | ||||
|       on:asProfileImage={() => (isShowProfileImageCrop = true)} | ||||
|     /> | ||||
|   </div> | ||||
|  | ||||
| @@ -332,6 +335,14 @@ | ||||
|       </svelte:fragment> | ||||
|     </ConfirmDialogue> | ||||
|   {/if} | ||||
|  | ||||
|   {#if isShowProfileImageCrop} | ||||
|     <ProfileImageCropper | ||||
|       {asset} | ||||
|       on:close={() => (isShowProfileImageCrop = false)} | ||||
|       on:close-viewer={handleCloseViewer} | ||||
|     /> | ||||
|   {/if} | ||||
| </section> | ||||
|  | ||||
| <style> | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
|  | ||||
|   export let asset: AssetResponseDto; | ||||
|   export let publicSharedKey = ''; | ||||
|   export let element: HTMLDivElement | undefined = undefined; | ||||
|   let imgElement: HTMLDivElement; | ||||
|  | ||||
|   let assetData: string; | ||||
| @@ -99,7 +100,11 @@ | ||||
|  | ||||
| <svelte:window on:keydown={handleKeypress} on:copyImage={doCopy} on:zoomImage={doZoomImage} /> | ||||
|  | ||||
| <div transition:fade={{ duration: 150 }} class="flex place-items-center place-content-center h-full select-none"> | ||||
| <div | ||||
|   bind:this={element} | ||||
|   transition:fade={{ duration: 150 }} | ||||
|   class="flex place-items-center place-content-center h-full select-none" | ||||
| > | ||||
|   {#await loadAssetData()} | ||||
|     <LoadingSpinner /> | ||||
|   {:then assetData} | ||||
|   | ||||
| @@ -0,0 +1,85 @@ | ||||
| <script lang="ts"> | ||||
|   import { AssetResponseDto, api } from '@api'; | ||||
|   import { createEventDispatcher } from 'svelte'; | ||||
|   import { notificationController, NotificationType } from './notification/notification'; | ||||
|   import { handleError } from '$lib/utils/handle-error'; | ||||
|   import domtoimage from 'dom-to-image'; | ||||
|   import PhotoViewer from '../asset-viewer/photo-viewer.svelte'; | ||||
|   import BaseModal from './base-modal.svelte'; | ||||
|   import Button from '../elements/buttons/button.svelte'; | ||||
|  | ||||
|   export let asset: AssetResponseDto; | ||||
|  | ||||
|   const dispatch = createEventDispatcher(); | ||||
|   let imgElement: HTMLDivElement; | ||||
|  | ||||
|   const hasTransparentPixels = async (blob: Blob) => { | ||||
|     const img = new Image(); | ||||
|     img.src = URL.createObjectURL(blob); | ||||
|     await img.decode(); | ||||
|     const canvas = document.createElement('canvas'); | ||||
|     canvas.width = img.width; | ||||
|     canvas.height = img.height; | ||||
|     const ctx = canvas.getContext('2d'); | ||||
|     if (!ctx) { | ||||
|       throw new Error('Could not get canvas context.'); | ||||
|     } | ||||
|     ctx.drawImage(img, 0, 0); | ||||
|     const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); | ||||
|     const data = imageData?.data; | ||||
|     if (!data) { | ||||
|       throw new Error('Could not get image data.'); | ||||
|     } | ||||
|     for (let i = 0; i < data.length; i += 4) { | ||||
|       if (data[i + 3] < 255) { | ||||
|         return true; | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|   }; | ||||
|  | ||||
|   const handleSetProfilePicture = async () => { | ||||
|     try { | ||||
|       const blob = await domtoimage.toBlob(imgElement); | ||||
|       if (await hasTransparentPixels(blob)) { | ||||
|         notificationController.show({ | ||||
|           type: NotificationType.Error, | ||||
|           message: 'Profile pictures cannot have transparent pixels. Please zoom in and/or move the image.', | ||||
|           timeout: 3000, | ||||
|         }); | ||||
|         return; | ||||
|       } | ||||
|       const file = new File([blob], 'profile-picture.png', { type: 'image/png' }); | ||||
|       await api.userApi.createProfileImage({ file }); | ||||
|       notificationController.show({ | ||||
|         type: NotificationType.Info, | ||||
|         message: 'Profile picture set.', | ||||
|         timeout: 3000, | ||||
|       }); | ||||
|     } catch (err) { | ||||
|       handleError(err, 'Error setting profile picture.'); | ||||
|     } | ||||
|     dispatch('close'); | ||||
|   }; | ||||
| </script> | ||||
|  | ||||
| <BaseModal on:close> | ||||
|   <svelte:fragment slot="title"> | ||||
|     <span class="flex gap-2 place-items-center"> | ||||
|       <p class="font-medium">Set profile picture</p> | ||||
|     </span> | ||||
|   </svelte:fragment> | ||||
|   <div class="flex justify-center place-items-center items-center"> | ||||
|     <div | ||||
|       class="w-1/2 aspect-square rounded-full overflow-hidden relative flex border-immich-primary dark:border-immich-dark-primary border-4 bg-immich-dark-primary dark:bg-immich-primary" | ||||
|     > | ||||
|       <PhotoViewer bind:element={imgElement} {asset} /> | ||||
|     </div> | ||||
|   </div> | ||||
|   <span class="p-4 flex justify-end"> | ||||
|     <Button on:click={handleSetProfilePicture}> | ||||
|       <p>Set as profile picture</p> | ||||
|     </Button> | ||||
|   </span> | ||||
|   <div class="max-h-[400px] flex flex-col mb-2" /> | ||||
| </BaseModal> | ||||
		Reference in New Issue
	
	Block a user