diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs index fc5e35ce6d..f855a99c53 100644 --- a/web/eslint.config.mjs +++ b/web/eslint.config.mjs @@ -2,6 +2,8 @@ import { FlatCompat } from '@eslint/eslintrc'; import js from '@eslint/js'; import typescriptEslint from '@typescript-eslint/eslint-plugin'; import tsParser from '@typescript-eslint/parser'; +import eslintPluginSvelte from 'eslint-plugin-svelte'; +import eslintPluginUnicorn from 'eslint-plugin-unicorn'; import globals from 'globals'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -11,11 +13,12 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const compat = new FlatCompat({ baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, - allConfig: js.configs.all, }); export default [ + ...eslintPluginSvelte.configs.recommended, + eslintPluginUnicorn.configs.recommended, + js.configs.recommended, { ignores: [ '**/.DS_Store', @@ -36,15 +39,11 @@ export default [ 'coverage', ], }, - ...compat.extends( - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:svelte/recommended', - 'plugin:unicorn/recommended', - ), + ...compat.extends('plugin:@typescript-eslint/recommended'), { plugins: { '@typescript-eslint': typescriptEslint, + svelte: eslintPluginSvelte, }, languageOptions: { diff --git a/web/package-lock.json b/web/package-lock.json index e181a5a9ba..6c9ceba459 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -57,8 +57,8 @@ "dotenv": "^16.4.7", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.0", - "eslint-plugin-svelte": "^2.46.1", - "eslint-plugin-unicorn": "^56.0.1", + "eslint-plugin-svelte": "^3.0.0", + "eslint-plugin-unicorn": "^57.0.0", "factory.ts": "^1.4.1", "globals": "^16.0.0", "postcss": "^8.5.0", @@ -663,16 +663,20 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } @@ -739,37 +743,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -2561,7 +2534,8 @@ "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/pbf": { "version": "3.0.5", @@ -3305,9 +3279,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", - "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "dev": true, "funding": [ { @@ -3344,12 +3318,13 @@ "dev": true }, "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-4.0.0.tgz", + "integrity": "sha512-p1n8zyCkt1BVrKNFymOHjcDSAl7oq/gUvfgULv2EblgpPVQlQr9yHnWjg9IJ2MhfwPqiYqMMrr01OY7yQoK2yA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=18.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3523,9 +3498,9 @@ } }, "node_modules/ci-info": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", - "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.1.0.tgz", + "integrity": "sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==", "dev": true, "funding": [ { @@ -3533,6 +3508,7 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } @@ -3710,13 +3686,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.39.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", - "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", + "version": "3.41.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", + "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.24.2" + "browserslist": "^4.24.4" }, "funding": { "type": "opencollective", @@ -4043,15 +4019,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, "node_modules/es-module-lexer": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", @@ -4250,9 +4217,9 @@ } }, "node_modules/eslint-compat-utils": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", - "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.6.4.tgz", + "integrity": "sha512-/u+GQt8NMfXO8w17QendT4gvO5acfxQsAKirAt0LVxDnr2N8YLCVbregaNc/Yhp7NM128DwCaRvr8PLDfeNkQw==", "dev": true, "license": "MIT", "dependencies": { @@ -4279,32 +4246,31 @@ } }, "node_modules/eslint-plugin-svelte": { - "version": "2.46.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.46.1.tgz", - "integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.0.2.tgz", + "integrity": "sha512-+0QglmWNryvXXxRQKzLF3i+AreTsueCw7PBb0nGVBq+F9HoYqAjQeJ/9N6vFAtjMjK3wgsETrLVyBKPdeufN6Q==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@jridgewell/sourcemap-codec": "^1.4.15", - "eslint-compat-utils": "^0.5.1", + "@eslint-community/eslint-utils": "^4.4.1", + "@jridgewell/sourcemap-codec": "^1.5.0", + "eslint-compat-utils": "^0.6.4", "esutils": "^2.0.3", "known-css-properties": "^0.35.0", - "postcss": "^8.4.38", + "postcss": "^8.4.49", "postcss-load-config": "^3.1.4", - "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.1.0", - "semver": "^7.6.2", - "svelte-eslint-parser": "^0.43.0" + "postcss-safe-parser": "^7.0.0", + "semver": "^7.6.3", + "svelte-eslint-parser": "^1.0.0" }, "engines": { - "node": "^14.17.0 || >=16.0.0" + "node": "^18.20.4 || ^20.18.0 || >=22.10.0" }, "funding": { "url": "https://github.com/sponsors/ota-meshi" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0", + "eslint": "^8.57.1 || ^9.0.0", "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "peerDependenciesMeta": { @@ -4314,28 +4280,28 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "56.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-56.0.1.tgz", - "integrity": "sha512-FwVV0Uwf8XPfVnKSGpMg7NtlZh0G0gBarCaFcMUOoqPxXryxdYxTRRv4kH6B9TFCVIrjRXG+emcxIk2ayZilog==", + "version": "57.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-57.0.0.tgz", + "integrity": "sha512-zUYYa6zfNdTeG9BISWDlcLmz16c+2Ck2o5ZDHh0UzXJz3DEP7xjmlVDTzbyV0W+XksgZ0q37WEWzN2D2Ze+g9Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "@eslint-community/eslint-utils": "^4.4.0", - "ci-info": "^4.0.0", + "@babel/helper-validator-identifier": "^7.25.9", + "@eslint-community/eslint-utils": "^4.4.1", + "ci-info": "^4.1.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.38.1", + "core-js-compat": "^3.40.0", "esquery": "^1.6.0", - "globals": "^15.9.0", - "indent-string": "^4.0.0", - "is-builtin-module": "^3.2.1", - "jsesc": "^3.0.2", + "globals": "^15.15.0", + "indent-string": "^5.0.0", + "is-builtin-module": "^4.0.0", + "jsesc": "^3.1.0", "pluralize": "^8.0.0", - "read-pkg-up": "^7.0.1", + "read-package-up": "^11.0.0", "regexp-tree": "^0.1.27", - "regjsparser": "^0.10.0", - "semver": "^7.6.3", - "strip-indent": "^3.0.0" + "regjsparser": "^0.12.0", + "semver": "^7.7.1", + "strip-indent": "^4.0.0" }, "engines": { "node": ">=18.18" @@ -4344,7 +4310,7 @@ "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": ">=8.56.0" + "eslint": ">=9.20.0" } }, "node_modules/eslint-plugin-unicorn/node_modules/globals": { @@ -4360,30 +4326,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-unicorn/node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "node_modules/eslint-plugin-unicorn/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.1" }, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -4494,23 +4477,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", @@ -4524,24 +4490,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/eslint/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -4586,17 +4534,31 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5051,6 +5013,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -5395,10 +5370,17 @@ "optional": true }, "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", @@ -5556,6 +5538,19 @@ "node": ">=8" } }, + "node_modules/index-to-position": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-0.1.2.tgz", + "integrity": "sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -5606,12 +5601,6 @@ "tslib": "2" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -5624,15 +5613,16 @@ } }, "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-4.0.0.tgz", + "integrity": "sha512-rWP3AMAalQSesXO8gleROyL2iKU73SX5Er66losQn9rWOWL4Gef0a/xOEOVqjWGMuR2vHG3FJ8UUmT700O8oFg==", "dev": true, + "license": "MIT", "dependencies": { - "builtin-modules": "^3.3.0" + "builtin-modules": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=18.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5918,6 +5908,19 @@ } } }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -5925,12 +5928,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -6073,6 +6070,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/lru-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", @@ -6546,24 +6549,18 @@ } }, "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/normalize-path": { @@ -6693,15 +6690,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/package-json-from-dist": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", @@ -6720,18 +6708,18 @@ } }, "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.1.0.tgz", + "integrity": "sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "@babel/code-frame": "^7.22.13", + "index-to-position": "^0.1.2", + "type-fest": "^4.7.1" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6796,11 +6784,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" - }, "node_modules/pathe": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz", @@ -7008,19 +6991,30 @@ } }, "node_modules/postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=18.0" }, "peerDependencies": { - "postcss": "^8.3.3" + "postcss": "^8.4.31" } }, "node_modules/postcss-scss": { @@ -7229,108 +7223,44 @@ "pify": "^2.3.0" } }, + "node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -7386,24 +7316,29 @@ } }, "node_modules/regjsparser": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz", - "integrity": "sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" } }, "node_modules/require-directory": { @@ -7687,9 +7622,9 @@ } }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "devOptional": true, "license": "ISC", "bin": { @@ -7968,32 +7903,36 @@ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "node_modules/spdx-exceptions": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", - "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", - "dev": true + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", - "dev": true + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true, + "license": "CC0-1.0" }, "node_modules/split-string": { "version": "3.1.0", @@ -8298,20 +8237,21 @@ } }, "node_modules/svelte-eslint-parser": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz", - "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.0.0.tgz", + "integrity": "sha512-diZzpeeFhAxormeIhmRS4vXx98GG6T7Dq5y1a6qffqs/5MBrBqqDg8bj88iEohp6bvhU4MIABJmOTa0gXWcbSQ==", "dev": true, "license": "MIT", "dependencies": { - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "postcss": "^8.4.39", - "postcss-scss": "^4.0.9" + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.0", + "postcss": "^8.4.49", + "postcss-scss": "^4.0.9", + "postcss-selector-parser": "^7.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.20.4 || ^20.18.0 || >=22.10.0" }, "funding": { "url": "https://github.com/sponsors/ota-meshi" @@ -8325,6 +8265,33 @@ } } }, + "node_modules/svelte-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/svelte-eslint-parser/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/svelte-gestures": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/svelte-gestures/-/svelte-gestures-5.1.3.tgz", @@ -9236,6 +9203,19 @@ "node": ">= 0.8.0" } }, + "node_modules/type-fest": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.36.0.tgz", + "integrity": "sha512-3T/PUdKTCnkUmhQU6FFJEHsLwadsRegktX3TNHk+2JJB9HlA8gp1/VXblXVDI93kSnXF2rdPx0GMbHtJIV2LPg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typescript": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", @@ -9275,6 +9255,19 @@ "node": ">=0.8.0" } }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -9358,6 +9351,7 @@ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" diff --git a/web/package.json b/web/package.json index 21266c5dea..23a6b5da0d 100644 --- a/web/package.json +++ b/web/package.json @@ -45,8 +45,8 @@ "dotenv": "^16.4.7", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.0", - "eslint-plugin-svelte": "^2.46.1", - "eslint-plugin-unicorn": "^56.0.1", + "eslint-plugin-svelte": "^3.0.0", + "eslint-plugin-unicorn": "^57.0.0", "factory.ts": "^1.4.1", "globals": "^16.0.0", "postcss": "^8.5.0", diff --git a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte index 4eb0bf6bb0..2c59f59416 100644 --- a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte +++ b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte @@ -169,7 +169,7 @@ </script> <div class="flex flex-col gap-7"> - {#each jobList as [jobName, { title, subtitle, description, disabled, allText, refreshText, missingText, icon, handleCommand: handleCommandOverride }]} + {#each jobList as [jobName, { title, subtitle, description, disabled, allText, refreshText, missingText, icon, handleCommand: handleCommandOverride }] (jobName)} {@const { jobCounts, queueStatus } = jobs[jobName]} <JobTile {icon} diff --git a/web/src/lib/components/admin-page/settings/job-settings/job-settings.svelte b/web/src/lib/components/admin-page/settings/job-settings/job-settings.svelte index 356de6ae86..5a95dbea30 100644 --- a/web/src/lib/components/admin-page/settings/job-settings/job-settings.svelte +++ b/web/src/lib/components/admin-page/settings/job-settings/job-settings.svelte @@ -46,7 +46,7 @@ <div> <div in:fade={{ duration: 500 }}> <form autocomplete="off" {onsubmit}> - {#each jobNames as jobName} + {#each jobNames as jobName (jobName)} <div class="ml-4 mt-4 flex flex-col gap-4"> {#if isSystemConfigJobDto(jobName)} <SettingInputField diff --git a/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte b/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte index 80c8904376..2a95e7a9f5 100644 --- a/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte +++ b/web/src/lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte @@ -46,7 +46,7 @@ <hr /> <div> - {#each config.machineLearning.urls as _, i} + {#each config.machineLearning.urls as _, i (i)} {#snippet removeButton()} {#if config.machineLearning.urls.length > 1} <CircleIconButton diff --git a/web/src/lib/components/admin-page/settings/storage-template/storage-template-settings.svelte b/web/src/lib/components/admin-page/settings/storage-template/storage-template-settings.svelte index 2a40156eac..9b4aa5e934 100644 --- a/web/src/lib/components/admin-page/settings/storage-template/storage-template-settings.svelte +++ b/web/src/lib/components/admin-page/settings/storage-template/storage-template-settings.svelte @@ -225,7 +225,7 @@ bind:value={selectedPreset} onchange={handlePresetSelection} > - {#each templateOptions.presetOptions as preset} + {#each templateOptions.presetOptions as preset (preset)} <option value={preset}>{renderTemplate(preset)}</option> {/each} </select> @@ -246,7 +246,7 @@ <SettingInputField label={$t('extension')} inputType={SettingInputFieldType.TEXT} - value={'.jpg'} + value=".jpg" disabled /> </div> diff --git a/web/src/lib/components/admin-page/settings/storage-template/supported-datetime-panel.svelte b/web/src/lib/components/admin-page/settings/storage-template/supported-datetime-panel.svelte index 379e366df6..9d8ff51cc0 100644 --- a/web/src/lib/components/admin-page/settings/storage-template/supported-datetime-panel.svelte +++ b/web/src/lib/components/admin-page/settings/storage-template/supported-datetime-panel.svelte @@ -19,6 +19,7 @@ <h4>{$t('date_and_time').toUpperCase()}</h4> </div> +<!-- eslint-disable svelte/no-useless-mustaches --> <div class="mt-2 rounded-lg bg-gray-200 p-4 text-xs dark:bg-gray-700 dark:text-immich-dark-fg"> <div class="mb-2 text-gray-600 dark:text-immich-dark-fg"> <p>{$t('admin.storage_template_date_time_description')}</p> @@ -28,7 +29,7 @@ <div> <p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('year').toUpperCase()}</p> <ul> - {#each options.yearOptions as yearFormat} + {#each options.yearOptions as yearFormat, index (index)} <li>{'{{'}{yearFormat}{'}}'} - {getLuxonExample(yearFormat)}</li> {/each} </ul> @@ -37,7 +38,7 @@ <div> <p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('month').toUpperCase()}</p> <ul> - {#each options.monthOptions as monthFormat} + {#each options.monthOptions as monthFormat, index (index)} <li>{'{{'}{monthFormat}{'}}'} - {getLuxonExample(monthFormat)}</li> {/each} </ul> @@ -46,7 +47,7 @@ <div> <p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('week').toUpperCase()}</p> <ul> - {#each options.weekOptions as weekFormat} + {#each options.weekOptions as weekFormat, index (index)} <li>{'{{'}{weekFormat}{'}}'} - {getLuxonExample(weekFormat)}</li> {/each} </ul> @@ -55,7 +56,7 @@ <div> <p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('day').toUpperCase()}</p> <ul> - {#each options.dayOptions as dayFormat} + {#each options.dayOptions as dayFormat, index (index)} <li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li> {/each} </ul> @@ -64,7 +65,7 @@ <div> <p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('hour').toUpperCase()}</p> <ul> - {#each options.hourOptions as dayFormat} + {#each options.hourOptions as dayFormat, index (index)} <li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li> {/each} </ul> @@ -73,7 +74,7 @@ <div> <p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('minute').toUpperCase()}</p> <ul> - {#each options.minuteOptions as dayFormat} + {#each options.minuteOptions as dayFormat, index (index)} <li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li> {/each} </ul> @@ -82,7 +83,7 @@ <div> <p class="font-medium text-immich-primary dark:text-immich-dark-primary">{$t('second').toUpperCase()}</p> <ul> - {#each options.secondOptions as dayFormat} + {#each options.secondOptions as dayFormat, index (index)} <li>{'{{'}{dayFormat}{'}}'} - {getLuxonExample(dayFormat)}</li> {/each} </ul> diff --git a/web/src/lib/components/admin-page/settings/template-settings/template-settings.svelte b/web/src/lib/components/admin-page/settings/template-settings/template-settings.svelte index c27df817c2..f23289d1e5 100644 --- a/web/src/lib/components/admin-page/settings/template-settings/template-settings.svelte +++ b/web/src/lib/components/admin-page/settings/template-settings/template-settings.svelte @@ -92,7 +92,7 @@ <LoadingSpinner /> {/if} - {#each templateConfigs as { label, templateKey, descriptionTags, templateName }} + {#each templateConfigs as { label, templateKey, descriptionTags, templateName } (templateKey)} <SettingTextarea {label} description={$t('admin.template_email_available_tags', { values: { tags: descriptionTags } })} diff --git a/web/src/lib/components/album-page/share-info-modal.svelte b/web/src/lib/components/album-page/share-info-modal.svelte index 778943af3a..35d8a84412 100644 --- a/web/src/lib/components/album-page/share-info-modal.svelte +++ b/web/src/lib/components/album-page/share-info-modal.svelte @@ -95,7 +95,7 @@ <p class="text-sm">{$t('owner')}</p> </div> </div> - {#each album.albumUsers as { user, role }} + {#each album.albumUsers as { user, role } (user.id)} <div class="flex w-full place-items-center justify-between gap-4 p-5 rounded-xl transition-colors hover:bg-gray-50 dark:hover:bg-gray-700" > 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 acbced70a0..cd454f515f 100644 --- a/web/src/lib/components/album-page/user-selection-modal.svelte +++ b/web/src/lib/components/album-page/user-selection-modal.svelte @@ -73,7 +73,7 @@ <div class="mb-2 py-2 sticky"> <p class="text-xs font-medium">{$t('selected')}</p> <div class="my-2"> - {#each Object.values(selectedUsers) as { user }} + {#each Object.values(selectedUsers) as { user } (user.id)} {#key user.id} <div class="flex place-items-center gap-4 p-4"> <div @@ -116,7 +116,7 @@ <Text>{$t('users')}</Text> <div class="my-2"> - {#each users as user} + {#each users as user (user.id)} {#if !Object.keys(selectedUsers).includes(user.id)} <div class="flex place-items-center transition-all hover:bg-gray-200 dark:hover:bg-gray-700 rounded-xl"> <button type="button" onclick={() => handleToggle(user)} class="flex w-full place-items-center gap-4 p-4"> @@ -161,7 +161,7 @@ </div> <Stack gap={4}> - {#each sharedLinks as sharedLink} + {#each sharedLinks as sharedLink (sharedLink.id)} <AlbumSharedLink {album} {sharedLink} /> {/each} </Stack> diff --git a/web/src/lib/components/asset-viewer/detail-panel.svelte b/web/src/lib/components/asset-viewer/detail-panel.svelte index a83c5edd1e..b96a4660ee 100644 --- a/web/src/lib/components/asset-viewer/detail-panel.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel.svelte @@ -536,7 +536,7 @@ {#if albums.length > 0} <section class="px-6 pt-6 dark:text-immich-dark-fg"> <p class="pb-4 text-sm">{$t('appears_in').toUpperCase()}</p> - {#each albums as album} + {#each albums as album (album.id)} <a href="{AppRoute.ALBUMS}/{album.id}"> <div class="flex gap-4 pt-2 hover:cursor-pointer items-center"> <div> diff --git a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-tool.svelte b/web/src/lib/components/asset-viewer/editor/crop-tool/crop-tool.svelte index 363bec7c1f..daeccd9074 100644 --- a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-tool.svelte +++ b/web/src/lib/components/asset-viewer/editor/crop-tool/crop-tool.svelte @@ -137,7 +137,7 @@ <div class="flex h-10 w-full items-center justify-between text-sm"> <h2>{$t('editor_crop_tool_h2_aspect_ratios').toUpperCase()}</h2> </div> - {#each sizesRows as sizesRow} + {#each sizesRows as sizesRow, index (index)} <ul class="flex-wrap flex-row flex gap-x-6 py-2 justify-evenly"> {#each sizesRow as size (size.name)} <CropPreset {size} {selectedSize} {rotateHorizontal} {selectType} /> diff --git a/web/src/lib/components/asset-viewer/face-editor/face-editor.svelte b/web/src/lib/components/asset-viewer/face-editor/face-editor.svelte index e7709cd9cc..c50c21bef8 100644 --- a/web/src/lib/components/asset-viewer/face-editor/face-editor.svelte +++ b/web/src/lib/components/asset-viewer/face-editor/face-editor.svelte @@ -325,7 +325,7 @@ <div class="h-[250px] overflow-y-auto mt-2"> {#if filteredCandidates.length > 0} <div class="mt-2 rounded-lg"> - {#each filteredCandidates as person} + {#each filteredCandidates as person (person.id)} <button onclick={() => tagFace(person)} type="button" diff --git a/web/src/lib/components/asset-viewer/photo-viewer.svelte b/web/src/lib/components/asset-viewer/photo-viewer.svelte index 0d79b9e5fc..24701685ef 100644 --- a/web/src/lib/components/asset-viewer/photo-viewer.svelte +++ b/web/src/lib/components/asset-viewer/photo-viewer.svelte @@ -225,6 +225,7 @@ : slideshowLookCssMapping[$slideshowLook]}" draggable="false" /> + <!-- eslint-disable-next-line svelte/require-each-key --> {#each getBoundingBox($boundingBoxesArray, $photoZoomState, $photoViewerImgElement) as boundingbox} <div class="absolute border-solid border-white border-[3px] rounded-lg" diff --git a/web/src/lib/components/elements/buttons/skip-link.svelte b/web/src/lib/components/elements/buttons/skip-link.svelte index 858d296c30..b80e7d1a44 100644 --- a/web/src/lib/components/elements/buttons/skip-link.svelte +++ b/web/src/lib/components/elements/buttons/skip-link.svelte @@ -22,7 +22,7 @@ <div class="absolute z-50 top-2 left-2 transition-transform {isFocused ? 'translate-y-0' : '-translate-y-10 sr-only'}"> <Button - size={'sm'} + size="sm" rounded="none" onclick={moveFocus} onfocus={() => (isFocused = true)} diff --git a/web/src/lib/components/elements/group-tab.svelte b/web/src/lib/components/elements/group-tab.svelte index 950c26f3f5..a751dd0fa1 100644 --- a/web/src/lib/components/elements/group-tab.svelte +++ b/web/src/lib/components/elements/group-tab.svelte @@ -18,7 +18,7 @@ class="dark:bg-immich-dark-gray flex h-full rounded-2xl bg-gray-200 ring-gray-400 has-[:focus-visible]:ring dark:ring-gray-600" > <legend class="sr-only">{label}</legend> - {#each filters as filter, index} + {#each filters as filter, index (`${id}-${index}`)} <div class="group"> <input type="radio" diff --git a/web/src/lib/components/faces-page/merge-face-selector.svelte b/web/src/lib/components/faces-page/merge-face-selector.svelte index 26ca99d863..88576d2845 100644 --- a/web/src/lib/components/faces-page/merge-face-selector.svelte +++ b/web/src/lib/components/faces-page/merge-face-selector.svelte @@ -111,7 +111,7 @@ <div></div> {/snippet} {#snippet trailing()} - <Button size={'sm'} disabled={!hasSelection} onclick={handleMerge}> + <Button size="sm" disabled={!hasSelection} onclick={handleMerge}> <Icon path={mdiMerge} size={18} /> <span class="ml-2">{$t('merge')}</span></Button > diff --git a/web/src/lib/components/faces-page/person-side-panel.svelte b/web/src/lib/components/faces-page/person-side-panel.svelte index 7bf87fc67b..b0e0f8fcc4 100644 --- a/web/src/lib/components/faces-page/person-side-panel.svelte +++ b/web/src/lib/components/faces-page/person-side-panel.svelte @@ -221,7 +221,7 @@ <LoadingSpinner /> </div> {:else} - {#each peopleWithFaces as face, index} + {#each peopleWithFaces as face, index (face.id)} {@const personName = face.person ? face.person?.name : $t('face_unassigned')} <div class="relative z-[20001] h-[115px] w-[95px]"> <div diff --git a/web/src/lib/components/faces-page/unmerge-face-selector.svelte b/web/src/lib/components/faces-page/unmerge-face-selector.svelte index 06c53f3618..e808c98748 100644 --- a/web/src/lib/components/faces-page/unmerge-face-selector.svelte +++ b/web/src/lib/components/faces-page/unmerge-face-selector.svelte @@ -131,7 +131,7 @@ <div class="flex gap-4"> <Button title={$t('create_new_person_hint')} - size={'sm'} + size="sm" disabled={disableButtons || hasSelection} onclick={handleCreate} > @@ -143,7 +143,7 @@ <span class="ml-2"> {$t('create_new_person')}</span></Button > <Button - size={'sm'} + size="sm" title={$t('reassing_hint')} disabled={disableButtons || !hasSelection} onclick={handleReassign} diff --git a/web/src/lib/components/forms/library-import-paths-form.svelte b/web/src/lib/components/forms/library-import-paths-form.svelte index 3acd46520f..6ad5b2598d 100644 --- a/web/src/lib/components/forms/library-import-paths-form.svelte +++ b/web/src/lib/components/forms/library-import-paths-form.svelte @@ -175,7 +175,7 @@ <form {onsubmit} autocomplete="off" class="m-4 flex flex-col gap-4"> <table class="text-left"> <tbody class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray"> - {#each validatedPaths as validatedPath, listIndex} + {#each validatedPaths as validatedPath, listIndex (validatedPath.importPath)} <tr class={`flex h-[80px] w-full place-items-center text-center dark:text-immich-dark-fg ${ listIndex % 2 == 0 diff --git a/web/src/lib/components/forms/library-scan-settings-form.svelte b/web/src/lib/components/forms/library-scan-settings-form.svelte index 68e99641e8..0ce414c10d 100644 --- a/web/src/lib/components/forms/library-scan-settings-form.svelte +++ b/web/src/lib/components/forms/library-scan-settings-form.svelte @@ -125,7 +125,7 @@ <form {onsubmit} autocomplete="off" class="m-4 flex flex-col gap-4"> <table class="w-full text-left"> <tbody class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray"> - {#each exclusionPatterns as exclusionPattern, listIndex} + {#each exclusionPatterns as exclusionPattern, listIndex (exclusionPattern)} <tr class={`flex h-[80px] w-full place-items-center text-center dark:text-immich-dark-fg ${ listIndex % 2 == 0 diff --git a/web/src/lib/components/i18n/format-message.svelte b/web/src/lib/components/i18n/format-message.svelte index d65e1096fe..bb8a066c6e 100644 --- a/web/src/lib/components/i18n/format-message.svelte +++ b/web/src/lib/components/i18n/format-message.svelte @@ -129,6 +129,7 @@ Used for every occurrence of an HTML tag in a message Result: Visit <a href="">docs</a> <strong>now</strong> ``` --> +<!-- eslint-disable-next-line svelte/require-each-key --> {#each parts as { tag, message }} {#if tag} {#if children}{@render children({ tag, message })}{:else}{message}{/if} diff --git a/web/src/lib/components/memory-page/memory-viewer.svelte b/web/src/lib/components/memory-page/memory-viewer.svelte index 3e8da972e1..c1ec31470f 100644 --- a/web/src/lib/components/memory-page/memory-viewer.svelte +++ b/web/src/lib/components/memory-page/memory-viewer.svelte @@ -183,6 +183,7 @@ if (!current) { return; } + // eslint-disable-next-line no-self-assign current.memory.assets = current.memory.assets; }; @@ -222,6 +223,7 @@ current.memory.assets = current.memory.assets.filter((asset) => asset.id !== current.asset.id); + // eslint-disable-next-line no-self-assign $memoryStore = $memoryStore; await removeMemoryAssets({ id: current.memory.id, bulkIdsDto: { ids: [current.asset.id] } }); @@ -351,7 +353,7 @@ class="hover:text-black" /> - {#each current.memory.assets as asset, index} + {#each current.memory.assets as asset, index (asset.id)} <a class="relative w-full py-2" href={asHref(asset)}> <span class="absolute left-0 h-[2px] w-full bg-gray-500"></span> {#await resetPromise} @@ -475,14 +477,10 @@ align="bottom-right" class="text-white dark:text-white" > - <MenuOption - onClick={() => handleDeleteMemory(current)} - text={'Remove memory'} - icon={mdiCardsOutline} - /> + <MenuOption onClick={() => handleDeleteMemory(current)} text="Remove memory" icon={mdiCardsOutline} /> <MenuOption onClick={() => handleDeleteMemoryAsset(current)} - text={'Remove photo from this memory'} + text="Remove photo from this memory" icon={mdiImageMinusOutline} /> <!-- shortcut={{ key: 'l', shift: shared }} --> diff --git a/web/src/lib/components/onboarding-page/onboarding-privacy.svelte b/web/src/lib/components/onboarding-page/onboarding-privacy.svelte index 8ff8a9200d..5bf750af96 100644 --- a/web/src/lib/components/onboarding-page/onboarding-privacy.svelte +++ b/web/src/lib/components/onboarding-page/onboarding-privacy.svelte @@ -32,41 +32,39 @@ {#if config && $user} <AdminSettings bind:config bind:this={adminSettingsComponent}> - {#snippet children()} - {#if config} - <SettingSwitch - title={$t('admin.map_settings')} - subtitle={$t('admin.map_implications')} - bind:checked={config.map.enabled} - /> - <SettingSwitch - title={$t('admin.version_check_settings')} - subtitle={$t('admin.version_check_implications')} - bind:checked={config.newVersionCheck.enabled} - /> - <div class="flex pt-4"> - <div class="w-full flex place-content-start"> - <Button class="flex gap-2 place-content-center" onclick={() => onPrevious()}> - <Icon path={mdiArrowLeft} size="18" /> - <p>{$t('theme')}</p> - </Button> - </div> - <div class="flex w-full place-content-end"> - <Button - onclick={() => { - adminSettingsComponent?.handleSave({ map: config?.map, newVersionCheck: config?.newVersionCheck }); - onDone(); - }} - > - <span class="flex place-content-center place-items-center gap-2"> - {$t('admin.storage_template_settings')} - <Icon path={mdiArrowRight} size="18" /> - </span> - </Button> - </div> + {#if config} + <SettingSwitch + title={$t('admin.map_settings')} + subtitle={$t('admin.map_implications')} + bind:checked={config.map.enabled} + /> + <SettingSwitch + title={$t('admin.version_check_settings')} + subtitle={$t('admin.version_check_implications')} + bind:checked={config.newVersionCheck.enabled} + /> + <div class="flex pt-4"> + <div class="w-full flex place-content-start"> + <Button class="flex gap-2 place-content-center" onclick={() => onPrevious()}> + <Icon path={mdiArrowLeft} size="18" /> + <p>{$t('theme')}</p> + </Button> </div> - {/if} - {/snippet} + <div class="flex w-full place-content-end"> + <Button + onclick={() => { + adminSettingsComponent?.handleSave({ map: config?.map, newVersionCheck: config?.newVersionCheck }); + onDone(); + }} + > + <span class="flex place-content-center place-items-center gap-2"> + {$t('admin.storage_template_settings')} + <Icon path={mdiArrowRight} size="18" /> + </span> + </Button> + </div> + </div> + {/if} </AdminSettings> {/if} </OnboardingCard> diff --git a/web/src/lib/components/photos-page/actions/asset-job-actions.svelte b/web/src/lib/components/photos-page/actions/asset-job-actions.svelte index b383729ecd..89c0b42165 100644 --- a/web/src/lib/components/photos-page/actions/asset-job-actions.svelte +++ b/web/src/lib/components/photos-page/actions/asset-job-actions.svelte @@ -33,7 +33,7 @@ }; </script> -{#each jobs as job} +{#each jobs as job (job)} {#if isAllVideos || job !== AssetJobName.TranscodeVideo} <MenuOption text={$getAssetJobName(job)} icon={getAssetJobIcon(job)} onClick={() => handleRunJob(job)} /> {/if} diff --git a/web/src/lib/components/photos-page/asset-date-group.svelte b/web/src/lib/components/photos-page/asset-date-group.svelte index 586491ef47..52704c58ee 100644 --- a/web/src/lib/components/photos-page/asset-date-group.svelte +++ b/web/src/lib/components/photos-page/asset-date-group.svelte @@ -119,7 +119,7 @@ data-date-group={dateGroup.date} style:height={dateGroup.height + 'px'} style:width={dateGroup.geometry.containerWidth + 'px'} - style:overflow={'clip'} + style:overflow="clip" > {#if !display} <Skeleton height={dateGroup.height + 'px'} title={dateGroup.groupTitle} /> diff --git a/web/src/lib/components/photos-page/measure-date-group.svelte b/web/src/lib/components/photos-page/measure-date-group.svelte index 80ad7640fb..a435f89fb5 100644 --- a/web/src/lib/components/photos-page/measure-date-group.svelte +++ b/web/src/lib/components/photos-page/measure-date-group.svelte @@ -67,7 +67,7 @@ </script> <section id="measure-asset-group-by-date" class="flex flex-wrap gap-x-12" use:measure> - {#each bucket.dateGroups as dateGroup} + {#each bucket.dateGroups as dateGroup (dateGroup.date)} <div id="date-group" data-date-group={dateGroup.date}> <div use:resizeObserver={({ height }) => $assetStore.updateBucketDateGroup(bucket, dateGroup, { height })}> <div @@ -83,7 +83,7 @@ class="relative overflow-clip" style:height={dateGroup.geometry.containerHeight + 'px'} style:width={dateGroup.geometry.containerWidth + 'px'} - style:visibility={'hidden'} + style:visibility="hidden" ></div> </div> </div> diff --git a/web/src/lib/components/photos-page/memory-lane.svelte b/web/src/lib/components/photos-page/memory-lane.svelte index b2db2f1f04..e2be2818b6 100644 --- a/web/src/lib/components/photos-page/memory-lane.svelte +++ b/web/src/lib/components/photos-page/memory-lane.svelte @@ -69,7 +69,7 @@ </div> {/if} <div class="inline-block" use:resizeObserver={({ width }) => (innerWidth = width)}> - {#each $memoryStore as memory} + {#each $memoryStore as memory (memory.id)} {#if memory.assets.length > 0} <a class="memory-card relative mr-8 inline-block aspect-[3/4] md:aspect-video h-[215px] rounded-xl" diff --git a/web/src/lib/components/places-page/places-card-group.svelte b/web/src/lib/components/places-page/places-card-group.svelte index 87b9870888..9bd863a95d 100644 --- a/web/src/lib/components/places-page/places-card-group.svelte +++ b/web/src/lib/components/places-page/places-card-group.svelte @@ -43,7 +43,7 @@ <div class="mt-4"> {#if !isCollapsed} <div class="flex flex-row flex-wrap gap-4"> - {#each places as item} + {#each places as item (item.id)} {@const city = item.exifInfo?.city} <a class="relative" href="{AppRoute.SEARCH}?{getMetadataSearchQuery({ city })}" draggable="false"> <div diff --git a/web/src/lib/components/shared-components/album-selection/album-selection-modal.svelte b/web/src/lib/components/shared-components/album-selection/album-selection-modal.svelte index 49b697b62a..50ffae0322 100644 --- a/web/src/lib/components/shared-components/album-selection/album-selection-modal.svelte +++ b/web/src/lib/components/shared-components/album-selection/album-selection-modal.svelte @@ -83,6 +83,7 @@ <FullScreenModal title={shared ? $t('add_to_shared_album') : $t('add_to_album')} {onClose}> <div class="mb-2 flex max-h-[400px] flex-col"> {#if loading} + <!-- eslint-disable-next-line svelte/require-each-key --> {#each { length: 3 } as _} <div class="flex animate-pulse gap-4 px-6 py-2"> <div class="h-12 w-12 rounded-xl bg-slate-200"></div> @@ -104,6 +105,7 @@ use:initInput /> <div class="immich-scrollbar overflow-y-auto"> + <!-- eslint-disable-next-line svelte/require-each-key --> {#each albumModalRows as row} {#if row.type === AlbumModalRowType.NEW_ALBUM} <NewAlbumListItem selected={row.selected || false} {onNewAlbum} searchQuery={search} /> diff --git a/web/src/lib/components/shared-components/change-location.svelte b/web/src/lib/components/shared-components/change-location.svelte index d2dbeb5488..4d20d9df91 100644 --- a/web/src/lib/components/shared-components/change-location.svelte +++ b/web/src/lib/components/shared-components/change-location.svelte @@ -139,7 +139,7 @@ use:clickOutside={{ onOutclick: () => (hideSuggestion = true) }} > {#if !hideSuggestion} - {#each suggestedPlaces as place, index} + {#each suggestedPlaces as place, index (place.latitude + place.longitude)} <button type="button" class=" flex w-full border-t border-gray-400 dark:border-immich-dark-gray h-14 place-items-center bg-gray-200 p-2 dark:bg-gray-700 hover:bg-gray-300 hover:dark:bg-[#232932] focus:bg-gray-300 focus:dark:bg-[#232932] {index === diff --git a/web/src/lib/components/shared-components/control-app-bar.svelte b/web/src/lib/components/shared-components/control-app-bar.svelte index 6f39536ef0..23bdaa8de3 100644 --- a/web/src/lib/components/shared-components/control-app-bar.svelte +++ b/web/src/lib/components/shared-components/control-app-bar.svelte @@ -75,7 +75,7 @@ > <div class="flex place-items-center sm:gap-6 justify-self-start dark:text-immich-dark-fg"> {#if showBackButton} - <CircleIconButton title={$t('close')} onclick={handleClose} icon={backIcon} size={'24'} class={buttonClass} /> + <CircleIconButton title={$t('close')} onclick={handleClose} icon={backIcon} size="24" class={buttonClass} /> {/if} {@render leading?.()} </div> diff --git a/web/src/lib/components/shared-components/modal-header.svelte b/web/src/lib/components/shared-components/modal-header.svelte index 53f3fbdabb..f2e4c960fa 100644 --- a/web/src/lib/components/shared-components/modal-header.svelte +++ b/web/src/lib/components/shared-components/modal-header.svelte @@ -37,5 +37,5 @@ </h1> </div> - <CircleIconButton onclick={onClose} icon={mdiClose} size={'20'} title={$t('close')} /> + <CircleIconButton onclick={onClose} icon={mdiClose} size="20" title={$t('close')} /> </div> diff --git a/web/src/lib/components/shared-components/navigation-bar/avatar-selector.svelte b/web/src/lib/components/shared-components/navigation-bar/avatar-selector.svelte index d762c7ba88..ce441d553b 100644 --- a/web/src/lib/components/shared-components/navigation-bar/avatar-selector.svelte +++ b/web/src/lib/components/shared-components/navigation-bar/avatar-selector.svelte @@ -18,7 +18,7 @@ <FullScreenModal title={$t('select_avatar_color')} width="auto" {onClose}> <div class="flex items-center justify-center mt-4"> <div class="grid grid-cols-2 md:grid-cols-5 gap-4"> - {#each colors as color} + {#each colors as color (color)} <button type="button" onclick={() => onChoose(color)}> <UserAvatar label={color} {user} {color} size="xl" showProfileImage={false} /> </button> diff --git a/web/src/lib/components/shared-components/purchasing/purchase-modal.svelte b/web/src/lib/components/shared-components/purchasing/purchase-modal.svelte index 0334fb9e99..eaf6d14674 100644 --- a/web/src/lib/components/shared-components/purchasing/purchase-modal.svelte +++ b/web/src/lib/components/shared-components/purchasing/purchase-modal.svelte @@ -15,7 +15,7 @@ </script> <Portal> - <FullScreenModal showLogo title={''} {onClose} width="wide"> + <FullScreenModal showLogo title="" {onClose} width="wide"> {#if showProductActivated} <PurchaseActivationSuccess onDone={onClose} /> {:else} diff --git a/web/src/lib/components/shared-components/scrubber/scrubber.svelte b/web/src/lib/components/shared-components/scrubber/scrubber.svelte index bdcca509bb..c51c03dd0f 100644 --- a/web/src/lib/components/shared-components/scrubber/scrubber.svelte +++ b/web/src/lib/components/shared-components/scrubber/scrubber.svelte @@ -278,7 +278,7 @@ {/if} </div> <!-- Time Segment --> - {#each segments as segment} + {#each segments as segment (segment.date)} <div id="time-segment" class="relative" diff --git a/web/src/lib/components/shared-components/settings/setting-accordion.svelte b/web/src/lib/components/shared-components/settings/setting-accordion.svelte index 0fe1c9dc14..bfa379edcd 100755 --- a/web/src/lib/components/shared-components/settings/setting-accordion.svelte +++ b/web/src/lib/components/shared-components/settings/setting-accordion.svelte @@ -44,6 +44,7 @@ } } else { $accordionState.delete(key); + // eslint-disable-next-line no-self-assign $accordionState = $accordionState; } }; diff --git a/web/src/lib/components/shared-components/settings/setting-checkboxes.svelte b/web/src/lib/components/shared-components/settings/setting-checkboxes.svelte index 09f0ea438b..048301442e 100644 --- a/web/src/lib/components/shared-components/settings/setting-checkboxes.svelte +++ b/web/src/lib/components/shared-components/settings/setting-checkboxes.svelte @@ -30,7 +30,7 @@ </script> <div class="mb-4 w-full"> - <div class={`flex h-[26px] place-items-center gap-1`}> + <div class="flex h-[26px] place-items-center gap-1"> <label class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" for="{name}-select"> {label} </label> @@ -51,7 +51,7 @@ </p> {/if} <div class="flex flex-col gap-2"> - {#each options as option} + {#each options as option (option.value)} <Checkbox id="{option.value}-checkbox" label={option.text} diff --git a/web/src/lib/components/shared-components/settings/setting-input-field.svelte b/web/src/lib/components/shared-components/settings/setting-input-field.svelte index 5ef1a764f7..d904089731 100644 --- a/web/src/lib/components/shared-components/settings/setting-input-field.svelte +++ b/web/src/lib/components/shared-components/settings/setting-input-field.svelte @@ -70,7 +70,7 @@ </script> <div class="mb-4 w-full"> - <div class={`flex place-items-center gap-1`}> + <div class="flex place-items-center gap-1"> <label class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" for={label}>{label}</label> {#if required} <div class="text-red-400">*</div> diff --git a/web/src/lib/components/shared-components/settings/setting-select.svelte b/web/src/lib/components/shared-components/settings/setting-select.svelte index 44f03075da..1cfd7123ac 100644 --- a/web/src/lib/components/shared-components/settings/setting-select.svelte +++ b/web/src/lib/components/shared-components/settings/setting-select.svelte @@ -39,7 +39,7 @@ </script> <div class="mb-4 w-full"> - <div class={`flex h-[26px] place-items-center gap-1`}> + <div class="flex h-[26px] place-items-center gap-1"> <label class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" for="{name}-select" >{label}</label > @@ -63,7 +63,7 @@ <div class="grid"> <Icon path={mdiChevronDown} - size={'1.2em'} + size="1.2em" ariaHidden={true} class="pointer-events-none right-1 relative col-start-1 row-start-1 self-center justify-self-end {disabled ? 'text-immich-bg' @@ -78,7 +78,7 @@ bind:value onchange={handleChange} > - {#each options as option} + {#each options as option (option.value)} <option value={option.value}>{option.text}</option> {/each} </select> diff --git a/web/src/lib/components/shared-components/settings/setting-textarea.svelte b/web/src/lib/components/shared-components/settings/setting-textarea.svelte index 9f9f885263..be638d25d9 100644 --- a/web/src/lib/components/shared-components/settings/setting-textarea.svelte +++ b/web/src/lib/components/shared-components/settings/setting-textarea.svelte @@ -30,7 +30,7 @@ </script> <div class="mb-4 w-full"> - <div class={`flex h-[26px] place-items-center gap-1`}> + <div class="flex h-[26px] place-items-center gap-1"> <label class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" for={label}>{label}</label> {#if required} <div class="text-red-400">*</div> diff --git a/web/src/lib/components/shared-components/show-shortcuts.svelte b/web/src/lib/components/shared-components/show-shortcuts.svelte index 9ca35c927e..5a940e6621 100644 --- a/web/src/lib/components/shared-components/show-shortcuts.svelte +++ b/web/src/lib/components/shared-components/show-shortcuts.svelte @@ -50,10 +50,10 @@ <div class="p-4"> <h2>{$t('general')}</h2> <div class="text-sm"> - {#each shortcuts.general as shortcut} + {#each shortcuts.general as shortcut (shortcut.key.join('-'))} <div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm"> <div class="flex justify-self-end"> - {#each shortcut.key as key} + {#each shortcut.key as key (key)} <p class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2"> {key} </p> @@ -69,10 +69,10 @@ <div class="p-4"> <h2>{$t('actions')}</h2> <div class="text-sm"> - {#each shortcuts.actions as shortcut} + {#each shortcuts.actions as shortcut (shortcut.key.join('-'))} <div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm"> <div class="flex justify-self-end"> - {#each shortcut.key as key} + {#each shortcut.key as key (key)} <p class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2"> {key} </p> diff --git a/web/src/lib/components/shared-components/side-bar/recent-albums.svelte b/web/src/lib/components/shared-components/side-bar/recent-albums.svelte index b11935d643..9674ed9366 100644 --- a/web/src/lib/components/shared-components/side-bar/recent-albums.svelte +++ b/web/src/lib/components/shared-components/side-bar/recent-albums.svelte @@ -23,7 +23,7 @@ }); </script> -{#each albums as album} +{#each albums as album (album.id)} <a href={'/albums/' + album.id} title={album.albumName} diff --git a/web/src/lib/components/shared-components/star-rating.svelte b/web/src/lib/components/shared-components/star-rating.svelte index 333248c227..bf9e5fbcaf 100644 --- a/web/src/lib/components/shared-components/star-rating.svelte +++ b/web/src/lib/components/shared-components/star-rating.svelte @@ -71,7 +71,7 @@ > <legend class="sr-only">{$t('rating')}</legend> <div class="flex flex-row" data-testid="star-container"> - {#each { length: count } as _, index} + {#each { length: count } as _, index (index)} {@const value = index + 1} {@const filled = hoverRating >= value || (hoverRating === 0 && ratingSelection >= value)} {@const starId = `${id}-${value}`} diff --git a/web/src/lib/components/shared-components/tree/breadcrumbs.svelte b/web/src/lib/components/shared-components/tree/breadcrumbs.svelte index c4ea635687..6ed915e683 100644 --- a/web/src/lib/components/shared-components/tree/breadcrumbs.svelte +++ b/web/src/lib/components/shared-components/tree/breadcrumbs.svelte @@ -45,7 +45,7 @@ onclick={() => {}} /> </li> - {#each pathSegments as segment, index} + {#each pathSegments as segment, index (segment)} {@const isLastSegment = index === pathSegments.length - 1} <li class="flex gap-2 items-center font-mono text-sm text-nowrap text-immich-primary dark:text-immich-dark-primary" diff --git a/web/src/lib/components/shared-components/tree/tree-item-thumbnails.svelte b/web/src/lib/components/shared-components/tree/tree-item-thumbnails.svelte index 36ef781656..71d87acb8d 100644 --- a/web/src/lib/components/shared-components/tree/tree-item-thumbnails.svelte +++ b/web/src/lib/components/shared-components/tree/tree-item-thumbnails.svelte @@ -14,7 +14,7 @@ <div class="w-full grid grid-cols-2 sm:grid-cols-4 lg:grid-cols-6 2xl:grid-cols-8 gap-2 bg-gray-50 dark:bg-immich-dark-gray/50 rounded-2xl border border-gray-100 dark:border-gray-900" > - {#each items as item} + {#each items as item (item)} <button class="flex flex-col place-items-center gap-2 py-2 px-4 hover:bg-immich-primary/10 dark:hover:bg-immich-primary/40 rounded-xl" onclick={() => onClick(item)} diff --git a/web/src/lib/components/shared-components/tree/tree-items.svelte b/web/src/lib/components/shared-components/tree/tree-items.svelte index 3724ced6c9..3b770e47ef 100644 --- a/web/src/lib/components/shared-components/tree/tree-items.svelte +++ b/web/src/lib/components/shared-components/tree/tree-items.svelte @@ -15,6 +15,7 @@ </script> <ul class="list-none ml-2"> + <!-- eslint-disable-next-line svelte/require-each-key --> {#each Object.entries(items).sort() as [path, tree]} {@const value = normalizeTreePath(`${parent}/${path}`)} {@const key = value + getColor(value)} diff --git a/web/src/lib/components/user-settings-page/device-list.svelte b/web/src/lib/components/user-settings-page/device-list.svelte index bb202b3606..ab9159eae9 100644 --- a/web/src/lib/components/user-settings-page/device-list.svelte +++ b/web/src/lib/components/user-settings-page/device-list.svelte @@ -71,7 +71,7 @@ <h3 class="mb-2 text-xs font-medium text-immich-primary dark:text-immich-dark-primary"> {$t('other_devices').toUpperCase()} </h3> - {#each otherDevices as device, index} + {#each otherDevices as device, index (device.id)} <DeviceCard {device} onDelete={() => handleDelete(device)} /> {#if index !== otherDevices.length - 1} <hr class="my-3" /> diff --git a/web/src/lib/components/user-settings-page/partner-selection-modal.svelte b/web/src/lib/components/user-settings-page/partner-selection-modal.svelte index 070246b612..d4080eb042 100644 --- a/web/src/lib/components/user-settings-page/partner-selection-modal.svelte +++ b/web/src/lib/components/user-settings-page/partner-selection-modal.svelte @@ -39,7 +39,7 @@ <FullScreenModal title={$t('add_partner')} showLogo {onClose}> <div class="immich-scrollbar max-h-[300px] overflow-y-auto"> {#if availableUsers.length > 0} - {#each availableUsers as user} + {#each availableUsers as user (user.id)} <button type="button" onclick={() => selectUser(user)} diff --git a/web/src/lib/components/user-settings-page/partner-settings.svelte b/web/src/lib/components/user-settings-page/partner-settings.svelte index a71266a76b..7db78082bb 100644 --- a/web/src/lib/components/user-settings-page/partner-settings.svelte +++ b/web/src/lib/components/user-settings-page/partner-settings.svelte @@ -144,7 +144,7 @@ <CircleIconButton onclick={() => handleRemovePartner(partner.user)} icon={mdiClose} - size={'16'} + size="16" title={$t('stop_sharing_photos_with_user')} /> {/if} diff --git a/web/src/lib/components/user-settings-page/user-api-key-list.svelte b/web/src/lib/components/user-settings-page/user-api-key-list.svelte index c5c6bae9e5..ffea572111 100644 --- a/web/src/lib/components/user-settings-page/user-api-key-list.svelte +++ b/web/src/lib/components/user-settings-page/user-api-key-list.svelte @@ -137,37 +137,35 @@ </tr> </thead> <tbody class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray"> - {#each keys as key, index} - {#key key.id} - <tr - class={`flex h-[80px] w-full place-items-center text-center dark:text-immich-dark-fg ${ - index % 2 == 0 - ? 'bg-immich-gray dark:bg-immich-dark-gray/75' - : 'bg-immich-bg dark:bg-immich-dark-gray/50' - }`} - > - <td class="w-1/3 text-ellipsis px-4 text-sm">{key.name}</td> - <td class="w-1/3 text-ellipsis px-4 text-sm" - >{new Date(key.createdAt).toLocaleDateString($locale, format)} - </td> - <td class="flex flex-row flex-wrap justify-center gap-x-2 gap-y-1 w-1/3"> - <CircleIconButton - color="primary" - icon={mdiPencilOutline} - title={$t('edit_key')} - size="16" - onclick={() => (editKey = key)} - /> - <CircleIconButton - color="primary" - icon={mdiTrashCanOutline} - title={$t('delete_key')} - size="16" - onclick={() => handleDelete(key)} - /> - </td> - </tr> - {/key} + {#each keys as key, index (key.id)} + <tr + class={`flex h-[80px] w-full place-items-center text-center dark:text-immich-dark-fg ${ + index % 2 == 0 + ? 'bg-immich-gray dark:bg-immich-dark-gray/75' + : 'bg-immich-bg dark:bg-immich-dark-gray/50' + }`} + > + <td class="w-1/3 text-ellipsis px-4 text-sm">{key.name}</td> + <td class="w-1/3 text-ellipsis px-4 text-sm" + >{new Date(key.createdAt).toLocaleDateString($locale, format)} + </td> + <td class="flex flex-row flex-wrap justify-center gap-x-2 gap-y-1 w-1/3"> + <CircleIconButton + color="primary" + icon={mdiPencilOutline} + title={$t('edit_key')} + size="16" + onclick={() => (editKey = key)} + /> + <CircleIconButton + color="primary" + icon={mdiTrashCanOutline} + title={$t('delete_key')} + size="16" + onclick={() => handleDelete(key)} + /> + </td> + </tr> {/each} </tbody> </table> diff --git a/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte index 5bb1ecce03..8d2808ac67 100644 --- a/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -137,7 +137,7 @@ await loadNextPage(); } - export const loadNextPage = async () => { + const loadNextPage = async () => { if (!nextPage || searchResultAssets.length >= MAX_ASSET_COUNT) { return; } @@ -230,6 +230,7 @@ return tagNames.join(', '); } + // eslint-disable-next-line no-self-assign const triggerAssetUpdate = () => (searchResultAssets = searchResultAssets); const onAddToAlbum = (assetIds: string[]) => { diff --git a/web/src/routes/admin/user-management/+page.svelte b/web/src/routes/admin/user-management/+page.svelte index aadbf3e949..6fe8dea1f3 100644 --- a/web/src/routes/admin/user-management/+page.svelte +++ b/web/src/routes/admin/user-management/+page.svelte @@ -195,7 +195,7 @@ </thead> <tbody class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray"> {#if allUsers} - {#each allUsers as immichUser, index} + {#each allUsers as immichUser, index (immichUser.id)} <tr class="flex h-[80px] overflow-hidden w-full place-items-center text-center dark:text-immich-dark-fg {immichUser.deletedAt ? 'bg-red-300 dark:bg-red-900'