merge main

This commit is contained in:
Alex Tran
2023-11-28 22:53:39 -06:00
205 changed files with 3298 additions and 2190 deletions
+1
View File
@@ -35,5 +35,6 @@ module.exports = {
varsIgnorePattern: '^_$',
},
],
curly: 2,
},
};
+1 -2
View File
@@ -3,7 +3,6 @@
"trailingComma": "all",
"printWidth": 120,
"semi": true,
"organizeImportsSkipDestructiveCodeActions": true,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": false
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}
+2 -1
View File
@@ -1,5 +1,6 @@
FROM node:20.9-alpine3.18
FROM node:iron-alpine3.18
USER node
WORKDIR /usr/src/app
COPY --chown=node:node package*.json ./
RUN npm ci
+176 -248
View File
@@ -10,7 +10,7 @@
"dependencies": {
"@egjs/svelte-view360": "^4.0.0-beta.7",
"@mdi/js": "^7.3.67",
"@zoom-image/svelte": "^0.1.8",
"@zoom-image/svelte": "^0.2.0",
"axios": "^0.27.2",
"buffer": "^6.0.3",
"copy-image-clipboard": "^2.1.2",
@@ -35,13 +35,12 @@
"@sveltejs/kit": "^1.20.4",
"@testing-library/jest-dom": "^6.0.0",
"@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/lodash-es": "^4.17.6",
"@types/luxon": "^3.2.0",
"@typescript-eslint/eslint-plugin": "^5.53.0",
"@typescript-eslint/parser": "^5.53.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"autoprefixer": "^10.4.13",
"babel-jest": "^29.4.3",
"eslint": "^8.34.0",
@@ -52,13 +51,12 @@
"jest": "^29.4.3",
"jest-environment-jsdom": "^29.4.3",
"postcss": "^8.4.21",
"prettier": "^2.8.4",
"prettier-plugin-svelte": "^2.10.1",
"prettier": "^3.1.0",
"prettier-plugin-svelte": "^3.1.2",
"svelte": "^4.0.5",
"svelte-check": "^3.4.3",
"svelte-jester": "^3.0.0",
"svelte-preprocess": "^5.0.3",
"tailwind-merge": "^1.14.0",
"tailwindcss": "^3.2.7",
"tslib": "^2.5.0",
"typescript": "^5.0.0",
@@ -1993,9 +1991,9 @@
}
},
"node_modules/@eslint/js": {
"version": "8.53.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz",
"integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==",
"version": "8.54.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz",
"integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -3044,9 +3042,9 @@
}
},
"node_modules/@sveltejs/kit": {
"version": "1.27.5",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.27.5.tgz",
"integrity": "sha512-+L1WPs/ZYNjXoBFoFARypD4aZOjkT51vFpRCtQI45+Fmmfi4Y0dH/8VFlmYD6VlGe89ViIPg7lgf/JpGQ2tr7A==",
"version": "1.27.6",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.27.6.tgz",
"integrity": "sha512-GsjTkMbKzXdbeRg0tk8S7HNShQ4879ftRr0ZHaZfjbig1xQwG57Bvcm9U9/mpLJtCapLbLWUnygKrgcLISLC8A==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@@ -3075,6 +3073,12 @@
"vite": "^4.0.0"
}
},
"node_modules/@sveltejs/kit/node_modules/@types/cookie": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.4.tgz",
"integrity": "sha512-7z/eR6O859gyWIAjuvBWFzNURmf2oPBmJlfVWkwehU5nzIyjwBsTh7WMmEEV4JFnHuQ3ex4oyTvfKzcyJVDBNA==",
"dev": true
},
"node_modules/@sveltejs/kit/node_modules/magic-string": {
"version": "0.30.5",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
@@ -3415,12 +3419,6 @@
"@babel/types": "^7.20.7"
}
},
"node_modules/@types/cookie": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.4.tgz",
"integrity": "sha512-7z/eR6O859gyWIAjuvBWFzNURmf2oPBmJlfVWkwehU5nzIyjwBsTh7WMmEEV4JFnHuQ3ex4oyTvfKzcyJVDBNA==",
"dev": true
},
"node_modules/@types/dom-to-image": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/@types/dom-to-image/-/dom-to-image-2.6.7.tgz",
@@ -3532,15 +3530,15 @@
}
},
"node_modules/@types/json-schema": {
"version": "7.0.13",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz",
"integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==",
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"dev": true
},
"node_modules/@types/justified-layout": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@types/justified-layout/-/justified-layout-4.1.3.tgz",
"integrity": "sha512-Ph0kv9PuAIM+rQo8vyqool1ss1Kc894umFREsSM5hrTuPzCppnHBOvMyFtXozLyhelHBiN88QB7XBbYklHVz2g==",
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@types/justified-layout/-/justified-layout-4.1.4.tgz",
"integrity": "sha512-q2ybP0u0NVj87oMnGZOGxY2iUN8ddr48zPOBHBdbOLpsMTA/keGj+93ou+OMCnJk0xewzlNIaVEkxM6VBD3E2w==",
"dev": true
},
"node_modules/@types/lodash": {
@@ -3550,18 +3548,18 @@
"dev": true
},
"node_modules/@types/lodash-es": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.11.tgz",
"integrity": "sha512-eCw8FYAWHt2DDl77s+AMLLzPn310LKohruumpucZI4oOFJkIgnlaJcy23OKMJxx4r9PeTF13Gv6w+jqjWQaYUg==",
"version": "4.17.12",
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"dev": true,
"dependencies": {
"@types/lodash": "*"
}
},
"node_modules/@types/luxon": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.4.tgz",
"integrity": "sha512-H9OXxv4EzJwE75aTPKpiGXJq+y4LFxjpsdgKwSmr503P5DkWc3AG7VAFYrFNVvqemT5DfgZJV9itYhqBHSGujA==",
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.5.tgz",
"integrity": "sha512-1cyf6Ge/94zlaWIZA2ei1pE6SZ8xpad2hXaYa5JEFiaUH0YS494CZwyi4MXNpXD9oEuv6ZH0Bmh0e7F9sPhmZA==",
"dev": true
},
"node_modules/@types/mapbox__point-geometry": {
@@ -3597,9 +3595,9 @@
"dev": true
},
"node_modules/@types/semver": {
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz",
"integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==",
"version": "7.5.6",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz",
"integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==",
"dev": true
},
"node_modules/@types/stack-utils": {
@@ -3643,32 +3641,33 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
"version": "6.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.1.tgz",
"integrity": "sha512-5bQDGkXaxD46bPvQt08BUz9YSaO4S0fB1LB5JHQuXTfkGPI3+UUeS387C/e9jRie5GqT8u5kFTrMvAjtX4O5kA==",
"dev": true,
"dependencies": {
"@eslint-community/regexpp": "^4.4.0",
"@typescript-eslint/scope-manager": "5.62.0",
"@typescript-eslint/type-utils": "5.62.0",
"@typescript-eslint/utils": "5.62.0",
"@eslint-community/regexpp": "^4.5.1",
"@typescript-eslint/scope-manager": "6.13.1",
"@typescript-eslint/type-utils": "6.13.1",
"@typescript-eslint/utils": "6.13.1",
"@typescript-eslint/visitor-keys": "6.13.1",
"debug": "^4.3.4",
"graphemer": "^1.4.0",
"ignore": "^5.2.0",
"natural-compare-lite": "^1.4.0",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
"ignore": "^5.2.4",
"natural-compare": "^1.4.0",
"semver": "^7.5.4",
"ts-api-utils": "^1.0.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
"@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha",
"eslint": "^7.0.0 || ^8.0.0"
},
"peerDependenciesMeta": {
"typescript": {
@@ -3710,25 +3709,26 @@
"dev": true
},
"node_modules/@typescript-eslint/parser": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
"version": "6.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.1.tgz",
"integrity": "sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.62.0",
"@typescript-eslint/types": "5.62.0",
"@typescript-eslint/typescript-estree": "5.62.0",
"@typescript-eslint/scope-manager": "6.13.1",
"@typescript-eslint/types": "6.13.1",
"@typescript-eslint/typescript-estree": "6.13.1",
"@typescript-eslint/visitor-keys": "6.13.1",
"debug": "^4.3.4"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
"eslint": "^7.0.0 || ^8.0.0"
},
"peerDependenciesMeta": {
"typescript": {
@@ -3737,16 +3737,16 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
"integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
"version": "6.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz",
"integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.62.0",
"@typescript-eslint/visitor-keys": "5.62.0"
"@typescript-eslint/types": "6.13.1",
"@typescript-eslint/visitor-keys": "6.13.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
@@ -3754,25 +3754,25 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz",
"integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==",
"version": "6.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.1.tgz",
"integrity": "sha512-A2qPlgpxx2v//3meMqQyB1qqTg1h1dJvzca7TugM3Yc2USDY+fsRBiojAEo92HO7f5hW5mjAUF6qobOPzlBCBQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/typescript-estree": "5.62.0",
"@typescript-eslint/utils": "5.62.0",
"@typescript-eslint/typescript-estree": "6.13.1",
"@typescript-eslint/utils": "6.13.1",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
"ts-api-utils": "^1.0.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "*"
"eslint": "^7.0.0 || ^8.0.0"
},
"peerDependenciesMeta": {
"typescript": {
@@ -3781,12 +3781,12 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
"integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
"version": "6.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz",
"integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
@@ -3794,21 +3794,21 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
"integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
"version": "6.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz",
"integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.62.0",
"@typescript-eslint/visitor-keys": "5.62.0",
"@typescript-eslint/types": "6.13.1",
"@typescript-eslint/visitor-keys": "6.13.1",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
"semver": "^7.5.4",
"ts-api-utils": "^1.0.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
@@ -3854,29 +3854,28 @@
"dev": true
},
"node_modules/@typescript-eslint/utils": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
"integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
"version": "6.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.1.tgz",
"integrity": "sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.62.0",
"@typescript-eslint/types": "5.62.0",
"@typescript-eslint/typescript-estree": "5.62.0",
"eslint-scope": "^5.1.1",
"semver": "^7.3.7"
"@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.12",
"@types/semver": "^7.5.0",
"@typescript-eslint/scope-manager": "6.13.1",
"@typescript-eslint/types": "6.13.1",
"@typescript-eslint/typescript-estree": "6.13.1",
"semver": "^7.5.4"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
"eslint": "^7.0.0 || ^8.0.0"
}
},
"node_modules/@typescript-eslint/utils/node_modules/lru-cache": {
@@ -3913,16 +3912,16 @@
"dev": true
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
"integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
"version": "6.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz",
"integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.62.0",
"eslint-visitor-keys": "^3.3.0"
"@typescript-eslint/types": "6.13.1",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
@@ -3936,9 +3935,9 @@
"dev": true
},
"node_modules/@zoom-image/core": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.28.0.tgz",
"integrity": "sha512-+tqhet1Ev/1QcJtKSNYgYJLgPIyQ5BZjbcMZu6bW8o2/ak+UQ1L4UeVyc2Q0Ivro1ltLYBe5ywLRgwzqhyAgkQ==",
"version": "0.31.0",
"resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.31.0.tgz",
"integrity": "sha512-lvFVfIe/CSASXVq1E2vWnt/inXqrBMgjW96lW/l1JdM9EaCj5yis6YXPL5z+Rz2WHmMg5bb7Ps6w1Gzs/bC8LQ==",
"dependencies": {
"@namnode/store": "^0.1.0"
},
@@ -3948,11 +3947,11 @@
}
},
"node_modules/@zoom-image/svelte": {
"version": "0.1.21",
"resolved": "https://registry.npmjs.org/@zoom-image/svelte/-/svelte-0.1.21.tgz",
"integrity": "sha512-a7Spta7WD1e94InjnWxyqAURBnq24fkEDiLN6sz0BuedxDYaT+kmdhHueXsrNEl7z8RSwXsdC7xABAmV+pEb0w==",
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@zoom-image/svelte/-/svelte-0.2.1.tgz",
"integrity": "sha512-UGOFsXJN5Sk/uJxp7ZMajedXusmdmQ23nTNgphR4T9Q0Aef4qJJZI5dpGZtMCbGH2kdLbpIm30Sbht9kIe1L1Q==",
"dependencies": {
"@zoom-image/core": "0.28.0"
"@zoom-image/core": "0.31.0"
},
"funding": {
"type": "github",
@@ -4767,14 +4766,6 @@
"periscopic": "^3.1.0"
}
},
"node_modules/code-red/node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/collect-v8-coverage": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz",
@@ -5471,15 +5462,15 @@
}
},
"node_modules/eslint": {
"version": "8.53.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz",
"integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==",
"version": "8.54.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz",
"integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.3",
"@eslint/js": "8.53.0",
"@eslint/js": "8.54.0",
"@humanwhocodes/config-array": "^0.11.13",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -5550,9 +5541,9 @@
}
},
"node_modules/eslint-plugin-svelte": {
"version": "2.35.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.35.0.tgz",
"integrity": "sha512-3WDFxNrkXaMlpqoNo3M1ZOQuoFLMO9+bdnN6oVVXaydXC7nzCJuGy9a0zqoNDHMSRPYt0Rqo6hIdHMEaI5sQnw==",
"version": "2.35.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.35.1.tgz",
"integrity": "sha512-IF8TpLnROSGy98Z3NrsKXWDSCbNY2ReHDcrYTuXZMbfX7VmESISR78TWgO9zdg4Dht1X8coub5jKwHzP0ExRug==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
@@ -5617,19 +5608,6 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"node_modules/eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"dev": true,
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/eslint-visitor-keys": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
@@ -5918,13 +5896,12 @@
"node": ">=4.0"
}
},
"node_modules/estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"dev": true,
"engines": {
"node": ">=4.0"
"node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/esutils": {
@@ -6934,6 +6911,14 @@
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
"dev": true
},
"node_modules/is-reference": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
"dependencies": {
"@types/estree": "*"
}
},
"node_modules/is-regex": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
@@ -9363,9 +9348,9 @@
}
},
"node_modules/luxon": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.3.tgz",
"integrity": "sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg==",
"version": "3.4.4",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz",
"integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==",
"engines": {
"node": ">=12"
}
@@ -9449,9 +9434,9 @@
}
},
"node_modules/maplibre-gl": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-3.6.0.tgz",
"integrity": "sha512-l+jBu+bMy96FOV4em7FgjMH77ewlOtLPXLAem/Q44y4+0vTGsJvPksJSoLoedmikcSff2QN20VZFo3+Zg0UJPQ==",
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-3.6.2.tgz",
"integrity": "sha512-krg2KFIdOpLPngONDhP6ixCoWl5kbdMINP0moMSJFVX7wX1Clm2M9hlNKXS8vBGlVWwR5R3ZfI6IPrYz7c+aCQ==",
"dependencies": {
"@mapbox/geojson-rewind": "^0.5.2",
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
@@ -9461,11 +9446,11 @@
"@mapbox/vector-tile": "^1.3.1",
"@mapbox/whoots-js": "^3.1.0",
"@maplibre/maplibre-gl-style-spec": "^19.3.3",
"@types/geojson": "^7946.0.12",
"@types/mapbox__point-geometry": "^0.1.3",
"@types/mapbox__vector-tile": "^1.3.3",
"@types/pbf": "^3.0.4",
"@types/supercluster": "^7.1.2",
"@types/geojson": "^7946.0.13",
"@types/mapbox__point-geometry": "^0.1.4",
"@types/mapbox__vector-tile": "^1.3.4",
"@types/pbf": "^3.0.5",
"@types/supercluster": "^7.1.3",
"earcut": "^2.2.4",
"geojson-vt": "^3.2.1",
"gl-matrix": "^3.4.3",
@@ -9652,12 +9637,6 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
"node_modules/natural-compare-lite": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
"dev": true
},
"node_modules/neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@@ -9979,22 +9958,6 @@
"is-reference": "^3.0.0"
}
},
"node_modules/periscopic/node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/periscopic/node_modules/is-reference": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
"dependencies": {
"@types/estree": "*"
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@@ -10239,28 +10202,28 @@
}
},
"node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz",
"integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=10.13.0"
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-plugin-svelte": {
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-2.10.1.tgz",
"integrity": "sha512-Wlq7Z5v2ueCubWo0TZzKc9XHcm7TDxqcuzRuGd0gcENfzfT4JZ9yDlCbEgxWgiPmLHkBjfOtpAWkcT28MCDpUQ==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.1.2.tgz",
"integrity": "sha512-7xfMZtwgAWHMT0iZc8jN4o65zgbAQ3+O32V6W7pXrqNvKnHnkoyQCGCbKeUyXKZLbYE0YhFRnamfxfkEGxm8qA==",
"dev": true,
"peerDependencies": {
"prettier": "^1.16.4 || ^2.0.0",
"svelte": "^3.2.0 || ^4.0.0-next.0"
"prettier": "^3.0.0",
"svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
}
},
"node_modules/pretty-format": {
@@ -11192,9 +11155,9 @@
}
},
"node_modules/svelte": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.3.tgz",
"integrity": "sha512-sqmG9KC6uUc7fb3ZuWoxXvqk6MI9Uu4ABA1M0fYDgTlFYu1k02xp96u6U9+yJZiVm84m9zge7rrA/BNZdFpOKw==",
"version": "4.2.7",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.7.tgz",
"integrity": "sha512-UExR1KS7raTdycsUrKLtStayu4hpdV3VZQgM0akX8XbXgLBlosdE/Sf3crOgyh9xIjqSYB3UEBuUlIQKRQX2hg==",
"dependencies": {
"@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15",
@@ -11215,9 +11178,9 @@
}
},
"node_modules/svelte-check": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.0.tgz",
"integrity": "sha512-8VfqhfuRJ1sKW+o8isH2kPi0RhjXH1nNsIbCFGyoUHG+ZxVxHYRKcb+S8eaL/1tyj3VGvWYx3Y5+oCUsJgnzcw==",
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.2.tgz",
"integrity": "sha512-E6iFh4aUCGJLRz6QZXH3gcN/VFfkzwtruWSRmlKrLWQTiO6VzLsivR6q02WYLGNAGecV3EocqZuCDrC2uttZ0g==",
"dev": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.17",
@@ -11331,9 +11294,9 @@
}
},
"node_modules/svelte-maplibre": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/svelte-maplibre/-/svelte-maplibre-0.7.0.tgz",
"integrity": "sha512-8Mm3MEr0mCq4en5ZmuemCxnv82ljd4mNzTt/pC+X3CTKEcfoVyJgr2PaDu8Znu3DOxUR378XBlG1z5Dw3amnvA==",
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/svelte-maplibre/-/svelte-maplibre-0.7.3.tgz",
"integrity": "sha512-mF/wAHQKqrutC6NxnEBDWfszfcQiYusyyE5ulbRVuwWayC0ZTm9lkm376nmNfgruAJOe0QzPx4Mdxa7c2JlGLA==",
"dependencies": {
"d3-geo": "^3.1.0",
"just-compare": "^2.3.0",
@@ -11360,9 +11323,9 @@
}
},
"node_modules/svelte-preprocess": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.0.tgz",
"integrity": "sha512-EkErPiDzHAc0k2MF5m6vBNmRUh338h2myhinUw/xaqsLs7/ZvsgREiLGj03VrSzbY/TB5ZXgBOsKraFee5yceA==",
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.1.tgz",
"integrity": "sha512-p/Dp4hmrBW5mrCCq29lEMFpIJT2FZsRlouxEc5qpbOmXRbaFs7clLs8oKPwD3xCFyZfv1bIhvOzpQkhMEVQdMw==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@@ -11421,22 +11384,6 @@
}
}
},
"node_modules/svelte/node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/svelte/node_modules/is-reference": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
"dependencies": {
"@types/estree": "*"
}
},
"node_modules/svelte/node_modules/magic-string": {
"version": "0.30.5",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
@@ -11454,16 +11401,6 @@
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
"dev": true
},
"node_modules/tailwind-merge": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz",
"integrity": "sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==",
"dev": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/dcastil"
}
},
"node_modules/tailwindcss": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz",
@@ -11683,6 +11620,18 @@
"node": ">=12"
}
},
"node_modules/ts-api-utils": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
"integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==",
"dev": true,
"engines": {
"node": ">=16.13.0"
},
"peerDependencies": {
"typescript": ">=4.2.0"
}
},
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -11695,27 +11644,6 @@
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
"dev": true
},
"node_modules/tsutils": {
"version": "3.21.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
"integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
"dev": true,
"dependencies": {
"tslib": "^1.8.1"
},
"engines": {
"node": ">= 6"
},
"peerDependencies": {
"typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
}
},
"node_modules/tsutils/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -11750,9 +11678,9 @@
}
},
"node_modules/typescript": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz",
"integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
+5 -7
View File
@@ -28,13 +28,12 @@
"@sveltejs/kit": "^1.20.4",
"@testing-library/jest-dom": "^6.0.0",
"@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/lodash-es": "^4.17.6",
"@types/luxon": "^3.2.0",
"@typescript-eslint/eslint-plugin": "^5.53.0",
"@typescript-eslint/parser": "^5.53.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"autoprefixer": "^10.4.13",
"babel-jest": "^29.4.3",
"eslint": "^8.34.0",
@@ -45,13 +44,12 @@
"jest": "^29.4.3",
"jest-environment-jsdom": "^29.4.3",
"postcss": "^8.4.21",
"prettier": "^2.8.4",
"prettier-plugin-svelte": "^2.10.1",
"prettier": "^3.1.0",
"prettier-plugin-svelte": "^3.1.2",
"svelte": "^4.0.5",
"svelte-check": "^3.4.3",
"svelte-jester": "^3.0.0",
"svelte-preprocess": "^5.0.3",
"tailwind-merge": "^1.14.0",
"tailwindcss": "^3.2.7",
"tslib": "^2.5.0",
"typescript": "^5.0.0",
@@ -61,7 +59,7 @@
"dependencies": {
"@egjs/svelte-view360": "^4.0.0-beta.7",
"@mdi/js": "^7.3.67",
"@zoom-image/svelte": "^0.1.8",
"@zoom-image/svelte": "^0.2.0",
"axios": "^0.27.2",
"buffer": "^6.0.3",
"copy-image-clipboard": "^2.1.2",
+98 -28
View File
@@ -1182,22 +1182,6 @@ export interface CheckExistingAssetsResponseDto {
*/
'existingIds': Array<string>;
}
/**
*
* @export
* @enum {string}
*/
export const CitiesFile = {
Cities15000: 'cities15000',
Cities5000: 'cities5000',
Cities1000: 'cities1000',
Cities500: 'cities500'
} as const;
export type CitiesFile = typeof CitiesFile[keyof typeof CitiesFile];
/**
*
* @export
@@ -3850,12 +3834,6 @@ export interface SystemConfigPasswordLoginDto {
* @interface SystemConfigReverseGeocodingDto
*/
export interface SystemConfigReverseGeocodingDto {
/**
*
* @type {CitiesFile}
* @memberof SystemConfigReverseGeocodingDto
*/
'citiesFileOverride': CitiesFile;
/**
*
* @type {boolean}
@@ -3863,8 +3841,6 @@ export interface SystemConfigReverseGeocodingDto {
*/
'enabled': boolean;
}
/**
*
* @export
@@ -6844,6 +6820,48 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Get all asset of a device that are in the database, ID only.
* @param {string} deviceId
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getAllUserAssetsByDeviceId: async (deviceId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'deviceId' is not null or undefined
assertParamExists('getAllUserAssetsByDeviceId', 'deviceId', deviceId)
const localVarPath = `/asset/device/{deviceId}`
.replace(`{${"deviceId"}}`, encodeURIComponent(String(deviceId)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication cookie required
// authentication api_key required
await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
// authentication bearer required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
@@ -7513,9 +7531,11 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
};
},
/**
* Get all asset of a device that are in the database, ID only.
*
* @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
* @param {string} deviceId
* @param {*} [options] Override http request option.
* @deprecated
* @throws {RequiredError}
*/
getUserAssetsByDeviceId: async (deviceId: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
@@ -8347,6 +8367,16 @@ export const AssetApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAllAssets(skip, take, userId, isFavorite, isArchived, updatedAfter, updatedBefore, ifNoneMatch, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
* Get all asset of a device that are in the database, ID only.
* @param {string} deviceId
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getAllUserAssetsByDeviceId(deviceId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAllUserAssetsByDeviceId(deviceId, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
* Get a single asset\'s information
* @param {string} id
@@ -8494,9 +8524,11 @@ export const AssetApiFp = function(configuration?: Configuration) {
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
* Get all asset of a device that are in the database, ID only.
*
* @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
* @param {string} deviceId
* @param {*} [options] Override http request option.
* @deprecated
* @throws {RequiredError}
*/
async getUserAssetsByDeviceId(deviceId: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
@@ -8722,6 +8754,15 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
getAllAssets(requestParameters: AssetApiGetAllAssetsRequest = {}, options?: AxiosRequestConfig): AxiosPromise<Array<AssetResponseDto>> {
return localVarFp.getAllAssets(requestParameters.skip, requestParameters.take, requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.updatedAfter, requestParameters.updatedBefore, requestParameters.ifNoneMatch, options).then((request) => request(axios, basePath));
},
/**
* Get all asset of a device that are in the database, ID only.
* @param {AssetApiGetAllUserAssetsByDeviceIdRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getAllUserAssetsByDeviceId(requestParameters: AssetApiGetAllUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
return localVarFp.getAllUserAssetsByDeviceId(requestParameters.deviceId, options).then((request) => request(axios, basePath));
},
/**
* Get a single asset\'s information
* @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
@@ -8828,9 +8869,11 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
return localVarFp.getTimeBuckets(requestParameters.size, requestParameters.userId, requestParameters.albumId, requestParameters.personId, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.isTrashed, requestParameters.withStacked, requestParameters.withPartners, requestParameters.key, options).then((request) => request(axios, basePath));
},
/**
* Get all asset of a device that are in the database, ID only.
*
* @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
* @param {AssetApiGetUserAssetsByDeviceIdRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @deprecated
* @throws {RequiredError}
*/
getUserAssetsByDeviceId(requestParameters: AssetApiGetUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
@@ -9066,6 +9109,20 @@ export interface AssetApiGetAllAssetsRequest {
readonly ifNoneMatch?: string
}
/**
* Request parameters for getAllUserAssetsByDeviceId operation in AssetApi.
* @export
* @interface AssetApiGetAllUserAssetsByDeviceIdRequest
*/
export interface AssetApiGetAllUserAssetsByDeviceIdRequest {
/**
*
* @type {string}
* @memberof AssetApiGetAllUserAssetsByDeviceId
*/
readonly deviceId: string
}
/**
* Request parameters for getAssetById operation in AssetApi.
* @export
@@ -10010,6 +10067,17 @@ export class AssetApi extends BaseAPI {
return AssetApiFp(this.configuration).getAllAssets(requestParameters.skip, requestParameters.take, requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.updatedAfter, requestParameters.updatedBefore, requestParameters.ifNoneMatch, options).then((request) => request(this.axios, this.basePath));
}
/**
* Get all asset of a device that are in the database, ID only.
* @param {AssetApiGetAllUserAssetsByDeviceIdRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof AssetApi
*/
public getAllUserAssetsByDeviceId(requestParameters: AssetApiGetAllUserAssetsByDeviceIdRequest, options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).getAllUserAssetsByDeviceId(requestParameters.deviceId, options).then((request) => request(this.axios, this.basePath));
}
/**
* Get a single asset\'s information
* @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
@@ -10140,9 +10208,11 @@ export class AssetApi extends BaseAPI {
}
/**
* Get all asset of a device that are in the database, ID only.
*
* @summary Use /asset/device/:deviceId instead - Remove in 1.92 release
* @param {AssetApiGetUserAssetsByDeviceIdRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @deprecated
* @throws {RequiredError}
* @memberof AssetApi
*/
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en" class="dark">
<head>
<meta charset="utf-8" />
@@ -9,8 +9,11 @@
const restoreUser = async () => {
const restoredUser = await api.userApi.restoreUser({ id: user.id });
if (restoredUser.data.deletedAt == null) dispatch('user-restore-success');
else dispatch('user-restore-fail');
if (restoredUser.data.deletedAt == null) {
dispatch('user-restore-success');
} else {
dispatch('user-restore-fail');
}
};
</script>
@@ -21,7 +21,8 @@
return '0'.repeat(zeroLength);
};
$: [statsUsage, statsUsageUnit] = getBytesWithUnit(stats.usage, 0);
const TiB = 1024 ** 4;
$: [statsUsage, statsUsageUnit] = getBytesWithUnit(stats.usage, stats.usage > TiB ? 2 : 0);
</script>
<div class="flex flex-col gap-5">
@@ -16,8 +16,18 @@
let savedConfig: SystemConfigJobDto;
let defaultConfig: SystemConfigJobDto;
const ignoredJobs = [JobName.BackgroundTask, JobName.Search] as JobName[];
const jobNames = Object.values(JobName).filter((jobName) => !ignoredJobs.includes(jobName as JobName));
const jobNames = [
JobName.ThumbnailGeneration,
JobName.MetadataExtraction,
JobName.Library,
JobName.Sidecar,
JobName.ObjectTagging,
JobName.ClipEncoding,
JobName.RecognizeFaces,
JobName.VideoConversion,
JobName.StorageTemplateMigration,
JobName.Migration,
];
async function getConfigs() {
[savedConfig, defaultConfig] = await Promise.all([
@@ -4,13 +4,12 @@
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import { handleError } from '$lib/utils/handle-error';
import { api, CitiesFile, SystemConfigDto } from '@api';
import { api, SystemConfigDto } from '@api';
import { cloneDeep, isEqual } from 'lodash-es';
import { fade } from 'svelte/transition';
import SettingAccordion from '../setting-accordion.svelte';
import SettingButtonsRow from '../setting-buttons-row.svelte';
import SettingSwitch from '../setting-switch.svelte';
import SettingSelect from '../setting-select.svelte';
import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte';
export let config: SystemConfigDto; // this is the config that is being edited
@@ -39,7 +38,6 @@
},
reverseGeocoding: {
enabled: config.reverseGeocoding.enabled,
citiesFileOverride: config.reverseGeocoding.citiesFileOverride,
},
},
});
@@ -131,24 +129,6 @@
subtitle="Enable reverse geocoding"
bind:checked={config.reverseGeocoding.enabled}
/>
<hr />
<SettingSelect
label="Precision"
desc="Set reverse geocoding precision"
name="reverse-geocoding-precision"
bind:value={config.reverseGeocoding.citiesFileOverride}
options={[
{ value: CitiesFile.Cities500, text: 'Cities with more than 500 people' },
{ value: CitiesFile.Cities1000, text: 'Cities with more than 1000 people' },
{ value: CitiesFile.Cities5000, text: 'Cities with more than 5000 people' },
{ value: CitiesFile.Cities15000, text: 'Cities with more than 15000 people' },
]}
disabled={disabled || !config.reverseGeocoding.enabled}
isEdited={config.reverseGeocoding.citiesFileOverride !==
savedConfig.reverseGeocoding.citiesFileOverride}
/>
</div></SettingAccordion
>
@@ -44,14 +44,10 @@
>
<span class="flex gap-1 text-sm">
{#if variant === 'simple'}
<span
>{#if album.shared}Shared{/if}
</span>
<span>{album.shared ? 'Shared' : ''}</span>
{:else}
<span>{album.assetCount} items</span>
<span
>{#if album.shared} · Shared{/if}
</span>
<span>{album.shared ? ' · Shared' : ''} </span>
{/if}
</span>
</div>
@@ -17,12 +17,14 @@
export let circle = false;
export let hidden = false;
export let border = false;
export let preload = true;
let complete = false;
export let eyeColor: 'black' | 'white' = 'white';
</script>
<img
loading={preload ? 'eager' : 'lazy'}
style:width={widthStyle}
style:height={heightStyle}
style:filter={hidden ? 'grayscale(50%)' : 'none'}
@@ -5,10 +5,10 @@
export let option: Sort;
const handleSort = () => {
if (albumViewSettings === option.sortTitle) {
if (albumViewSettings === option.title) {
option.sortDesc = !option.sortDesc;
} else {
albumViewSettings = option.sortTitle;
albumViewSettings = option.title;
}
};
</script>
@@ -18,12 +18,12 @@
class="rounded-lg p-2 hover:bg-immich-dark-primary hover:dark:bg-immich-dark-primary/50"
on:click={() => handleSort()}
>
{#if albumViewSettings === option.sortTitle}
{#if albumViewSettings === option.title}
{#if option.sortDesc}
&#8595;
{:else}
&#8593;
{/if}
{/if}{option.table}</button
{/if}{option.title}</button
></th
>
@@ -12,15 +12,21 @@
import { handleError } from '$lib/utils/handle-error';
import { goto } from '$app/navigation';
import { AppRoute } from '$lib/constants';
import { mdiCallMerge, mdiMerge, mdiSwapHorizontal } from '@mdi/js';
import { mdiCallMerge, mdiClose, mdiMagnify, mdiMerge, mdiSwapHorizontal } from '@mdi/js';
import Icon from '$lib/components/elements/icon.svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { cloneDeep } from 'lodash-es';
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
export let person: PersonResponseDto;
let people: PersonResponseDto[] = [];
let peopleCopy: PersonResponseDto[] = [];
let selectedPeople: PersonResponseDto[] = [];
let screenHeight: number;
let isShowConfirmation = false;
let name = '';
let searchWord: string;
let isSearchingPeople = false;
let dispatch = createEventDispatcher();
$: hasSelection = selectedPeople.length > 0;
@@ -31,12 +37,49 @@
onMount(async () => {
const { data } = await api.personApi.getAllPeople({ withHidden: false });
people = data.people;
peopleCopy = cloneDeep(people);
});
const onClose = () => {
dispatch('go-back');
};
const resetSearch = () => {
name = '';
people = peopleCopy;
};
const searchPeople = async (force: boolean) => {
if (name === '') {
people = peopleCopy;
return;
}
if (!force) {
if (people.length < 20 && name.startsWith(searchWord)) {
people = peopleCopy
.filter((person: PersonResponseDto) => {
const nameParts = person.name.split(' ');
return nameParts.some((splitName) => splitName.toLowerCase().startsWith(name.toLowerCase()));
})
.slice(0, 10);
return;
}
}
const timeout = setTimeout(() => (isSearchingPeople = true), 100);
try {
const { data } = await api.searchApi.searchPerson({ name });
people = data;
searchWord = name;
} catch (error) {
handleError(error, "Can't search people");
} finally {
clearTimeout(timeout);
}
isSearchingPeople = false;
};
const handleSwapPeople = () => {
[person, selectedPeople[0]] = [selectedPeople[0], person];
goto(`${AppRoute.PEOPLE}/${person.id}?action=merge`);
@@ -136,9 +179,39 @@
<FaceThumbnail {person} border circle selectable={false} thumbnailSize={180} />
</div>
</div>
<div
class="immich-scrollbar overflow-y-auto rounded-3xl bg-gray-200 p-10 dark:bg-immich-dark-gray"
style:max-height={screenHeight - 200 - 200 + 'px'}
class="flex w-40 sm:w-48 md:w-96 h-14 rounded-lg bg-gray-100 p-2 dark:bg-gray-700 mb-8 gap-2 place-items-center"
>
<button on:click={() => searchPeople(true)}>
<div class="w-fit">
<Icon path={mdiMagnify} size="24" />
</div>
</button>
<!-- svelte-ignore a11y-autofocus -->
<input
autofocus
class="w-full gap-2 bg-gray-100 dark:bg-gray-700 dark:text-white"
type="text"
placeholder="Search names"
bind:value={name}
on:input={() => searchPeople(false)}
/>
{#if name}
<button on:click={resetSearch}>
<Icon path={mdiClose} />
</button>
{/if}
{#if isSearchingPeople}
<div class="flex place-items-center">
<LoadingSpinner />
</div>
{/if}
</div>
<div
class="immich-scrollbar overflow-y-auto rounded-3xl bg-gray-200 pt-8 px-8 pb-10 dark:bg-immich-dark-gray"
style:max-height={screenHeight - 250 - 250 + 'px'}
>
<div class="grid-col-2 grid gap-8 md:grid-cols-3 lg:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10">
{#each unselectedPeople as person (person.id)}
@@ -12,6 +12,7 @@
import Icon from '$lib/components/elements/icon.svelte';
export let person: PersonResponseDto;
export let preload = false;
type MenuItemEvent = 'change-name' | 'set-birth-date' | 'merge-faces' | 'hide-face';
let dispatch = createEventDispatcher<{
@@ -48,6 +49,7 @@
<div class="h-48 w-48 rounded-xl brightness-95 filter">
<ImageThumbnail
shadow
{preload}
url={api.getPeopleThumbnailUrl(person.id)}
altText={person.name}
title={person.name}
@@ -275,6 +275,8 @@
<style>
.main-view {
box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.3), 0 8px 12px 6px rgba(0, 0, 0, 0.15);
box-shadow:
0 4px 4px 0 rgba(0, 0, 0, 0.3),
0 8px 12px 6px rgba(0, 0, 0, 0.15);
}
</style>
@@ -91,6 +91,8 @@
<style>
.memory-card {
box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
box-shadow:
rgba(60, 64, 67, 0.3) 0px 1px 2px 0px,
rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
}
</style>
@@ -52,7 +52,7 @@
<svelte:fragment slot="title">
<span class="flex place-items-center gap-2">
<p class="font-medium">
Add to {#if shared}Shared {/if} Album
Add to {shared ? 'Shared ' : ''}Album
</p>
</span>
</svelte:fragment>
@@ -88,7 +88,7 @@
<Icon path={mdiPlus} size="30" />
</div>
<p class="">
New {#if shared}Shared {/if}Album {#if search.length > 0}<b>{search}</b>{/if}
New {shared ? 'Shared ' : ''}Album {#if search.length > 0}<b>{search}</b>{/if}
</p>
</button>
{#if filteredAlbums.length > 0}
@@ -101,7 +101,8 @@
{#if !shared}
<p class="px-5 py-3 text-xs">
{#if search.length === 0}ALL {/if}ALBUMS
{#if search.length === 0}ALL
{/if}ALBUMS
</p>
{/if}
{#each filteredAlbums as album (album.id)}
@@ -111,10 +111,20 @@
</script>
{#await style then style}
<MapLibre {style} class="h-full" {center} {zoom} attributionControl={false} diffStyleUpdates={true} let:map bind:map>
<MapLibre
{style}
class="h-full"
{center}
{zoom}
attributionControl={false}
diffStyleUpdates={true}
let:map
on:load={(event) => event.detail.setMaxZoom(14)}
bind:map
>
<NavigationControl position="top-left" showCompass={!simplified} />
{#if !simplified}
<GeolocateControl position="top-left" fitBoundsOptions={{ maxZoom: 12 }} />
<GeolocateControl position="top-left" />
<FullscreenControl position="top-left" />
<ScaleControl />
<AttributionControl compact={false} />
@@ -134,7 +144,7 @@
}),
}}
id="geojson"
cluster={{ maxZoom: 14, radius: 500 }}
cluster={{ radius: 500 }}
>
<MarkerLayer
applyToClusters
@@ -66,13 +66,17 @@
<div class="h-[15px] rounded-md bg-immich-warning transition-all" style="width: 100%" />
<p class="absolute top-0 h-full w-full text-center text-[10px]">
Skipped
{#if uploadAsset.message} ({uploadAsset.message}){/if}
{#if uploadAsset.message}
({uploadAsset.message})
{/if}
</p>
{:else if uploadAsset.state === UploadState.DONE}
<div class="h-[15px] rounded-md bg-immich-success transition-all" style="width: 100%" />
<p class="absolute top-0 h-full w-full text-center text-[10px]">
Uploaded
{#if uploadAsset.message} ({uploadAsset.message}){/if}
{#if uploadAsset.message}
({uploadAsset.message})
{/if}
</p>
{/if}
</div>
@@ -7,13 +7,14 @@
import { createEventDispatcher } from 'svelte';
import { goto } from '$app/navigation';
import { mdiCircleEditOutline, mdiContentCopy, mdiDelete, mdiOpenInNew } from '@mdi/js';
import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
export let link: SharedLinkResponseDto;
let expirationCountdown: luxon.DurationObjectUnits;
const dispatch = createEventDispatcher();
const getAssetInfo = async (): Promise<AssetResponseDto> => {
const getThumbnail = async (): Promise<AssetResponseDto> => {
let assetId = '';
if (link.album?.albumThumbnailAssetId) {
@@ -60,18 +61,28 @@
class="flex w-full gap-4 border-b border-gray-200 py-4 transition-all hover:border-immich-primary dark:border-gray-600 dark:text-immich-gray dark:hover:border-immich-dark-primary"
>
<div>
{#await getAssetInfo()}
<LoadingSpinner />
{:then asset}
{#if link?.album?.albumThumbnailAssetId || link.assets.length > 0}
{#await getThumbnail()}
<LoadingSpinner />
{:then asset}
<img
id={asset.id}
src={api.getAssetThumbnailUrl(asset.id, ThumbnailFormat.Webp)}
alt={asset.id}
class="h-[100px] w-[100px] rounded-lg object-cover"
loading="lazy"
draggable="false"
/>
{/await}
{:else}
<img
id={asset.id}
src={api.getAssetThumbnailUrl(asset.id, ThumbnailFormat.Webp)}
alt={asset.id}
src={noThumbnailUrl}
alt={'Album without assets'}
class="h-[100px] w-[100px] rounded-lg object-cover"
loading="lazy"
draggable="false"
/>
{/await}
{/if}
</div>
<div class="flex flex-col justify-between">
+4 -1
View File
@@ -73,7 +73,10 @@ export class AssetStore {
assets: AssetResponseDto[] = [];
albumAssets: Set<string> = new Set();
constructor(options: AssetStoreOptions, private albumId?: string) {
constructor(
options: AssetStoreOptions,
private albumId?: string,
) {
this.options = { ...options, size: TimeBucketSize.Month };
this.store$.set(this);
}
+20 -6
View File
@@ -7,12 +7,26 @@
export function getThumbnailSize(assetCount: number, viewWidth: number): number {
if (assetCount < 6) {
return Math.min(320, Math.floor(viewWidth / assetCount - assetCount));
} else {
if (viewWidth > 600) return viewWidth / 7 - 7;
else if (viewWidth > 400) return viewWidth / 4 - 6;
else if (viewWidth > 300) return viewWidth / 2 - 6;
else if (viewWidth > 200) return viewWidth / 2 - 6;
else if (viewWidth > 100) return viewWidth / 1 - 6;
}
if (viewWidth > 600) {
return viewWidth / 7 - 7;
}
if (viewWidth > 400) {
return viewWidth / 4 - 6;
}
if (viewWidth > 300) {
return viewWidth / 2 - 6;
}
if (viewWidth > 200) {
return viewWidth / 2 - 6;
}
if (viewWidth > 100) {
return viewWidth / 1 - 6;
}
return 300;
+90 -38
View File
@@ -1,9 +1,6 @@
<script lang="ts" context="module">
// table is the text printed in the table and sortTitle is the text printed in the dropDow menu
export interface Sort {
table: string;
sortTitle: string;
title: string;
sortDesc: boolean;
widthClass: string;
sortFn: (reverse: boolean, albums: AlbumResponseDto[]) => AlbumResponseDto[];
@@ -54,46 +51,75 @@
let sortByOptions: Record<string, Sort> = {
albumTitle: {
table: 'Album title',
sortTitle: 'Album title',
title: 'Album title',
sortDesc: $albumViewSettings.sortDesc, // Load Sort Direction
widthClass: 'w-8/12 text-left sm:w-4/12 md:w-4/12 md:w-4/12 2xl:w-6/12',
widthClass: 'text-left w-8/12 sm:w-4/12 md:w-4/12 md:w-4/12 xl:w-[30%] 2xl:w-[40%]',
sortFn: (reverse, albums) => {
return orderBy(albums, 'albumName', [reverse ? 'desc' : 'asc']);
},
},
numberOfAssets: {
table: 'Assets',
sortTitle: 'Number of assets',
title: 'Number of assets',
sortDesc: $albumViewSettings.sortDesc,
widthClass: 'w-4/12 text-center sm:w-2/12 2xl:w-1/12',
widthClass: 'text-center w-4/12 m:w-2/12 md:w-2/12 xl:w-[15%] 2xl:w-[12%]',
sortFn: (reverse, albums) => {
return orderBy(albums, 'assetCount', [reverse ? 'desc' : 'asc']);
},
},
lastModified: {
table: 'Updated date',
sortTitle: 'Last modified',
title: 'Last modified',
sortDesc: $albumViewSettings.sortDesc,
widthClass: 'text-center hidden sm:block w-3/12 lg:w-2/12',
widthClass: 'text-center hidden sm:block w-3/12 xl:w-[15%] 2xl:w-[12%]',
sortFn: (reverse, albums) => {
return orderBy(albums, [(album) => new Date(album.updatedAt)], [reverse ? 'desc' : 'asc']);
},
},
mostRecent: {
table: 'Created date',
sortTitle: 'Most recent photo',
created: {
title: 'Created date',
sortDesc: $albumViewSettings.sortDesc,
widthClass: 'text-center hidden sm:block w-3/12 lg:w-2/12',
widthClass: 'text-center hidden sm:block w-3/12 xl:w-[15%] 2xl:w-[12%]',
sortFn: (reverse, albums) => {
return orderBy(albums, [(album) => new Date(album.createdAt)], [reverse ? 'desc' : 'asc']);
},
},
mostRecent: {
title: 'Most recent photo',
sortDesc: $albumViewSettings.sortDesc,
widthClass: 'text-center hidden xl:block xl:w-[15%] 2xl:w-[12%]',
sortFn: (reverse, albums) => {
return orderBy(
albums,
[
(album) =>
album.lastModifiedAssetTimestamp ? new Date(album.lastModifiedAssetTimestamp) : new Date(album.updatedAt),
],
[(album) => (album.endDate ? new Date(album.endDate) : '')],
[reverse ? 'desc' : 'asc'],
);
).sort((a, b) => {
if (a.endDate === undefined) {
return 1;
}
if (b.endDate === undefined) {
return -1;
}
return 0;
});
},
},
mostOld: {
title: 'Oldest photo',
sortDesc: $albumViewSettings.sortDesc,
widthClass: 'text-center hidden xl:block xl:w-[15%] 2xl:w-[12%]',
sortFn: (reverse, albums) => {
return orderBy(
albums,
[(album) => (album.startDate ? new Date(album.startDate) : null)],
[reverse ? 'desc' : 'asc'],
).sort((a, b) => {
if (a.startDate === undefined) {
return 1;
}
if (b.startDate === undefined) {
return -1;
}
return 0;
});
},
},
};
@@ -144,16 +170,25 @@
};
$: {
const { sortBy } = $albumViewSettings;
for (const key in sortByOptions) {
if (sortByOptions[key].sortTitle === sortBy) {
if (sortByOptions[key].title === $albumViewSettings.sortBy) {
$albums = sortByOptions[key].sortFn(sortByOptions[key].sortDesc, $unsortedAlbums);
$albumViewSettings.sortDesc = sortByOptions[key].sortDesc; // "Save" sortDesc
$albumViewSettings.sortBy = sortByOptions[key].title;
break;
}
}
}
const test = (searched: string): Sort => {
for (const key in sortByOptions) {
if (sortByOptions[key].title === searched) {
return sortByOptions[key];
}
}
return sortByOptions[0];
};
const handleCreateAlbum = async () => {
const newAlbum = await createAlbum();
if (newAlbum) {
@@ -220,19 +255,20 @@
<Dropdown
options={Object.values(sortByOptions)}
selectedOption={test($albumViewSettings.sortBy)}
render={(option) => {
return {
title: option.sortTitle,
title: option.title,
icon: option.sortDesc ? mdiArrowDownThin : mdiArrowUpThin,
};
}}
on:select={(event) => {
for (const key in sortByOptions) {
if (sortByOptions[key].sortTitle === event.detail.sortTitle) {
if (sortByOptions[key].title === event.detail.title) {
sortByOptions[key].sortDesc = !sortByOptions[key].sortDesc;
$albumViewSettings.sortBy = sortByOptions[key].title;
}
}
$albumViewSettings.sortBy = event.detail.sortTitle;
}}
/>
@@ -251,7 +287,7 @@
{#if $albums.length !== 0}
<!-- Album Card -->
{#if $albumViewSettings.view === AlbumViewMode.Cover}
<div class="grid grid-cols-[repeat(auto-fill,minmax(13rem,1fr))]">
<div class="grid grid-cols-[repeat(auto-fill,minmax(14rem,1fr))]">
{#each $albums as album (album.id)}
<a data-sveltekit-preload-data="hover" href={`albums/${album.id}`} animate:flip={{ duration: 200 }}>
<AlbumCard
@@ -271,7 +307,7 @@
{#each Object.keys(sortByOptions) as key (key)}
<TableHeader bind:albumViewSettings={$albumViewSettings.sortBy} bind:option={sortByOptions[key]} />
{/each}
<th class="hidden w-2/12 text-center text-sm font-medium lg:block 2xl:w-1/12">Action</th>
<th class="hidden text-center text-sm font-medium 2xl:block 2xl:w-[12%]">Action</th>
</tr>
</thead>
<tbody
@@ -284,18 +320,34 @@
on:keydown={(event) => event.key === 'Enter' && goto(`albums/${album.id}`)}
tabindex="0"
>
<td class="text-md w-8/12 text-ellipsis text-left sm:w-4/12 md:w-4/12 2xl:w-6/12">{album.albumName}</td>
<td class="text-md w-4/12 text-ellipsis text-center sm:w-2/12 md:w-2/12 2xl:w-1/12">
{album.assetCount}
{album.assetCount == 1 ? `item` : `items`}
</td>
<td class="text-md hidden w-3/12 text-ellipsis text-center sm:block lg:w-2/12"
>{dateLocaleString(album.updatedAt)}</td
<td class="text-md text-ellipsis text-left w-8/12 sm:w-4/12 md:w-4/12 xl:w-[30%] 2xl:w-[40%]"
>{album.albumName}</td
>
<td class="text-md hidden w-3/12 text-ellipsis text-center sm:block lg:w-2/12"
<td class="text-md text-ellipsis text-center sm:w-2/12 md:w-2/12 xl:w-[15%] 2xl:w-[12%]">
{album.assetCount}
{album.assetCount > 1 ? `items` : `item`}
</td>
<td class="text-md hidden text-ellipsis text-center sm:block w-3/12 xl:w-[15%] 2xl:w-[12%]"
>{dateLocaleString(album.updatedAt)}
</td>
<td class="text-md hidden text-ellipsis text-center sm:block w-3/12 xl:w-[15%] 2xl:w-[12%]"
>{dateLocaleString(album.createdAt)}</td
>
<td class="text-md hidden w-2/12 text-ellipsis text-center lg:block 2xl:w-1/12">
<td class="text-md text-ellipsis text-center hidden xl:block xl:w-[15%] 2xl:w-[12%]">
{#if album.endDate}
{dateLocaleString(album.endDate)}
{:else}
&#10060;
{/if}</td
>
<td class="text-md text-ellipsis text-center hidden xl:block xl:w-[15%] 2xl:w-[12%]"
>{#if album.startDate}
{dateLocaleString(album.startDate)}
{:else}
&#10060;
{/if}</td
>
<td class="text-md hidden text-ellipsis text-center 2xl:block xl:w-[15%] 2xl:w-[12%]">
<button
on:click|stopPropagation={() => handleEdit(album)}
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"
+4 -2
View File
@@ -372,10 +372,11 @@
{#if countVisiblePeople > 0}
<div class="pl-4">
<div class="flex flex-row flex-wrap gap-1">
{#each people as person (person.id)}
{#each people as person, idx (person.id)}
{#if !person.isHidden}
<PeopleCard
{person}
preload={idx < 20}
on:change-name={() => handleChangeName(person)}
on:set-birth-date={() => handleSetBirthDate(person)}
on:merge-faces={() => handleMergeFaces(person)}
@@ -444,7 +445,7 @@
bind:showLoadingSpinner
bind:toggleVisibility
>
{#each people as person (person.id)}
{#each people as person, idx (person.id)}
<button
class="relative h-36 w-36 md:h-48 md:w-48"
on:click={() => (person.isHidden = !person.isHidden)}
@@ -452,6 +453,7 @@
on:mouseleave={() => (eyeColorMap[person.id] = 'white')}
>
<ImageThumbnail
preload={idx < 20}
bind:hidden={person.isHidden}
shadow
url={api.getPeopleThumbnailUrl(person.id)}
+3 -3
View File
@@ -3,8 +3,8 @@
import { page } from '$app/stores';
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte';
import ChangeDate from '$lib/components/photos-page/actions/change-location-action.svelte';
import ChangeLocation from '$lib/components/photos-page/actions/change-datetion-action.svelte';
import ChangeDate from '$lib/components/photos-page/actions/change-date-action.svelte';
import ChangeLocation from '$lib/components/photos-page/actions/change-location-action.svelte';
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
@@ -137,7 +137,7 @@
{#if albums.length}
<section>
<div class="ml-6 text-4xl font-medium text-black/70 dark:text-white/80">ALBUMS</div>
<div class="grid grid-cols-[repeat(auto-fill,minmax(13rem,1fr))]">
<div class="grid grid-cols-[repeat(auto-fill,minmax(14rem,1fr))]">
{#each albums as album (album.id)}
<a data-sveltekit-preload-data="hover" href={`albums/${album.id}`} animate:flip={{ duration: 200 }}>
<AlbumCard {album} user={data.user} isSharingView={false} showItemCount={false} showContextMenu={false} />
+1 -1
View File
@@ -93,7 +93,7 @@
<div>
<!-- Share Album List -->
<div class="grid grid-cols-[repeat(auto-fill,minmax(13rem,1fr))]">
<div class="grid grid-cols-[repeat(auto-fill,minmax(14rem,1fr))]">
{#each data.sharedAlbums as album (album.id)}
<a data-sveltekit-preload-data="hover" href={`albums/${album.id}`} animate:flip={{ duration: 200 }}>
<AlbumCard {album} user={data.user} isSharingView showContextMenu={false} />
@@ -181,8 +181,8 @@
isDeleted(user)
? 'bg-red-300 dark:bg-red-900'
: i % 2 == 0
? 'bg-immich-gray dark:bg-immich-dark-gray/75'
: 'bg-immich-bg dark:bg-immich-dark-gray/50'
? 'bg-immich-gray dark:bg-immich-dark-gray/75'
: 'bg-immich-bg dark:bg-immich-dark-gray/50'
}`}
>
<td class="w-4/12 text-ellipsis break-all px-2 text-sm">{user.email}</td>
@@ -247,8 +247,8 @@
isDeleted(user)
? 'bg-red-300 dark:bg-red-900'
: i % 2 == 0
? 'bg-immich-gray dark:bg-immich-dark-gray/75'
: 'bg-immich-bg dark:bg-immich-dark-gray/50'
? 'bg-immich-gray dark:bg-immich-dark-gray/75'
: 'bg-immich-bg dark:bg-immich-dark-gray/50'
}`}
>
<td class="w-1/4 text-ellipsis break-words px-2 text-sm">{user.name}</td>