From 6b49104d59b0206b2ad70a6da5c4b3028983db51 Mon Sep 17 00:00:00 2001 From: Alex <alex.tran1502@gmail.com> Date: Sat, 9 Nov 2024 09:40:13 -0600 Subject: [PATCH 01/36] fix(mobile): make sure date locale is inititialized for some languages (#14035) --- mobile/lib/main.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index 48bc936a82..3b582e336c 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -11,6 +11,7 @@ import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/utils/download.dart'; +import 'package:intl/date_symbol_data_local.dart'; import 'package:timezone/data/latest.dart'; import 'package:immich_mobile/constants/locales.dart'; import 'package:immich_mobile/services/background.service.dart'; @@ -56,6 +57,7 @@ void main() async { Future<void> initApp() async { await EasyLocalization.ensureInitialized(); + await initializeDateFormatting(); if (kReleaseMode && Platform.isAndroid) { try { From 5c31acbcf0d84f6fc217012acfb6646fb8067cfd Mon Sep 17 00:00:00 2001 From: mcarbonne <46689813+mcarbonne@users.noreply.github.com> Date: Sat, 9 Nov 2024 19:11:20 +0100 Subject: [PATCH 02/36] feat(web): stable json settings export (#14036) * recursively sort json output (settings) * fix format/lint/...g --- .../routes/admin/system-settings/+page.svelte | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/web/src/routes/admin/system-settings/+page.svelte b/web/src/routes/admin/system-settings/+page.svelte index f724e2d145..9eb7351060 100644 --- a/web/src/routes/admin/system-settings/+page.svelte +++ b/web/src/routes/admin/system-settings/+page.svelte @@ -64,8 +64,20 @@ type SettingsComponent = ComponentType<SvelteComponent<SettingsComponentProps>>; + // https://stackoverflow.com/questions/16167581/sort-object-properties-and-json-stringify/43636793#43636793 + const jsonReplacer = (key: string, value: unknown) => + value instanceof Object && !Array.isArray(value) + ? Object.keys(value) + .sort() + // eslint-disable-next-line unicorn/no-array-reduce + .reduce((sorted: { [key: string]: unknown }, key) => { + sorted[key] = (value as { [key: string]: unknown })[key]; + return sorted; + }, {}) + : value; + const downloadConfig = () => { - const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' }); + const blob = new Blob([JSON.stringify(config, jsonReplacer, 2)], { type: 'application/json' }); const downloadKey = 'immich-config.json'; downloadManager.add(downloadKey, blob.size); downloadManager.update(downloadKey, blob.size); @@ -240,7 +252,7 @@ <div class="hidden lg:block"> <SearchBar placeholder={$t('search_settings')} bind:name={searchQuery} showLoadingSpinner={false} /> </div> - <LinkButton on:click={() => copyToClipboard(JSON.stringify(config, null, 2))}> + <LinkButton on:click={() => copyToClipboard(JSON.stringify(config, jsonReplacer, 2))}> <div class="flex place-items-center gap-2 text-sm"> <Icon path={mdiContentCopy} size="18" /> {$t('copy_to_clipboard')} From edce096680bc3d529b2a467fed3fbe90c3f0f26b Mon Sep 17 00:00:00 2001 From: Snowknight26 <Snowknight26@users.noreply.github.com> Date: Sat, 9 Nov 2024 12:15:25 -0600 Subject: [PATCH 03/36] chore(web): Update the new version announcement text (#14001) * Update en.json * Update en.json * Update en.json --- i18n/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en.json b/i18n/en.json index 72e3e1e1bf..a1c79bbec4 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1283,7 +1283,7 @@ "variables": "Variables", "version": "Version", "version_announcement_closing": "Your friend, Alex", - "version_announcement_message": "Hi friend, there is a new version of the application please take your time to visit the <link>release notes</link> and ensure your <code>docker-compose.yml</code>, and <code>.env</code> setup is up-to-date to prevent any misconfigurations, especially if you use WatchTower or any mechanism that handles updating your application automatically.", + "version_announcement_message": "Hi there! A new version of Immich is available. Please take some time to read the <link>release notes</link> to ensure your setup is up-to-date to prevent any misconfigurations, especially if you use WatchTower or any mechanism that handles updating your Immich instance automatically.", "version_history": "Version History", "version_history_item": "Installed {version} on {date}", "video": "Video", From 54d881e5c6ffd0163e17df20cdbaed05aeb5ed1b Mon Sep 17 00:00:00 2001 From: Joren Guillaume <guillaume.joren@gmail.com> Date: Sun, 10 Nov 2024 19:33:51 +0100 Subject: [PATCH 04/36] docs: Fix DCM docs link (#14059) Fix DCM docs link --- docs/docs/developer/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/developer/setup.md b/docs/docs/developer/setup.md index 32e79849ef..e7bde2178b 100644 --- a/docs/docs/developer/setup.md +++ b/docs/docs/developer/setup.md @@ -76,7 +76,7 @@ Setting these in the IDE give a better developer experience, auto-formatting cod ### Dart Code Metrics -The mobile app uses DCM (Dart Code Metrics) for linting and metrics calculation. Please refer to the [Getting Started](https://dcm.dev/docs/getting-started/#installation) page for more information on setting up DCM +The mobile app uses DCM (Dart Code Metrics) for linting and metrics calculation. Please refer to the [Getting Started](https://dcm.dev/docs/) page for more information on setting up DCM Note: Activating the license is not required. From 00d6cc86ad213c4f12b4c4eebb57a6b67463f2bb Mon Sep 17 00:00:00 2001 From: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com> Date: Sun, 10 Nov 2024 21:49:23 +0100 Subject: [PATCH 05/36] chore: add weblate requests (#14051) --- i18n/fil.json | 1 + i18n/nn.json | 1 + web/src/lib/constants.ts | 2 ++ 3 files changed, 4 insertions(+) create mode 100644 i18n/fil.json create mode 100644 i18n/nn.json diff --git a/i18n/fil.json b/i18n/fil.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/i18n/fil.json @@ -0,0 +1 @@ +{} diff --git a/i18n/nn.json b/i18n/nn.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/i18n/nn.json @@ -0,0 +1 @@ +{} diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts index aa1d976b6f..390f4be378 100644 --- a/web/src/lib/constants.ts +++ b/web/src/lib/constants.ts @@ -270,6 +270,7 @@ export const langs = [ { name: 'Estonian', code: 'et', loader: () => import('$i18n/et.json') }, { name: 'Persian', code: 'fa', loader: () => import('$i18n/fa.json') }, { name: 'Finnish', code: 'fi', loader: () => import('$i18n/fi.json') }, + { name: 'Filipino', code: 'fil', loader: () => import('$i18n/fil.json') }, { name: 'French', code: 'fr', loader: () => import('$i18n/fr.json') }, { name: 'Hebrew', code: 'he', loader: () => import('$i18n/he.json') }, { name: 'Hindi', code: 'hi', loader: () => import('$i18n/hi.json') }, @@ -291,6 +292,7 @@ export const langs = [ { name: 'Malay', code: 'ms', loader: () => import('$i18n/ms.json') }, { name: 'Norwegian Bokmål', code: 'nb-NO', weblateCode: 'nb_NO', loader: () => import('$i18n/nb_NO.json') }, { name: 'Dutch', code: 'nl', loader: () => import('$i18n/nl.json') }, + { name: 'Norwegian Nynorsk', code: 'nn', loader: () => import('$i18n/nn.json') }, { name: 'Polish', code: 'pl', loader: () => import('$i18n/pl.json') }, { name: 'Portuguese', code: 'pt', loader: () => import('$i18n/pt.json') }, { name: 'Portuguese (Brazil) ', code: 'pt-BR', weblateCode: 'pt_BR', loader: () => import('$i18n/pt_BR.json') }, From 7aacc92699162aca0ad66945b2039b89b3640c8c Mon Sep 17 00:00:00 2001 From: gamescom15 <10470023+gamescom15@users.noreply.github.com> Date: Mon, 11 Nov 2024 04:51:00 +0100 Subject: [PATCH 06/36] docs: clarify file size impact in hardware-transcoding.md (#14049) --- docs/docs/features/hardware-transcoding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/features/hardware-transcoding.md b/docs/docs/features/hardware-transcoding.md index 4f059281f3..a561bafa80 100644 --- a/docs/docs/features/hardware-transcoding.md +++ b/docs/docs/features/hardware-transcoding.md @@ -1,7 +1,7 @@ # Hardware Transcoding [Experimental] This feature allows you to use a GPU to accelerate transcoding and reduce CPU load. -Note that hardware transcoding is much less efficient for file sizes. +Note that hardware transcoding produces significantly larger videos than software transcoding with similar settings, typically with lower quality. Using slow presets and preferring more efficient codecs can narrow this gap. As this is a new feature, it is still experimental and may not work on all systems. :::info From 5097c92494aaa91f9c5b74a96cbb1e11a31844f9 Mon Sep 17 00:00:00 2001 From: Zack Pollard <zackpollard@ymail.com> Date: Mon, 11 Nov 2024 12:08:52 +0000 Subject: [PATCH 07/36] fix(server): attempt to delete failed backups immediately after failure (#13995) --- server/src/services/backup.service.spec.ts | 8 ++++++++ server/src/services/backup.service.ts | 3 +++ 2 files changed, 11 insertions(+) diff --git a/server/src/services/backup.service.spec.ts b/server/src/services/backup.service.spec.ts index 5f00596622..7ec2bb87c1 100644 --- a/server/src/services/backup.service.spec.ts +++ b/server/src/services/backup.service.spec.ts @@ -146,6 +146,7 @@ describe(BackupService.name, () => { storageMock.readdir.mockResolvedValue([]); processMock.spawn.mockReturnValue(mockSpawn(0, 'data', '')); storageMock.rename.mockResolvedValue(); + storageMock.unlink.mockResolvedValue(); systemMock.get.mockResolvedValue(systemConfigStub.backupEnabled); storageMock.createWriteStream.mockReturnValue(new PassThrough()); }); @@ -188,5 +189,12 @@ describe(BackupService.name, () => { const result = await sut.handleBackupDatabase(); expect(result).toBe(JobStatus.FAILED); }); + it('should ignore unlink failing and still return failed job status', async () => { + processMock.spawn.mockReturnValueOnce(mockSpawn(1, '', 'error')); + storageMock.unlink.mockRejectedValue(new Error('error')); + const result = await sut.handleBackupDatabase(); + expect(storageMock.unlink).toHaveBeenCalled(); + expect(result).toBe(JobStatus.FAILED); + }); }); }); diff --git a/server/src/services/backup.service.ts b/server/src/services/backup.service.ts index d08e0d397b..40753a2c76 100644 --- a/server/src/services/backup.service.ts +++ b/server/src/services/backup.service.ts @@ -163,6 +163,9 @@ export class BackupService extends BaseService { await this.storageRepository.rename(backupFilePath, backupFilePath.replace('.tmp', '')); } catch (error) { this.logger.error('Database Backup Failure', error); + await this.storageRepository + .unlink(backupFilePath) + .catch((error) => this.logger.error('Failed to delete failed backup file', error)); return JobStatus.FAILED; } From f1c9b763cf335001ee553042fad3670fee044b8c Mon Sep 17 00:00:00 2001 From: Zack Pollard <zackpollard@ymail.com> Date: Mon, 11 Nov 2024 12:28:53 +0000 Subject: [PATCH 08/36] docs: backup folder name is backups (#14073) --- docs/docs/guides/custom-locations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/guides/custom-locations.md b/docs/docs/guides/custom-locations.md index 52cd0ccb25..514008611d 100644 --- a/docs/docs/guides/custom-locations.md +++ b/docs/docs/guides/custom-locations.md @@ -17,7 +17,7 @@ In our `.env` file, we will define variables that will help us in the future whe + THUMB_LOCATION=/custom/path/immich/thumbs + ENCODED_VIDEO_LOCATION=/custom/path/immich/encoded-video + PROFILE_LOCATION=/custom/path/immich/profile -+ BACKUP_LOCATION=/custom/path/immich/backup ++ BACKUP_LOCATION=/custom/path/immich/backups ... ``` @@ -31,7 +31,7 @@ services: + - ${THUMB_LOCATION}:/usr/src/app/upload/thumbs + - ${ENCODED_VIDEO_LOCATION}:/usr/src/app/upload/encoded-video + - ${PROFILE_LOCATION}:/usr/src/app/upload/profile -+ - ${BACKUP_LOCATION}:/usr/src/app/upload/backup ++ - ${BACKUP_LOCATION}:/usr/src/app/upload/backups - /etc/localtime:/etc/localtime:ro ``` From d4ca7d0075f8374ed9e15398989b9a3440083d26 Mon Sep 17 00:00:00 2001 From: Zack Pollard <zackpollard@ymail.com> Date: Mon, 11 Nov 2024 12:50:09 +0000 Subject: [PATCH 09/36] fix: config updates not applying for job and storage template service (#14074) --- server/src/services/job.service.spec.ts | 4 ++-- server/src/services/job.service.ts | 8 ++++++-- server/src/services/storage-template.service.spec.ts | 6 +++--- server/src/services/storage-template.service.ts | 8 ++++++-- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/server/src/services/job.service.spec.ts b/server/src/services/job.service.spec.ts index 260497fcea..a23b05073c 100644 --- a/server/src/services/job.service.spec.ts +++ b/server/src/services/job.service.spec.ts @@ -1,5 +1,5 @@ import { BadRequestException } from '@nestjs/common'; -import { defaults } from 'src/config'; +import { defaults, SystemConfig } from 'src/config'; import { ImmichWorker } from 'src/enum'; import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IConfigRepository } from 'src/interfaces/config.interface'; @@ -31,7 +31,7 @@ describe(JobService.name, () => { describe('onConfigUpdate', () => { it('should update concurrency', () => { - sut.onConfigInitOrUpdate({ newConfig: defaults }); + sut.onConfigUpdate({ newConfig: defaults, oldConfig: {} as SystemConfig }); expect(jobMock.setConcurrency).toHaveBeenCalledTimes(15); expect(jobMock.setConcurrency).toHaveBeenNthCalledWith(5, QueueName.FACIAL_RECOGNITION, 1); diff --git a/server/src/services/job.service.ts b/server/src/services/job.service.ts index 64490d4505..0528a4a925 100644 --- a/server/src/services/job.service.ts +++ b/server/src/services/job.service.ts @@ -39,8 +39,7 @@ const asJobItem = (dto: JobCreateDto): JobItem => { @Injectable() export class JobService extends BaseService { @OnEvent({ name: 'config.init' }) - @OnEvent({ name: 'config.update', server: true }) - onConfigInitOrUpdate({ newConfig: config }: ArgOf<'config.init'>) { + onConfigInit({ newConfig: config }: ArgOf<'config.init'>) { if (this.worker !== ImmichWorker.MICROSERVICES) { return; } @@ -56,6 +55,11 @@ export class JobService extends BaseService { } } + @OnEvent({ name: 'config.update', server: true }) + onConfigUpdate({ newConfig: config }: ArgOf<'config.update'>) { + this.onConfigInit({ newConfig: config }); + } + async create(dto: JobCreateDto): Promise<void> { await this.jobRepository.queue(asJobItem(dto)); } diff --git a/server/src/services/storage-template.service.spec.ts b/server/src/services/storage-template.service.spec.ts index 496468a028..728e891d05 100644 --- a/server/src/services/storage-template.service.spec.ts +++ b/server/src/services/storage-template.service.spec.ts @@ -38,7 +38,7 @@ describe(StorageTemplateService.name, () => { systemMock.get.mockResolvedValue({ storageTemplate: { enabled: true } }); - sut.onConfigInitOrUpdate({ newConfig: defaults }); + sut.onConfigInit({ newConfig: defaults }); }); describe('onConfigValidate', () => { @@ -171,7 +171,7 @@ describe(StorageTemplateService.name, () => { const config = structuredClone(defaults); config.storageTemplate.template = '{{y}}/{{#if album}}{{album}}{{else}}other/{{MM}}{{/if}}/{{filename}}'; - sut.onConfigInitOrUpdate({ newConfig: config }); + sut.onConfigInit({ newConfig: config }); userMock.get.mockResolvedValue(user); assetMock.getByIds.mockResolvedValueOnce([asset]); @@ -192,7 +192,7 @@ describe(StorageTemplateService.name, () => { const user = userStub.user1; const config = structuredClone(defaults); config.storageTemplate.template = '{{y}}/{{#if album}}{{album}}{{else}}other//{{MM}}{{/if}}/{{filename}}'; - sut.onConfigInitOrUpdate({ newConfig: config }); + sut.onConfigInit({ newConfig: config }); userMock.get.mockResolvedValue(user); assetMock.getByIds.mockResolvedValueOnce([asset]); diff --git a/server/src/services/storage-template.service.ts b/server/src/services/storage-template.service.ts index 08566446e3..e8e4bd12a5 100644 --- a/server/src/services/storage-template.service.ts +++ b/server/src/services/storage-template.service.ts @@ -75,8 +75,7 @@ export class StorageTemplateService extends BaseService { } @OnEvent({ name: 'config.init' }) - @OnEvent({ name: 'config.update', server: true }) - onConfigInitOrUpdate({ newConfig }: ArgOf<'config.init'>) { + onConfigInit({ newConfig }: ArgOf<'config.init'>) { const template = newConfig.storageTemplate.template; if (!this._template || template !== this.template.raw) { this.logger.debug(`Compiling new storage template: ${template}`); @@ -84,6 +83,11 @@ export class StorageTemplateService extends BaseService { } } + @OnEvent({ name: 'config.update', server: true }) + onConfigUpdate({ newConfig }: ArgOf<'config.update'>) { + this.onConfigInit({ newConfig }); + } + @OnEvent({ name: 'config.validate' }) onConfigValidate({ newConfig }: ArgOf<'config.validate'>) { try { From e3426c880f19f57007b47d9c0040aba931099e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=BCtz?= <mail@dotlambda.de> Date: Mon, 11 Nov 2024 20:08:29 -0800 Subject: [PATCH 10/36] chore(ml): replace fastapi-slim with fastapi (#14091) The two have been identical since version 0.112.0: https://github.com/fastapi/fastapi/discussions/11525#discussioncomment-10219861 --- machine-learning/poetry.lock | 8 ++++---- machine-learning/pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/machine-learning/poetry.lock b/machine-learning/poetry.lock index 32a2b73ffc..de4d03c4f4 100644 --- a/machine-learning/poetry.lock +++ b/machine-learning/poetry.lock @@ -747,14 +747,14 @@ files = [ test = ["pytest (>=6)"] [[package]] -name = "fastapi-slim" +name = "fastapi" version = "0.115.4" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi_slim-0.115.4-py3-none-any.whl", hash = "sha256:8947515618c21665590a1673a0bfe4c721db4267999c149d5301c3c0f7b3d9ce"}, - {file = "fastapi_slim-0.115.4.tar.gz", hash = "sha256:6d37987e4d1f6adefb8c7119c9b804e59c9b3f1a488be5425994d52308e2f958"}, + {file = "fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742"}, + {file = "fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349"}, ] [package.dependencies] @@ -3778,4 +3778,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<4.0" -content-hash = "f95dddfd343a4b2f4d19ffee71ce6b2f5137e5514a60765424164259c4dc1044" +content-hash = "b690d5fbd141da3947f4f1dc029aba1b95e7faafd723166f2c4bdc47a66c095e" diff --git a/machine-learning/pyproject.toml b/machine-learning/pyproject.toml index 2b64a00ebe..0a8c9fbcdb 100644 --- a/machine-learning/pyproject.toml +++ b/machine-learning/pyproject.toml @@ -11,7 +11,7 @@ python = ">=3.10,<4.0" insightface = ">=0.7.3,<1.0" opencv-python-headless = ">=4.7.0.72,<5.0" pillow = ">=9.5.0,<11.0" -fastapi-slim = ">=0.95.2,<1.0" +fastapi = ">=0.95.2,<1.0" uvicorn = {extras = ["standard"], version = ">=0.22.0,<1.0"} pydantic = "^2.0.0" pydantic-settings = "^2.5.2" From bda97c4e0e3924d1cbb27124183253d0140a6cba Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 07:32:52 -0500 Subject: [PATCH 11/36] chore(deps): update node (#14090) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- cli/Dockerfile | 2 +- cli/package-lock.json | 4 ++-- cli/package.json | 2 +- e2e/package-lock.json | 6 +++--- e2e/package.json | 2 +- open-api/typescript-sdk/package-lock.json | 2 +- open-api/typescript-sdk/package.json | 2 +- server/Dockerfile | 2 +- server/package-lock.json | 2 +- server/package.json | 2 +- web/Dockerfile | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cli/Dockerfile b/cli/Dockerfile index c4b99869c6..bc7a074f5f 100644 --- a/cli/Dockerfile +++ b/cli/Dockerfile @@ -1,4 +1,4 @@ -FROM node:22.11.0-alpine3.20@sha256:f265794478aa0b1a23d85a492c8311ed795bc527c3fe7e43453b3c872dcd71a3 AS core +FROM node:22.11.0-alpine3.20@sha256:dc8ba2f61dd86c44e43eb25a7812ad03c5b1b224a19fc6f77e1eb9e5669f0b82 AS core WORKDIR /usr/src/open-api/typescript-sdk COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./ diff --git a/cli/package-lock.json b/cli/package-lock.json index f6e514644c..f99c53aa64 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -24,7 +24,7 @@ "@types/cli-progress": "^3.11.0", "@types/lodash-es": "^4.17.12", "@types/mock-fs": "^4.13.1", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", "@vitest/coverage-v8": "^2.0.5", @@ -59,7 +59,7 @@ "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "typescript": "^5.3.3" } }, diff --git a/cli/package.json b/cli/package.json index 5caa25778e..75189b279a 100644 --- a/cli/package.json +++ b/cli/package.json @@ -20,7 +20,7 @@ "@types/cli-progress": "^3.11.0", "@types/lodash-es": "^4.17.12", "@types/mock-fs": "^4.13.1", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", "@vitest/coverage-v8": "^2.0.5", diff --git a/e2e/package-lock.json b/e2e/package-lock.json index 0357d6e507..77fe8ce09d 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -15,7 +15,7 @@ "@immich/sdk": "file:../open-api/typescript-sdk", "@playwright/test": "^1.44.1", "@types/luxon": "^3.4.2", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@types/oidc-provider": "^8.5.1", "@types/pg": "^8.11.0", "@types/pngjs": "^6.0.4", @@ -64,7 +64,7 @@ "@types/cli-progress": "^3.11.0", "@types/lodash-es": "^4.17.12", "@types/mock-fs": "^4.13.1", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", "@vitest/coverage-v8": "^2.0.5", @@ -99,7 +99,7 @@ "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "typescript": "^5.3.3" } }, diff --git a/e2e/package.json b/e2e/package.json index c1a5227f93..fdc821bb82 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -25,7 +25,7 @@ "@immich/sdk": "file:../open-api/typescript-sdk", "@playwright/test": "^1.44.1", "@types/luxon": "^3.4.2", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@types/oidc-provider": "^8.5.1", "@types/pg": "^8.11.0", "@types/pngjs": "^6.0.4", diff --git a/open-api/typescript-sdk/package-lock.json b/open-api/typescript-sdk/package-lock.json index d7f3059b80..c1f885d30a 100644 --- a/open-api/typescript-sdk/package-lock.json +++ b/open-api/typescript-sdk/package-lock.json @@ -12,7 +12,7 @@ "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "typescript": "^5.3.3" } }, diff --git a/open-api/typescript-sdk/package.json b/open-api/typescript-sdk/package.json index 0cf484196d..60a085ae17 100644 --- a/open-api/typescript-sdk/package.json +++ b/open-api/typescript-sdk/package.json @@ -19,7 +19,7 @@ "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "typescript": "^5.3.3" }, "repository": { diff --git a/server/Dockerfile b/server/Dockerfile index 896a2de300..a2383b32d7 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -25,7 +25,7 @@ COPY --from=dev /usr/src/app/node_modules/@img ./node_modules/@img COPY --from=dev /usr/src/app/node_modules/exiftool-vendored.pl ./node_modules/exiftool-vendored.pl # web build -FROM node:22.11.0-alpine3.20@sha256:f265794478aa0b1a23d85a492c8311ed795bc527c3fe7e43453b3c872dcd71a3 AS web +FROM node:22.11.0-alpine3.20@sha256:dc8ba2f61dd86c44e43eb25a7812ad03c5b1b224a19fc6f77e1eb9e5669f0b82 AS web WORKDIR /usr/src/open-api/typescript-sdk COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./ diff --git a/server/package-lock.json b/server/package-lock.json index 19398bb59d..4300cb3780 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -83,7 +83,7 @@ "@types/lodash": "^4.14.197", "@types/mock-fs": "^4.13.1", "@types/multer": "^1.4.7", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@types/nodemailer": "^6.4.14", "@types/picomatch": "^3.0.0", "@types/pngjs": "^6.0.5", diff --git a/server/package.json b/server/package.json index 1ef0da4942..35e727ef86 100644 --- a/server/package.json +++ b/server/package.json @@ -108,7 +108,7 @@ "@types/lodash": "^4.14.197", "@types/mock-fs": "^4.13.1", "@types/multer": "^1.4.7", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@types/nodemailer": "^6.4.14", "@types/picomatch": "^3.0.0", "@types/pngjs": "^6.0.5", diff --git a/web/Dockerfile b/web/Dockerfile index 7e4d9769be..72bd9344da 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -1,4 +1,4 @@ -FROM node:22.11.0-alpine3.20@sha256:f265794478aa0b1a23d85a492c8311ed795bc527c3fe7e43453b3c872dcd71a3 +FROM node:22.11.0-alpine3.20@sha256:dc8ba2f61dd86c44e43eb25a7812ad03c5b1b224a19fc6f77e1eb9e5669f0b82 RUN apk add --no-cache tini USER node From b9a0c3c79f069c2b57e4e9f681d35b9d98c39967 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:49:31 +0000 Subject: [PATCH 12/36] chore(deps): update base-image to v20241112 (major) (#14088) chore(deps): update base-image to v20241112 Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- server/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/Dockerfile b/server/Dockerfile index a2383b32d7..6c8da4e305 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,5 +1,5 @@ # dev build -FROM ghcr.io/immich-app/base-server-dev:20241105@sha256:99eec44db9e281e30eb9c50161cfb8e810f06e4338896b900fb5cafd09e82cd5 AS dev +FROM ghcr.io/immich-app/base-server-dev:20241112@sha256:889647c747b3f999b05e387eff414bcec5e42477958b267930e58ac58dadcfc7 AS dev RUN apt-get install --no-install-recommends -yqq tini WORKDIR /usr/src/app @@ -42,7 +42,7 @@ RUN npm run build # prod build -FROM ghcr.io/immich-app/base-server-prod:20241105@sha256:dbe566f5c53f36640da910ca86a7c5575a26e9b9f6bc8d90ae0a53b8bc3a1f73 +FROM ghcr.io/immich-app/base-server-prod:20241112@sha256:26a209563689f52b9a63feeedde9a16a8e0e558483cd3feb5c936423e55c7eea WORKDIR /usr/src/app ENV NODE_ENV=production \ From dfa8a8a6e18aa5adeff8c47b1734ee3ce2cd4463 Mon Sep 17 00:00:00 2001 From: Zack Pollard <zackpollard@ymail.com> Date: Tue, 12 Nov 2024 14:58:29 +0000 Subject: [PATCH 13/36] feat(server): use pg_dumpall version that matches the database version (#14083) --- server/src/services/backup.service.spec.ts | 29 ++++++++++++++++++++++ server/src/services/backup.service.ts | 29 +++++++++++++++++----- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/server/src/services/backup.service.spec.ts b/server/src/services/backup.service.spec.ts index 7ec2bb87c1..4152d88cb1 100644 --- a/server/src/services/backup.service.spec.ts +++ b/server/src/services/backup.service.spec.ts @@ -149,6 +149,7 @@ describe(BackupService.name, () => { storageMock.unlink.mockResolvedValue(); systemMock.get.mockResolvedValue(systemConfigStub.backupEnabled); storageMock.createWriteStream.mockReturnValue(new PassThrough()); + databaseMock.getPostgresVersion.mockResolvedValue('14.3.2'); }); it('should run a database backup successfully', async () => { const result = await sut.handleBackupDatabase(); @@ -196,5 +197,33 @@ describe(BackupService.name, () => { expect(storageMock.unlink).toHaveBeenCalled(); expect(result).toBe(JobStatus.FAILED); }); + it.each` + postgresVersion | expectedVersion + ${'14.6.4'} | ${14} + ${'15.3.3'} | ${15} + ${'16.4.2'} | ${16} + ${'17.15.1'} | ${17} + `( + `should use pg_dumpall $expectedVersion with postgres version $postgresVersion`, + async ({ postgresVersion, expectedVersion }) => { + databaseMock.getPostgresVersion.mockResolvedValue(postgresVersion); + await sut.handleBackupDatabase(); + expect(processMock.spawn).toHaveBeenCalledWith( + `/usr/lib/postgresql/${expectedVersion}/bin/pg_dumpall`, + expect.any(Array), + expect.any(Object), + ); + }, + ); + it.each` + postgresVersion + ${'13.99.99'} + ${'18.0.0'} + `(`should fail if postgres version $postgresVersion is not supported`, async ({ postgresVersion }) => { + databaseMock.getPostgresVersion.mockResolvedValue(postgresVersion); + const result = await sut.handleBackupDatabase(); + expect(processMock.spawn).not.toHaveBeenCalled(); + expect(result).toBe(JobStatus.FAILED); + }); }); }); diff --git a/server/src/services/backup.service.ts b/server/src/services/backup.service.ts index 40753a2c76..76b8fcd85b 100644 --- a/server/src/services/backup.service.ts +++ b/server/src/services/backup.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@nestjs/common'; import { default as path } from 'node:path'; +import semver from 'semver'; import { StorageCore } from 'src/cores/storage.core'; import { OnEvent, OnJob } from 'src/decorators'; import { ImmichWorker, StorageFolder } from 'src/enum'; @@ -101,14 +102,30 @@ export class BackupService extends BaseService { `immich-db-backup-${Date.now()}.sql.gz.tmp`, ); + const databaseVersion = await this.databaseRepository.getPostgresVersion(); + const databaseSemver = semver.coerce(databaseVersion); + const databaseMajorVersion = databaseSemver?.major; + const databaseSupported = semver.satisfies(databaseVersion, '>=14.0.0 <18.0.0'); + + if (!databaseMajorVersion || !databaseSupported) { + this.logger.error(`Database Backup Failure: Unsupported PostgreSQL version: ${databaseVersion}`); + return JobStatus.FAILED; + } + + this.logger.log(`Database Backup Starting. Database Version: ${databaseMajorVersion}`); + try { await new Promise<void>((resolve, reject) => { - const pgdump = this.processRepository.spawn(`pg_dumpall`, databaseParams, { - env: { - PATH: process.env.PATH, - PGPASSWORD: isUrlConnection ? undefined : config.password, + const pgdump = this.processRepository.spawn( + `/usr/lib/postgresql/${databaseMajorVersion}/bin/pg_dumpall`, + databaseParams, + { + env: { + PATH: process.env.PATH, + PGPASSWORD: isUrlConnection ? undefined : config.password, + }, }, - }); + ); // NOTE: `--rsyncable` is only supported in GNU gzip const gzip = this.processRepository.spawn(`gzip`, ['--rsyncable']); @@ -169,7 +186,7 @@ export class BackupService extends BaseService { return JobStatus.FAILED; } - this.logger.debug(`Database Backup Success`); + this.logger.log(`Database Backup Success`); await this.cleanupDatabaseBackups(); return JobStatus.SUCCESS; } From 2f9019c0e1bd7d305e97d90ede1fa9f241038884 Mon Sep 17 00:00:00 2001 From: Alex <alex.tran1502@gmail.com> Date: Tue, 12 Nov 2024 09:07:56 -0600 Subject: [PATCH 14/36] fix(server): correct rotation for common files (#14092) * fix(server): correct rotation for common files * fix: test: * pr feedback --- server/src/services/media.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/services/media.service.ts b/server/src/services/media.service.ts index c7b3dbced1..0aa6bd03fb 100644 --- a/server/src/services/media.service.ts +++ b/server/src/services/media.service.ts @@ -214,7 +214,7 @@ export class MediaService extends BaseService { const colorspace = this.isSRGB(asset) ? Colorspace.SRGB : image.colorspace; const processInvalidImages = process.env.IMMICH_PROCESS_INVALID_IMAGES === 'true'; - const orientation = Number(asset.exifInfo?.orientation) || undefined; + const orientation = useExtracted && asset.exifInfo?.orientation ? Number(asset.exifInfo.orientation) : undefined; const decodeOptions = { colorspace, processInvalidImages, size: image.preview.size, orientation }; const { data, info } = await this.mediaRepository.decodeImage(inputPath, decodeOptions); From e17bd8efc66f09e9481a9fc2ea1e0e691dfd057f Mon Sep 17 00:00:00 2001 From: Zack Pollard <zackpollard@ymail.com> Date: Tue, 12 Nov 2024 16:57:05 +0000 Subject: [PATCH 15/36] fix(server): backup version checks not handling database versions correctly (#14102) --- server/src/services/backup.service.spec.ts | 13 +++++++------ server/src/services/backup.service.ts | 3 +-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/server/src/services/backup.service.spec.ts b/server/src/services/backup.service.spec.ts index 4152d88cb1..41ba7c2153 100644 --- a/server/src/services/backup.service.spec.ts +++ b/server/src/services/backup.service.spec.ts @@ -149,7 +149,6 @@ describe(BackupService.name, () => { storageMock.unlink.mockResolvedValue(); systemMock.get.mockResolvedValue(systemConfigStub.backupEnabled); storageMock.createWriteStream.mockReturnValue(new PassThrough()); - databaseMock.getPostgresVersion.mockResolvedValue('14.3.2'); }); it('should run a database backup successfully', async () => { const result = await sut.handleBackupDatabase(); @@ -198,11 +197,13 @@ describe(BackupService.name, () => { expect(result).toBe(JobStatus.FAILED); }); it.each` - postgresVersion | expectedVersion - ${'14.6.4'} | ${14} - ${'15.3.3'} | ${15} - ${'16.4.2'} | ${16} - ${'17.15.1'} | ${17} + postgresVersion | expectedVersion + ${'14.10'} | ${14} + ${'14.10.3'} | ${14} + ${'14.10 (Debian 14.10-1.pgdg120+1)'} | ${14} + ${'15.3.3'} | ${15} + ${'16.4.2'} | ${16} + ${'17.15.1'} | ${17} `( `should use pg_dumpall $expectedVersion with postgres version $postgresVersion`, async ({ postgresVersion, expectedVersion }) => { diff --git a/server/src/services/backup.service.ts b/server/src/services/backup.service.ts index 76b8fcd85b..daa7d180f1 100644 --- a/server/src/services/backup.service.ts +++ b/server/src/services/backup.service.ts @@ -105,9 +105,8 @@ export class BackupService extends BaseService { const databaseVersion = await this.databaseRepository.getPostgresVersion(); const databaseSemver = semver.coerce(databaseVersion); const databaseMajorVersion = databaseSemver?.major; - const databaseSupported = semver.satisfies(databaseVersion, '>=14.0.0 <18.0.0'); - if (!databaseMajorVersion || !databaseSupported) { + if (!databaseMajorVersion || !databaseSemver || !semver.satisfies(databaseSemver, '>=14.0.0 <18.0.0')) { this.logger.error(`Database Backup Failure: Unsupported PostgreSQL version: ${databaseVersion}`); return JobStatus.FAILED; } From 31a1e64b58d01f66d8014c7e91c10cfd20e6aab1 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:30:29 +0000 Subject: [PATCH 16/36] chore: version v1.120.2 --- cli/package-lock.json | 6 +++--- cli/package.json | 2 +- docs/static/archived-versions.json | 4 ++++ e2e/package-lock.json | 8 ++++---- e2e/package.json | 2 +- machine-learning/pyproject.toml | 2 +- mobile/android/fastlane/Fastfile | 4 ++-- mobile/ios/fastlane/Fastfile | 2 +- mobile/openapi/README.md | Bin 32074 -> 32074 bytes mobile/pubspec.yaml | 2 +- open-api/immich-openapi-specs.json | 2 +- open-api/typescript-sdk/package-lock.json | 4 ++-- open-api/typescript-sdk/package.json | 2 +- open-api/typescript-sdk/src/fetch-client.ts | 2 +- server/package-lock.json | 4 ++-- server/package.json | 2 +- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 18 files changed, 31 insertions(+), 27 deletions(-) diff --git a/cli/package-lock.json b/cli/package-lock.json index f99c53aa64..3993009171 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -1,12 +1,12 @@ { "name": "@immich/cli", - "version": "2.2.30", + "version": "2.2.31", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@immich/cli", - "version": "2.2.30", + "version": "2.2.31", "license": "GNU Affero General Public License version 3", "dependencies": { "fast-glob": "^3.3.2", @@ -52,7 +52,7 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.120.1", + "version": "1.120.2", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { diff --git a/cli/package.json b/cli/package.json index 75189b279a..4c668d99d8 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@immich/cli", - "version": "2.2.30", + "version": "2.2.31", "description": "Command Line Interface (CLI) for Immich", "type": "module", "exports": "./dist/index.js", diff --git a/docs/static/archived-versions.json b/docs/static/archived-versions.json index 52ce0d57e5..bcd908c151 100644 --- a/docs/static/archived-versions.json +++ b/docs/static/archived-versions.json @@ -1,4 +1,8 @@ [ + { + "label": "v1.120.2", + "url": "https://v1.120.2.archive.immich.app" + }, { "label": "v1.120.1", "url": "https://v1.120.1.archive.immich.app" diff --git a/e2e/package-lock.json b/e2e/package-lock.json index 77fe8ce09d..ba27b69ad8 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -1,12 +1,12 @@ { "name": "immich-e2e", - "version": "1.120.1", + "version": "1.120.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "immich-e2e", - "version": "1.120.1", + "version": "1.120.2", "license": "GNU Affero General Public License version 3", "devDependencies": { "@eslint/eslintrc": "^3.1.0", @@ -45,7 +45,7 @@ }, "../cli": { "name": "@immich/cli", - "version": "2.2.30", + "version": "2.2.31", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { @@ -92,7 +92,7 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.120.1", + "version": "1.120.2", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { diff --git a/e2e/package.json b/e2e/package.json index fdc821bb82..b573d2e730 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -1,6 +1,6 @@ { "name": "immich-e2e", - "version": "1.120.1", + "version": "1.120.2", "description": "", "main": "index.js", "type": "module", diff --git a/machine-learning/pyproject.toml b/machine-learning/pyproject.toml index 0a8c9fbcdb..8029dcd250 100644 --- a/machine-learning/pyproject.toml +++ b/machine-learning/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "machine-learning" -version = "1.120.1" +version = "1.120.2" description = "" authors = ["Hau Tran <alex.tran1502@gmail.com>"] readme = "README.md" diff --git a/mobile/android/fastlane/Fastfile b/mobile/android/fastlane/Fastfile index 6a3df82f07..59deb9a3be 100644 --- a/mobile/android/fastlane/Fastfile +++ b/mobile/android/fastlane/Fastfile @@ -35,8 +35,8 @@ platform :android do task: 'bundle', build_type: 'Release', properties: { - "android.injected.version.code" => 166, - "android.injected.version.name" => "1.120.1", + "android.injected.version.code" => 167, + "android.injected.version.name" => "1.120.2", } ) upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab') diff --git a/mobile/ios/fastlane/Fastfile b/mobile/ios/fastlane/Fastfile index a08ad49208..c4e0f6ca5c 100644 --- a/mobile/ios/fastlane/Fastfile +++ b/mobile/ios/fastlane/Fastfile @@ -19,7 +19,7 @@ platform :ios do desc "iOS Release" lane :release do increment_version_number( - version_number: "1.120.1" + version_number: "1.120.2" ) increment_build_number( build_number: latest_testflight_build_number + 1, diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 47bbc4be3c9256877f3959f615ba81e1bcf0e7af..cebb6817ebb9ce3ce0232d0ef517d340763a21ed 100644 GIT binary patch delta 14 WcmX^0i}BPi#tCy7jW*6(Qv(1xkOyJ_ delta 14 WcmX^0i}BPi#tCy74L8nPQv(1xiw9u< diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index bf75dad455..f20fb7afda 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -2,7 +2,7 @@ name: immich_mobile description: Immich - selfhosted backup media file on mobile phone publish_to: 'none' -version: 1.120.1+166 +version: 1.120.2+167 environment: sdk: '>=3.3.0 <4.0.0' diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 5f907340e9..2d3f2fa6c2 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -7385,7 +7385,7 @@ "info": { "title": "Immich", "description": "Immich API", - "version": "1.120.1", + "version": "1.120.2", "contact": {} }, "tags": [], diff --git a/open-api/typescript-sdk/package-lock.json b/open-api/typescript-sdk/package-lock.json index c1f885d30a..da78d70a77 100644 --- a/open-api/typescript-sdk/package-lock.json +++ b/open-api/typescript-sdk/package-lock.json @@ -1,12 +1,12 @@ { "name": "@immich/sdk", - "version": "1.120.1", + "version": "1.120.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@immich/sdk", - "version": "1.120.1", + "version": "1.120.2", "license": "GNU Affero General Public License version 3", "dependencies": { "@oazapfts/runtime": "^1.0.2" diff --git a/open-api/typescript-sdk/package.json b/open-api/typescript-sdk/package.json index 60a085ae17..5cc9cb3e9a 100644 --- a/open-api/typescript-sdk/package.json +++ b/open-api/typescript-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@immich/sdk", - "version": "1.120.1", + "version": "1.120.2", "description": "Auto-generated TypeScript SDK for the Immich API", "type": "module", "main": "./build/index.js", diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index f47c63a989..c2906ff6e0 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -1,6 +1,6 @@ /** * Immich - * 1.120.1 + * 1.120.2 * DO NOT MODIFY - This file has been generated using oazapfts. * See https://www.npmjs.com/package/oazapfts */ diff --git a/server/package-lock.json b/server/package-lock.json index 4300cb3780..08ad8a066f 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,12 +1,12 @@ { "name": "immich", - "version": "1.120.1", + "version": "1.120.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "immich", - "version": "1.120.1", + "version": "1.120.2", "license": "GNU Affero General Public License version 3", "dependencies": { "@nestjs/bullmq": "^10.0.1", diff --git a/server/package.json b/server/package.json index 35e727ef86..a54212052a 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "immich", - "version": "1.120.1", + "version": "1.120.2", "description": "", "author": "", "private": true, diff --git a/web/package-lock.json b/web/package-lock.json index 8cd702d7bd..63e7c05ca4 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "immich-web", - "version": "1.120.1", + "version": "1.120.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "immich-web", - "version": "1.120.1", + "version": "1.120.2", "license": "GNU Affero General Public License version 3", "dependencies": { "@formatjs/icu-messageformat-parser": "^2.7.8", @@ -74,13 +74,13 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.120.1", + "version": "1.120.2", "license": "GNU Affero General Public License version 3", "dependencies": { "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "typescript": "^5.3.3" } }, diff --git a/web/package.json b/web/package.json index b03379ee01..af5e87c57e 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "immich-web", - "version": "1.120.1", + "version": "1.120.2", "license": "GNU Affero General Public License version 3", "scripts": { "dev": "vite dev --host 0.0.0.0 --port 3000", From a9525de356e3464058d4443c4e8c9376e88928c0 Mon Sep 17 00:00:00 2001 From: Alex <alex.tran1502@gmail.com> Date: Tue, 12 Nov 2024 13:34:33 -0600 Subject: [PATCH 17/36] chore(mobile): post release tasks (#14105) --- mobile/ios/Runner.xcodeproj/project.pbxproj | 6 +++--- mobile/ios/Runner/Info.plist | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj index 6c233a7e29..f01807716e 100644 --- a/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -401,7 +401,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 183; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -543,7 +543,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 183; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -571,7 +571,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 183; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist index 2887a17c73..2617c7f96f 100644 --- a/mobile/ios/Runner/Info.plist +++ b/mobile/ios/Runner/Info.plist @@ -58,11 +58,11 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>1.120.1</string> + <string>1.120.2</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> - <string>183</string> + <string>184</string> <key>FLTEnableImpeller</key> <true/> <key>ITSAppUsesNonExemptEncryption</key> From 93346496fc5751d430abe5f8d1b18437373e1d61 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2024 01:15:30 +0000 Subject: [PATCH 18/36] chore(deps): update redis:6.2-alpine docker digest to 77c6e37 (#14098) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/docker-compose.dev.yml | 2 +- docker/docker-compose.prod.yml | 2 +- e2e/docker-compose.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 26e58f18d7..f729cd61e5 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -103,7 +103,7 @@ services: redis: container_name: immich_redis - image: redis:6.2-alpine@sha256:2ba50e1ac3a0ea17b736ce9db2b0a9f6f8b85d4c27d5f5accc6a416d8f42c6d5 + image: redis:6.2-alpine@sha256:77c6e37734720700cd47d8b7d9e8a9a6f24fc32862833b064c76e830145bebce healthcheck: test: redis-cli ping || exit 1 diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml index 48d4328c85..982bef7d8d 100644 --- a/docker/docker-compose.prod.yml +++ b/docker/docker-compose.prod.yml @@ -47,7 +47,7 @@ services: redis: container_name: immich_redis - image: redis:6.2-alpine@sha256:2ba50e1ac3a0ea17b736ce9db2b0a9f6f8b85d4c27d5f5accc6a416d8f42c6d5 + image: redis:6.2-alpine@sha256:77c6e37734720700cd47d8b7d9e8a9a6f24fc32862833b064c76e830145bebce healthcheck: test: redis-cli ping || exit 1 restart: always diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index f8f41eac46..1ce7d03a31 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -34,7 +34,7 @@ services: - 2285:2285 redis: - image: redis:6.2-alpine@sha256:2ba50e1ac3a0ea17b736ce9db2b0a9f6f8b85d4c27d5f5accc6a416d8f42c6d5 + image: redis:6.2-alpine@sha256:77c6e37734720700cd47d8b7d9e8a9a6f24fc32862833b064c76e830145bebce database: image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 From 8ba2c99b0835085f6a21ea8cb287b4f67c74344c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2024 01:15:45 +0000 Subject: [PATCH 19/36] chore(deps): update docker.io/redis:6.2-alpine docker digest to 77c6e37 (#14097) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 979343364c..d7aca88038 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -48,7 +48,7 @@ services: redis: container_name: immich_redis - image: docker.io/redis:6.2-alpine@sha256:2ba50e1ac3a0ea17b736ce9db2b0a9f6f8b85d4c27d5f5accc6a416d8f42c6d5 + image: docker.io/redis:6.2-alpine@sha256:77c6e37734720700cd47d8b7d9e8a9a6f24fc32862833b064c76e830145bebce healthcheck: test: redis-cli ping || exit 1 restart: always From f2e950d89c8dae9d4624ef7a21bb4a93dcbcfb43 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2024 01:27:37 +0000 Subject: [PATCH 20/36] chore(deps): bump ytanikin/PRConventionalCommits from 1.2.0 to 1.3.0 (#13051) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pr-require-conventional-commit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-require-conventional-commit.yml b/.github/workflows/pr-require-conventional-commit.yml index 4899031249..d4bd44ec43 100644 --- a/.github/workflows/pr-require-conventional-commit.yml +++ b/.github/workflows/pr-require-conventional-commit.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: PR Conventional Commit Validation - uses: ytanikin/PRConventionalCommits@1.2.0 + uses: ytanikin/PRConventionalCommits@1.3.0 with: task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]' add_label: 'false' From 53a7ac386857e21dbf564e9f2f36ff13d9d132d3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 23:30:06 -0500 Subject: [PATCH 21/36] chore(deps): update prom/prometheus docker digest to 2659f4c (#13928) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/docker-compose.prod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml index 982bef7d8d..128000c3aa 100644 --- a/docker/docker-compose.prod.yml +++ b/docker/docker-compose.prod.yml @@ -94,7 +94,7 @@ services: container_name: immich_prometheus ports: - 9090:9090 - image: prom/prometheus@sha256:378f4e03703557d1c6419e6caccf922f96e6d88a530f7431d66a4c4f4b1000fe + image: prom/prometheus@sha256:2659f4c2ebb718e7695cb9b25ffa7d6be64db013daba13e05c875451cf51b0d3 volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus From e1feba2198ebcb09035b3792e791820ee097ba37 Mon Sep 17 00:00:00 2001 From: Mert <101130780+mertalev@users.noreply.github.com> Date: Wed, 13 Nov 2024 01:13:21 -0500 Subject: [PATCH 22/36] refactor(mobile): video controls (#14086) * refactor video controls * inline * make mute icon const * move placeholder to private widget * adjust text width, move volume button slightly right --- mobile/lib/constants/immich_colors.dart | 2 + mobile/lib/utils/immich_app_theme.dart | 8 +- .../asset_viewer/formatted_duration.dart | 34 +++++ .../widgets/asset_viewer/video_controls.dart | 128 +++--------------- .../asset_viewer/video_mute_button.dart | 23 ++++ .../widgets/asset_viewer/video_position.dart | 86 ++++++++++++ 6 files changed, 168 insertions(+), 113 deletions(-) create mode 100644 mobile/lib/widgets/asset_viewer/formatted_duration.dart create mode 100644 mobile/lib/widgets/asset_viewer/video_mute_button.dart create mode 100644 mobile/lib/widgets/asset_viewer/video_position.dart diff --git a/mobile/lib/constants/immich_colors.dart b/mobile/lib/constants/immich_colors.dart index 6f6d1a6a31..37e98a7f70 100644 --- a/mobile/lib/constants/immich_colors.dart +++ b/mobile/lib/constants/immich_colors.dart @@ -19,6 +19,8 @@ const String defaultColorPresetName = "indigo"; const Color immichBrandColorLight = Color(0xFF4150AF); const Color immichBrandColorDark = Color(0xFFACCBFA); +const Color whiteOpacity75 = Color.fromARGB((0.75 * 255) ~/ 1, 255, 255, 255); +const Color blackOpacity40 = Color.fromARGB((0.40 * 255) ~/ 1, 0, 0, 0); final Map<ImmichColorPreset, ImmichTheme> _themePresetsMap = { ImmichColorPreset.indigo: ImmichTheme( diff --git a/mobile/lib/utils/immich_app_theme.dart b/mobile/lib/utils/immich_app_theme.dart index c0cf60514f..42d338956f 100644 --- a/mobile/lib/utils/immich_app_theme.dart +++ b/mobile/lib/utils/immich_app_theme.dart @@ -7,10 +7,10 @@ import 'package:immich_mobile/providers/app_settings.provider.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; class ImmichTheme { - ColorScheme light; - ColorScheme dark; + final ColorScheme light; + final ColorScheme dark; - ImmichTheme({required this.light, required this.dark}); + const ImmichTheme({required this.light, required this.dark}); } ImmichTheme? _immichDynamicTheme; @@ -151,7 +151,7 @@ ThemeData getThemeData({required ColorScheme colorScheme}) { return ThemeData( useMaterial3: true, - brightness: isDark ? Brightness.dark : Brightness.light, + brightness: colorScheme.brightness, colorScheme: colorScheme, primaryColor: primaryColor, hintColor: colorScheme.onSurfaceSecondary, diff --git a/mobile/lib/widgets/asset_viewer/formatted_duration.dart b/mobile/lib/widgets/asset_viewer/formatted_duration.dart new file mode 100644 index 0000000000..bf64a0c002 --- /dev/null +++ b/mobile/lib/widgets/asset_viewer/formatted_duration.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:immich_mobile/constants/immich_colors.dart'; + +@pragma('vm:prefer-inline') +String _formatDuration(Duration position) { + final seconds = position.inSeconds.remainder(60).toString().padLeft(2, "0"); + final minutes = position.inMinutes.remainder(60).toString().padLeft(2, "0"); + if (position.inHours == 0) { + return "$minutes:$seconds"; + } + final hours = position.inHours.toString().padLeft(2, '0'); + return "$hours:$minutes:$seconds"; +} + +class FormattedDuration extends StatelessWidget { + final Duration data; + const FormattedDuration(this.data, {super.key}); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: data.inHours > 0 ? 64 : 43, // use a fixed width to prevent jitter + child: Text( + _formatDuration(data), + style: const TextStyle( + fontSize: 14.0, + color: whiteOpacity75, + fontWeight: FontWeight.normal, + ), + textAlign: TextAlign.center, + ), + ); + } +} diff --git a/mobile/lib/widgets/asset_viewer/video_controls.dart b/mobile/lib/widgets/asset_viewer/video_controls.dart index a5f5f18ce8..c96d58d374 100644 --- a/mobile/lib/widgets/asset_viewer/video_controls.dart +++ b/mobile/lib/widgets/asset_viewer/video_controls.dart @@ -1,125 +1,35 @@ -import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/immich_colors.dart'; import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart'; -import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart'; -import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart'; +import 'package:immich_mobile/widgets/asset_viewer/video_position.dart'; -/// The video controls for the [videPlayerControlsProvider] +/// The video controls for the [videoPlayerControlsProvider] class VideoControls extends ConsumerWidget { const VideoControls({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - final duration = - ref.watch(videoPlaybackValueProvider.select((v) => v.duration)); - final position = - ref.watch(videoPlaybackValueProvider.select((v) => v.position)); - + final isPortrait = + MediaQuery.orientationOf(context) == Orientation.portrait; return AnimatedOpacity( opacity: ref.watch(showControlsProvider) ? 1.0 : 0.0, duration: const Duration(milliseconds: 100), - child: OrientationBuilder( - builder: (context, orientation) => Container( - padding: EdgeInsets.symmetric( - horizontal: orientation == Orientation.portrait ? 12.0 : 64.0, - ), - color: Colors.black.withOpacity(0.4), - child: Padding( - padding: MediaQuery.of(context).orientation == Orientation.portrait - ? const EdgeInsets.symmetric(horizontal: 12.0) - : const EdgeInsets.symmetric(horizontal: 64.0), - child: Row( - children: [ - Text( - _formatDuration(position), - style: TextStyle( - fontSize: 14.0, - color: Colors.white.withOpacity(.75), - fontWeight: FontWeight.normal, - ), - ), - Expanded( - child: Slider( - value: duration == Duration.zero - ? 0.0 - : min( - position.inMicroseconds / - duration.inMicroseconds * - 100, - 100, - ), - min: 0, - max: 100, - thumbColor: Colors.white, - activeColor: Colors.white, - inactiveColor: Colors.white.withOpacity(0.75), - onChanged: (position) { - ref.read(videoPlayerControlsProvider.notifier).position = - position; - }, - ), - ), - Text( - _formatDuration(duration), - style: TextStyle( - fontSize: 14.0, - color: Colors.white.withOpacity(.75), - fontWeight: FontWeight.normal, - ), - ), - IconButton( - icon: Icon( - ref.watch( - videoPlayerControlsProvider.select((value) => value.mute), - ) - ? Icons.volume_off - : Icons.volume_up, - ), - onPressed: () => ref - .read(videoPlayerControlsProvider.notifier) - .toggleMute(), - color: Colors.white, - ), - ], + child: isPortrait + ? const ColoredBox( + color: blackOpacity40, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 24.0), + child: VideoPosition(), + ), + ) + : const ColoredBox( + color: blackOpacity40, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 128.0), + child: VideoPosition(), + ), ), - ), - ), - ), ); } - - String _formatDuration(Duration position) { - final ms = position.inMilliseconds; - - int seconds = ms ~/ 1000; - final int hours = seconds ~/ 3600; - seconds = seconds % 3600; - final minutes = seconds ~/ 60; - seconds = seconds % 60; - - final hoursString = hours >= 10 - ? '$hours' - : hours == 0 - ? '00' - : '0$hours'; - - final minutesString = minutes >= 10 - ? '$minutes' - : minutes == 0 - ? '00' - : '0$minutes'; - - final secondsString = seconds >= 10 - ? '$seconds' - : seconds == 0 - ? '00' - : '0$seconds'; - - final formattedTime = - '${hoursString == '00' ? '' : '$hoursString:'}$minutesString:$secondsString'; - - return formattedTime; - } } diff --git a/mobile/lib/widgets/asset_viewer/video_mute_button.dart b/mobile/lib/widgets/asset_viewer/video_mute_button.dart new file mode 100644 index 0000000000..da0f6f3174 --- /dev/null +++ b/mobile/lib/widgets/asset_viewer/video_mute_button.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart'; + +class VideoMuteButton extends ConsumerWidget { + const VideoMuteButton({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return IconButton( + icon: ref.watch( + videoPlayerControlsProvider.select((value) => value.mute), + ) + ? const Icon(Icons.volume_off) + : const Icon(Icons.volume_up), + onPressed: () => + ref.read(videoPlayerControlsProvider.notifier).toggleMute(), + color: Colors.white, + padding: const EdgeInsets.all(0), + alignment: Alignment.centerRight, + ); + } +} diff --git a/mobile/lib/widgets/asset_viewer/video_position.dart b/mobile/lib/widgets/asset_viewer/video_position.dart new file mode 100644 index 0000000000..0512785782 --- /dev/null +++ b/mobile/lib/widgets/asset_viewer/video_position.dart @@ -0,0 +1,86 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/immich_colors.dart'; +import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart'; +import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart'; +import 'package:immich_mobile/widgets/asset_viewer/formatted_duration.dart'; +import 'package:immich_mobile/widgets/asset_viewer/video_mute_button.dart'; + +class VideoPosition extends HookConsumerWidget { + const VideoPosition({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final (position, duration) = ref.watch( + videoPlaybackValueProvider.select((v) => (v.position, v.duration)), + ); + final wasPlaying = useRef<bool>(true); + return duration == Duration.zero + ? const _VideoPositionPlaceholder() + : Row( + children: [ + FormattedDuration(position), + Expanded( + child: Slider( + value: min( + position.inMicroseconds / duration.inMicroseconds * 100, + 100, + ), + min: 0, + max: 100, + thumbColor: Colors.white, + activeColor: Colors.white, + inactiveColor: whiteOpacity75, + onChangeStart: (value) { + final state = ref.read(videoPlaybackValueProvider).state; + wasPlaying.value = state != VideoPlaybackState.paused; + ref.read(videoPlayerControlsProvider.notifier).pause(); + }, + onChangeEnd: (value) { + if (wasPlaying.value) { + ref.read(videoPlayerControlsProvider.notifier).play(); + } + }, + onChanged: (position) { + ref.read(videoPlayerControlsProvider.notifier).position = + position; + }, + ), + ), + FormattedDuration(duration), + const VideoMuteButton(), + ], + ); + } +} + +class _VideoPositionPlaceholder extends StatelessWidget { + const _VideoPositionPlaceholder(); + + static void _onChangedDummy(_) {} + + @override + Widget build(BuildContext context) { + return const Row( + children: [ + FormattedDuration(Duration.zero), + Expanded( + child: Slider( + value: 0.0, + min: 0, + max: 100, + thumbColor: Colors.white, + activeColor: Colors.white, + inactiveColor: whiteOpacity75, + onChanged: _onChangedDummy, + ), + ), + FormattedDuration(Duration.zero), + VideoMuteButton(), + ], + ); + } +} From ecb8349085bc7e99b3b40e78481488d35c097926 Mon Sep 17 00:00:00 2001 From: Xuesong <amorphobia@users.noreply.github.com> Date: Wed, 13 Nov 2024 18:05:53 +0800 Subject: [PATCH 23/36] chore(docs): encode db dump in UTF-8 without BOM for Windows (#13775) --- docs/docs/administration/backup-and-restore.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/administration/backup-and-restore.md b/docs/docs/administration/backup-and-restore.md index 8e09d6339c..9ae4e3e51f 100644 --- a/docs/docs/administration/backup-and-restore.md +++ b/docs/docs/administration/backup-and-restore.md @@ -58,7 +58,7 @@ docker compose up -d # Start remainder of Immich apps <TabItem value="Windows system (PowerShell)" label="Windows system (PowerShell)"> ```powershell title='Backup' -docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres | Set-Content -Encoding utf8 "C:\path\to\backup\dump.sql" +[System.IO.File]::WriteAllLines("C:\absolute\path\to\backup\dump.sql", (docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres)) ``` ```powershell title='Restore' From b0bb11f9e0d9b112d4ef7fbe32bed3db75a65a3c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2024 07:12:06 -0500 Subject: [PATCH 24/36] chore(deps): update docker.io/redis:6.2-alpine docker digest to eaba718 (#14113) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index d7aca88038..86ec637cbb 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -48,7 +48,7 @@ services: redis: container_name: immich_redis - image: docker.io/redis:6.2-alpine@sha256:77c6e37734720700cd47d8b7d9e8a9a6f24fc32862833b064c76e830145bebce + image: docker.io/redis:6.2-alpine@sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8 healthcheck: test: redis-cli ping || exit 1 restart: always From 4ca27a3e7f12e094f209e68652ec210141a5a1a8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2024 07:12:30 -0500 Subject: [PATCH 25/36] chore(deps): update redis:6.2-alpine docker digest to eaba718 (#14114) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker/docker-compose.dev.yml | 2 +- docker/docker-compose.prod.yml | 2 +- e2e/docker-compose.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index f729cd61e5..1487f8adbe 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -103,7 +103,7 @@ services: redis: container_name: immich_redis - image: redis:6.2-alpine@sha256:77c6e37734720700cd47d8b7d9e8a9a6f24fc32862833b064c76e830145bebce + image: redis:6.2-alpine@sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8 healthcheck: test: redis-cli ping || exit 1 diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml index 128000c3aa..fa7d110f94 100644 --- a/docker/docker-compose.prod.yml +++ b/docker/docker-compose.prod.yml @@ -47,7 +47,7 @@ services: redis: container_name: immich_redis - image: redis:6.2-alpine@sha256:77c6e37734720700cd47d8b7d9e8a9a6f24fc32862833b064c76e830145bebce + image: redis:6.2-alpine@sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8 healthcheck: test: redis-cli ping || exit 1 restart: always diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index 1ce7d03a31..d9117b1b4a 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -34,7 +34,7 @@ services: - 2285:2285 redis: - image: redis:6.2-alpine@sha256:77c6e37734720700cd47d8b7d9e8a9a6f24fc32862833b064c76e830145bebce + image: redis:6.2-alpine@sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8 database: image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 From 3dad19883d2ba8cf04e6d2b443a49b8aafc821e7 Mon Sep 17 00:00:00 2001 From: Alex <alex.tran1502@gmail.com> Date: Wed, 13 Nov 2024 09:39:21 -0600 Subject: [PATCH 26/36] fix(mobile): duration ui overflow (#14120) * fix(mobile): duration ui overflow * pr feedback --- mobile/lib/widgets/asset_viewer/formatted_duration.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/lib/widgets/asset_viewer/formatted_duration.dart b/mobile/lib/widgets/asset_viewer/formatted_duration.dart index bf64a0c002..4a334cd7cc 100644 --- a/mobile/lib/widgets/asset_viewer/formatted_duration.dart +++ b/mobile/lib/widgets/asset_viewer/formatted_duration.dart @@ -19,7 +19,7 @@ class FormattedDuration extends StatelessWidget { @override Widget build(BuildContext context) { return SizedBox( - width: data.inHours > 0 ? 64 : 43, // use a fixed width to prevent jitter + width: data.inHours > 0 ? 70 : 60, // use a fixed width to prevent jitter child: Text( _formatDuration(data), style: const TextStyle( From 333ca8827e45a6f06e69d3d21309c6b4a9c01145 Mon Sep 17 00:00:00 2001 From: Pablo Molina <gitju@pablomolina.me> Date: Wed, 13 Nov 2024 18:17:14 +0100 Subject: [PATCH 27/36] feat: use dateTimeOriginal to calculate album date (#14119) --- server/src/dtos/album.dto.ts | 5 +++-- server/src/utils/date-time.ts | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 server/src/utils/date-time.ts diff --git a/server/src/dtos/album.dto.ts b/server/src/dtos/album.dto.ts index b12847ee62..76f4fdfc98 100644 --- a/server/src/dtos/album.dto.ts +++ b/server/src/dtos/album.dto.ts @@ -7,6 +7,7 @@ import { AuthDto } from 'src/dtos/auth.dto'; import { UserResponseDto, mapUser } from 'src/dtos/user.dto'; import { AlbumEntity } from 'src/entities/album.entity'; import { AlbumUserRole, AssetOrder } from 'src/enum'; +import { getAssetDateTime } from 'src/utils/date-time'; import { Optional, ValidateBoolean, ValidateUUID } from 'src/validation'; export class AlbumInfoDto { @@ -164,8 +165,8 @@ export const mapAlbum = (entity: AlbumEntity, withAssets: boolean, auth?: AuthDt const hasSharedLink = entity.sharedLinks?.length > 0; const hasSharedUser = sharedUsers.length > 0; - let startDate = assets.at(0)?.fileCreatedAt || undefined; - let endDate = assets.at(-1)?.fileCreatedAt || undefined; + let startDate = getAssetDateTime(assets.at(0)); + let endDate = getAssetDateTime(assets.at(-1)); // Swap dates if start date is greater than end date. if (startDate && endDate && startDate > endDate) { [startDate, endDate] = [endDate, startDate]; diff --git a/server/src/utils/date-time.ts b/server/src/utils/date-time.ts new file mode 100644 index 0000000000..e1578cbb19 --- /dev/null +++ b/server/src/utils/date-time.ts @@ -0,0 +1,5 @@ +import { AssetEntity } from 'src/entities/asset.entity'; + +export const getAssetDateTime = (asset: AssetEntity | undefined) => { + return asset?.exifInfo?.dateTimeOriginal || asset?.fileCreatedAt; +}; From c58bd307cee77c9724a8011c363d79ebcef679c6 Mon Sep 17 00:00:00 2001 From: Nicholas Flamy <30300649+NicholasFlamy@users.noreply.github.com> Date: Wed, 13 Nov 2024 12:26:23 -0500 Subject: [PATCH 28/36] docs: Update TrueNAS docs for TrueNAS SCALE 24.10 (#14067) * initial-docs-update * add-info-about-external-libraries --- docs/docs/install/img/truenas01.png | Bin 8902 -> 9593 bytes docs/docs/install/img/truenas02.png | Bin 87664 -> 130088 bytes docs/docs/install/img/truenas03.png | Bin 20023 -> 35640 bytes docs/docs/install/img/truenas04.png | Bin 80737 -> 131115 bytes docs/docs/install/img/truenas05.png | Bin 6147 -> 23257 bytes docs/docs/install/img/truenas06.png | Bin 4120 -> 5619 bytes docs/docs/install/img/truenas07.png | Bin 19859 -> 64687 bytes docs/docs/install/img/truenas08.png | Bin 6379 -> 24348 bytes docs/docs/install/img/truenas09.png | Bin 10168 -> 12613 bytes docs/docs/install/img/truenas10.png | Bin 0 -> 16632 bytes docs/docs/install/img/truenas11.png | Bin 0 -> 5063 bytes docs/docs/install/img/truenas12.png | Bin 0 -> 19649 bytes docs/docs/install/truenas.md | 271 +++++++++++++++++----------- 13 files changed, 164 insertions(+), 107 deletions(-) create mode 100644 docs/docs/install/img/truenas10.png create mode 100644 docs/docs/install/img/truenas11.png create mode 100644 docs/docs/install/img/truenas12.png diff --git a/docs/docs/install/img/truenas01.png b/docs/docs/install/img/truenas01.png index 81b0430a75ac2d36e36468749efc1104eb297497..e648ab3734e9d9dd609670be95278bfd3e72f4ea 100644 GIT binary patch literal 9593 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 literal 8902 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 BwlM$z diff --git a/docs/docs/install/img/truenas02.png b/docs/docs/install/img/truenas02.png index ae7d41e62425feb52e6a5ec91db1fa4eeb03bb59..66f0dec7fa49c8f27b84718b8fd662e90d567eef 100644 GIT binary patch literal 130088 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≈gH{Gz)dJdofcNs{1Wp*)|Q2|B97(fRdK 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 literal 87664 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 diff --git a/docs/docs/install/img/truenas03.png b/docs/docs/install/img/truenas03.png index 90ff25b7ac9164bf65d1696b144bc08f35327f18..d9970f5aebe90fc7e8d49eb70908a520e519e69a 100644 GIT binary patch literal 35640 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 L_yY0V%?JMvybLb5 literal 20023 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 X&Rp?piGQB}qm9AS)z4*}Q$iB}T{ABD diff --git a/docs/docs/install/img/truenas04.png b/docs/docs/install/img/truenas04.png index 281d02350a8cd514ad96d1dae8e9f814d27417e3..45fa87e5e5e72c8268a1c3ed02d7ef20f6d33d24 100644 GIT binary patch literal 131115 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”_W8S) z%|xB;4g{h#E#CT~Bs;ZS?*@cwmpzd^HTvrxt};8l+;x$#H<#=Z%aFp(0DsnO{YL8- zv<)otRn=<SqkA!XQG2P&9Lx8XMYl&!tQe?+(a~Wxn0q!qCQvC(e)1Riqz$*g-iEo> z8lX7cEGu#GN)A>QhUGdh$9>yh6<UQMg^?=@MB$(4pJm|Ar|(4sJ8?dFvaDs3zPQ|Y zVzoE}#--1!Qr?&;KEajhgtszBqNHXKujU}&#k{~@GzT)Bv(0((6f0mj*@j<{qagsA z3$v%k5uE%D_ip#d-Z~3}8&3EdIU6%gy;<hP5pX3vIesbgkvTM4(v^-NeCC@3$A>Q? zqW9ZK;T;~i-VF1pZv732z@Cel$Uq&lTeWd#KlaUwkc`uXJ42Vj<A(wv1o|2AsDpWH zY403O-L$_JgV8zi<E^RADZ<2v*R2T#?fnO#S6Np%)8u@IIbRoRF65VWUfq0gw}i>( z@@meeVN&8$MX|3Y>rxu=ea0)E(&rw!etGNzWm6-5=hfzlvX{e(L9*a1{|OIe9clE^ z>Ab=X<G~6wD}5?9;2myhHsKwo2#Fi?G|Pg>Y9p^&@?7M?wNv7RV%5FsARVFv(}~Q2 zZ)=`aigSH0+92fa@pRM4RFmWWJ%0DjbiG-C7Yu_t;lqakA@95n2k)REm&$-9BP@!+ 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 literal 80737 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 CB=q|L diff --git a/docs/docs/install/img/truenas05.png b/docs/docs/install/img/truenas05.png index 919b008030736d6801ad66134c5e23f3ccd97a39..0f9d6a835aeb10a21f93179285e61474af388581 100644 GIT binary patch literal 23257 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 VQdwvy8|tVPPCB|cu<gFP@?S5mw7viU literal 6147 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 P50RIJ$rL<&^T&Sy?)N30 diff --git a/docs/docs/install/img/truenas06.png b/docs/docs/install/img/truenas06.png index 26cf06738a634e0d112154d56b93bc14d1f11714..3daf250e36706b54ef722c8031aaadc493a79565 100644 GIT binary patch literal 5619 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 literal 4120 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 R|3}NOb4yR-_1`v6{tJ2u@C^U} diff --git a/docs/docs/install/img/truenas07.png b/docs/docs/install/img/truenas07.png index 17943e5c8155e2e2b8458e7022d331cc28f3f636..946c1401ac7ddd657cfbf224532b1a64d2f749f2 100644 GIT binary patch literal 64687 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𝔯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 literal 19859 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 diff --git a/docs/docs/install/img/truenas08.png b/docs/docs/install/img/truenas08.png index 4c5a90be6befb0684f27535a6b43b06b8bb23e3f..4ace8b49ca0b9cf896ab7382dd7388d08ff56ec8 100644 GIT binary patch literal 24348 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 Qw8svZA2KU8{r>#l0D(#KZ~y=R literal 6379 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 diff --git a/docs/docs/install/img/truenas09.png b/docs/docs/install/img/truenas09.png index 647c7295b420c720f818b5534b527403b54a44b2..41830fe9e6046ca85238db3da5b318aee3100615 100644 GIT binary patch literal 12613 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 GH~$O15l9#S literal 10168 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 Kv+TzGC;tnMz3mGC diff --git a/docs/docs/install/img/truenas10.png b/docs/docs/install/img/truenas10.png new file mode 100644 index 0000000000000000000000000000000000000000..730685c309f9906129a32996a9495f888f9038c4 GIT binary patch literal 16632 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 F{u?c%y_^65 literal 0 HcmV?d00001 diff --git a/docs/docs/install/img/truenas11.png b/docs/docs/install/img/truenas11.png new file mode 100644 index 0000000000000000000000000000000000000000..88c166aed38103d099337f8334c160d5eae8b306 GIT binary patch literal 5063 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 literal 0 HcmV?d00001 diff --git a/docs/docs/install/img/truenas12.png b/docs/docs/install/img/truenas12.png new file mode 100644 index 0000000000000000000000000000000000000000..a107a85f24c76db83a1bc6bde1593acdac13e640 GIT binary patch literal 19649 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 literal 0 HcmV?d00001 diff --git a/docs/docs/install/truenas.md b/docs/docs/install/truenas.md index ffb559ed12..f35e9aa37a 100644 --- a/docs/docs/install/truenas.md +++ b/docs/docs/install/truenas.md @@ -7,7 +7,9 @@ sidebar_position: 80 :::note This is a community contribution and not officially supported by the Immich team, but included here for convenience. -**Please report issues to the corresponding [Github Repository](https://github.com/truenas/charts/tree/master/community/immich).** +Community support can be found in the dedicated channel on the [Discord Server](https://discord.immich.app/). + +**Please report app issues to the corresponding [Github Repository](https://github.com/truenas/charts/tree/master/community/immich).** ::: Immich can easily be installed on TrueNAS SCALE via the **Community** train application. @@ -20,18 +22,26 @@ TrueNAS SCALE makes installing and updating Immich easy, but you must use the Im The Immich app in TrueNAS SCALE installs, completes the initial configuration, then starts the Immich web portal. When updates become available, SCALE alerts and provides easy updates. -Before installing the Immich app in SCALE, review the [Environment Variables](/docs/install/environment-variables.md) documentation to see if you want to configure any during installation. -You can configure environment variables at any time after deploying the application. +Before installing the Immich app in SCALE, review the [Environment Variables](#environment-variables) documentation to see if you want to configure any during installation. +You may also configure environment variables at any time after deploying the application. -You can allow SCALE to create the datasets Immich requires automatically during app installation. -Or before beginning app installation, [create the datasets](https://www.truenas.com/docs/scale/scaletutorials/storage/datasets/datasetsscale/) to use in the **Storage Configuration** section during installation. -Immich requires seven datasets: **library**, **pgBackup**, **pgData**, **profile**, **thumbs**, **uploads**, and **video**. -You can organize these as one parent with seven child datasets, for example `mnt/tank/immich/library`, `mnt/tank/immich/pgBackup`, and so on. +### Setting up Storage Datasets + +Before beginning app installation, [create the datasets](https://www.truenas.com/docs/scale/scaletutorials/storage/datasets/datasetsscale/) to use in the **Storage Configuration** section during installation. +Immich requires seven datasets: `library`, `upload`, `thumbs`, `profile`, `video`, `backups`, and `pgData`. +You can organize these as one parent with seven child datasets, for example `/mnt/tank/immich/library`, `/mnt/tank/immich/upload`, and so on. + +<img +src={require('./img/truenas12.png').default} +width="30%" +alt="Immich App Widget" +className="border rounded-xl" +/> :::info Permissions The **pgData** dataset must be owned by the user `netdata` (UID 999) for postgres to start. The other datasets must be owned by the user `root` (UID 0) or a group that includes the user `root` (UID 0) for immich to have the necessary permissions. -The **library** dataset must have [ACL mode](https://www.truenas.com/docs/core/coretutorials/storage/pools/permissions/#access-control-lists) set to `Passthrough` if you plan on using a [storage template](/docs/administration/storage-template.mdx) and the dataset is configured for network sharing (its ACL type is set to `SMB/NFSv4`). When the template is applied and files need to be moved from **uploads** to **library**, immich performs `chmod` internally and needs to be allowed to execute the command. +If the **library** dataset uses ACL it must have [ACL mode](https://www.truenas.com/docs/core/coretutorials/storage/pools/permissions/#access-control-lists) set to `Passthrough` if you plan on using a [storage template](/docs/administration/storage-template.mdx) and the dataset is configured for network sharing (its ACL type is set to `SMB/NFSv4`). When the template is applied and files need to be moved from **upload** to **library**, immich performs `chmod` internally and needs to be allowed to execute the command. [More info.](https://github.com/immich-app/immich/pull/13017) ::: ## Installing the Immich Application @@ -47,6 +57,8 @@ className="border rounded-xl" Click on the widget to open the **Immich** application details screen. +<br/><br/> + <img src={require('./img/truenas02.png').default} width="100%" @@ -56,9 +68,13 @@ className="border rounded-xl" Click **Install** to open the Immich application configuration screen. +<br/><br/> + Application configuration settings are presented in several sections, each explained below. To find specific fields click in the **Search Input Fields** search field, scroll down to a particular section or click on the section heading on the navigation area in the upper-right corner. +### Application Name and Version + <img src={require('./img/truenas03.png').default} width="100%" @@ -66,21 +82,123 @@ alt="Install Immich Screen" className="border rounded-xl" /> -Accept the default values in **Application Name** and **Version**. +Accept the default value or enter a name in **Application Name** field. +In most cases use the default name, but if adding a second deployment of the application you must change this name. + +Accept the default version number in **Version**. +When a new version becomes available, the application has an update badge. +The **Installed Applications** screen shows the option to update applications. + +### Immich Configuration + +<img +src={require('./img/truenas05.png').default} +width="40%" +alt="Configuration Settings" +className="border rounded-xl" +/> Accept the default value in **Timezone** or change to match your local timezone. **Timezone** is only used by the Immich `exiftool` microservice if it cannot be determined from the image metadata. -Accept the default port in **Web Port**. +Untick **Enable Machine Learning** if you will not use face recognition, image search, and smart duplicate detection. + +Accept the default option or select the **Machine Learning Image Type** for your hardware based on the [Hardware-Accelerated Machine Learning Supported Backends](/docs/features/ml-hardware-acceleration.md#supported-backends). + +Immich's default is `postgres` but you should consider setting the **Database Password** to a custom value using only the characters `A-Za-z0-9`. + +The **Redis Password** should be set to a custom value using only the characters `A-Za-z0-9`. + +Accept the **Log Level** default of **Log**. + +Leave **Hugging Face Endpoint** blank. (This is for downloading ML models from a different source.) + +Leave **Additional Environment Variables** blank or see [Environment Variables](#environment-variables) to set before installing. + +### Network Configuration + +<img +src={require('./img/truenas06.png').default} +width="40%" +alt="Networking Settings" +className="border rounded-xl" +/> + +Accept the default port `30041` in **WebUI Port** or enter a custom port number. +:::info Allowed Port Numbers +Only numbers within the range 9000-65535 may be used on SCALE versions below TrueNAS Scale 24.10 Electric Eel. + +Regardless of version, to avoid port conflicts, don't use [ports on this list](https://www.truenas.com/docs/references/defaultports/). +::: + +### Storage Configuration Immich requires seven storage datasets. -You can allow SCALE to create them for you, or use the dataset(s) created in [First Steps](#first-steps). -Select the storage options you want to use for **Immich Uploads Storage**, **Immich Library Storage**, **Immich Thumbs Storage**, **Immich Profile Storage**, **Immich Video Storage**, **Immich Postgres Data Storage**, **Immich Postgres Backup Storage**. -Select **ixVolume (dataset created automatically by the system)** in **Type** to let SCALE create the dataset or select **Host Path** to use the existing datasets created on the system. -Accept the defaults in Resources or change the CPU and memory limits to suit your use case. +<img +src={require('./img/truenas07.png').default} +width="20%" +alt="Configure Storage ixVolumes" +className="border rounded-xl" +/> -Click **Install**. +:::note Default Setting (Not recommended) +The default setting for datasets is **ixVolume (dataset created automatically by the system)** but this results in your data being harder to access manually and can result in data loss if you delete the immich app. (Not recommended) +::: + +For each Storage option select **Host Path (Path that already exists on the system)** and then select the matching dataset [created before installing the app](#setting-up-storage-datasets): **Immich Library Storage**: `library`, **Immich Uploads Storage**: `upload`, **Immich Thumbs Storage**: `thumbs`, **Immich Profile Storage**: `profile`, **Immich Video Storage**: `video`, **Immich Backups Storage**: `backups`, **Postgres Data Storage**: `pgData`. + +<img +src={require('./img/truenas08.png').default} +width="40%" +alt="Configure Storage Host Paths" +className="border rounded-xl" +/> +The image above has example values. + +<br/> + +### Additional Storage [(External Libraries)](/docs/features/libraries) + +<img +src={require('./img/truenas10.png').default} +width="40%" +alt="Configure Storage Host Paths" +className="border rounded-xl" +/> + +You may configure [External Libraries](/docs/features/libraries) by mounting them using **Additional Storage**. +The **Mount Path** is the loaction you will need to copy and paste into the External Library settings within Immich. +The **Host Path** is the location on the TrueNAS SCALE server where your external library is located. + +<!-- A section for Labels would go here but I don't know what they do. --> + +### Resources Configuration + +<img +src={require('./img/truenas09.png').default} +width="40%" +alt="Resource Limits" +className="border rounded-xl" +/> + +Accept the default **CPU** limit of `2` threads or specify the number of threads (CPUs with Multi-/Hyper-threading have 2 threads per core). + +Accept the default **Memory** limit of `4096` MB or specify the number of MB of RAM. If you're using Machine Learning you should probably set this above 8000 MB. + +:::info Older SCALE Versions +Before TrueNAS SCALE version 24.10 Electric Eel: + +The **CPU** value was specified in a different format with a default of `4000m` which is 4 threads. + +The **Memory** value was specified in a different format with a default of `8Gi` which is 8 GiB of RAM. The value was specified in bytes or a number with a measurement suffix. Examples: `129M`, `123Mi`, `1000000000` +::: + +Enable **GPU Configuration** options if you have a GPU that you will use for [Hardware Transcoding](/docs/features/hardware-transcoding) and/or [Hardware-Accelerated Machine Learning](/docs/features/ml-hardware-acceleration.md). More info: [GPU Passtrough Docs for TrueNAS Apps](https://www.truenas.com/docs/truenasapps/#gpu-passthrough) + +### Install + +Finally, click **Install**. The system opens the **Installed Applications** screen with the Immich app in the **Deploying** state. When the installation completes it changes to **Running**. @@ -97,102 +215,41 @@ Click **Web Portal** on the **Application Info** widget to open the Immich web i For more information on how to use the application once installed, please refer to the [Post Install](/docs/install/post-install.mdx) guide. ::: -## Editing Environment Variables +## Edit App Settings -Go to the **Installed Applications** screen and select Immich from the list of installed applications. -Click **Edit** on the **Application Info** widget to open the **Edit Immich** screen. -The settings on the edit screen are the same as on the install screen. -You cannot edit **Storage Configuration** paths after the initial app install. +- Go to the **Installed Applications** screen and select Immich from the list of installed applications. +- Click **Edit** on the **Application Info** widget to open the **Edit Immich** screen. +- Change any settings you would like to change. + - The settings on the edit screen are the same as on the install screen. +- Click **Update** at the very bottom of the page to save changes. + - TrueNAS automatically updates, recreates, and redeploys the Immich container with the updated settings. -Click **Update** to save changes. -TrueNAS automatically updates, recreates, and redeploys the Immich container with the updated environment variables. +## Environment Variables + +You can set [Environment Variables](/docs/install/environment-variables) by clicking **Add** on the **Additional Environment Variables** option and filling in the **Name** and **Value**. + +<img +src={require('./img/truenas11.png').default} +width="40%" +alt="Environment Variables" +className="border rounded-xl" +/> + +:::info +Some Environment Variables are not available for the TrueNAS SCALE app. This is mainly because they can be configured through GUI options in the [Edit Immich screen](#edit-app-settings). + +Some examples are: `IMMICH_VERSION`, `UPLOAD_LOCATION`, `DB_DATA_LOCATION`, `TZ`, `IMMICH_LOG_LEVEL`, `DB_PASSWORD`, `REDIS_PASSWORD`. +::: ## Updating the App When updates become available, SCALE alerts and provides easy updates. -To update the app to the latest version, click **Update** on the **Application Info** widget from the **Installed Applications** screen. +To update the app to the latest version: -Update opens an update window for the application that includes two selectable options, Images (to be updated) and Changelog. Click on the down arrow to see the options available for each. - -Click **Upgrade** to begin the process and open a counter dialog that shows the upgrade progress. When complete, the update badge and buttons disappear and the application Update state on the Installed screen changes from Update Available to Up to date. - -## Understanding Immich Settings in TrueNAS SCALE - -Accept the default value or enter a name in **Application Name** field. -In most cases use the default name, but if adding a second deployment of the application you must change this name. - -Accept the default version number in **Version**. -When a new version becomes available, the application has an update badge. -The **Installed Applications** screen shows the option to update applications. - -### Immich Configuration Settings - -You can accept the defaults in the **Immich Configuration** settings, or enter the settings you want to use. - -<img -src={require('./img/truenas05.png').default} -width="100%" -alt="Configuration Settings" -className="border rounded-xl" -/> - -Accept the default setting in **Timezone** or change to match your local timezone. -**Timezone** is only used by the Immich `exiftool` microservice if it cannot be determined from the image metadata. - -You can enter a **Public Login Message** to display on the login page, or leave it blank. - -### Networking Settings - -Accept the default port numbers in **Web Port**. -The SCALE Immich app listens on port **30041**. - -Refer to the TrueNAS [default port list](https://www.truenas.com/docs/references/defaultports/) for a list of assigned port numbers. -To change the port numbers, enter a number within the range 9000-65535. - -<img -src={require('./img/truenas06.png').default} -width="100%" -alt="Networking Settings" -className="border rounded-xl" -/> - -### Storage Settings - -You can install Immich using the default setting **ixVolume (dataset created automatically by the system)** or use the host path option with datasets [created before installing the app](#first-steps). - -<img -src={require('./img/truenas07.png').default} -width="100%" -alt="Configure Storage ixVolumes" -className="border rounded-xl" -/> - -Select **Host Path (Path that already exists on the system)** to browse to and select the datasets. - -<img -src={require('./img/truenas08.png').default} -width="100%" -alt="Configure Storage Host Paths" -className="border rounded-xl" -/> - -### Resource Configuration Settings - -Accept the default values in **Resources Configuration** or enter new CPU and memory values -By default, this application is limited to use no more than 4 CPU cores and 8 Gigabytes available memory. The application might use considerably less system resources. - -<img -src={require('./img/truenas09.png').default} -width="100%" -alt="Resource Limits" -className="border rounded-xl" -/> - -To customize the CPU and memory allocated to the container Immich uses, enter new CPU values as a plain integer value followed by the suffix m (milli). -Default is 4000m. - -Accept the default value 8Gi allocated memory or enter a new limit in bytes. -Enter a plain integer followed by the measurement suffix, for example 129M or 123Mi. - -Systems with compatible GPU(s) display devices in **GPU Configuration**. -See [Managing GPUs](https://www.truenas.com/docs/scale/scaletutorials/systemsettings/advanced/managegpuscale/) for more information about allocating isolated GPU devices in TrueNAS SCALE. +- Go to the **Installed Applications** screen and select Immich from the list of installed applications. +- Click **Update** on the **Application Info** widget from the **Installed Applications** screen. +- This opens an update window with some options + - You may select an Image update too. + - You may view the Changelog. +- Click **Upgrade** to begin the process and open a counter dialog that shows the upgrade progress. + - When complete, the update badge and buttons disappear and the application Update state on the Installed screen changes from Update Available to Up to date. From de993289ad9bbc21ae538b3e0f88f1ea6ae946cd Mon Sep 17 00:00:00 2001 From: John Stef <john@johnstef.com> Date: Wed, 13 Nov 2024 19:27:49 +0200 Subject: [PATCH 29/36] fix(mobile): fix logout timeout (#14104) * fix(mobile): add timeout to logout * chore(mobile): refactor timeout durations * feat(mobile): add loading state to logout button * chore(mobile): format authentication.provider.dart * chore: format * chore: revert settings.json change --------- Co-authored-by: Alex <alex.tran1502@gmail.com> --- .vscode/settings.json | 2 +- .../providers/authentication.provider.dart | 15 ++++++----- .../common/app_bar_dialog/app_bar_dialog.dart | 27 ++++++++++++++++--- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a8661326a0..49dbf3944c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -41,4 +41,4 @@ "explorer.fileNesting.patterns": { "*.ts": "${capture}.spec.ts,${capture}.mock.ts" } -} +} \ No newline at end of file diff --git a/mobile/lib/providers/authentication.provider.dart b/mobile/lib/providers/authentication.provider.dart index 1fe7db5d46..60e31d707e 100644 --- a/mobile/lib/providers/authentication.provider.dart +++ b/mobile/lib/providers/authentication.provider.dart @@ -41,6 +41,8 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> { _ref; final _log = Logger("AuthenticationNotifier"); + static const Duration _timeoutDuration = Duration(seconds: 7); + Future<bool> login( String email, String password, @@ -102,12 +104,15 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> { await _apiService.authenticationApi .logout() + .timeout(_timeoutDuration) .then((_) => log.info("Logout was successful for $userEmail")) .onError( (error, stackTrace) => log.severe("Logout failed for $userEmail", error, stackTrace), ); - + } catch (e, stack) { + log.severe('Logout failed', e, stack); + } finally { await Future.wait([ clearAssetsAndAlbums(_db), Store.delete(StoreKey.currentUser), @@ -125,8 +130,6 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> { shouldChangePassword: false, isAuthenticated: false, ); - } catch (e, stack) { - log.severe('Logout failed', e, stack); } } @@ -168,10 +171,8 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> { UserPreferencesResponseDto? userPreferences; try { final responses = await Future.wait([ - _apiService.usersApi.getMyUser().timeout(const Duration(seconds: 7)), - _apiService.usersApi - .getMyPreferences() - .timeout(const Duration(seconds: 7)), + _apiService.usersApi.getMyUser().timeout(_timeoutDuration), + _apiService.usersApi.getMyPreferences().timeout(_timeoutDuration), ]); userResponse = responses[0] as UserAdminResponseDto; userPreferences = responses[1] as UserPreferencesResponseDto; diff --git a/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart b/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart index cd694336bc..38d161f852 100644 --- a/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart +++ b/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart @@ -28,6 +28,7 @@ class ImmichAppBarDialog extends HookConsumerWidget { bool isHorizontal = !context.isMobile; final horizontalPadding = isHorizontal ? 100.0 : 20.0; final user = ref.watch(currentUserProvider); + final isLoggingOut = useState(false); useEffect( () { @@ -63,11 +64,16 @@ class ImmichAppBarDialog extends HookConsumerWidget { ); } - buildActionButton(IconData icon, String text, Function() onTap) { + buildActionButton( + IconData icon, + String text, + Function() onTap, { + Widget? trailing, + }) { return ListTile( dense: true, visualDensity: VisualDensity.standard, - contentPadding: const EdgeInsets.only(left: 30), + contentPadding: const EdgeInsets.only(left: 30, right: 30), minLeadingWidth: 40, leading: SizedBox( child: Icon( @@ -83,6 +89,7 @@ class ImmichAppBarDialog extends HookConsumerWidget { ), ).tr(), onTap: onTap, + trailing: trailing, ); } @@ -107,6 +114,10 @@ class ImmichAppBarDialog extends HookConsumerWidget { Icons.logout_rounded, "profile_drawer_sign_out", () async { + if (isLoggingOut.value) { + return; + } + showDialog( context: context, builder: (BuildContext ctx) { @@ -115,7 +126,11 @@ class ImmichAppBarDialog extends HookConsumerWidget { content: "app_bar_signout_dialog_content", ok: "app_bar_signout_dialog_ok", onOk: () async { - await ref.read(authenticationProvider.notifier).logout(); + isLoggingOut.value = true; + await ref + .read(authenticationProvider.notifier) + .logout() + .whenComplete(() => isLoggingOut.value = false); ref.read(manualUploadProvider.notifier).cancelBackup(); ref.read(backupProvider.notifier).cancelBackup(); @@ -127,6 +142,12 @@ class ImmichAppBarDialog extends HookConsumerWidget { }, ); }, + trailing: isLoggingOut.value + ? SizedBox.square( + dimension: 20, + child: const CircularProgressIndicator(strokeWidth: 2), + ) + : null, ); } From 5a2af558fb26706f27d58d2dedc316f320efef4d Mon Sep 17 00:00:00 2001 From: mcarbonne <46689813+mcarbonne@users.noreply.github.com> Date: Wed, 13 Nov 2024 18:28:07 +0100 Subject: [PATCH 30/36] feat: add minimal devcontainer setup (#14038) * add minimal devcontainer setup * fix Makefile & update doc * fix Makefile * add warning regarding devcontainer + add newline at EOF --- .devcontainer/Dockerfile | 2 ++ .devcontainer/devcontainer.json | 20 ++++++++++++++++++++ Makefile | 18 ++++++++---------- docs/docs/developer/pr-checklist.md | 4 ++++ 4 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000000..e83165a7af --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,2 @@ +ARG BASEIMAGE=mcr.microsoft.com/devcontainers/typescript-node:22 +FROM ${BASEIMAGE} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..b297f9a2d8 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,20 @@ +{ + "name": "Immich devcontainers", + "build": { + "dockerfile": "Dockerfile", + "args": { + "BASEIMAGE": "mcr.microsoft.com/devcontainers/typescript-node:22" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "svelte.svelte-vscode" + ] + } + }, + "forwardPorts": [], + "postCreateCommand": "make install-all", + "remoteUser": "node" +} + diff --git a/Makefile b/Makefile index 2096cf86df..0899d82d24 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ attach-server: renovate: LOG_LEVEL=debug npx renovate --platform=local --repository-cache=reset -MODULES = e2e server web cli sdk +MODULES = e2e server web cli sdk docs audit-%: npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix @@ -48,11 +48,9 @@ install-%: build-cli: build-sdk build-web: build-sdk build-%: install-% - npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run | grep 'build' >/dev/null \ - && npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run build || true + npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run build format-%: - npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run | grep 'format:fix' >/dev/null \ - && npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run format:fix || true + npm --prefix $* run format:fix lint-%: npm --prefix $* run lint:fix check-%: @@ -79,14 +77,14 @@ test-medium: test-medium-dev: docker exec -it immich_server /bin/sh -c "npm run test:medium" -build-all: $(foreach M,$(MODULES),build-$M) ; +build-all: $(foreach M,$(filter-out e2e,$(MODULES)),build-$M) ; install-all: $(foreach M,$(MODULES),install-$M) ; -check-all: $(foreach M,$(MODULES),check-$M) ; -lint-all: $(foreach M,$(MODULES),lint-$M) ; -format-all: $(foreach M,$(MODULES),format-$M) ; +check-all: $(foreach M,$(filter-out sdk cli docs,$(MODULES)),check-$M) ; +lint-all: $(foreach M,$(filter-out sdk docs,$(MODULES)),lint-$M) ; +format-all: $(foreach M,$(filter-out sdk,$(MODULES)),format-$M) ; audit-all: $(foreach M,$(MODULES),audit-$M) ; hygiene-all: lint-all format-all check-all sql audit-all; -test-all: $(foreach M,$(MODULES),test-$M) ; +test-all: $(foreach M,$(filter-out sdk docs,$(MODULES)),test-$M) ; clean: find . -name "node_modules" -type d -prune -exec rm -rf '{}' + diff --git a/docs/docs/developer/pr-checklist.md b/docs/docs/developer/pr-checklist.md index d2e7fbee40..6015694976 100644 --- a/docs/docs/developer/pr-checklist.md +++ b/docs/docs/developer/pr-checklist.md @@ -1,5 +1,9 @@ # PR Checklist +A minimal devcontainer is supplied with this repository. All commands can be executed directly inside this container to avoid tedious installation of the environment. +:::warning +The provided devcontainer isn't complete at the moment. At least all dockerized steps in the Makefile won't work (`make dev`, ....). Feel free to contribute! +::: When contributing code through a pull request, please check the following: ## Web Checks From 11403abfbc5e6dfc366470a944e20b4def48a218 Mon Sep 17 00:00:00 2001 From: Mert <101130780+mertalev@users.noreply.github.com> Date: Wed, 13 Nov 2024 19:49:25 -0500 Subject: [PATCH 31/36] feat(mobile): new video slider ui (#14126) --- mobile/lib/constants/immich_colors.dart | 2 +- .../asset_viewer/bottom_gallery_bar.dart | 75 +++++++----- .../asset_viewer/formatted_duration.dart | 5 +- .../widgets/asset_viewer/video_controls.dart | 27 +---- .../asset_viewer/video_mute_button.dart | 23 ---- .../widgets/asset_viewer/video_position.dart | 110 +++++++++++------- 6 files changed, 120 insertions(+), 122 deletions(-) delete mode 100644 mobile/lib/widgets/asset_viewer/video_mute_button.dart diff --git a/mobile/lib/constants/immich_colors.dart b/mobile/lib/constants/immich_colors.dart index 37e98a7f70..d63928b5b8 100644 --- a/mobile/lib/constants/immich_colors.dart +++ b/mobile/lib/constants/immich_colors.dart @@ -20,7 +20,7 @@ const String defaultColorPresetName = "indigo"; const Color immichBrandColorLight = Color(0xFF4150AF); const Color immichBrandColorDark = Color(0xFFACCBFA); const Color whiteOpacity75 = Color.fromARGB((0.75 * 255) ~/ 1, 255, 255, 255); -const Color blackOpacity40 = Color.fromARGB((0.40 * 255) ~/ 1, 0, 0, 0); +const Color blackOpacity90 = Color.fromARGB((0.90 * 255) ~/ 1, 0, 0, 0); final Map<ImmichColorPreset, ImmichTheme> _themePresetsMap = { ImmichColorPreset.indigo: ImmichTheme( diff --git a/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart b/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart index f550857b9d..eadaf0bf9f 100644 --- a/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart +++ b/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart @@ -5,6 +5,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/immich_colors.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/providers/album/album.provider.dart'; import 'package:immich_mobile/providers/album/current_album.provider.dart'; @@ -327,39 +328,51 @@ class BottomGalleryBar extends ConsumerWidget { child: AnimatedOpacity( duration: const Duration(milliseconds: 100), opacity: ref.watch(showControlsProvider) ? 1.0 : 0.0, - child: Column( - children: [ - Visibility( - visible: showVideoPlayerControls, - child: const VideoControls(), + child: DecoratedBox( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + colors: [blackOpacity90, Colors.transparent], ), - BottomNavigationBar( - backgroundColor: Colors.black.withOpacity(0.4), - unselectedIconTheme: const IconThemeData(color: Colors.white), - selectedIconTheme: const IconThemeData(color: Colors.white), - unselectedLabelStyle: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.w500, - height: 2.3, - ), - selectedLabelStyle: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.w500, - height: 2.3, - ), - unselectedFontSize: 14, - selectedFontSize: 14, - selectedItemColor: Colors.white, - unselectedItemColor: Colors.white, - showSelectedLabels: true, - showUnselectedLabels: true, - items: - albumActions.map((e) => e.keys.first).toList(growable: false), - onTap: (index) { - albumActions[index].values.first.call(index); - }, + ), + position: DecorationPosition.background, + child: Padding( + padding: EdgeInsets.only(top: 40.0), + child: Column( + children: [ + if (showVideoPlayerControls) const VideoControls(), + BottomNavigationBar( + elevation: 0.0, + backgroundColor: Colors.transparent, + unselectedIconTheme: const IconThemeData(color: Colors.white), + selectedIconTheme: const IconThemeData(color: Colors.white), + unselectedLabelStyle: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.w500, + height: 2.3, + ), + selectedLabelStyle: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.w500, + height: 2.3, + ), + unselectedFontSize: 14, + selectedFontSize: 14, + selectedItemColor: Colors.white, + unselectedItemColor: Colors.white, + showSelectedLabels: true, + showUnselectedLabels: true, + items: albumActions + .map((e) => e.keys.first) + .toList(growable: false), + onTap: (index) { + albumActions[index].values.first.call(index); + }, + ), + ], ), - ], + ), ), ), ); diff --git a/mobile/lib/widgets/asset_viewer/formatted_duration.dart b/mobile/lib/widgets/asset_viewer/formatted_duration.dart index 4a334cd7cc..a34aab7d12 100644 --- a/mobile/lib/widgets/asset_viewer/formatted_duration.dart +++ b/mobile/lib/widgets/asset_viewer/formatted_duration.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:immich_mobile/constants/immich_colors.dart'; @pragma('vm:prefer-inline') String _formatDuration(Duration position) { @@ -24,8 +23,8 @@ class FormattedDuration extends StatelessWidget { _formatDuration(data), style: const TextStyle( fontSize: 14.0, - color: whiteOpacity75, - fontWeight: FontWeight.normal, + color: Colors.white, + fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), diff --git a/mobile/lib/widgets/asset_viewer/video_controls.dart b/mobile/lib/widgets/asset_viewer/video_controls.dart index c96d58d374..e4d78324c8 100644 --- a/mobile/lib/widgets/asset_viewer/video_controls.dart +++ b/mobile/lib/widgets/asset_viewer/video_controls.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/constants/immich_colors.dart'; -import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart'; import 'package:immich_mobile/widgets/asset_viewer/video_position.dart'; /// The video controls for the [videoPlayerControlsProvider] @@ -12,24 +10,11 @@ class VideoControls extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final isPortrait = MediaQuery.orientationOf(context) == Orientation.portrait; - return AnimatedOpacity( - opacity: ref.watch(showControlsProvider) ? 1.0 : 0.0, - duration: const Duration(milliseconds: 100), - child: isPortrait - ? const ColoredBox( - color: blackOpacity40, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 24.0), - child: VideoPosition(), - ), - ) - : const ColoredBox( - color: blackOpacity40, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 128.0), - child: VideoPosition(), - ), - ), - ); + return isPortrait + ? const VideoPosition() + : const Padding( + padding: EdgeInsets.symmetric(horizontal: 60.0), + child: VideoPosition(), + ); } } diff --git a/mobile/lib/widgets/asset_viewer/video_mute_button.dart b/mobile/lib/widgets/asset_viewer/video_mute_button.dart deleted file mode 100644 index da0f6f3174..0000000000 --- a/mobile/lib/widgets/asset_viewer/video_mute_button.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart'; - -class VideoMuteButton extends ConsumerWidget { - const VideoMuteButton({super.key}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - return IconButton( - icon: ref.watch( - videoPlayerControlsProvider.select((value) => value.mute), - ) - ? const Icon(Icons.volume_off) - : const Icon(Icons.volume_up), - onPressed: () => - ref.read(videoPlayerControlsProvider.notifier).toggleMute(), - color: Colors.white, - padding: const EdgeInsets.all(0), - alignment: Alignment.centerRight, - ); - } -} diff --git a/mobile/lib/widgets/asset_viewer/video_position.dart b/mobile/lib/widgets/asset_viewer/video_position.dart index 0512785782..ef309b9c85 100644 --- a/mobile/lib/widgets/asset_viewer/video_position.dart +++ b/mobile/lib/widgets/asset_viewer/video_position.dart @@ -7,7 +7,6 @@ import 'package:immich_mobile/constants/immich_colors.dart'; import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart'; import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart'; import 'package:immich_mobile/widgets/asset_viewer/formatted_duration.dart'; -import 'package:immich_mobile/widgets/asset_viewer/video_mute_button.dart'; class VideoPosition extends HookConsumerWidget { const VideoPosition({super.key}); @@ -20,38 +19,52 @@ class VideoPosition extends HookConsumerWidget { final wasPlaying = useRef<bool>(true); return duration == Duration.zero ? const _VideoPositionPlaceholder() - : Row( + : Column( children: [ - FormattedDuration(position), - Expanded( - child: Slider( - value: min( - position.inMicroseconds / duration.inMicroseconds * 100, - 100, - ), - min: 0, - max: 100, - thumbColor: Colors.white, - activeColor: Colors.white, - inactiveColor: whiteOpacity75, - onChangeStart: (value) { - final state = ref.read(videoPlaybackValueProvider).state; - wasPlaying.value = state != VideoPlaybackState.paused; - ref.read(videoPlayerControlsProvider.notifier).pause(); - }, - onChangeEnd: (value) { - if (wasPlaying.value) { - ref.read(videoPlayerControlsProvider.notifier).play(); - } - }, - onChanged: (position) { - ref.read(videoPlayerControlsProvider.notifier).position = - position; - }, + Padding( + // align with slider's inherent padding + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FormattedDuration(position), + FormattedDuration(duration), + ], ), ), - FormattedDuration(duration), - const VideoMuteButton(), + Row( + children: [ + Expanded( + child: Slider( + value: min( + position.inMicroseconds / duration.inMicroseconds * 100, + 100, + ), + min: 0, + max: 100, + thumbColor: Colors.white, + activeColor: Colors.white, + inactiveColor: whiteOpacity75, + onChangeStart: (value) { + final state = + ref.read(videoPlaybackValueProvider).state; + wasPlaying.value = state != VideoPlaybackState.paused; + ref.read(videoPlayerControlsProvider.notifier).pause(); + }, + onChangeEnd: (value) { + if (wasPlaying.value) { + ref.read(videoPlayerControlsProvider.notifier).play(); + } + }, + onChanged: (position) { + ref + .read(videoPlayerControlsProvider.notifier) + .position = position; + }, + ), + ), + ], + ), ], ); } @@ -64,22 +77,33 @@ class _VideoPositionPlaceholder extends StatelessWidget { @override Widget build(BuildContext context) { - return const Row( + return const Column( children: [ - FormattedDuration(Duration.zero), - Expanded( - child: Slider( - value: 0.0, - min: 0, - max: 100, - thumbColor: Colors.white, - activeColor: Colors.white, - inactiveColor: whiteOpacity75, - onChanged: _onChangedDummy, + Padding( + padding: EdgeInsets.symmetric(horizontal: 12.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FormattedDuration(Duration.zero), + FormattedDuration(Duration.zero), + ], ), ), - FormattedDuration(Duration.zero), - VideoMuteButton(), + Row( + children: [ + Expanded( + child: Slider( + value: 0.0, + min: 0, + max: 100, + thumbColor: Colors.white, + activeColor: Colors.white, + inactiveColor: whiteOpacity75, + onChanged: _onChangedDummy, + ), + ), + ], + ), ], ); } From 9203a61709b561c27475066a5d736ad9fe302a55 Mon Sep 17 00:00:00 2001 From: Lukas <lukas@lschaefer.xyz> Date: Thu, 14 Nov 2024 02:07:04 -0500 Subject: [PATCH 32/36] fix(server): Some MTS videos fail to generate thumbnail (#14134) * Stop skipping of all frames in MTS video * Only skip flag for mts videos * Fix lint checks * Adds test * Add comment for why flag is removed --- server/src/interfaces/media.interface.ts | 7 ++++++- server/src/services/media.service.spec.ts | 16 ++++++++++++++++ server/src/services/media.service.ts | 13 +++++++++---- server/src/utils/media.ts | 19 ++++++++++++++----- server/test/fixtures/media.stub.ts | 7 +++++++ 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/server/src/interfaces/media.interface.ts b/server/src/interfaces/media.interface.ts index fe11d17b5f..468a6ad88d 100644 --- a/server/src/interfaces/media.interface.ts +++ b/server/src/interfaces/media.interface.ts @@ -114,7 +114,12 @@ export interface ImageBuffer { } export interface VideoCodecSWConfig { - getCommand(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream: AudioStreamInfo): TranscodeCommand; + getCommand( + target: TranscodeTarget, + videoStream: VideoStreamInfo, + audioStream: AudioStreamInfo, + format?: VideoFormat, + ): TranscodeCommand; } export interface VideoCodecHWConfig extends VideoCodecSWConfig { diff --git a/server/src/services/media.service.spec.ts b/server/src/services/media.service.spec.ts index df1a04dff8..069376b8d3 100644 --- a/server/src/services/media.service.spec.ts +++ b/server/src/services/media.service.spec.ts @@ -487,6 +487,22 @@ describe(MediaService.name, () => { }), ); }); + it('should not skip intra frames for MTS file', async () => { + mediaMock.probe.mockResolvedValue(probeStub.videoStreamMTS); + assetMock.getById.mockResolvedValue(assetStub.video); + await sut.handleGenerateThumbnails({ id: assetStub.video.id }); + + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/thumbs/user-id/as/se/asset-id-preview.jpeg', + expect.objectContaining({ + inputOptions: ['-sws_flags accurate_rnd+full_chroma_int'], + outputOptions: expect.any(Array), + progress: expect.any(Object), + twoPass: false, + }), + ); + }); it('should use scaling divisible by 2 even when using quick sync', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStream2160p); diff --git a/server/src/services/media.service.ts b/server/src/services/media.service.ts index 0aa6bd03fb..770e26b243 100644 --- a/server/src/services/media.service.ts +++ b/server/src/services/media.service.ts @@ -239,7 +239,7 @@ export class MediaService extends BaseService { const thumbnailPath = StorageCore.getImagePath(asset, AssetPathType.THUMBNAIL, image.thumbnail.format); this.storageCore.ensureFolders(previewPath); - const { audioStreams, videoStreams } = await this.mediaRepository.probe(asset.originalPath); + const { format, audioStreams, videoStreams } = await this.mediaRepository.probe(asset.originalPath); const mainVideoStream = this.getMainStream(videoStreams); if (!mainVideoStream) { throw new Error(`No video streams found for asset ${asset.id}`); @@ -248,9 +248,14 @@ export class MediaService extends BaseService { const previewConfig = ThumbnailConfig.create({ ...ffmpeg, targetResolution: image.preview.size.toString() }); const thumbnailConfig = ThumbnailConfig.create({ ...ffmpeg, targetResolution: image.thumbnail.size.toString() }); - - const previewOptions = previewConfig.getCommand(TranscodeTarget.VIDEO, mainVideoStream, mainAudioStream); - const thumbnailOptions = thumbnailConfig.getCommand(TranscodeTarget.VIDEO, mainVideoStream, mainAudioStream); + const previewOptions = previewConfig.getCommand(TranscodeTarget.VIDEO, mainVideoStream, mainAudioStream, format); + const thumbnailOptions = thumbnailConfig.getCommand( + TranscodeTarget.VIDEO, + mainVideoStream, + mainAudioStream, + format, + ); + this.logger.error(format.formatName); await this.mediaRepository.transcode(asset.originalPath, previewPath, previewOptions); await this.mediaRepository.transcode(asset.originalPath, thumbnailPath, thumbnailOptions); diff --git a/server/src/utils/media.ts b/server/src/utils/media.ts index f61b472b75..98d3c7fdbb 100644 --- a/server/src/utils/media.ts +++ b/server/src/utils/media.ts @@ -6,6 +6,7 @@ import { TranscodeCommand, VideoCodecHWConfig, VideoCodecSWConfig, + VideoFormat, VideoStreamInfo, } from 'src/interfaces/media.interface'; @@ -77,9 +78,14 @@ export class BaseConfig implements VideoCodecSWConfig { return handler; } - getCommand(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream?: AudioStreamInfo) { + getCommand( + target: TranscodeTarget, + videoStream: VideoStreamInfo, + audioStream?: AudioStreamInfo, + format?: VideoFormat, + ) { const options = { - inputOptions: this.getBaseInputOptions(videoStream), + inputOptions: this.getBaseInputOptions(videoStream, format), outputOptions: [...this.getBaseOutputOptions(target, videoStream, audioStream), '-v verbose'], twoPass: this.eligibleForTwoPass(), progress: { frameCount: videoStream.frameCount, percentInterval: 5 }, @@ -101,7 +107,7 @@ export class BaseConfig implements VideoCodecSWConfig { } // eslint-disable-next-line @typescript-eslint/no-unused-vars - getBaseInputOptions(videoStream: VideoStreamInfo): string[] { + getBaseInputOptions(videoStream: VideoStreamInfo, format?: VideoFormat): string[] { return this.getInputThreadOptions(); } @@ -377,8 +383,11 @@ export class ThumbnailConfig extends BaseConfig { return new ThumbnailConfig(config); } - getBaseInputOptions(): string[] { - return ['-skip_frame nointra', '-sws_flags accurate_rnd+full_chroma_int']; + getBaseInputOptions(videoStream: VideoStreamInfo, format?: VideoFormat): string[] { + // skip_frame nointra skips all frames for some MPEG-TS files. Look at ffmpeg tickets 7950 and 7895 for more details. + return format?.formatName === 'mpegts' + ? ['-sws_flags accurate_rnd+full_chroma_int'] + : ['-skip_frame nointra', '-sws_flags accurate_rnd+full_chroma_int']; } getBaseOutputOptions() { diff --git a/server/test/fixtures/media.stub.ts b/server/test/fixtures/media.stub.ts index 082959c227..de11c23f0a 100644 --- a/server/test/fixtures/media.stub.ts +++ b/server/test/fixtures/media.stub.ts @@ -95,6 +95,13 @@ export const probeStub = { ...probeStubDefault, videoStreams: [{ ...probeStubDefaultVideoStream[0], bitrate: 40_000_000 }], }), + videoStreamMTS: Object.freeze<VideoInfo>({ + ...probeStubDefault, + format: { + ...probeStubDefaultFormat, + formatName: 'mpegts', + }, + }), videoStreamHDR: Object.freeze<VideoInfo>({ ...probeStubDefault, videoStreams: [ From 0b3742cf13071ffa74d4923df0a0a047fc20a3d7 Mon Sep 17 00:00:00 2001 From: Alex <alex.tran1502@gmail.com> Date: Thu, 14 Nov 2024 08:43:25 -0600 Subject: [PATCH 33/36] chore(web): migration svelte 5 syntax (#13883) --- web/package-lock.json | 6 +- web/package.json | 6 +- .../actions/__test__/focus-trap-test.svelte | 10 +- web/src/lib/actions/autogrow.ts | 2 +- .../lib/actions/context-menu-navigation.ts | 8 +- web/src/lib/actions/list-navigation.ts | 9 +- .../admin-page/delete-confirm-dialogue.svelte | 35 ++- .../admin-page/jobs/job-tile-button.svelte | 18 +- .../admin-page/jobs/job-tile-status.svelte | 13 +- .../admin-page/jobs/job-tile.svelte | 64 ++-- .../admin-page/jobs/jobs-panel.svelte | 12 +- .../jobs/storage-migration-description.svelte | 15 +- .../admin-page/restore-dialogue.svelte | 22 +- .../server-stats/server-stats-panel.svelte | 22 +- .../admin-page/server-stats/stats-card.svelte | 16 +- .../admin-page/settings/admin-settings.svelte | 24 +- .../settings/auth/auth-settings.svelte | 79 ++--- .../backup-settings/backup-settings.svelte | 57 ++-- .../settings/ffmpeg/ffmpeg-settings.svelte | 71 +++-- .../settings/image/image-settings.svelte | 41 ++- .../settings/job-settings/job-settings.svelte | 31 +- .../library-settings/library-settings.svelte | 65 ++-- .../logging-settings/logging-settings.svelte | 22 +- .../machine-learning-settings.svelte | 51 ++-- .../settings/map-settings/map-settings.svelte | 55 ++-- .../metadata-settings.svelte | 22 +- .../new-version-check-settings.svelte | 22 +- .../notification-settings.svelte | 41 +-- .../settings/server/server-settings.svelte | 31 +- .../storage-template-settings.svelte | 170 ++++++----- .../supported-datetime-panel.svelte | 6 +- .../settings/theme/theme-settings.svelte | 24 +- .../trash-settings/trash-settings.svelte | 29 +- .../user-settings/user-settings.svelte | 25 +- .../album-page/__tests__/album-card.spec.ts | 15 +- .../album-page/album-card-group.svelte | 37 ++- .../components/album-page/album-card.svelte | 25 +- .../components/album-page/album-cover.svelte | 17 +- .../album-page/album-description.svelte | 10 +- .../album-page/album-options.svelte | 38 ++- .../album-page/album-summary.svelte | 9 +- .../components/album-page/album-title.svelte | 20 +- .../components/album-page/album-viewer.svelte | 22 +- .../album-page/albums-controls.svelte | 94 +++--- .../components/album-page/albums-list.svelte | 78 +++-- .../album-page/albums-table-header.svelte | 28 +- .../album-page/albums-table-row.svelte | 18 +- .../components/album-page/albums-table.svelte | 13 +- .../album-page/share-info-modal.svelte | 20 +- .../album-page/user-selection-modal.svelte | 28 +- .../actions/add-to-album-action.svelte | 12 +- .../actions/archive-action.svelte | 8 +- .../asset-viewer/actions/close-action.svelte | 8 +- .../asset-viewer/actions/delete-action.svelte | 12 +- .../actions/download-action.svelte | 10 +- .../actions/favorite-action.svelte | 13 +- .../actions/motion-photo-action.svelte | 10 +- .../actions/next-asset-action.svelte | 6 +- .../actions/previous-asset-action.svelte | 6 +- .../actions/restore-action.svelte | 8 +- .../actions/set-album-cover-action.svelte | 8 +- .../actions/set-profile-picture-action.svelte | 8 +- .../asset-viewer/actions/share-action.svelte | 15 +- .../actions/show-detail-action.svelte | 8 +- .../actions/unstack-action.svelte | 8 +- .../asset-viewer/activity-status.svelte | 18 +- .../asset-viewer/activity-viewer.svelte | 99 ++++--- .../album-list-item-details.svelte | 6 +- .../asset-viewer/album-list-item.svelte | 18 +- .../asset-viewer/asset-viewer-nav-bar.svelte | 61 ++-- .../asset-viewer/asset-viewer.svelte | 152 +++++----- .../detail-panel-description.svelte | 14 +- .../asset-viewer/detail-panel-location.svelte | 14 +- .../detail-panel-star-rating.svelte | 10 +- .../asset-viewer/detail-panel-tags.svelte | 16 +- .../asset-viewer/detail-panel.svelte | 88 +++--- .../asset-viewer/download-panel.svelte | 2 +- .../editor/crop-tool/crop-area.svelte | 26 +- .../editor/crop-tool/crop-preset.svelte | 36 ++- .../editor/crop-tool/crop-tool.svelte | 17 +- .../asset-viewer/editor/editor-panel.svelte | 22 +- .../asset-viewer/navigation-area.svelte | 15 +- .../asset-viewer/panorama-viewer.svelte | 15 +- .../photo-sphere-viewer-adapter.svelte | 20 +- .../asset-viewer/photo-viewer.svelte | 80 +++-- .../asset-viewer/slideshow-bar.svelte | 56 ++-- .../asset-viewer/video-native-viewer.svelte | 77 +++-- .../asset-viewer/video-wrapper-viewer.svelte | 34 ++- .../lib/components/assets/broken-asset.svelte | 13 +- .../assets/thumbnail/image-thumbnail.svelte | 80 +++-- .../assets/thumbnail/thumbnail.svelte | 131 ++++---- .../assets/thumbnail/video-thumbnail.svelte | 70 +++-- web/src/lib/components/elements/badge.svelte | 15 +- .../components/elements/buttons/button.svelte | 103 +++---- .../buttons/circle-icon-button.svelte | 114 +++---- .../elements/buttons/link-button.svelte | 29 +- .../elements/buttons/skip-link.svelte | 22 +- .../lib/components/elements/checkbox.svelte | 30 +- .../lib/components/elements/date-input.svelte | 30 +- .../lib/components/elements/dropdown.svelte | 44 ++- .../lib/components/elements/group-tab.svelte | 14 +- web/src/lib/components/elements/icon.svelte | 51 +++- .../components/elements/radio-button.svelte | 14 +- .../lib/components/elements/search-bar.svelte | 33 ++- web/src/lib/components/elements/slider.svelte | 34 ++- web/src/lib/components/error.svelte | 8 +- .../faces-page/assign-face-side-panel.svelte | 42 +-- .../faces-page/edit-name-input.svelte | 36 ++- .../faces-page/face-thumbnail.svelte | 28 +- .../manage-people-visibility.svelte | 98 +++--- .../faces-page/merge-face-selector.svelte | 32 +- .../faces-page/merge-suggestion-modal.svelte | 44 ++- .../components/faces-page/people-card.svelte | 24 +- .../faces-page/people-infinite-scroll.svelte | 27 +- .../components/faces-page/people-list.svelte | 32 +- .../faces-page/people-search.svelte | 52 ++-- .../faces-page/person-side-panel.svelte | 48 +-- .../faces-page/set-birth-date-modal.svelte | 24 +- .../faces-page/unmerge-face-selector.svelte | 48 +-- .../forms/admin-registration-form.svelte | 23 +- .../lib/components/forms/api-key-form.svelte | 36 ++- .../components/forms/api-key-secret.svelte | 16 +- .../forms/change-password-form.svelte | 25 +- .../components/forms/create-user-form.svelte | 56 ++-- .../components/forms/edit-album-form.svelte | 32 +- .../components/forms/edit-user-form.svelte | 46 ++- .../library-exclusion-pattern-form.svelte | 48 ++- .../forms/library-import-path-form.svelte | 54 +++- .../forms/library-import-paths-form.svelte | 37 ++- .../forms/library-rename-form.svelte | 19 +- .../forms/library-scan-settings-form.svelte | 33 ++- .../forms/library-user-picker-form.svelte | 26 +- .../lib/components/forms/login-form.svelte | 31 +- .../components/forms/tag-asset-form.svelte | 42 ++- .../i18n/__test__/format-tag-b.svelte | 18 +- .../i18n/format-bold-message.svelte | 18 +- .../lib/components/i18n/format-message.svelte | 19 +- .../layouts/user-page-layout.svelte | 58 ++-- .../map-page/map-settings-modal.svelte | 34 ++- .../memory-page/memory-viewer.svelte | 91 +++--- .../onboarding-page/onboarding-card.svelte | 12 +- .../onboarding-page/onboarding-hello.svelte | 8 +- .../onboarding-page/onboarding-privacy.svelte | 79 ++--- .../onboarding-storage-template.svelte | 87 +++--- .../onboarding-page/onboarding-theme.svelte | 12 +- .../photos-page/actions/add-to-album.svelte | 10 +- .../photos-page/actions/archive-action.svelte | 19 +- .../actions/asset-job-actions.svelte | 14 +- .../actions/change-date-action.svelte | 8 +- .../actions/change-location-action.svelte | 8 +- .../actions/create-shared-link.svelte | 4 +- .../photos-page/actions/delete-assets.svelte | 20 +- .../actions/download-action.svelte | 12 +- .../actions/favorite-action.svelte | 19 +- .../actions/link-live-photo-action.svelte | 22 +- .../actions/remove-from-album.svelte | 12 +- .../actions/remove-from-shared-link.svelte | 8 +- .../photos-page/actions/restore-assets.svelte | 10 +- .../actions/select-all-assets.svelte | 12 +- .../photos-page/actions/stack-action.svelte | 10 +- .../photos-page/actions/tag-action.svelte | 14 +- .../components/photos-page/asset-grid.svelte | 279 ++++++++++-------- .../asset-select-control-bar.svelte | 28 +- .../photos-page/delete-asset-dialog.svelte | 22 +- .../photos-page/measure-date-group.svelte | 12 +- .../components/photos-page/memory-lane.svelte | 28 +- .../components/photos-page/skeleton.svelte | 8 +- .../individual-shared-viewer.svelte | 32 +- .../album-selection-modal.svelte | 38 +-- .../autogrow-textarea.svelte | 28 +- .../shared-components/change-date.spec.ts | 10 + .../shared-components/change-date.svelte | 64 ++-- .../shared-components/change-location.svelte | 196 ++++++------ .../shared-components/combobox.svelte | 82 ++--- .../context-menu/button-context-menu.svelte | 87 +++--- .../context-menu/context-menu.svelte | 49 ++- .../context-menu/menu-option.svelte | 35 ++- .../right-click-context-menu.svelte | 55 ++-- .../shared-components/control-app-bar.svelte | 42 ++- .../coordinates-input.svelte | 10 +- .../create-shared-link-modal.svelte | 66 +++-- .../dialog/confirm-dialog.svelte | 53 ++-- .../drag-and-drop-upload-overlay.svelte | 45 ++- .../empty-placeholder.svelte | 18 +- .../full-screen-modal.svelte | 68 +++-- .../fullscreen-container.svelte | 15 +- .../gallery-viewer/gallery-viewer.svelte | 68 +++-- .../help-and-feedback-modal.svelte | 7 +- .../immich-logo-small-link.svelte | 6 +- .../shared-components/immich-logo.svelte | 8 +- .../shared-components/loading-spinner.svelte | 6 +- .../shared-components/map/map.svelte | 229 +++++++------- .../shared-components/modal-header.svelte | 34 ++- .../navigation-bar/account-info-panel.svelte | 18 +- .../navigation-bar/avatar-selector.svelte | 12 +- .../navigation-bar/navigation-bar.svelte | 37 ++- .../navigation-loading-bar.svelte | 2 +- .../notification-component-test.svelte | 6 +- .../notification/notification-card.svelte | 25 +- .../number-range-input.svelte | 49 ++- .../shared-components/password-field.svelte | 14 +- .../shared-components/portal/portal.svelte | 19 +- .../profile-image-cropper.svelte | 25 +- .../progress-bar/progress-bar.svelte | 58 ++-- .../purchase-activation-success.svelte | 8 +- .../purchasing/purchase-content.svelte | 15 +- .../purchasing/purchase-modal.svelte | 8 +- .../scrubber/scrubber.svelte | 79 +++-- .../search-bar/search-bar.svelte | 89 +++--- .../search-bar/search-camera-section.svelte | 25 +- .../search-bar/search-date-section.svelte | 8 +- .../search-bar/search-display-section.svelte | 8 +- .../search-bar/search-filter-modal.svelte | 35 ++- .../search-bar/search-history-box.svelte | 57 ++-- .../search-bar/search-location-section.svelte | 31 +- .../search-bar/search-media-section.svelte | 6 +- .../search-bar/search-people-section.svelte | 16 +- .../search-bar/search-text-section.svelte | 8 +- .../server-about-modal.svelte | 9 +- .../settings/setting-accordion-state.svelte | 34 ++- .../settings/setting-accordion.svelte | 50 +++- .../settings/setting-buttons-row.svelte | 18 +- .../settings/setting-checkboxes.svelte | 28 +- .../settings/setting-combobox.svelte | 31 +- .../settings/setting-dropdown.svelte | 27 +- .../settings/setting-input-field.spec.ts | 4 +- .../settings/setting-input-field.svelte | 77 ++--- .../settings/setting-select.svelte | 34 ++- .../settings/setting-switch.svelte | 32 +- .../settings/setting-textarea.svelte | 36 ++- .../shared-components/show-shortcuts.svelte | 42 +-- .../side-bar/more-information-albums.svelte | 6 +- .../side-bar/more-information-assets.svelte | 6 +- .../side-bar/purchase-info.svelte | 54 ++-- .../side-bar/server-status.svelte | 19 +- .../side-bar/side-bar-link.svelte | 45 ++- .../side-bar/side-bar-section.svelte | 9 +- .../side-bar/side-bar.svelte | 40 +-- .../side-bar/storage-space.svelte | 18 +- .../side-bar/supporter-badge.svelte | 8 +- .../shared-components/single-grid-row.svelte | 24 +- .../shared-components/star-rating.svelte | 38 ++- .../shared-components/theme-button.svelte | 17 +- .../shared-components/tree/breadcrumbs.svelte | 16 +- .../tree/tree-item-thumbnails.svelte | 12 +- .../shared-components/tree/tree-items.svelte | 16 +- .../shared-components/tree/tree.svelte | 42 +-- .../upload-asset-preview.svelte | 12 +- .../shared-components/upload-panel.svelte | 30 +- .../shared-components/user-avatar.svelte | 59 ++-- .../version-announcement-box.svelte | 43 +-- .../actions/shared-link-copy.svelte | 10 +- .../actions/shared-link-delete.svelte | 10 +- .../actions/shared-link-edit.svelte | 10 +- .../covers/asset-cover.svelte | 17 +- .../sharedlinks-page/covers/no-cover.svelte | 11 +- .../covers/share-cover.svelte | 11 +- .../sharedlinks-page/shared-link-card.svelte | 14 +- .../lib/components/slideshow-settings.svelte | 22 +- .../user-settings-page/app-settings.svelte | 42 +-- .../change-password-settings.svelte | 19 +- .../user-settings-page/device-card.svelte | 10 +- .../user-settings-page/device-list.svelte | 12 +- .../download-settings.svelte | 19 +- .../feature-settings.svelte | 24 +- .../notifications-settings.svelte | 14 +- .../user-settings-page/oauth-settings.svelte | 12 +- .../partner-selection-modal.svelte | 18 +- .../partner-settings.svelte | 14 +- .../user-api-key-list.svelte | 18 +- .../user-profile-settings.svelte | 14 +- .../user-purchase-settings.svelte | 9 +- .../user-settings-list.svelte | 8 +- .../duplicates/duplicate-asset.svelte | 20 +- .../duplicates-compare-control.svelte | 29 +- web/src/lib/constants.ts | 27 ++ web/src/routes/(user)/+layout.svelte | 14 +- web/src/routes/(user)/albums/+page.svelte | 22 +- .../[[assetId=id]]/+page.svelte | 236 +++++++-------- .../[[assetId=id]]/+page.svelte | 12 +- web/src/routes/(user)/buy/+page.svelte | 8 +- web/src/routes/(user)/explore/+page.svelte | 73 +++-- .../[[assetId=id]]/+page.svelte | 12 +- .../[[assetId=id]]/+page.svelte | 48 +-- .../[[assetId=id]]/+page.svelte | 22 +- .../[[assetId=id]]/+page.svelte | 10 +- web/src/routes/(user)/people/+page.svelte | 113 ++++--- .../[[assetId=id]]/+page.svelte | 145 +++++---- .../(user)/photos/[[assetId=id]]/+page.svelte | 17 +- web/src/routes/(user)/places/+page.svelte | 12 +- .../[[assetId=id]]/+page.svelte | 119 ++++---- .../[[assetId=id]]/+page.svelte | 32 +- web/src/routes/(user)/sharing/+page.svelte | 40 ++- .../(user)/sharing/sharedlinks/+page.svelte | 8 +- .../[[assetId=id]]/+page.svelte | 142 +++++---- .../[[assetId=id]]/+page.svelte | 40 ++- .../routes/(user)/user-settings/+page.svelte | 14 +- web/src/routes/(user)/utilities/+page.svelte | 6 +- .../[[assetId=id]]/+page.svelte | 80 ++--- web/src/routes/+layout.svelte | 30 +- web/src/routes/admin/jobs-status/+page.svelte | 69 +++-- .../admin/library-management/+page.svelte | 68 +++-- web/src/routes/admin/repair/+page.svelte | 83 +++--- .../routes/admin/server-status/+page.svelte | 6 +- .../routes/admin/system-settings/+page.svelte | 122 ++++---- .../routes/admin/user-management/+page.svelte | 42 +-- .../routes/auth/change-password/+page.svelte | 20 +- web/src/routes/auth/login/+page.svelte | 16 +- web/src/routes/auth/onboarding/+page.svelte | 16 +- web/src/routes/auth/register/+page.svelte | 14 +- 310 files changed, 6435 insertions(+), 4176 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 63e7c05ca4..e9f26bee80 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -36,7 +36,7 @@ "@faker-js/faker": "^9.0.0", "@socket.io/component-emitter": "^3.1.0", "@sveltejs/adapter-static": "^3.0.5", - "@sveltejs/enhanced-img": "^0.3.0", + "@sveltejs/enhanced-img": "^0.3.9", "@sveltejs/kit": "^2.7.2", "@sveltejs/vite-plugin-svelte": "^4.0.0", "@testing-library/jest-dom": "^6.4.2", @@ -53,7 +53,7 @@ "dotenv": "^16.4.5", "eslint": "^9.0.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-svelte": "^2.43.0", + "eslint-plugin-svelte": "^2.45.1", "eslint-plugin-unicorn": "^55.0.0", "factory.ts": "^1.4.1", "globals": "^15.9.0", @@ -68,7 +68,7 @@ "tailwindcss": "^3.4.1", "tslib": "^2.6.2", "typescript": "^5.5.0", - "vite": "^5.1.4", + "vite": "^5.4.4", "vitest": "^2.0.5" } }, diff --git a/web/package.json b/web/package.json index af5e87c57e..c0c600f5bc 100644 --- a/web/package.json +++ b/web/package.json @@ -28,7 +28,7 @@ "@faker-js/faker": "^9.0.0", "@socket.io/component-emitter": "^3.1.0", "@sveltejs/adapter-static": "^3.0.5", - "@sveltejs/enhanced-img": "^0.3.0", + "@sveltejs/enhanced-img": "^0.3.9", "@sveltejs/kit": "^2.7.2", "@sveltejs/vite-plugin-svelte": "^4.0.0", "@testing-library/jest-dom": "^6.4.2", @@ -45,7 +45,7 @@ "dotenv": "^16.4.5", "eslint": "^9.0.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-svelte": "^2.43.0", + "eslint-plugin-svelte": "^2.45.1", "eslint-plugin-unicorn": "^55.0.0", "factory.ts": "^1.4.1", "globals": "^15.9.0", @@ -60,7 +60,7 @@ "tailwindcss": "^3.4.1", "tslib": "^2.6.2", "typescript": "^5.5.0", - "vite": "^5.1.4", + "vite": "^5.4.4", "vitest": "^2.0.5" }, "type": "module", diff --git a/web/src/lib/actions/__test__/focus-trap-test.svelte b/web/src/lib/actions/__test__/focus-trap-test.svelte index 207c880cd9..e1cb6fa4fb 100644 --- a/web/src/lib/actions/__test__/focus-trap-test.svelte +++ b/web/src/lib/actions/__test__/focus-trap-test.svelte @@ -1,16 +1,20 @@ <script lang="ts"> import { focusTrap } from '$lib/actions/focus-trap'; - export let show: boolean; + interface Props { + show: boolean; + } + + let { show = $bindable() }: Props = $props(); </script> -<button type="button" on:click={() => (show = true)}>Open</button> +<button type="button" onclick={() => (show = true)}>Open</button> {#if show} <div use:focusTrap> <div> <span>text</span> - <button data-testid="one" type="button" on:click={() => (show = false)}>Close</button> + <button data-testid="one" type="button" onclick={() => (show = false)}>Close</button> </div> <input data-testid="two" disabled /> <input data-testid="three" /> diff --git a/web/src/lib/actions/autogrow.ts b/web/src/lib/actions/autogrow.ts index ff80454ef3..664039cb2a 100644 --- a/web/src/lib/actions/autogrow.ts +++ b/web/src/lib/actions/autogrow.ts @@ -1,4 +1,4 @@ -export const autoGrowHeight = (textarea: HTMLTextAreaElement, height = 'auto') => { +export const autoGrowHeight = (textarea?: HTMLTextAreaElement, height = 'auto') => { if (!textarea) { return; } diff --git a/web/src/lib/actions/context-menu-navigation.ts b/web/src/lib/actions/context-menu-navigation.ts index 3b45e7fe52..89b7b76d24 100644 --- a/web/src/lib/actions/context-menu-navigation.ts +++ b/web/src/lib/actions/context-menu-navigation.ts @@ -10,7 +10,7 @@ interface Options { /** * The container element that with direct children that should be navigated. */ - container: HTMLElement; + container?: HTMLElement; /** * Indicates if the dropdown is open. */ @@ -52,7 +52,11 @@ export const contextMenuNavigation: Action<HTMLElement, Options> = (node, option await tick(); } - const children = Array.from(container?.children).filter((child) => child.tagName !== 'HR') as HTMLElement[]; + if (!container) { + return; + } + + const children = Array.from(container.children).filter((child) => child.tagName !== 'HR') as HTMLElement[]; if (children.length === 0) { return; } diff --git a/web/src/lib/actions/list-navigation.ts b/web/src/lib/actions/list-navigation.ts index 8f8ed62ed0..cd4214f700 100644 --- a/web/src/lib/actions/list-navigation.ts +++ b/web/src/lib/actions/list-navigation.ts @@ -6,8 +6,15 @@ import type { Action } from 'svelte/action'; * @param node Element which listens for keyboard events * @param container Element containing the list of elements */ -export const listNavigation: Action<HTMLElement, HTMLElement> = (node, container: HTMLElement) => { +export const listNavigation: Action<HTMLElement, HTMLElement | undefined> = ( + node: HTMLElement, + container?: HTMLElement, +) => { const moveFocus = (direction: 'up' | 'down') => { + if (!container) { + return; + } + const children = Array.from(container?.children); if (children.length === 0) { return; diff --git a/web/src/lib/components/admin-page/delete-confirm-dialogue.svelte b/web/src/lib/components/admin-page/delete-confirm-dialogue.svelte index a2fbbe787a..6eb603263e 100644 --- a/web/src/lib/components/admin-page/delete-confirm-dialogue.svelte +++ b/web/src/lib/components/admin-page/delete-confirm-dialogue.svelte @@ -7,13 +7,17 @@ import { deleteUserAdmin, type UserResponseDto } from '@immich/sdk'; import { t } from 'svelte-i18n'; - export let user: UserResponseDto; - export let onSuccess: () => void; - export let onFail: () => void; - export let onCancel: () => void; + interface Props { + user: UserResponseDto; + onSuccess: () => void; + onFail: () => void; + onCancel: () => void; + } - let forceDelete = false; - let deleteButtonDisabled = false; + let { user, onSuccess, onFail, onCancel }: Props = $props(); + + let forceDelete = $state(false); + let deleteButtonDisabled = $state(false); let userIdInput: string = ''; const handleDeleteUser = async () => { @@ -47,12 +51,14 @@ {onCancel} disabled={deleteButtonDisabled} > - <svelte:fragment slot="prompt"> + {#snippet promptSnippet()} <div class="flex flex-col gap-4"> {#if forceDelete} <p> - <FormatMessage key="admin.user_delete_immediately" values={{ user: user.name }} let:message> - <b>{message}</b> + <FormatMessage key="admin.user_delete_immediately" values={{ user: user.name }}> + {#snippet children({ message })} + <b>{message}</b> + {/snippet} </FormatMessage> </p> {:else} @@ -60,9 +66,10 @@ <FormatMessage key="admin.user_delete_delay" values={{ user: user.name, delay: $serverConfig.userDeleteDelay }} - let:message > - <b>{message}</b> + {#snippet children({ message })} + <b>{message}</b> + {/snippet} </FormatMessage> </p> {/if} @@ -73,7 +80,7 @@ label={$t('admin.user_delete_immediately_checkbox')} labelClass="text-sm dark:text-immich-dark-fg" bind:checked={forceDelete} - on:change={() => { + onchange={() => { deleteButtonDisabled = forceDelete; }} /> @@ -92,9 +99,9 @@ aria-describedby="confirm-user-desc" name="confirm-user-id" type="text" - on:input={handleConfirm} + oninput={handleConfirm} /> {/if} </div> - </svelte:fragment> + {/snippet} </ConfirmDialog> diff --git a/web/src/lib/components/admin-page/jobs/job-tile-button.svelte b/web/src/lib/components/admin-page/jobs/job-tile-button.svelte index 69d3706230..f71d8a3e44 100644 --- a/web/src/lib/components/admin-page/jobs/job-tile-button.svelte +++ b/web/src/lib/components/admin-page/jobs/job-tile-button.svelte @@ -1,10 +1,18 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export type Colors = 'light-gray' | 'gray' | 'dark-gray'; </script> <script lang="ts"> - export let color: Colors; - export let disabled = false; + import type { Snippet } from 'svelte'; + + interface Props { + color: Colors; + disabled?: boolean; + children?: Snippet; + onClick?: () => void; + } + + let { color, disabled = false, onClick = () => {}, children }: Props = $props(); const colorClasses: Record<Colors, string> = { 'light-gray': 'bg-gray-300/80 dark:bg-gray-700', @@ -23,7 +31,7 @@ class="flex h-full w-full flex-col place-content-center place-items-center gap-2 px-8 py-2 text-xs text-gray-600 transition-colors dark:text-gray-200 {colorClasses[ color ]} {hoverClasses}" - on:click + onclick={onClick} > - <slot /> + {@render children?.()} </button> diff --git a/web/src/lib/components/admin-page/jobs/job-tile-status.svelte b/web/src/lib/components/admin-page/jobs/job-tile-status.svelte index ca36764797..5bffa45b89 100644 --- a/web/src/lib/components/admin-page/jobs/job-tile-status.svelte +++ b/web/src/lib/components/admin-page/jobs/job-tile-status.svelte @@ -1,9 +1,16 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export type Color = 'success' | 'warning'; </script> <script lang="ts"> - export let color: Color; + import type { Snippet } from 'svelte'; + + interface Props { + color: Color; + children?: Snippet; + } + + let { color, children }: Props = $props(); const colorClasses: Record<Color, string> = { success: 'bg-green-500/70 text-gray-900 dark:bg-green-700/90 dark:text-gray-100', @@ -12,5 +19,5 @@ </script> <div class="w-full p-2 text-center text-sm {colorClasses[color]}"> - <slot /> + {@render children?.()} </div> diff --git a/web/src/lib/components/admin-page/jobs/job-tile.svelte b/web/src/lib/components/admin-page/jobs/job-tile.svelte index 81c23e927b..0e39647c75 100644 --- a/web/src/lib/components/admin-page/jobs/job-tile.svelte +++ b/web/src/lib/components/admin-page/jobs/job-tile.svelte @@ -19,22 +19,37 @@ import JobTileButton from './job-tile-button.svelte'; import JobTileStatus from './job-tile-status.svelte'; - export let title: string; - export let subtitle: string | undefined; - export let description: Component | undefined; - export let jobCounts: JobCountsDto; - export let queueStatus: QueueStatusDto; - export let icon: string; - export let disabled = false; + interface Props { + title: string; + subtitle: string | undefined; + description: Component | undefined; + jobCounts: JobCountsDto; + queueStatus: QueueStatusDto; + icon: string; + disabled?: boolean; + allText: string | undefined; + refreshText: string | undefined; + missingText: string; + onCommand: (command: JobCommandDto) => void; + } - export let allText: string | undefined; - export let refreshText: string | undefined; - export let missingText: string; - export let onCommand: (command: JobCommandDto) => void; + let { + title, + subtitle, + description, + jobCounts, + queueStatus, + icon, + disabled = false, + allText, + refreshText, + missingText, + onCommand, + }: Props = $props(); - $: waitingCount = jobCounts.waiting + jobCounts.paused + jobCounts.delayed; - $: isIdle = !queueStatus.isActive && !queueStatus.isPaused; - $: multipleButtons = allText || refreshText; + let waitingCount = $derived(jobCounts.waiting + jobCounts.paused + jobCounts.delayed); + let isIdle = $derived(!queueStatus.isActive && !queueStatus.isPaused); + let multipleButtons = $derived(allText || refreshText); const commonClasses = 'flex place-items-center justify-between w-full py-2 sm:py-4 pr-4 pl-6'; </script> @@ -67,7 +82,7 @@ title={$t('clear_message')} size="12" padding="1" - on:click={() => onCommand({ command: JobCommand.ClearFailed, force: false })} + onclick={() => onCommand({ command: JobCommand.ClearFailed, force: false })} /> </div> </Badge> @@ -87,8 +102,9 @@ {/if} {#if description} + {@const SvelteComponent = description} <div class="text-sm dark:text-white"> - <svelte:component this={description} /> + <SvelteComponent /> </div> {/if} @@ -118,7 +134,7 @@ <JobTileButton disabled={true} color="light-gray" - on:click={() => onCommand({ command: JobCommand.Start, force: false })} + onClick={() => onCommand({ command: JobCommand.Start, force: false })} > <Icon path={mdiAlertCircle} size="36" /> {$t('disabled').toUpperCase()} @@ -127,20 +143,20 @@ {#if !disabled && !isIdle} {#if waitingCount > 0} - <JobTileButton color="gray" on:click={() => onCommand({ command: JobCommand.Empty, force: false })}> + <JobTileButton color="gray" onClick={() => onCommand({ command: JobCommand.Empty, force: false })}> <Icon path={mdiClose} size="24" /> {$t('clear').toUpperCase()} </JobTileButton> {/if} {#if queueStatus.isPaused} {@const size = waitingCount > 0 ? '24' : '48'} - <JobTileButton color="light-gray" on:click={() => onCommand({ command: JobCommand.Resume, force: false })}> + <JobTileButton color="light-gray" onClick={() => onCommand({ command: JobCommand.Resume, force: false })}> <!-- size property is not reactive, so have to use width and height --> <Icon path={mdiFastForward} {size} /> {$t('resume').toUpperCase()} </JobTileButton> {:else} - <JobTileButton color="light-gray" on:click={() => onCommand({ command: JobCommand.Pause, force: false })}> + <JobTileButton color="light-gray" onClick={() => onCommand({ command: JobCommand.Pause, force: false })}> <Icon path={mdiPause} size="24" /> {$t('pause').toUpperCase()} </JobTileButton> @@ -149,25 +165,25 @@ {#if !disabled && multipleButtons && isIdle} {#if allText} - <JobTileButton color="dark-gray" on:click={() => onCommand({ command: JobCommand.Start, force: true })}> + <JobTileButton color="dark-gray" onClick={() => onCommand({ command: JobCommand.Start, force: true })}> <Icon path={mdiAllInclusive} size="24" /> {allText} </JobTileButton> {/if} {#if refreshText} - <JobTileButton color="gray" on:click={() => onCommand({ command: JobCommand.Start, force: undefined })}> + <JobTileButton color="gray" onClick={() => onCommand({ command: JobCommand.Start, force: undefined })}> <Icon path={mdiImageRefreshOutline} size="24" /> {refreshText} </JobTileButton> {/if} - <JobTileButton color="light-gray" on:click={() => onCommand({ command: JobCommand.Start, force: false })}> + <JobTileButton color="light-gray" onClick={() => onCommand({ command: JobCommand.Start, force: false })}> <Icon path={mdiSelectionSearch} size="24" /> {missingText} </JobTileButton> {/if} {#if !disabled && !multipleButtons && isIdle} - <JobTileButton color="light-gray" on:click={() => onCommand({ command: JobCommand.Start, force: false })}> + <JobTileButton color="light-gray" onClick={() => onCommand({ command: JobCommand.Start, force: false })}> <Icon path={mdiPlay} size="48" /> {$t('start').toUpperCase()} </JobTileButton> 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 67d672d398..9b4f3ffdd6 100644 --- a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte +++ b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte @@ -25,7 +25,11 @@ import { dialogController } from '$lib/components/shared-components/dialog/dialog'; import { t } from 'svelte-i18n'; - export let jobs: AllJobStatusResponseDto; + interface Props { + jobs: AllJobStatusResponseDto; + } + + let { jobs = $bindable() }: Props = $props(); interface JobDetails { title: string; @@ -56,8 +60,7 @@ await handleCommand(jobId, dto); }; - // svelte-ignore reactive_declaration_non_reactive_property - $: jobDetails = <Partial<Record<JobName, JobDetails>>>{ + let jobDetails: Partial<Record<JobName, JobDetails>> = { [JobName.ThumbnailGeneration]: { icon: mdiFileJpgBox, title: $getJobName(JobName.ThumbnailGeneration), @@ -142,7 +145,8 @@ missingText: $t('missing'), }, }; - $: jobList = Object.entries(jobDetails) as [JobName, JobDetails][]; + + let jobList = Object.entries(jobDetails) as [JobName, JobDetails][]; async function handleCommand(jobId: JobName, jobCommand: JobCommandDto) { const title = jobDetails[jobId]?.title; diff --git a/web/src/lib/components/admin-page/jobs/storage-migration-description.svelte b/web/src/lib/components/admin-page/jobs/storage-migration-description.svelte index 8a74d2c5ad..b47df1daae 100644 --- a/web/src/lib/components/admin-page/jobs/storage-migration-description.svelte +++ b/web/src/lib/components/admin-page/jobs/storage-migration-description.svelte @@ -7,12 +7,13 @@ <FormatMessage key="admin.storage_template_migration_description" values={{ template: $t('admin.storage_template_settings') }} - let:message > - <a - href="{AppRoute.ADMIN_SETTINGS}?{QueryParameter.IS_OPEN}={OpenSettingQueryParameterValue.STORAGE_TEMPLATE}" - class="text-immich-primary dark:text-immich-dark-primary" - > - {message} - </a> + {#snippet children({ message })} + <a + href="{AppRoute.ADMIN_SETTINGS}?{QueryParameter.IS_OPEN}={OpenSettingQueryParameterValue.STORAGE_TEMPLATE}" + class="text-immich-primary dark:text-immich-dark-primary" + > + {message} + </a> + {/snippet} </FormatMessage> diff --git a/web/src/lib/components/admin-page/restore-dialogue.svelte b/web/src/lib/components/admin-page/restore-dialogue.svelte index 25afbc6d4b..a72ada2ca5 100644 --- a/web/src/lib/components/admin-page/restore-dialogue.svelte +++ b/web/src/lib/components/admin-page/restore-dialogue.svelte @@ -5,10 +5,14 @@ import { restoreUserAdmin, type UserResponseDto } from '@immich/sdk'; import { t } from 'svelte-i18n'; - export let user: UserResponseDto; - export let onSuccess: () => void; - export let onFail: () => void; - export let onCancel: () => void; + interface Props { + user: UserResponseDto; + onSuccess: () => void; + onFail: () => void; + onCancel: () => void; + } + + let { user, onSuccess, onFail, onCancel }: Props = $props(); const handleRestoreUser = async () => { try { @@ -32,11 +36,13 @@ onConfirm={handleRestoreUser} {onCancel} > - <svelte:fragment slot="prompt"> + {#snippet promptSnippet()} <p> - <FormatMessage key="admin.user_restore_description" values={{ user: user.name }} let:message> - <b>{message}</b> + <FormatMessage key="admin.user_restore_description" values={{ user: user.name }}> + {#snippet children({ message })} + <b>{message}</b> + {/snippet} </FormatMessage> </p> - </svelte:fragment> + {/snippet} </ConfirmDialog> diff --git a/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte b/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte index 35afc0962d..feab6a9c6d 100644 --- a/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte +++ b/web/src/lib/components/admin-page/server-stats/server-stats-panel.svelte @@ -7,14 +7,20 @@ import StatsCard from './stats-card.svelte'; import { t } from 'svelte-i18n'; - export let stats: ServerStatsResponseDto = { - photos: 0, - videos: 0, - usage: 0, - usageByUser: [], - }; + interface Props { + stats?: ServerStatsResponseDto; + } - $: zeros = (value: number) => { + let { + stats = { + photos: 0, + videos: 0, + usage: 0, + usageByUser: [], + }, + }: Props = $props(); + + const zeros = (value: number) => { const maxLength = 13; const valueLength = value.toString().length; const zeroLength = maxLength - valueLength; @@ -23,7 +29,7 @@ }; const TiB = 1024 ** 4; - $: [statsUsage, statsUsageUnit] = getBytesWithUnit(stats.usage, stats.usage > TiB ? 2 : 0); + let [statsUsage, statsUsageUnit] = $derived(getBytesWithUnit(stats.usage, stats.usage > TiB ? 2 : 0)); </script> <div class="flex flex-col gap-5"> diff --git a/web/src/lib/components/admin-page/server-stats/stats-card.svelte b/web/src/lib/components/admin-page/server-stats/stats-card.svelte index 31baa0afdd..14d32c055f 100644 --- a/web/src/lib/components/admin-page/server-stats/stats-card.svelte +++ b/web/src/lib/components/admin-page/server-stats/stats-card.svelte @@ -2,18 +2,22 @@ import Icon from '$lib/components/elements/icon.svelte'; import { ByteUnit } from '$lib/utils/byte-units'; - export let icon: string; - export let title: string; - export let value: number; - export let unit: ByteUnit | undefined = undefined; + interface Props { + icon: string; + title: string; + value: number; + unit?: ByteUnit | undefined; + } - $: zeros = () => { + let { icon, title, value, unit = undefined }: Props = $props(); + + const zeros = $derived(() => { const maxLength = 13; const valueLength = value.toString().length; const zeroLength = maxLength - valueLength; return '0'.repeat(zeroLength); - }; + }); </script> <div class="flex h-[140px] w-[250px] flex-col justify-between rounded-3xl bg-immich-gray p-5 dark:bg-immich-dark-gray"> diff --git a/web/src/lib/components/admin-page/settings/admin-settings.svelte b/web/src/lib/components/admin-page/settings/admin-settings.svelte index 19a8580d6b..199db0b571 100644 --- a/web/src/lib/components/admin-page/settings/admin-settings.svelte +++ b/web/src/lib/components/admin-page/settings/admin-settings.svelte @@ -1,5 +1,3 @@ -<svelte:options accessors /> - <script lang="ts"> import { NotificationType, @@ -13,12 +11,17 @@ import type { SettingsResetOptions } from './admin-settings'; import { t } from 'svelte-i18n'; - export let config: SystemConfigDto; + interface Props { + config: SystemConfigDto; + children: import('svelte').Snippet<[{ savedConfig: SystemConfigDto; defaultConfig: SystemConfigDto }]>; + } - let savedConfig: SystemConfigDto; - let defaultConfig: SystemConfigDto; + let { config = $bindable(), children }: Props = $props(); - const handleReset = async (options: SettingsResetOptions) => { + let savedConfig: SystemConfigDto | undefined = $state(); + let defaultConfig: SystemConfigDto | undefined = $state(); + + export const handleReset = async (options: SettingsResetOptions) => { await (options.default ? resetToDefault(options.configKeys) : reset(options.configKeys)); }; @@ -26,7 +29,8 @@ let systemConfigDto = { ...savedConfig, ...update, - }; + } as SystemConfigDto; + if (isEqual(systemConfigDto, savedConfig)) { return; } @@ -59,6 +63,10 @@ }; const resetToDefault = (configKeys: Array<keyof SystemConfigDto>) => { + if (!defaultConfig) { + return; + } + for (const key of configKeys) { config = { ...config, [key]: defaultConfig[key] }; } @@ -75,5 +83,5 @@ </script> {#if savedConfig && defaultConfig} - <slot {handleReset} {handleSave} {savedConfig} {defaultConfig} /> + {@render children({ savedConfig, defaultConfig })} {/if} diff --git a/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte b/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte index 9b0e4b3270..7f94dfa253 100644 --- a/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte +++ b/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte @@ -2,9 +2,7 @@ import ConfirmDialog from '$lib/components/shared-components/dialog/confirm-dialog.svelte'; import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import { type SystemConfigDto } from '@immich/sdk'; import { isEqual } from 'lodash-es'; @@ -12,15 +10,20 @@ import type { SettingsResetEvent, SettingsSaveEvent } from '../admin-settings'; import { t } from 'svelte-i18n'; import FormatMessage from '$lib/components/i18n/format-message.svelte'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } - let isConfirmOpen = false; + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + let isConfirmOpen = $state(false); const handleToggleOverride = () => { // click runs before bind @@ -48,29 +51,31 @@ onCancel={() => (isConfirmOpen = false)} onConfirm={() => handleSave(true)} > - <svelte:fragment slot="prompt"> + {#snippet promptSnippet()} <div class="flex flex-col gap-4"> <p>{$t('admin.authentication_settings_disable_all')}</p> <p> - <FormatMessage key="admin.authentication_settings_reenable" let:message> - <a - href="https://immich.app/docs/administration/server-commands" - rel="noreferrer" - target="_blank" - class="underline" - > - {message} - </a> + <FormatMessage key="admin.authentication_settings_reenable"> + {#snippet children({ message })} + <a + href="https://immich.app/docs/administration/server-commands" + rel="noreferrer" + target="_blank" + class="underline" + > + {message} + </a> + {/snippet} </FormatMessage> </p> </div> - </svelte:fragment> + {/snippet} </ConfirmDialog> {/if} <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" onsubmit={(e) => e.preventDefault()}> <div class="ml-4 mt-4 flex flex-col"> <SettingAccordion key="oauth" @@ -79,15 +84,17 @@ > <div class="ml-4 mt-4 flex flex-col gap-4"> <p class="text-sm dark:text-immich-dark-fg"> - <FormatMessage key="admin.oauth_settings_more_details" let:message> - <a - href="https://immich.app/docs/administration/oauth" - class="underline" - target="_blank" - rel="noreferrer" - > - {message} - </a> + <FormatMessage key="admin.oauth_settings_more_details"> + {#snippet children({ message })} + <a + href="https://immich.app/docs/administration/oauth" + class="underline" + target="_blank" + rel="noreferrer" + > + {message} + </a> + {/snippet} </FormatMessage> </p> @@ -147,7 +154,7 @@ <SettingInputField inputType={SettingInputFieldType.TEXT} label={$t('admin.oauth_profile_signing_algorithm').toUpperCase()} - desc={$t('admin.oauth_profile_signing_algorithm_description')} + description={$t('admin.oauth_profile_signing_algorithm_description')} bind:value={config.oauth.profileSigningAlgorithm} required={true} disabled={disabled || !config.oauth.enabled} @@ -157,7 +164,7 @@ <SettingInputField inputType={SettingInputFieldType.TEXT} label={$t('admin.oauth_storage_label_claim').toUpperCase()} - desc={$t('admin.oauth_storage_label_claim_description')} + description={$t('admin.oauth_storage_label_claim_description')} bind:value={config.oauth.storageLabelClaim} required={true} disabled={disabled || !config.oauth.enabled} @@ -167,7 +174,7 @@ <SettingInputField inputType={SettingInputFieldType.TEXT} label={$t('admin.oauth_storage_quota_claim').toUpperCase()} - desc={$t('admin.oauth_storage_quota_claim_description')} + description={$t('admin.oauth_storage_quota_claim_description')} bind:value={config.oauth.storageQuotaClaim} required={true} disabled={disabled || !config.oauth.enabled} @@ -177,7 +184,7 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('admin.oauth_storage_quota_default').toUpperCase()} - desc={$t('admin.oauth_storage_quota_default_description')} + description={$t('admin.oauth_storage_quota_default_description')} bind:value={config.oauth.defaultStorageQuota} required={true} disabled={disabled || !config.oauth.enabled} @@ -213,7 +220,7 @@ values: { callback: 'app.immich:///oauth-callback' }, })} disabled={disabled || !config.oauth.enabled} - on:click={() => handleToggleOverride()} + onToggle={() => handleToggleOverride()} bind:checked={config.oauth.mobileOverrideEnabled} /> diff --git a/web/src/lib/components/admin-page/settings/backup-settings/backup-settings.svelte b/web/src/lib/components/admin-page/settings/backup-settings/backup-settings.svelte index 05543f1124..3ec477e29c 100644 --- a/web/src/lib/components/admin-page/settings/backup-settings/backup-settings.svelte +++ b/web/src/lib/components/admin-page/settings/backup-settings/backup-settings.svelte @@ -3,33 +3,40 @@ import { isEqual } from 'lodash-es'; import { fade } from 'svelte/transition'; import type { SettingsResetEvent, SettingsSaveEvent } from '../admin-settings'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; import SettingSelect from '$lib/components/shared-components/settings/setting-select.svelte'; import { t } from 'svelte-i18n'; import FormatMessage from '$lib/components/i18n/format-message.svelte'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } - $: cronExpressionOptions = [ + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + let cronExpressionOptions = $derived([ { text: $t('interval.night_at_midnight'), value: '0 0 * * *' }, { text: $t('interval.night_at_twoam'), value: '0 02 * * *' }, { text: $t('interval.day_at_onepm'), value: '0 13 * * *' }, { text: $t('interval.hours', { values: { hours: 6 } }), value: '0 */6 * * *' }, - ]; + ]); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingSwitch title={$t('admin.backup_database_enable_description')} @@ -53,21 +60,23 @@ bind:value={config.backup.database.cronExpression} isEdited={config.backup.database.cronExpression !== savedConfig.backup.database.cronExpression} > - <svelte:fragment slot="desc"> + {#snippet descriptionSnippet()} <p class="text-sm dark:text-immich-dark-fg"> - <FormatMessage key="admin.cron_expression_description" let:message> - <a - href="https://crontab.guru/#{config.backup.database.cronExpression.replaceAll(' ', '_')}" - class="underline" - target="_blank" - rel="noreferrer" - > - {message} - <br /> - </a> + <FormatMessage key="admin.cron_expression_description"> + {#snippet children({ message })} + <a + href="https://crontab.guru/#{config.backup.database.cronExpression.replaceAll(' ', '_')}" + class="underline" + target="_blank" + rel="noreferrer" + > + {message} + <br /> + </a> + {/snippet} </FormatMessage> </p> - </svelte:fragment> + {/snippet} </SettingInputField> <SettingInputField diff --git a/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte b/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte index 8f5b587ae6..702ec1c171 100644 --- a/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte +++ b/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte @@ -15,44 +15,53 @@ import { fade } from 'svelte/transition'; import type { SettingsResetEvent, SettingsSaveEvent } from '../admin-settings'; import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import SettingSelect from '$lib/components/shared-components/settings/setting-select.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import SettingCheckboxes from '$lib/components/shared-components/settings/setting-checkboxes.svelte'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; import { t } from 'svelte-i18n'; import FormatMessage from '$lib/components/i18n/format-message.svelte'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } + + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4 flex flex-col gap-4"> <p class="text-sm dark:text-immich-dark-fg"> <Icon path={mdiHelpCircleOutline} class="inline" size="15" /> - <FormatMessage key="admin.transcoding_codecs_learn_more" let:tag let:message> - {#if tag === 'h264-link'} - <a href="https://trac.ffmpeg.org/wiki/Encode/H.264" class="underline" target="_blank" rel="noreferrer"> - {message} - </a> - {:else if tag === 'hevc-link'} - <a href="https://trac.ffmpeg.org/wiki/Encode/H.265" class="underline" target="_blank" rel="noreferrer"> - {message} - </a> - {:else if tag === 'vp9-link'} - <a href="https://trac.ffmpeg.org/wiki/Encode/VP9" class="underline" target="_blank" rel="noreferrer"> - {message} - </a> - {/if} + <FormatMessage key="admin.transcoding_codecs_learn_more"> + {#snippet children({ tag, message })} + {#if tag === 'h264-link'} + <a href="https://trac.ffmpeg.org/wiki/Encode/H.264" class="underline" target="_blank" rel="noreferrer"> + {message} + </a> + {:else if tag === 'hevc-link'} + <a href="https://trac.ffmpeg.org/wiki/Encode/H.265" class="underline" target="_blank" rel="noreferrer"> + {message} + </a> + {:else if tag === 'vp9-link'} + <a href="https://trac.ffmpeg.org/wiki/Encode/VP9" class="underline" target="_blank" rel="noreferrer"> + {message} + </a> + {/if} + {/snippet} </FormatMessage> </p> @@ -60,7 +69,7 @@ inputType={SettingInputFieldType.NUMBER} {disabled} label={$t('admin.transcoding_constant_rate_factor')} - desc={$t('admin.transcoding_constant_rate_factor_description')} + description={$t('admin.transcoding_constant_rate_factor_description')} bind:value={config.ffmpeg.crf} required={true} isEdited={config.ffmpeg.crf !== savedConfig.ffmpeg.crf} @@ -186,7 +195,7 @@ inputType={SettingInputFieldType.TEXT} {disabled} label={$t('admin.transcoding_max_bitrate')} - desc={$t('admin.transcoding_max_bitrate_description')} + description={$t('admin.transcoding_max_bitrate_description')} bind:value={config.ffmpeg.maxBitrate} isEdited={config.ffmpeg.maxBitrate !== savedConfig.ffmpeg.maxBitrate} /> @@ -195,7 +204,7 @@ inputType={SettingInputFieldType.NUMBER} {disabled} label={$t('admin.transcoding_threads')} - desc={$t('admin.transcoding_threads_description')} + description={$t('admin.transcoding_threads_description')} bind:value={config.ffmpeg.threads} isEdited={config.ffmpeg.threads !== savedConfig.ffmpeg.threads} /> @@ -329,7 +338,7 @@ <SettingInputField inputType={SettingInputFieldType.TEXT} label={$t('admin.transcoding_preferred_hardware_device')} - desc={$t('admin.transcoding_preferred_hardware_device_description')} + description={$t('admin.transcoding_preferred_hardware_device_description')} bind:value={config.ffmpeg.preferredHwDevice} isEdited={config.ffmpeg.preferredHwDevice !== savedConfig.ffmpeg.preferredHwDevice} {disabled} @@ -346,7 +355,7 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('admin.transcoding_max_b_frames')} - desc={$t('admin.transcoding_max_b_frames_description')} + description={$t('admin.transcoding_max_b_frames_description')} bind:value={config.ffmpeg.bframes} isEdited={config.ffmpeg.bframes !== savedConfig.ffmpeg.bframes} {disabled} @@ -355,7 +364,7 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('admin.transcoding_reference_frames')} - desc={$t('admin.transcoding_reference_frames_description')} + description={$t('admin.transcoding_reference_frames_description')} bind:value={config.ffmpeg.refs} isEdited={config.ffmpeg.refs !== savedConfig.ffmpeg.refs} {disabled} @@ -364,7 +373,7 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('admin.transcoding_max_keyframe_interval')} - desc={$t('admin.transcoding_max_keyframe_interval_description')} + description={$t('admin.transcoding_max_keyframe_interval_description')} bind:value={config.ffmpeg.gopSize} isEdited={config.ffmpeg.gopSize !== savedConfig.ffmpeg.gopSize} {disabled} diff --git a/web/src/lib/components/admin-page/settings/image/image-settings.svelte b/web/src/lib/components/admin-page/settings/image/image-settings.svelte index 50ae494570..2f2bcbca64 100644 --- a/web/src/lib/components/admin-page/settings/image/image-settings.svelte +++ b/web/src/lib/components/admin-page/settings/image/image-settings.svelte @@ -7,24 +7,39 @@ import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import { t } from 'svelte-i18n'; import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; - export let openByDefault = false; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + openByDefault?: boolean; + } + + let { + savedConfig, + defaultConfig, + config = $bindable(), + disabled = false, + onReset, + onSave, + openByDefault = false, + }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingAccordion key="thumbnail-settings" @@ -65,7 +80,7 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('admin.image_quality')} - desc={$t('admin.image_thumbnail_quality_description')} + description={$t('admin.image_thumbnail_quality_description')} bind:value={config.image.thumbnail.quality} isEdited={config.image.thumbnail.quality !== savedConfig.image.thumbnail.quality} {disabled} @@ -110,7 +125,7 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('admin.image_quality')} - desc={$t('admin.image_preview_quality_description')} + description={$t('admin.image_preview_quality_description')} bind:value={config.image.preview.quality} isEdited={config.image.preview.quality !== savedConfig.image.preview.quality} {disabled} 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 e09fde8bae..356de6ae86 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 @@ -5,17 +5,20 @@ import { fade } from 'svelte/transition'; import type { SettingsResetEvent, SettingsSaveEvent } from '../admin-settings'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import { t } from 'svelte-i18n'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } + + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); const jobNames = [ JobName.ThumbnailGeneration, @@ -34,11 +37,15 @@ function isSystemConfigJobDto(jobName: any): jobName is keyof SystemConfigJobDto { return jobName in config.job; } + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> {#each jobNames as jobName} <div class="ml-4 mt-4 flex flex-col gap-4"> {#if isSystemConfigJobDto(jobName)} @@ -46,7 +53,7 @@ inputType={SettingInputFieldType.NUMBER} {disabled} label={$t('admin.job_concurrency', { values: { job: $getJobName(jobName) } })} - desc="" + description="" bind:value={config.job[jobName].concurrency} required={true} isEdited={!(config.job[jobName].concurrency == savedConfig.job[jobName].concurrency)} @@ -55,7 +62,7 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('admin.job_concurrency', { values: { job: $getJobName(jobName) } })} - desc="" + description="" value="1" disabled={true} title={$t('admin.job_not_concurrency_safe')} diff --git a/web/src/lib/components/admin-page/settings/library-settings/library-settings.svelte b/web/src/lib/components/admin-page/settings/library-settings/library-settings.svelte index b494dca53f..b1012c0287 100644 --- a/web/src/lib/components/admin-page/settings/library-settings/library-settings.svelte +++ b/web/src/lib/components/admin-page/settings/library-settings/library-settings.svelte @@ -4,34 +4,49 @@ import { fade } from 'svelte/transition'; import type { SettingsResetEvent, SettingsSaveEvent } from '../admin-settings'; import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; import { t } from 'svelte-i18n'; import FormatMessage from '$lib/components/i18n/format-message.svelte'; import SettingSelect from '$lib/components/shared-components/settings/setting-select.svelte'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; - export let openByDefault = false; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + openByDefault?: boolean; + } - $: cronExpressionOptions = [ + let { + savedConfig, + defaultConfig, + config = $bindable(), + disabled = false, + onReset, + onSave, + openByDefault = false, + }: Props = $props(); + + let cronExpressionOptions = $derived([ { text: $t('interval.night_at_midnight'), value: '0 0 * * *' }, { text: $t('interval.night_at_twoam'), value: '0 2 * * *' }, { text: $t('interval.day_at_onepm'), value: '0 13 * * *' }, { text: $t('interval.hours', { values: { hours: 6 } }), value: '0 */6 * * *' }, - ]; + ]); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingAccordion key="library-watching" @@ -77,20 +92,22 @@ bind:value={config.library.scan.cronExpression} isEdited={config.library.scan.cronExpression !== savedConfig.library.scan.cronExpression} > - <svelte:fragment slot="desc"> + {#snippet descriptionSnippet()} <p class="text-sm dark:text-immich-dark-fg"> - <FormatMessage key="admin.cron_expression_description" let:message> - <a - href="https://crontab.guru/#{config.library.scan.cronExpression.replaceAll(' ', '_')}" - class="underline" - target="_blank" - rel="noreferrer" - > - {message} - </a> + <FormatMessage key="admin.cron_expression_description"> + {#snippet children({ message })} + <a + href="https://crontab.guru/#{config.library.scan.cronExpression.replaceAll(' ', '_')}" + class="underline" + target="_blank" + rel="noreferrer" + > + {message} + </a> + {/snippet} </FormatMessage> </p> - </svelte:fragment> + {/snippet} </SettingInputField> </div> </SettingAccordion> diff --git a/web/src/lib/components/admin-page/settings/logging-settings/logging-settings.svelte b/web/src/lib/components/admin-page/settings/logging-settings/logging-settings.svelte index 6e71ba926c..29a1c65162 100644 --- a/web/src/lib/components/admin-page/settings/logging-settings/logging-settings.svelte +++ b/web/src/lib/components/admin-page/settings/logging-settings/logging-settings.svelte @@ -8,17 +8,25 @@ import SettingSelect from '$lib/components/shared-components/settings/setting-select.svelte'; import { t } from 'svelte-i18n'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } + + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingSwitch title={$t('admin.logging_enable_description')} 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 aac8cd5212..13678a31c1 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 @@ -5,26 +5,33 @@ import type { SettingsResetEvent, SettingsSaveEvent } from '../admin-settings'; import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import SettingSelect from '$lib/components/shared-components/settings/setting-select.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import { featureFlags } from '$lib/stores/server-config.store'; import { t } from 'svelte-i18n'; import FormatMessage from '$lib/components/i18n/format-message.svelte'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } + + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div class="mt-2"> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault class="mx-4 mt-4"> + <form autocomplete="off" {onsubmit} class="mx-4 mt-4"> <div class="flex flex-col gap-4"> <SettingSwitch title={$t('admin.machine_learning_enabled')} @@ -38,7 +45,7 @@ <SettingInputField inputType={SettingInputFieldType.TEXT} label={$t('url')} - desc={$t('admin.machine_learning_url_description')} + description={$t('admin.machine_learning_url_description')} bind:value={config.machineLearning.url} required={true} disabled={disabled || !config.machineLearning.enabled} @@ -69,11 +76,15 @@ disabled={disabled || !config.machineLearning.enabled || !config.machineLearning.clip.enabled} isEdited={config.machineLearning.clip.modelName !== savedConfig.machineLearning.clip.modelName} > - <p slot="desc" class="immich-form-label pb-2 text-sm"> - <FormatMessage key="admin.machine_learning_clip_model_description" let:message> - <a href="https://huggingface.co/immich-app"><u>{message}</u></a> - </FormatMessage> - </p> + {#snippet descriptionSnippet()} + <p class="immich-form-label pb-2 text-sm"> + <FormatMessage key="admin.machine_learning_clip_model_description"> + {#snippet children({ message })} + <a href="https://huggingface.co/immich-app"><u>{message}</u></a> + {/snippet} + </FormatMessage> + </p> + {/snippet} </SettingInputField> </div> </SettingAccordion> @@ -100,7 +111,7 @@ step="0.0005" min={0.001} max={0.1} - desc={$t('admin.machine_learning_max_detection_distance_description')} + description={$t('admin.machine_learning_max_detection_distance_description')} disabled={disabled || !$featureFlags.duplicateDetection} isEdited={config.machineLearning.duplicateDetection.maxDistance !== savedConfig.machineLearning.duplicateDetection.maxDistance} @@ -142,7 +153,7 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('admin.machine_learning_min_detection_score')} - desc={$t('admin.machine_learning_min_detection_score_description')} + description={$t('admin.machine_learning_min_detection_score_description')} bind:value={config.machineLearning.facialRecognition.minScore} step="0.1" min={0.1} @@ -155,7 +166,7 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('admin.machine_learning_max_recognition_distance')} - desc={$t('admin.machine_learning_max_recognition_distance_description')} + description={$t('admin.machine_learning_max_recognition_distance_description')} bind:value={config.machineLearning.facialRecognition.maxDistance} step="0.1" min={0.1} @@ -168,7 +179,7 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('admin.machine_learning_min_recognized_faces')} - desc={$t('admin.machine_learning_min_recognized_faces_description')} + description={$t('admin.machine_learning_min_recognized_faces_description')} bind:value={config.machineLearning.facialRecognition.minFaces} step="1" min={1} diff --git a/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte b/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte index 7c2c5c856a..4a4b23ded2 100644 --- a/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte +++ b/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte @@ -6,23 +6,30 @@ import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import { t } from 'svelte-i18n'; import FormatMessage from '$lib/components/i18n/format-message.svelte'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } + + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div class="mt-2"> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="flex flex-col gap-4"> <SettingAccordion key="map" title={$t('admin.map_settings')} subtitle={$t('admin.map_settings_description')}> <div class="ml-4 mt-4 flex flex-col gap-4"> @@ -38,7 +45,7 @@ <SettingInputField inputType={SettingInputFieldType.TEXT} label={$t('admin.map_light_style')} - desc={$t('admin.map_style_description')} + description={$t('admin.map_style_description')} bind:value={config.map.lightStyle} disabled={disabled || !config.map.enabled} isEdited={config.map.lightStyle !== savedConfig.map.lightStyle} @@ -46,7 +53,7 @@ <SettingInputField inputType={SettingInputFieldType.TEXT} label={$t('admin.map_dark_style')} - desc={$t('admin.map_style_description')} + description={$t('admin.map_style_description')} bind:value={config.map.darkStyle} disabled={disabled || !config.map.enabled} isEdited={config.map.darkStyle !== savedConfig.map.darkStyle} @@ -55,20 +62,22 @@ > <SettingAccordion key="reverse-geocoding" title={$t('admin.map_reverse_geocoding_settings')}> - <svelte:fragment slot="subtitle"> + {#snippet subtitleSnippet()} <p class="text-sm dark:text-immich-dark-fg"> - <FormatMessage key="admin.map_manage_reverse_geocoding_settings" let:message> - <a - href="https://immich.app/docs/features/reverse-geocoding" - class="underline" - target="_blank" - rel="noreferrer" - > - {message} - </a> + <FormatMessage key="admin.map_manage_reverse_geocoding_settings"> + {#snippet children({ message })} + <a + href="https://immich.app/docs/features/reverse-geocoding" + class="underline" + target="_blank" + rel="noreferrer" + > + {message} + </a> + {/snippet} </FormatMessage> </p> - </svelte:fragment> + {/snippet} <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingSwitch title={$t('admin.map_reverse_geocoding_enable_description')} diff --git a/web/src/lib/components/admin-page/settings/metadata-settings/metadata-settings.svelte b/web/src/lib/components/admin-page/settings/metadata-settings/metadata-settings.svelte index c28050e022..1ba82b2eb9 100644 --- a/web/src/lib/components/admin-page/settings/metadata-settings/metadata-settings.svelte +++ b/web/src/lib/components/admin-page/settings/metadata-settings/metadata-settings.svelte @@ -7,17 +7,25 @@ import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import { t } from 'svelte-i18n'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } + + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div class="mt-2"> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault class="mx-4 mt-4"> + <form autocomplete="off" {onsubmit} class="mx-4 mt-4"> <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingSwitch title={$t('admin.metadata_faces_import_setting')} diff --git a/web/src/lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte b/web/src/lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte index 76c238df82..1a6f0ab866 100644 --- a/web/src/lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte +++ b/web/src/lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte @@ -7,17 +7,25 @@ import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import { t } from 'svelte-i18n'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } + + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4"> <SettingSwitch title={$t('admin.version_check_enabled_description')} diff --git a/web/src/lib/components/admin-page/settings/notification-settings/notification-settings.svelte b/web/src/lib/components/admin-page/settings/notification-settings/notification-settings.svelte index fcd26c684b..28187978f9 100644 --- a/web/src/lib/components/admin-page/settings/notification-settings/notification-settings.svelte +++ b/web/src/lib/components/admin-page/settings/notification-settings/notification-settings.svelte @@ -3,9 +3,7 @@ import { isEqual } from 'lodash-es'; import { fade } from 'svelte/transition'; import type { SettingsResetEvent, SettingsSaveEvent } from '../admin-settings'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; @@ -18,15 +16,20 @@ import { user } from '$lib/stores/user.store'; import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; import { handleError } from '$lib/utils/handle-error'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } - let isSending = false; + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + let isSending = $state(false); const handleSendTestEmail = async () => { if (isSending) { @@ -65,11 +68,15 @@ isSending = false; } }; + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault class="mt-4"> + <form autocomplete="off" {onsubmit} class="mt-4"> <div class="flex flex-col gap-4"> <SettingAccordion key="email" title={$t('email')} subtitle={$t('admin.notification_email_setting_description')}> <div class="ml-4 mt-4 flex flex-col gap-4"> @@ -85,7 +92,7 @@ inputType={SettingInputFieldType.TEXT} required label={$t('host')} - desc={$t('admin.notification_email_host_description')} + description={$t('admin.notification_email_host_description')} disabled={disabled || !config.notifications.smtp.enabled} bind:value={config.notifications.smtp.transport.host} isEdited={config.notifications.smtp.transport.host !== savedConfig.notifications.smtp.transport.host} @@ -95,7 +102,7 @@ inputType={SettingInputFieldType.NUMBER} required label={$t('port')} - desc={$t('admin.notification_email_port_description')} + description={$t('admin.notification_email_port_description')} disabled={disabled || !config.notifications.smtp.enabled} bind:value={config.notifications.smtp.transport.port} isEdited={config.notifications.smtp.transport.port !== savedConfig.notifications.smtp.transport.port} @@ -104,7 +111,7 @@ <SettingInputField inputType={SettingInputFieldType.TEXT} label={$t('username')} - desc={$t('admin.notification_email_username_description')} + description={$t('admin.notification_email_username_description')} disabled={disabled || !config.notifications.smtp.enabled} bind:value={config.notifications.smtp.transport.username} isEdited={config.notifications.smtp.transport.username !== @@ -114,7 +121,7 @@ <SettingInputField inputType={SettingInputFieldType.PASSWORD} label={$t('password')} - desc={$t('admin.notification_email_password_description')} + description={$t('admin.notification_email_password_description')} disabled={disabled || !config.notifications.smtp.enabled} bind:value={config.notifications.smtp.transport.password} isEdited={config.notifications.smtp.transport.password !== @@ -134,14 +141,14 @@ inputType={SettingInputFieldType.TEXT} required label={$t('admin.notification_email_from_address')} - desc={$t('admin.notification_email_from_address_description')} + description={$t('admin.notification_email_from_address_description')} disabled={disabled || !config.notifications.smtp.enabled} bind:value={config.notifications.smtp.from} isEdited={config.notifications.smtp.from !== savedConfig.notifications.smtp.from} /> <div class="flex gap-2 place-items-center"> - <Button size="sm" disabled={!config.notifications.smtp.enabled} on:click={handleSendTestEmail}> + <Button size="sm" disabled={!config.notifications.smtp.enabled} onclick={handleSendTestEmail}> {#if disabled} {$t('admin.notification_email_test_email')} {:else} diff --git a/web/src/lib/components/admin-page/settings/server/server-settings.svelte b/web/src/lib/components/admin-page/settings/server/server-settings.svelte index f021c99f24..14d5624c5f 100644 --- a/web/src/lib/components/admin-page/settings/server/server-settings.svelte +++ b/web/src/lib/components/admin-page/settings/server/server-settings.svelte @@ -3,28 +3,35 @@ import { isEqual } from 'lodash-es'; import { fade } from 'svelte/transition'; import type { SettingsResetEvent, SettingsSaveEvent } from '../admin-settings'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; import { t } from 'svelte-i18n'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } + + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="mt-4 ml-4"> <SettingInputField inputType={SettingInputFieldType.TEXT} label={$t('admin.server_external_domain_settings')} - desc={$t('admin.server_external_domain_settings_description')} + description={$t('admin.server_external_domain_settings_description')} bind:value={config.server.externalDomain} isEdited={config.server.externalDomain !== savedConfig.server.externalDomain} /> @@ -32,7 +39,7 @@ <SettingInputField inputType={SettingInputFieldType.TEXT} label={$t('admin.server_welcome_message')} - desc={$t('admin.server_welcome_message_description')} + description={$t('admin.server_welcome_message_description')} bind:value={config.server.loginPageMessage} isEdited={config.server.loginPageMessage !== savedConfig.server.loginPageMessage} /> 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 4ebf4ed118..74d240a4a6 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 @@ -1,6 +1,9 @@ <script lang="ts"> + import { createBubbler, preventDefault } from 'svelte/legacy'; + + const bubble = createBubbler(); import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; - import { AppRoute } from '$lib/constants'; + import { AppRoute, SettingInputFieldType } from '$lib/constants'; import { user } from '$lib/stores/user.store'; import { getStorageTemplateOptions, @@ -15,24 +18,38 @@ import SupportedDatetimePanel from './supported-datetime-panel.svelte'; import SupportedVariablesPanel from './supported-variables-panel.svelte'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import { t } from 'svelte-i18n'; import FormatMessage from '$lib/components/i18n/format-message.svelte'; + import type { Snippet } from 'svelte'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let minified = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; - export let duration: number = 500; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + minified?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + duration?: number; + children?: Snippet; + } - let templateOptions: SystemConfigTemplateStorageOptionDto; - let selectedPreset = ''; + let { + savedConfig, + defaultConfig, + config = $bindable(), + disabled = false, + minified = false, + onReset, + onSave, + duration = 500, + children, + }: Props = $props(); + + let templateOptions: SystemConfigTemplateStorageOptionDto | undefined = $state(); + let selectedPreset = $state(''); const getTemplateOptions = async () => { templateOptions = await getStorageTemplateOptions(); @@ -41,15 +58,11 @@ const getSupportDateTimeFormat = () => getStorageTemplateOptions(); - $: parsedTemplate = () => { - try { - return renderTemplate(config.storageTemplate.template); - } catch { - return 'error'; - } - }; - const renderTemplate = (templateString: string) => { + if (!templateOptions) { + return ''; + } + const template = handlebar.compile(templateString, { knownHelpers: undefined, }); @@ -85,31 +98,40 @@ const handlePresetSelection = () => { config.storageTemplate.template = selectedPreset; }; + let parsedTemplate = $derived(() => { + try { + return renderTemplate(config.storageTemplate.template); + } catch { + return 'error'; + } + }); </script> <section class="dark:text-immich-dark-fg mt-2"> <div in:fade={{ duration }} class="mx-4 flex flex-col gap-4 py-4"> <p class="text-sm dark:text-immich-dark-fg"> - <FormatMessage key="admin.storage_template_more_details" let:tag let:message> - {#if tag === 'template-link'} - <a - href="https://immich.app/docs/administration/storage-template" - class="underline" - target="_blank" - rel="noreferrer" - > - {message} - </a> - {:else if tag === 'implications-link'} - <a - href="https://immich.app/docs/administration/backup-and-restore#asset-types-and-storage-locations" - class="underline" - target="_blank" - rel="noreferrer" - > - {message} - </a> - {/if} + <FormatMessage key="admin.storage_template_more_details"> + {#snippet children({ tag, message })} + {#if tag === 'template-link'} + <a + href="https://immich.app/docs/administration/storage-template" + class="underline" + target="_blank" + rel="noreferrer" + > + {message} + </a> + {:else if tag === 'implications-link'} + <a + href="https://immich.app/docs/administration/backup-and-restore#asset-types-and-storage-locations" + class="underline" + target="_blank" + rel="noreferrer" + > + {message} + </a> + {/if} + {/snippet} </FormatMessage> </p> </div> @@ -164,19 +186,18 @@ <FormatMessage key="admin.storage_template_path_length" values={{ length: parsedTemplate().length + $user.id.length + 'UPLOAD_LOCATION'.length, limit: 260 }} - let:message > - <span class="font-semibold text-immich-primary dark:text-immich-dark-primary">{message}</span> + {#snippet children({ message })} + <span class="font-semibold text-immich-primary dark:text-immich-dark-primary">{message}</span> + {/snippet} </FormatMessage> </p> <p class="text-sm"> - <FormatMessage - key="admin.storage_template_user_label" - values={{ label: $user.storageLabel || $user.id }} - let:message - > - <code class="text-immich-primary dark:text-immich-dark-primary">{message}</code> + <FormatMessage key="admin.storage_template_user_label" values={{ label: $user.storageLabel || $user.id }}> + {#snippet children({ message })} + <code class="text-immich-primary dark:text-immich-dark-primary">{message}</code> + {/snippet} </FormatMessage> </p> @@ -186,24 +207,30 @@ >/{parsedTemplate()}.jpg </p> - <form autocomplete="off" class="flex flex-col" on:submit|preventDefault> + <form autocomplete="off" class="flex flex-col" onsubmit={preventDefault(bubble('submit'))}> <div class="flex flex-col my-2"> - <label class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" for="preset-select"> - {$t('preset')} - </label> - <select - class="immich-form-input p-2 mt-2 text-sm rounded-lg bg-slate-200 hover:cursor-pointer dark:bg-gray-600" - disabled={disabled || !config.storageTemplate.enabled} - name="presets" - id="preset-select" - bind:value={selectedPreset} - on:change={handlePresetSelection} - > - {#each templateOptions.presetOptions as preset} - <option value={preset}>{renderTemplate(preset)}</option> - {/each} - </select> + {#if templateOptions} + <label + class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm" + for="preset-select" + > + {$t('preset')} + </label> + <select + class="immich-form-input p-2 mt-2 text-sm rounded-lg bg-slate-200 hover:cursor-pointer dark:bg-gray-600" + disabled={disabled || !config.storageTemplate.enabled} + name="presets" + id="preset-select" + bind:value={selectedPreset} + onchange={handlePresetSelection} + > + {#each templateOptions.presetOptions as preset} + <option value={preset}>{renderTemplate(preset)}</option> + {/each} + </select> + {/if} </div> + <div class="flex gap-2 align-bottom"> <SettingInputField label={$t('template')} @@ -232,11 +259,12 @@ <FormatMessage key="admin.storage_template_migration_info" values={{ job: $t('admin.storage_template_migration_job') }} - let:message > - <a href={AppRoute.ADMIN_JOBS} class="text-immich-primary dark:text-immich-dark-primary"> - {message} - </a> + {#snippet children({ message })} + <a href={AppRoute.ADMIN_JOBS} class="text-immich-primary dark:text-immich-dark-primary"> + {message} + </a> + {/snippet} </FormatMessage> </p> </section> @@ -247,7 +275,7 @@ {/if} {#if minified} - <slot /> + {@render children?.()} {:else} <SettingButtonsRow onReset={(options) => onReset({ ...options, configKeys: ['storageTemplate'] })} 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 10f22c1805..379e366df6 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 @@ -4,7 +4,11 @@ import { DateTime } from 'luxon'; import { t } from 'svelte-i18n'; - export let options: SystemConfigTemplateStorageOptionDto; + interface Props { + options: SystemConfigTemplateStorageOptionDto; + } + + let { options }: Props = $props(); const getLuxonExample = (format: string) => { return DateTime.fromISO('2022-09-04T20:03:05.250Z', { locale: $locale }).toFormat(format); diff --git a/web/src/lib/components/admin-page/settings/theme/theme-settings.svelte b/web/src/lib/components/admin-page/settings/theme/theme-settings.svelte index 84a12e05c9..ca5b4c934b 100644 --- a/web/src/lib/components/admin-page/settings/theme/theme-settings.svelte +++ b/web/src/lib/components/admin-page/settings/theme/theme-settings.svelte @@ -7,22 +7,30 @@ import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; import { t } from 'svelte-i18n'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } + + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingTextarea {disabled} label={$t('admin.theme_custom_css_settings')} - desc={$t('admin.theme_custom_css_settings_description')} + description={$t('admin.theme_custom_css_settings_description')} bind:value={config.theme.customCss} required={true} isEdited={config.theme.customCss !== savedConfig.theme.customCss} diff --git a/web/src/lib/components/admin-page/settings/trash-settings/trash-settings.svelte b/web/src/lib/components/admin-page/settings/trash-settings/trash-settings.svelte index 8f287d48e0..05979bf9f0 100644 --- a/web/src/lib/components/admin-page/settings/trash-settings/trash-settings.svelte +++ b/web/src/lib/components/admin-page/settings/trash-settings/trash-settings.svelte @@ -4,23 +4,30 @@ import { fade } from 'svelte/transition'; import type { SettingsResetEvent, SettingsSaveEvent } from '../admin-settings'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; import { t } from 'svelte-i18n'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } + + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingSwitch title={$t('admin.trash_enabled_description')} {disabled} bind:checked={config.trash.enabled} /> @@ -29,7 +36,7 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('admin.trash_number_of_days')} - desc={$t('admin.trash_number_of_days_description')} + description={$t('admin.trash_number_of_days_description')} bind:value={config.trash.days} required={true} disabled={disabled || !config.trash.enabled} diff --git a/web/src/lib/components/admin-page/settings/user-settings/user-settings.svelte b/web/src/lib/components/admin-page/settings/user-settings/user-settings.svelte index 21453cbc70..f96c3808a8 100644 --- a/web/src/lib/components/admin-page/settings/user-settings/user-settings.svelte +++ b/web/src/lib/components/admin-page/settings/user-settings/user-settings.svelte @@ -5,28 +5,31 @@ import type { SettingsResetEvent, SettingsSaveEvent } from '../admin-settings'; import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import { t } from 'svelte-i18n'; + import { SettingInputFieldType } from '$lib/constants'; - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - export let onReset: SettingsResetEvent; - export let onSave: SettingsSaveEvent; + interface Props { + savedConfig: SystemConfigDto; + defaultConfig: SystemConfigDto; + config: SystemConfigDto; + disabled?: boolean; + onReset: SettingsResetEvent; + onSave: SettingsSaveEvent; + } + + let { savedConfig, defaultConfig, config = $bindable(), disabled = false, onReset, onSave }: Props = $props(); </script> <div> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" onsubmit={(e) => e.preventDefault()}> <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingInputField inputType={SettingInputFieldType.NUMBER} min={1} label={$t('admin.user_delete_delay_settings')} - desc={$t('admin.user_delete_delay_settings_description')} + description={$t('admin.user_delete_delay_settings_description')} bind:value={config.user.deleteDelay} isEdited={config.user.deleteDelay !== savedConfig.user.deleteDelay} /> diff --git a/web/src/lib/components/album-page/__tests__/album-card.spec.ts b/web/src/lib/components/album-page/__tests__/album-card.spec.ts index 8da9fbfd45..9e396bec3e 100644 --- a/web/src/lib/components/album-page/__tests__/album-card.spec.ts +++ b/web/src/lib/components/album-page/__tests__/album-card.spec.ts @@ -1,14 +1,15 @@ import { sdkMock } from '$lib/__mocks__/sdk.mock'; import { albumFactory } from '@test-data/factories/album-factory'; import '@testing-library/jest-dom'; -import { fireEvent, render, waitFor, type RenderResult } from '@testing-library/svelte'; +import { render, waitFor, type RenderResult } from '@testing-library/svelte'; +import userEvent from '@testing-library/user-event'; import { init, register, waitLocale } from 'svelte-i18n'; import AlbumCard from '../album-card.svelte'; const onShowContextMenu = vi.fn(); describe('AlbumCard component', () => { - let sut: RenderResult<AlbumCard>; + let sut: RenderResult<typeof AlbumCard>; beforeAll(async () => { await init({ fallbackLocale: 'en-US' }); @@ -110,13 +111,9 @@ describe('AlbumCard component', () => { toJSON: () => ({}), }); - await fireEvent( - contextMenuButton, - new MouseEvent('click', { - clientX: 123, - clientY: 456, - }), - ); + const user = userEvent.setup(); + await user.click(contextMenuButton); + expect(onShowContextMenu).toHaveBeenCalledTimes(1); expect(onShowContextMenu).toHaveBeenCalledWith(expect.objectContaining({ x: 123, y: 456 })); }); diff --git a/web/src/lib/components/album-page/album-card-group.svelte b/web/src/lib/components/album-page/album-card-group.svelte index f899cebd8c..ae2b27efac 100644 --- a/web/src/lib/components/album-page/album-card-group.svelte +++ b/web/src/lib/components/album-page/album-card-group.svelte @@ -11,28 +11,43 @@ import Icon from '$lib/components/elements/icon.svelte'; import { t } from 'svelte-i18n'; - export let albums: AlbumResponseDto[]; - export let group: AlbumGroup | undefined = undefined; - export let showOwner = false; - export let showDateRange = false; - export let showItemCount = false; - export let onShowContextMenu: ((position: ContextMenuPosition, album: AlbumResponseDto) => unknown) | undefined = - undefined; + interface Props { + albums: AlbumResponseDto[]; + group?: AlbumGroup | undefined; + showOwner?: boolean; + showDateRange?: boolean; + showItemCount?: boolean; + onShowContextMenu?: ((position: ContextMenuPosition, album: AlbumResponseDto) => unknown) | undefined; + } - $: isCollapsed = !!group && isAlbumGroupCollapsed($albumViewSettings, group.id); + let { + albums, + group = undefined, + showOwner = false, + showDateRange = false, + showItemCount = false, + onShowContextMenu = undefined, + }: Props = $props(); + + let isCollapsed = $derived(!!group && isAlbumGroupCollapsed($albumViewSettings, group.id)); const showContextMenu = (position: ContextMenuPosition, album: AlbumResponseDto) => { onShowContextMenu?.(position, album); }; - $: iconRotation = isCollapsed ? 'rotate-0' : 'rotate-90'; + let iconRotation = $derived(isCollapsed ? 'rotate-0' : 'rotate-90'); + + const oncontextmenu = (event: MouseEvent, album: AlbumResponseDto) => { + event.preventDefault(); + showContextMenu({ x: event.x, y: event.y }, album); + }; </script> {#if group} <div class="grid"> <button type="button" - on:click={() => toggleAlbumGroupCollapsing(group.id)} + onclick={() => toggleAlbumGroupCollapsing(group.id)} class="w-fit mt-2 pt-2 pr-2 mb-2 dark:text-immich-dark-fg" aria-expanded={!isCollapsed} > @@ -56,7 +71,7 @@ data-sveltekit-preload-data="hover" href="{AppRoute.ALBUMS}/{album.id}" animate:flip={{ duration: 400 }} - on:contextmenu|preventDefault={(e) => showContextMenu({ x: e.x, y: e.y }, album)} + oncontextmenu={(event) => oncontextmenu(event, album)} > <AlbumCard {album} diff --git a/web/src/lib/components/album-page/album-card.svelte b/web/src/lib/components/album-page/album-card.svelte index f574c65f0b..cec4919e4e 100644 --- a/web/src/lib/components/album-page/album-card.svelte +++ b/web/src/lib/components/album-page/album-card.svelte @@ -8,12 +8,23 @@ import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; import { t } from 'svelte-i18n'; - export let album: AlbumResponseDto; - export let showOwner = false; - export let showDateRange = false; - export let showItemCount = false; - export let preload = false; - export let onShowContextMenu: ((position: ContextMenuPosition) => unknown) | undefined = undefined; + interface Props { + album: AlbumResponseDto; + showOwner?: boolean; + showDateRange?: boolean; + showItemCount?: boolean; + preload?: boolean; + onShowContextMenu?: ((position: ContextMenuPosition) => unknown) | undefined; + } + + let { + album, + showOwner = false, + showDateRange = false, + showItemCount = false, + preload = false, + onShowContextMenu = undefined, + }: Props = $props(); const showAlbumContextMenu = (e: MouseEvent) => { e.stopPropagation(); @@ -39,7 +50,7 @@ size="20" padding="2" class="icon-white-drop-shadow" - on:click={showAlbumContextMenu} + onclick={showAlbumContextMenu} /> </div> {/if} diff --git a/web/src/lib/components/album-page/album-cover.svelte b/web/src/lib/components/album-page/album-cover.svelte index d0444f3599..3f71bbe632 100644 --- a/web/src/lib/components/album-page/album-cover.svelte +++ b/web/src/lib/components/album-page/album-cover.svelte @@ -5,13 +5,18 @@ import AssetCover from '$lib/components/sharedlinks-page/covers/asset-cover.svelte'; import { t } from 'svelte-i18n'; - export let album: AlbumResponseDto; - export let preload = false; - let className = ''; - export { className as class }; + interface Props { + album: AlbumResponseDto; + preload?: boolean; + class?: string; + } - $: alt = album.albumName || $t('unnamed_album'); - $: thumbnailUrl = album.albumThumbnailAssetId ? getAssetThumbnailUrl({ id: album.albumThumbnailAssetId }) : null; + let { album, preload = false, class: className = '' }: Props = $props(); + + let alt = $derived(album.albumName || $t('unnamed_album')); + let thumbnailUrl = $derived( + album.albumThumbnailAssetId ? getAssetThumbnailUrl({ id: album.albumThumbnailAssetId }) : null, + ); </script> {#if thumbnailUrl} diff --git a/web/src/lib/components/album-page/album-description.svelte b/web/src/lib/components/album-page/album-description.svelte index b3ad688a30..46b424f93a 100644 --- a/web/src/lib/components/album-page/album-description.svelte +++ b/web/src/lib/components/album-page/album-description.svelte @@ -4,9 +4,13 @@ import AutogrowTextarea from '$lib/components/shared-components/autogrow-textarea.svelte'; import { t } from 'svelte-i18n'; - export let id: string; - export let description: string; - export let isOwned: boolean; + interface Props { + id: string; + description: string; + isOwned: boolean; + } + + let { id, description = $bindable(), isOwned }: Props = $props(); const handleUpdateDescription = async (newDescription: string) => { try { diff --git a/web/src/lib/components/album-page/album-options.svelte b/web/src/lib/components/album-page/album-options.svelte index 3ec1842757..884de8c2a2 100644 --- a/web/src/lib/components/album-page/album-options.svelte +++ b/web/src/lib/components/album-page/album-options.svelte @@ -23,24 +23,38 @@ import { notificationController, NotificationType } from '../shared-components/notification/notification'; import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte'; - export let album: AlbumResponseDto; - export let order: AssetOrder | undefined; - export let user: UserResponseDto; // Declare user as a prop - export let onChangeOrder: (order: AssetOrder) => void; - export let onClose: () => void; - export let onToggleEnabledActivity: () => void; - export let onShowSelectSharedUser: () => void; - export let onRemove: (userId: string) => void; - export let onRefreshAlbum: () => void; + interface Props { + album: AlbumResponseDto; + order: AssetOrder | undefined; + user: UserResponseDto; + onChangeOrder: (order: AssetOrder) => void; + onClose: () => void; + onToggleEnabledActivity: () => void; + onShowSelectSharedUser: () => void; + onRemove: (userId: string) => void; + onRefreshAlbum: () => void; + } - let selectedRemoveUser: UserResponseDto | null = null; + let { + album, + order, + user, + onChangeOrder, + onClose, + onToggleEnabledActivity, + onShowSelectSharedUser, + onRemove, + onRefreshAlbum, + }: Props = $props(); + + let selectedRemoveUser: UserResponseDto | null = $state(null); const options: Record<AssetOrder, RenderedOption> = { [AssetOrder.Asc]: { icon: mdiArrowUpThin, title: $t('oldest_first') }, [AssetOrder.Desc]: { icon: mdiArrowDownThin, title: $t('newest_first') }, }; - $: selectedOption = order ? options[order] : options[AssetOrder.Desc]; + let selectedOption = $derived(order ? options[order] : options[AssetOrder.Desc]); const handleToggle = async (returnedOption: RenderedOption): Promise<void> => { if (selectedOption === returnedOption) { @@ -125,7 +139,7 @@ <div class="py-2"> <div class="text-gray text-sm mb-3">{$t('people').toUpperCase()}</div> <div class="p-2"> - <button type="button" class="flex items-center gap-2" on:click={onShowSelectSharedUser}> + <button type="button" class="flex items-center gap-2" onclick={onShowSelectSharedUser}> <div class="rounded-full w-10 h-10 border border-gray-500 flex items-center justify-center"> <div><Icon path={mdiPlus} size="25" /></div> </div> diff --git a/web/src/lib/components/album-page/album-summary.svelte b/web/src/lib/components/album-page/album-summary.svelte index 0277035d5c..f2cd23f616 100644 --- a/web/src/lib/components/album-page/album-summary.svelte +++ b/web/src/lib/components/album-page/album-summary.svelte @@ -4,10 +4,11 @@ import type { AlbumResponseDto } from '@immich/sdk'; import { t } from 'svelte-i18n'; - export let album: AlbumResponseDto; + interface Props { + album: AlbumResponseDto; + } - $: startDate = formatDate(album.startDate); - $: endDate = formatDate(album.endDate); + let { album }: Props = $props(); const formatDate = (date?: string) => { return date ? new Date(date).toLocaleDateString($locale, dateFormats.album) : undefined; @@ -24,6 +25,8 @@ return ''; }; + let startDate = $derived(formatDate(album.startDate)); + let endDate = $derived(formatDate(album.endDate)); </script> <span class="my-2 flex gap-2 text-sm font-medium text-gray-500" data-testid="album-details"> diff --git a/web/src/lib/components/album-page/album-title.svelte b/web/src/lib/components/album-page/album-title.svelte index 1e69ecf1a3..74786c1ea4 100644 --- a/web/src/lib/components/album-page/album-title.svelte +++ b/web/src/lib/components/album-page/album-title.svelte @@ -4,12 +4,20 @@ import { shortcut } from '$lib/actions/shortcut'; import { t } from 'svelte-i18n'; - export let id: string; - export let albumName: string; - export let isOwned: boolean; - export let onUpdate: (albumName: string) => void; + interface Props { + id: string; + albumName: string; + isOwned: boolean; + onUpdate: (albumName: string) => void; + } - $: newAlbumName = albumName; + let { id, albumName = $bindable(), isOwned, onUpdate }: Props = $props(); + + let newAlbumName = $state(albumName); + + $effect(() => { + newAlbumName = albumName; + }); const handleUpdateName = async () => { if (newAlbumName === albumName) { @@ -33,7 +41,7 @@ <input use:shortcut={{ shortcut: { key: 'Enter' }, onShortcut: (e) => e.currentTarget.blur() }} - on:blur={handleUpdateName} + onblur={handleUpdateName} class="w-[99%] mb-2 border-b-2 border-transparent text-2xl md:text-4xl lg:text-6xl text-immich-primary outline-none transition-all dark:text-immich-dark-primary {isOwned ? 'hover:border-gray-400' : 'hover:border-transparent'} bg-immich-bg focus:border-b-2 focus:border-immich-primary focus:outline-none dark:bg-immich-dark-bg dark:focus:border-immich-dark-primary dark:focus:bg-immich-dark-gray" diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte index 87b3d8e2c5..1dc43c5b61 100644 --- a/web/src/lib/components/album-page/album-viewer.svelte +++ b/web/src/lib/components/album-page/album-viewer.svelte @@ -21,11 +21,15 @@ import { t } from 'svelte-i18n'; import { onDestroy } from 'svelte'; - export let sharedLink: SharedLinkResponseDto; - export let user: UserResponseDto | undefined = undefined; + interface Props { + sharedLink: SharedLinkResponseDto; + user?: UserResponseDto | undefined; + } + + let { sharedLink, user = undefined }: Props = $props(); const album = sharedLink.album as AlbumResponseDto; - let innerWidth: number; + let innerWidth: number = $state(0); let { isViewing: showAssetViewer } = assetViewingStore; @@ -70,15 +74,15 @@ </AssetSelectControlBar> {:else} <ControlAppBar showBackButton={false}> - <svelte:fragment slot="leading"> + {#snippet leading()} <ImmichLogoSmallLink width={innerWidth} /> - </svelte:fragment> + {/snippet} - <svelte:fragment slot="trailing"> + {#snippet trailing()} {#if sharedLink.allowUpload} <CircleIconButton title={$t('add_photos')} - on:click={() => openFileUploadDialog({ albumId: album.id })} + onclick={() => openFileUploadDialog({ albumId: album.id })} icon={mdiFileImagePlusOutline} /> {/if} @@ -86,13 +90,13 @@ {#if album.assetCount > 0 && sharedLink.allowDownload} <CircleIconButton title={$t('download')} - on:click={() => downloadAlbum(album)} + onclick={() => downloadAlbum(album)} icon={mdiFolderDownloadOutline} /> {/if} <ThemeButton /> - </svelte:fragment> + {/snippet} </ControlAppBar> {/if} </header> diff --git a/web/src/lib/components/album-page/albums-controls.svelte b/web/src/lib/components/album-page/albums-controls.svelte index 34563eddd3..85a7260f40 100644 --- a/web/src/lib/components/album-page/albums-controls.svelte +++ b/web/src/lib/components/album-page/albums-controls.svelte @@ -38,8 +38,12 @@ import { fly } from 'svelte/transition'; import { t } from 'svelte-i18n'; - export let albumGroups: string[]; - export let searchQuery: string; + interface Props { + albumGroups: string[]; + searchQuery: string; + } + + let { albumGroups, searchQuery = $bindable() }: Props = $props(); const flipOrdering = (ordering: string) => { return ordering === SortOrder.Asc ? SortOrder.Desc : SortOrder.Asc; @@ -73,62 +77,38 @@ $albumViewSettings.view === AlbumViewMode.Cover ? AlbumViewMode.List : AlbumViewMode.Cover; }; - let selectedGroupOption: AlbumGroupOptionMetadata; - let groupIcon: string; - - $: selectedFilterOption = albumFilterNames[findFilterOption($albumViewSettings.filter)]; - - $: selectedSortOption = findSortOptionMetadata($albumViewSettings.sortBy); - - $: { - selectedGroupOption = findGroupOptionMetadata($albumViewSettings.groupBy); - if (selectedGroupOption.isDisabled()) { - selectedGroupOption = findGroupOptionMetadata(AlbumGroupBy.None); + let groupIcon = $derived.by(() => { + if (selectedGroupOption?.id === AlbumGroupBy.None) { + return mdiFolderRemoveOutline; } - } + return $albumViewSettings.groupOrder === SortOrder.Desc ? mdiFolderArrowDownOutline : mdiFolderArrowUpOutline; + }); - // svelte-ignore reactive_declaration_non_reactive_property - $: { - if (selectedGroupOption.id === AlbumGroupBy.None) { - groupIcon = mdiFolderRemoveOutline; - } else { - groupIcon = - $albumViewSettings.groupOrder === SortOrder.Desc ? mdiFolderArrowDownOutline : mdiFolderArrowUpOutline; - } - } + let albumFilterNames: Record<AlbumFilter, string> = $derived({ + [AlbumFilter.All]: $t('all'), + [AlbumFilter.Owned]: $t('owned'), + [AlbumFilter.Shared]: $t('shared'), + }); - // svelte-ignore reactive_declaration_non_reactive_property - $: sortIcon = $albumViewSettings.sortOrder === SortOrder.Desc ? mdiArrowDownThin : mdiArrowUpThin; + let selectedFilterOption = $derived(albumFilterNames[findFilterOption($albumViewSettings.filter)]); + let selectedSortOption = $derived(findSortOptionMetadata($albumViewSettings.sortBy)); + let selectedGroupOption = $derived(findGroupOptionMetadata($albumViewSettings.groupBy)); + let sortIcon = $derived($albumViewSettings.sortOrder === SortOrder.Desc ? mdiArrowDownThin : mdiArrowUpThin); - // svelte-ignore reactive_declaration_non_reactive_property - $: albumFilterNames = ((): Record<AlbumFilter, string> => { - return { - [AlbumFilter.All]: $t('all'), - [AlbumFilter.Owned]: $t('owned'), - [AlbumFilter.Shared]: $t('shared'), - }; - })(); + let albumSortByNames: Record<AlbumSortBy, string> = $derived({ + [AlbumSortBy.Title]: $t('sort_title'), + [AlbumSortBy.ItemCount]: $t('sort_items'), + [AlbumSortBy.DateModified]: $t('sort_modified'), + [AlbumSortBy.DateCreated]: $t('sort_created'), + [AlbumSortBy.MostRecentPhoto]: $t('sort_recent'), + [AlbumSortBy.OldestPhoto]: $t('sort_oldest'), + }); - // svelte-ignore reactive_declaration_non_reactive_property - $: albumSortByNames = ((): Record<AlbumSortBy, string> => { - return { - [AlbumSortBy.Title]: $t('sort_title'), - [AlbumSortBy.ItemCount]: $t('sort_items'), - [AlbumSortBy.DateModified]: $t('sort_modified'), - [AlbumSortBy.DateCreated]: $t('sort_created'), - [AlbumSortBy.MostRecentPhoto]: $t('sort_recent'), - [AlbumSortBy.OldestPhoto]: $t('sort_oldest'), - }; - })(); - - // svelte-ignore reactive_declaration_non_reactive_property - $: albumGroupByNames = ((): Record<AlbumGroupBy, string> => { - return { - [AlbumGroupBy.None]: $t('group_no'), - [AlbumGroupBy.Owner]: $t('group_owner'), - [AlbumGroupBy.Year]: $t('group_year'), - }; - })(); + let albumGroupByNames: Record<AlbumGroupBy, string> = $derived({ + [AlbumGroupBy.None]: $t('group_no'), + [AlbumGroupBy.Owner]: $t('group_owner'), + [AlbumGroupBy.Year]: $t('group_year'), + }); </script> <!-- Filter Albums by Sharing Status (All, Owned, Shared) --> @@ -147,7 +127,7 @@ </div> <!-- Create Album --> -<LinkButton on:click={() => createAlbumAndRedirect()}> +<LinkButton onclick={() => createAlbumAndRedirect()}> <div class="flex place-items-center gap-2 text-sm"> <Icon path={mdiPlusBoxOutline} size="18" /> <p class="hidden md:block">{$t('create_album')}</p> @@ -184,7 +164,7 @@ <!-- Expand Album Groups --> <div class="hidden xl:flex gap-0"> <div class="block"> - <LinkButton title={$t('expand_all')} on:click={() => expandAllAlbumGroups()}> + <LinkButton title={$t('expand_all')} onclick={() => expandAllAlbumGroups()}> <div class="flex place-items-center gap-2 text-sm"> <Icon path={mdiUnfoldMoreHorizontal} size="18" /> </div> @@ -193,7 +173,7 @@ <!-- Collapse Album Groups --> <div class="block"> - <LinkButton title={$t('collapse_all')} on:click={() => collapseAllAlbumGroups(albumGroups)}> + <LinkButton title={$t('collapse_all')} onclick={() => collapseAllAlbumGroups(albumGroups)}> <div class="flex place-items-center gap-2 text-sm"> <Icon path={mdiUnfoldLessHorizontal} size="18" /> </div> @@ -204,7 +184,7 @@ {/if} <!-- Cover/List Display Toggle --> -<LinkButton on:click={() => handleChangeListMode()}> +<LinkButton onclick={() => handleChangeListMode()}> <div class="flex place-items-center gap-2 text-sm"> {#if $albumViewSettings.view === AlbumViewMode.List} <Icon path={mdiViewGridOutline} size="18" /> diff --git a/web/src/lib/components/album-page/albums-list.svelte b/web/src/lib/components/album-page/albums-list.svelte index 3858dd23b7..178190dc34 100644 --- a/web/src/lib/components/album-page/albums-list.svelte +++ b/web/src/lib/components/album-page/albums-list.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { onMount } from 'svelte'; + import { onMount, type Snippet } from 'svelte'; import { groupBy } from 'lodash-es'; import { addUsersToAlbum, deleteAlbum, type AlbumUserAddDto, type AlbumResponseDto, isHttpError } from '@immich/sdk'; import { mdiDeleteOutline, mdiShareVariantOutline, mdiFolderDownloadOutline, mdiRenameOutline } from '@mdi/js'; @@ -38,14 +38,29 @@ import { goto } from '$app/navigation'; import { AppRoute } from '$lib/constants'; import { t } from 'svelte-i18n'; + import { run } from 'svelte/legacy'; - export let ownedAlbums: AlbumResponseDto[] = []; - export let sharedAlbums: AlbumResponseDto[] = []; - export let searchQuery: string = ''; - export let userSettings: AlbumViewSettings; - export let allowEdit = false; - export let showOwner = false; - export let albumGroupIds: string[] = []; + interface Props { + ownedAlbums?: AlbumResponseDto[]; + sharedAlbums?: AlbumResponseDto[]; + searchQuery?: string; + userSettings: AlbumViewSettings; + allowEdit?: boolean; + showOwner?: boolean; + albumGroupIds?: string[]; + empty?: Snippet; + } + + let { + ownedAlbums = $bindable([]), + sharedAlbums = $bindable([]), + searchQuery = '', + userSettings, + allowEdit = false, + showOwner = false, + albumGroupIds = $bindable([]), + empty, + }: Props = $props(); interface AlbumGroupOption { [option: string]: (order: SortOrder, albums: AlbumResponseDto[]) => AlbumGroup[]; @@ -118,25 +133,24 @@ }, }; - let albums: AlbumResponseDto[] = []; - let filteredAlbums: AlbumResponseDto[] = []; - let groupedAlbums: AlbumGroup[] = []; + let albums: AlbumResponseDto[] = $state([]); + let filteredAlbums: AlbumResponseDto[] = $state([]); + let groupedAlbums: AlbumGroup[] = $state([]); - let albumGroupOption: string = AlbumGroupBy.None; + let albumGroupOption: string = $state(AlbumGroupBy.None); - let showShareByURLModal = false; + let showShareByURLModal = $state(false); - let albumToEdit: AlbumResponseDto | null = null; - let albumToShare: AlbumResponseDto | null = null; + let albumToEdit: AlbumResponseDto | null = $state(null); + let albumToShare: AlbumResponseDto | null = $state(null); let albumToDelete: AlbumResponseDto | null = null; - let contextMenuPosition: ContextMenuPosition = { x: 0, y: 0 }; - let contextMenuTargetAlbum: AlbumResponseDto | null = null; - let isOpen = false; + let contextMenuPosition: ContextMenuPosition = $state({ x: 0, y: 0 }); + let contextMenuTargetAlbum: AlbumResponseDto | undefined = $state(); + let isOpen = $state(false); // Step 1: Filter between Owned and Shared albums, or both. - // svelte-ignore reactive_declaration_non_reactive_property - $: { + run(() => { switch (userSettings.filter) { case AlbumFilter.Owned: { albums = ownedAlbums; @@ -152,10 +166,10 @@ albums = nonOwnedAlbums.length > 0 ? ownedAlbums.concat(nonOwnedAlbums) : ownedAlbums; } } - } + }); // Step 2: Filter using the given search query. - $: { + run(() => { if (searchQuery) { const searchAlbumNormalized = normalizeSearchString(searchQuery); @@ -165,17 +179,17 @@ } else { filteredAlbums = albums; } - } + }); // Step 3: Group albums. - $: { + run(() => { albumGroupOption = getSelectedAlbumGroupOption(userSettings); const groupFunc = groupOptions[albumGroupOption] ?? groupOptions[AlbumGroupBy.None]; groupedAlbums = groupFunc(stringToSortOrder(userSettings.groupOrder), filteredAlbums); - } + }); // Step 4: Sort albums amongst each group. - $: { + run(() => { groupedAlbums = groupedAlbums.map((group) => ({ id: group.id, name: group.name, @@ -183,9 +197,11 @@ })); albumGroupIds = groupedAlbums.map(({ id }) => id); - } + }); - $: showFullContextMenu = allowEdit && contextMenuTargetAlbum && contextMenuTargetAlbum.ownerId === $user.id; + let showFullContextMenu = $derived( + allowEdit && contextMenuTargetAlbum && contextMenuTargetAlbum.ownerId === $user.id, + ); onMount(async () => { if (allowEdit) { @@ -320,6 +336,10 @@ }; const openShareModal = () => { + if (!contextMenuTargetAlbum) { + return; + } + albumToShare = contextMenuTargetAlbum; closeAlbumContextMenu(); }; @@ -359,7 +379,7 @@ {/if} {:else} <!-- Empty Message --> - <slot name="empty" /> + {@render empty?.()} {/if} <!-- Context Menu --> diff --git a/web/src/lib/components/album-page/albums-table-header.svelte b/web/src/lib/components/album-page/albums-table-header.svelte index 84e32b82f5..4c018f7454 100644 --- a/web/src/lib/components/album-page/albums-table-header.svelte +++ b/web/src/lib/components/album-page/albums-table-header.svelte @@ -3,7 +3,11 @@ import type { AlbumSortOptionMetadata } from '$lib/utils/album-utils'; import { t } from 'svelte-i18n'; - export let option: AlbumSortOptionMetadata; + interface Props { + option: AlbumSortOptionMetadata; + } + + let { option }: Props = $props(); const handleSort = () => { if ($albumViewSettings.sortBy === option.id) { @@ -13,24 +17,22 @@ $albumViewSettings.sortOrder = option.defaultOrder; } }; - // svelte-ignore reactive_declaration_non_reactive_property - $: albumSortByNames = ((): Record<AlbumSortBy, string> => { - return { - [AlbumSortBy.Title]: $t('sort_title'), - [AlbumSortBy.ItemCount]: $t('sort_items'), - [AlbumSortBy.DateModified]: $t('sort_modified'), - [AlbumSortBy.DateCreated]: $t('sort_created'), - [AlbumSortBy.MostRecentPhoto]: $t('sort_recent'), - [AlbumSortBy.OldestPhoto]: $t('sort_oldest'), - }; - })(); + + let albumSortByNames: Record<AlbumSortBy, string> = $derived({ + [AlbumSortBy.Title]: $t('sort_title'), + [AlbumSortBy.ItemCount]: $t('sort_items'), + [AlbumSortBy.DateModified]: $t('sort_modified'), + [AlbumSortBy.DateCreated]: $t('sort_created'), + [AlbumSortBy.MostRecentPhoto]: $t('sort_recent'), + [AlbumSortBy.OldestPhoto]: $t('sort_oldest'), + }); </script> <th class="text-sm font-medium {option.columnStyle}"> <button type="button" class="rounded-lg p-2 hover:bg-immich-dark-primary hover:dark:bg-immich-dark-primary/50" - on:click={handleSort} + onclick={handleSort} > {#if $albumViewSettings.sortBy === option.id} {#if $albumViewSettings.sortOrder === SortOrder.Desc} diff --git a/web/src/lib/components/album-page/albums-table-row.svelte b/web/src/lib/components/album-page/albums-table-row.svelte index 3e9027de3d..c900930f8a 100644 --- a/web/src/lib/components/album-page/albums-table-row.svelte +++ b/web/src/lib/components/album-page/albums-table-row.svelte @@ -9,9 +9,12 @@ import Icon from '$lib/components/elements/icon.svelte'; import { t } from 'svelte-i18n'; - export let album: AlbumResponseDto; - export let onShowContextMenu: ((position: ContextMenuPosition, album: AlbumResponseDto) => unknown) | undefined = - undefined; + interface Props { + album: AlbumResponseDto; + onShowContextMenu?: ((position: ContextMenuPosition, album: AlbumResponseDto) => unknown) | undefined; + } + + let { album, onShowContextMenu = undefined }: Props = $props(); const showContextMenu = (position: ContextMenuPosition) => { onShowContextMenu?.(position, album); @@ -20,12 +23,17 @@ const dateLocaleString = (dateString: string) => { return new Date(dateString).toLocaleDateString($locale, dateFormats.album); }; + + const oncontextmenu = (event: MouseEvent) => { + event.preventDefault(); + showContextMenu({ x: event.x, y: event.y }); + }; </script> <tr class="flex h-[50px] w-full place-items-center border-[3px] border-transparent p-2 text-center odd:bg-immich-gray even:bg-immich-bg hover:cursor-pointer hover:border-immich-primary/75 odd:dark:bg-immich-dark-gray/75 even:dark:bg-immich-dark-gray/50 dark:hover:border-immich-dark-primary/75 md:p-5" - on:click={() => goto(`${AppRoute.ALBUMS}/${album.id}`)} - on:contextmenu|preventDefault={(e) => showContextMenu({ x: e.x, y: e.y })} + onclick={() => goto(`${AppRoute.ALBUMS}/${album.id}`)} + {oncontextmenu} > <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%] items-center"> {album.albumName} diff --git a/web/src/lib/components/album-page/albums-table.svelte b/web/src/lib/components/album-page/albums-table.svelte index d9ffe8595b..bd7c7fd7f5 100644 --- a/web/src/lib/components/album-page/albums-table.svelte +++ b/web/src/lib/components/album-page/albums-table.svelte @@ -15,10 +15,13 @@ } from '$lib/utils/album-utils'; import { t } from 'svelte-i18n'; - export let groupedAlbums: AlbumGroup[]; - export let albumGroupOption: string = AlbumGroupBy.None; - export let onShowContextMenu: ((position: ContextMenuPosition, album: AlbumResponseDto) => unknown) | undefined = - undefined; + interface Props { + groupedAlbums: AlbumGroup[]; + albumGroupOption?: string; + onShowContextMenu?: ((position: ContextMenuPosition, album: AlbumResponseDto) => unknown) | undefined; + } + + let { groupedAlbums, albumGroupOption = AlbumGroupBy.None, onShowContextMenu }: Props = $props(); </script> <table class="mt-2 w-full text-left"> @@ -46,7 +49,7 @@ > <tr class="flex w-full place-items-center p-2 md:pl-5 md:pr-5 md:pt-3 md:pb-3" - on:click={() => toggleAlbumGroupCollapsing(albumGroup.id)} + onclick={() => toggleAlbumGroupCollapsing(albumGroup.id)} aria-expanded={!isCollapsed} > <td class="text-md text-left -mb-1"> 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 ee98d5a821..778943af3a 100644 --- a/web/src/lib/components/album-page/share-info-modal.svelte +++ b/web/src/lib/components/album-page/share-info-modal.svelte @@ -18,15 +18,19 @@ import { t } from 'svelte-i18n'; import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte'; - export let album: AlbumResponseDto; - export let onClose: () => void; - export let onRemove: (userId: string) => void; - export let onRefreshAlbum: () => void; + interface Props { + album: AlbumResponseDto; + onClose: () => void; + onRemove: (userId: string) => void; + onRefreshAlbum: () => void; + } - let currentUser: UserResponseDto; - let selectedRemoveUser: UserResponseDto | null = null; + let { album, onClose, onRemove, onRefreshAlbum }: Props = $props(); - $: isOwned = currentUser?.id == album.ownerId; + let currentUser: UserResponseDto | undefined = $state(); + let selectedRemoveUser: UserResponseDto | null = $state(null); + + let isOwned = $derived(currentUser?.id == album.ownerId); onMount(async () => { try { @@ -123,7 +127,7 @@ {:else if user.id == currentUser?.id} <button type="button" - on:click={() => (selectedRemoveUser = user)} + onclick={() => (selectedRemoveUser = user)} class="text-sm font-medium text-immich-primary transition-colors hover:text-immich-primary/75 dark:text-immich-dark-primary" >{$t('leave')}</button > 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 ee0a5c7410..fca244ac75 100644 --- a/web/src/lib/components/album-page/user-selection-modal.svelte +++ b/web/src/lib/components/album-page/user-selection-modal.svelte @@ -18,13 +18,17 @@ import UserAvatar from '../shared-components/user-avatar.svelte'; import { t } from 'svelte-i18n'; - export let album: AlbumResponseDto; - export let onClose: () => void; - export let onSelect: (selectedUsers: AlbumUserAddDto[]) => void; - export let onShare: () => void; + interface Props { + album: AlbumResponseDto; + onClose: () => void; + onSelect: (selectedUsers: AlbumUserAddDto[]) => void; + onShare: () => void; + } - let users: UserResponseDto[] = []; - let selectedUsers: Record<string, { user: UserResponseDto; role: AlbumUserRole }> = {}; + let { album, onClose, onSelect, onShare }: Props = $props(); + + let users: UserResponseDto[] = $state([]); + let selectedUsers: Record<string, { user: UserResponseDto; role: AlbumUserRole }> = $state({}); const roleOptions: Array<{ title: string; value: AlbumUserRole | 'none'; icon?: string }> = [ { title: $t('role_editor'), value: AlbumUserRole.Editor, icon: mdiPencil }, @@ -32,7 +36,7 @@ { title: $t('remove_user'), value: 'none' }, ]; - let sharedLinks: SharedLinkResponseDto[] = []; + let sharedLinks: SharedLinkResponseDto[] = $state([]); onMount(async () => { await getSharedLinks(); const data = await searchUsers(); @@ -121,11 +125,7 @@ {#each users as user} {#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" - on:click={() => handleToggle(user)} - class="flex w-full place-items-center gap-4 p-4" - > + <button type="button" onclick={() => handleToggle(user)} class="flex w-full place-items-center gap-4 p-4"> <UserAvatar {user} size="md" /> <div class="text-left flex-grow"> <p class="text-immich-fg dark:text-immich-dark-fg"> @@ -150,7 +150,7 @@ fullwidth rounded="full" disabled={Object.keys(selectedUsers).length === 0} - on:click={() => + onclick={() => onSelect(Object.values(selectedUsers).map(({ user, ...rest }) => ({ userId: user.id, ...rest })))} >{$t('add')}</Button > @@ -163,7 +163,7 @@ <button type="button" class="flex flex-col place-content-center place-items-center gap-2 hover:cursor-pointer" - on:click={onShare} + onclick={onShare} > <Icon path={mdiLink} size={24} /> <p class="text-sm">{$t('create_link')}</p> diff --git a/web/src/lib/components/asset-viewer/actions/add-to-album-action.svelte b/web/src/lib/components/asset-viewer/actions/add-to-album-action.svelte index cd4e8091af..ab0da059d0 100644 --- a/web/src/lib/components/asset-viewer/actions/add-to-album-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/add-to-album-action.svelte @@ -9,11 +9,15 @@ import { mdiImageAlbum, mdiShareVariantOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let asset: AssetResponseDto; - export let onAction: OnAction; - export let shared = false; + interface Props { + asset: AssetResponseDto; + onAction: OnAction; + shared?: boolean; + } - let showSelectionModal = false; + let { asset, onAction, shared = false }: Props = $props(); + + let showSelectionModal = $state(false); const handleAddToNewAlbum = async (albumName: string) => { showSelectionModal = false; diff --git a/web/src/lib/components/asset-viewer/actions/archive-action.svelte b/web/src/lib/components/asset-viewer/actions/archive-action.svelte index 3e2c453f39..6337b27892 100644 --- a/web/src/lib/components/asset-viewer/actions/archive-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/archive-action.svelte @@ -8,8 +8,12 @@ import { mdiArchiveArrowDownOutline, mdiArchiveArrowUpOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let asset: AssetResponseDto; - export let onAction: OnAction; + interface Props { + asset: AssetResponseDto; + onAction: OnAction; + } + + let { asset, onAction }: Props = $props(); const onArchive = async () => { const updatedAsset = await toggleArchive(asset); diff --git a/web/src/lib/components/asset-viewer/actions/close-action.svelte b/web/src/lib/components/asset-viewer/actions/close-action.svelte index 647ad61e4f..26cb81edd8 100644 --- a/web/src/lib/components/asset-viewer/actions/close-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/close-action.svelte @@ -4,9 +4,13 @@ import { mdiArrowLeft } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let onClose: () => void; + interface Props { + onClose: () => void; + } + + let { onClose }: Props = $props(); </script> <svelte:window use:shortcut={{ shortcut: { key: 'Escape' }, onShortcut: onClose }} /> -<CircleIconButton color="opaque" icon={mdiArrowLeft} title={$t('go_back')} on:click={onClose} /> +<CircleIconButton color="opaque" icon={mdiArrowLeft} title={$t('go_back')} onclick={onClose} /> diff --git a/web/src/lib/components/asset-viewer/actions/delete-action.svelte b/web/src/lib/components/asset-viewer/actions/delete-action.svelte index ae5f83c456..c0f163634a 100644 --- a/web/src/lib/components/asset-viewer/actions/delete-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/delete-action.svelte @@ -16,10 +16,14 @@ import { t } from 'svelte-i18n'; import type { OnAction } from './action'; - export let asset: AssetResponseDto; - export let onAction: OnAction; + interface Props { + asset: AssetResponseDto; + onAction: OnAction; + } - let showConfirmModal = false; + let { asset, onAction }: Props = $props(); + + let showConfirmModal = $state(false); const trashOrDelete = async (force = false) => { if (force || !$featureFlags.trash) { @@ -77,7 +81,7 @@ color="opaque" icon={asset.isTrashed ? mdiDeleteForeverOutline : mdiDeleteOutline} title={asset.isTrashed ? $t('permanently_delete') : $t('delete')} - on:click={() => trashOrDelete(asset.isTrashed)} + onclick={() => trashOrDelete(asset.isTrashed)} /> {#if showConfirmModal} diff --git a/web/src/lib/components/asset-viewer/actions/download-action.svelte b/web/src/lib/components/asset-viewer/actions/download-action.svelte index 88c0eeadf2..d7f4f56352 100644 --- a/web/src/lib/components/asset-viewer/actions/download-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/download-action.svelte @@ -7,8 +7,12 @@ import { mdiFolderDownloadOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let asset: AssetResponseDto; - export let menuItem = false; + interface Props { + asset: AssetResponseDto; + menuItem?: boolean; + } + + let { asset, menuItem = false }: Props = $props(); const onDownloadFile = () => downloadFile(asset); </script> @@ -16,7 +20,7 @@ <svelte:window use:shortcut={{ shortcut: { key: 'd', shift: true }, onShortcut: onDownloadFile }} /> {#if !menuItem} - <CircleIconButton color="opaque" icon={mdiFolderDownloadOutline} title={$t('download')} on:click={onDownloadFile} /> + <CircleIconButton color="opaque" icon={mdiFolderDownloadOutline} title={$t('download')} onclick={onDownloadFile} /> {:else} <MenuOption icon={mdiFolderDownloadOutline} text={$t('download')} onClick={onDownloadFile} /> {/if} diff --git a/web/src/lib/components/asset-viewer/actions/favorite-action.svelte b/web/src/lib/components/asset-viewer/actions/favorite-action.svelte index 488ed7ecb2..0cc3188d51 100644 --- a/web/src/lib/components/asset-viewer/actions/favorite-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/favorite-action.svelte @@ -12,8 +12,12 @@ import { t } from 'svelte-i18n'; import type { OnAction } from './action'; - export let asset: AssetResponseDto; - export let onAction: OnAction; + interface Props { + asset: AssetResponseDto; + onAction: OnAction; + } + + let { asset, onAction }: Props = $props(); const toggleFavorite = async () => { try { @@ -24,7 +28,8 @@ }, }); - asset.isFavorite = data.isFavorite; + asset = { ...asset, isFavorite: data.isFavorite }; + onAction({ type: asset.isFavorite ? AssetAction.FAVORITE : AssetAction.UNFAVORITE, asset }); notificationController.show({ @@ -43,5 +48,5 @@ color="opaque" icon={asset.isFavorite ? mdiHeart : mdiHeartOutline} title={asset.isFavorite ? $t('unfavorite') : $t('to_favorite')} - on:click={toggleFavorite} + onclick={toggleFavorite} /> diff --git a/web/src/lib/components/asset-viewer/actions/motion-photo-action.svelte b/web/src/lib/components/asset-viewer/actions/motion-photo-action.svelte index fd519a05d4..f629a42db7 100644 --- a/web/src/lib/components/asset-viewer/actions/motion-photo-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/motion-photo-action.svelte @@ -3,13 +3,17 @@ import { mdiMotionPauseOutline, mdiPlaySpeed } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let isPlaying: boolean; - export let onClick: (shouldPlay: boolean) => void; + interface Props { + isPlaying: boolean; + onClick: (shouldPlay: boolean) => void; + } + + let { isPlaying, onClick }: Props = $props(); </script> <CircleIconButton color="opaque" icon={isPlaying ? mdiMotionPauseOutline : mdiPlaySpeed} title={isPlaying ? $t('stop_motion_photo') : $t('play_motion_photo')} - on:click={() => onClick(!isPlaying)} + onclick={() => onClick(!isPlaying)} /> diff --git a/web/src/lib/components/asset-viewer/actions/next-asset-action.svelte b/web/src/lib/components/asset-viewer/actions/next-asset-action.svelte index cc074f3b6c..355f816a6b 100644 --- a/web/src/lib/components/asset-viewer/actions/next-asset-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/next-asset-action.svelte @@ -5,7 +5,11 @@ import { t } from 'svelte-i18n'; import NavigationArea from '../navigation-area.svelte'; - export let onNextAsset: () => void; + interface Props { + onNextAsset: () => void; + } + + let { onNextAsset }: Props = $props(); </script> <svelte:window diff --git a/web/src/lib/components/asset-viewer/actions/previous-asset-action.svelte b/web/src/lib/components/asset-viewer/actions/previous-asset-action.svelte index 9f8c638e12..1770bc673a 100644 --- a/web/src/lib/components/asset-viewer/actions/previous-asset-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/previous-asset-action.svelte @@ -5,7 +5,11 @@ import { t } from 'svelte-i18n'; import NavigationArea from '../navigation-area.svelte'; - export let onPreviousAsset: () => void; + interface Props { + onPreviousAsset: () => void; + } + + let { onPreviousAsset }: Props = $props(); </script> <svelte:window diff --git a/web/src/lib/components/asset-viewer/actions/restore-action.svelte b/web/src/lib/components/asset-viewer/actions/restore-action.svelte index c000dad9a1..abcae5c4c9 100644 --- a/web/src/lib/components/asset-viewer/actions/restore-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/restore-action.svelte @@ -11,8 +11,12 @@ import { t } from 'svelte-i18n'; import type { OnAction } from './action'; - export let asset: AssetResponseDto; - export let onAction: OnAction; + interface Props { + asset: AssetResponseDto; + onAction: OnAction; + } + + let { asset = $bindable(), onAction }: Props = $props(); const handleRestoreAsset = async () => { try { diff --git a/web/src/lib/components/asset-viewer/actions/set-album-cover-action.svelte b/web/src/lib/components/asset-viewer/actions/set-album-cover-action.svelte index f20c4872bc..c015c224ff 100644 --- a/web/src/lib/components/asset-viewer/actions/set-album-cover-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/set-album-cover-action.svelte @@ -9,8 +9,12 @@ import { mdiImageOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let asset: AssetResponseDto; - export let album: AlbumResponseDto; + interface Props { + asset: AssetResponseDto; + album: AlbumResponseDto; + } + + let { asset, album }: Props = $props(); const handleUpdateThumbnail = async () => { try { diff --git a/web/src/lib/components/asset-viewer/actions/set-profile-picture-action.svelte b/web/src/lib/components/asset-viewer/actions/set-profile-picture-action.svelte index 23c147815c..a35ff11c48 100644 --- a/web/src/lib/components/asset-viewer/actions/set-profile-picture-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/set-profile-picture-action.svelte @@ -6,9 +6,13 @@ import { mdiAccountCircleOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let asset: AssetResponseDto; + interface Props { + asset: AssetResponseDto; + } - let showProfileImageCrop = false; + let { asset }: Props = $props(); + + let showProfileImageCrop = $state(false); </script> <MenuOption diff --git a/web/src/lib/components/asset-viewer/actions/share-action.svelte b/web/src/lib/components/asset-viewer/actions/share-action.svelte index f0b2177128..6fd5aa456e 100644 --- a/web/src/lib/components/asset-viewer/actions/share-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/share-action.svelte @@ -6,17 +6,16 @@ import { mdiShareVariantOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let asset: AssetResponseDto; + interface Props { + asset: AssetResponseDto; + } - let showModal = false; + let { asset }: Props = $props(); + + let showModal = $state(false); </script> -<CircleIconButton - color="opaque" - icon={mdiShareVariantOutline} - on:click={() => (showModal = true)} - title={$t('share')} -/> +<CircleIconButton color="opaque" icon={mdiShareVariantOutline} onclick={() => (showModal = true)} title={$t('share')} /> {#if showModal} <Portal target="body"> diff --git a/web/src/lib/components/asset-viewer/actions/show-detail-action.svelte b/web/src/lib/components/asset-viewer/actions/show-detail-action.svelte index 66e5d0e10f..5613114cad 100644 --- a/web/src/lib/components/asset-viewer/actions/show-detail-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/show-detail-action.svelte @@ -4,9 +4,13 @@ import { mdiInformationOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let onShowDetail: () => void; + interface Props { + onShowDetail: () => void; + } + + let { onShowDetail }: Props = $props(); </script> <svelte:window use:shortcut={{ shortcut: { key: 'i' }, onShortcut: onShowDetail }} /> -<CircleIconButton color="opaque" icon={mdiInformationOutline} on:click={onShowDetail} title={$t('info')} /> +<CircleIconButton color="opaque" icon={mdiInformationOutline} onclick={onShowDetail} title={$t('info')} /> diff --git a/web/src/lib/components/asset-viewer/actions/unstack-action.svelte b/web/src/lib/components/asset-viewer/actions/unstack-action.svelte index bd18e0e8bf..f2a50cce13 100644 --- a/web/src/lib/components/asset-viewer/actions/unstack-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/unstack-action.svelte @@ -7,8 +7,12 @@ import { t } from 'svelte-i18n'; import type { OnAction } from './action'; - export let stack: StackResponseDto; - export let onAction: OnAction; + interface Props { + stack: StackResponseDto; + onAction: OnAction; + } + + let { stack, onAction }: Props = $props(); const handleUnstack = async () => { const unstackedAssets = await deleteStack([stack.id]); diff --git a/web/src/lib/components/asset-viewer/activity-status.svelte b/web/src/lib/components/asset-viewer/activity-status.svelte index fe6ee79363..494c6fcbf7 100644 --- a/web/src/lib/components/asset-viewer/activity-status.svelte +++ b/web/src/lib/components/asset-viewer/activity-status.svelte @@ -4,20 +4,24 @@ import { mdiCommentOutline, mdiHeart, mdiHeartOutline } from '@mdi/js'; import Icon from '../elements/icon.svelte'; - export let isLiked: ActivityResponseDto | null; - export let numberOfComments: number | undefined; - export let disabled: boolean; - export let onOpenActivityTab: () => void; - export let onFavorite: () => void; + interface Props { + isLiked: ActivityResponseDto | null; + numberOfComments: number | undefined; + disabled: boolean; + onOpenActivityTab: () => void; + onFavorite: () => void; + } + + let { isLiked, numberOfComments, disabled, onOpenActivityTab, onFavorite }: Props = $props(); </script> <div class="w-full flex p-4 text-white items-center justify-center rounded-full gap-5 bg-immich-dark-bg bg-opacity-60"> - <button type="button" class={disabled ? 'cursor-not-allowed' : ''} on:click={onFavorite} {disabled}> + <button type="button" class={disabled ? 'cursor-not-allowed' : ''} onclick={onFavorite} {disabled}> <div class="items-center justify-center"> <Icon path={isLiked ? mdiHeart : mdiHeartOutline} size={24} /> </div> </button> - <button type="button" on:click={onOpenActivityTab}> + <button type="button" onclick={onOpenActivityTab}> <div class="flex gap-2 items-center justify-center"> <Icon path={mdiCommentOutline} class="scale-x-[-1]" size={24} /> {#if numberOfComments} diff --git a/web/src/lib/components/asset-viewer/activity-viewer.svelte b/web/src/lib/components/asset-viewer/activity-viewer.svelte index 4f4fdb2649..34940aee56 100644 --- a/web/src/lib/components/asset-viewer/activity-viewer.svelte +++ b/web/src/lib/components/asset-viewer/activity-viewer.svelte @@ -47,40 +47,45 @@ return relativeFormatter.format(Math.trunc(diff.as(unit)), unit); }; - export let reactions: ActivityResponseDto[]; - export let user: UserResponseDto; - export let assetId: string | undefined = undefined; - export let albumId: string; - export let assetType: AssetTypeEnum | undefined = undefined; - export let albumOwnerId: string; - export let disabled: boolean; - export let isLiked: ActivityResponseDto | null; - export let onDeleteComment: () => void; - export let onDeleteLike: () => void; - export let onAddComment: () => void; - export let onClose: () => void; - - let textArea: HTMLTextAreaElement; - let innerHeight: number; - let activityHeight: number; - let chatHeight: number; - let divHeight: number; - let previousAssetId: string | undefined = assetId; - let message = ''; - let isSendingMessage = false; - - $: { - if (innerHeight && activityHeight) { - divHeight = innerHeight - activityHeight; - } + interface Props { + reactions: ActivityResponseDto[]; + user: UserResponseDto; + assetId?: string | undefined; + albumId: string; + assetType?: AssetTypeEnum | undefined; + albumOwnerId: string; + disabled: boolean; + isLiked: ActivityResponseDto | null; + onDeleteComment: () => void; + onDeleteLike: () => void; + onAddComment: () => void; + onClose: () => void; } - $: { - if (assetId && previousAssetId != assetId) { - handlePromiseError(getReactions()); - previousAssetId = assetId; - } - } + let { + reactions = $bindable(), + user, + assetId = undefined, + albumId, + assetType = undefined, + albumOwnerId, + disabled, + isLiked, + onDeleteComment, + onDeleteLike, + onAddComment, + onClose, + }: Props = $props(); + + let textArea: HTMLTextAreaElement | undefined = $state(); + let innerHeight: number = $state(0); + let activityHeight: number = $state(0); + let chatHeight: number = $state(0); + let divHeight: number = $state(0); + let previousAssetId: string | undefined = $state(assetId); + let message = $state(''); + let isSendingMessage = $state(false); + onMount(async () => { await getReactions(); }); @@ -136,7 +141,11 @@ activityCreateDto: { albumId, assetId, type: ReactionType.Comment, comment: message }, }); reactions.push(data); - textArea.style.height = '18px'; + + if (textArea) { + textArea.style.height = '18px'; + } + message = ''; onAddComment(); // Re-render the activity feed @@ -148,6 +157,22 @@ } isSendingMessage = false; }; + $effect(() => { + if (innerHeight && activityHeight) { + divHeight = innerHeight - activityHeight; + } + }); + $effect(() => { + if (assetId && previousAssetId != assetId) { + handlePromiseError(getReactions()); + previousAssetId = assetId; + } + }); + + const onsubmit = async (event: Event) => { + event.preventDefault(); + await handleSendComment(); + }; </script> <div class="overflow-y-hidden relative h-full" bind:offsetHeight={innerHeight}> @@ -157,7 +182,7 @@ bind:clientHeight={activityHeight} > <div class="flex place-items-center gap-2"> - <CircleIconButton on:click={onClose} icon={mdiClose} title={$t('close')} /> + <CircleIconButton onclick={onClose} icon={mdiClose} title={$t('close')} /> <p class="text-lg text-immich-fg dark:text-immich-dark-fg">{$t('activity')}</p> </div> @@ -277,7 +302,7 @@ <div> <UserAvatar {user} size="md" showTitle={false} /> </div> - <form class="flex w-full max-h-56 gap-1" on:submit|preventDefault={() => handleSendComment()}> + <form class="flex w-full max-h-56 gap-1" {onsubmit}> <div class="flex w-full items-center gap-4"> <textarea {disabled} @@ -285,7 +310,7 @@ bind:value={message} use:autoGrowHeight={'5px'} placeholder={disabled ? $t('comments_are_disabled') : $t('say_something')} - on:input={() => autoGrowHeight(textArea, '5px')} + oninput={() => autoGrowHeight(textArea, '5px')} use:shortcut={{ shortcut: { key: 'Enter' }, onShortcut: () => handleSendComment(), @@ -308,7 +333,7 @@ size="15" icon={mdiSend} class="dark:text-immich-dark-gray" - on:click={() => handleSendComment()} + onclick={() => handleSendComment()} /> </div> {/if} diff --git a/web/src/lib/components/asset-viewer/album-list-item-details.svelte b/web/src/lib/components/asset-viewer/album-list-item-details.svelte index ecc38b7c24..08dd105ca1 100644 --- a/web/src/lib/components/asset-viewer/album-list-item-details.svelte +++ b/web/src/lib/components/asset-viewer/album-list-item-details.svelte @@ -2,7 +2,11 @@ import type { AlbumResponseDto } from '@immich/sdk'; import { t } from 'svelte-i18n'; - export let album: AlbumResponseDto; + interface Props { + album: AlbumResponseDto; + } + + let { album }: Props = $props(); </script> <span>{$t('items_count', { values: { count: album.assetCount } })}</span> diff --git a/web/src/lib/components/asset-viewer/album-list-item.svelte b/web/src/lib/components/asset-viewer/album-list-item.svelte index 8e9f6f6b5a..43352a4904 100644 --- a/web/src/lib/components/asset-viewer/album-list-item.svelte +++ b/web/src/lib/components/asset-viewer/album-list-item.svelte @@ -4,15 +4,19 @@ import { normalizeSearchString } from '$lib/utils/string-utils.js'; import AlbumListItemDetails from './album-list-item-details.svelte'; - export let album: AlbumResponseDto; - export let searchQuery = ''; - export let onAlbumClick: () => void; + interface Props { + album: AlbumResponseDto; + searchQuery?: string; + onAlbumClick: () => void; + } - let albumNameArray: string[] = ['', '', '']; + let { album, searchQuery = '', onAlbumClick }: Props = $props(); + + let albumNameArray: string[] = $state(['', '', '']); // This part of the code is responsible for splitting album name into 3 parts where part 2 is the search query // It is used to highlight the search query in the album name - $: { + $effect(() => { let { albumName } = album; let findIndex = normalizeSearchString(albumName).indexOf(normalizeSearchString(searchQuery)); let findLength = searchQuery.length; @@ -21,12 +25,12 @@ albumName.slice(findIndex, findIndex + findLength), albumName.slice(findIndex + findLength), ]; - } + }); </script> <button type="button" - on:click={onAlbumClick} + onclick={onAlbumClick} class="flex w-full gap-4 px-6 py-2 text-left transition-colors hover:bg-gray-200 dark:hover:bg-gray-700 rounded-xl" > <span class="h-12 w-12 shrink-0 rounded-xl bg-slate-300"> diff --git a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte index d142c43f20..7972ff6c72 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte @@ -44,25 +44,44 @@ } from '@mdi/js'; import { canCopyImageToClipboard } from '$lib/utils/asset-utils'; import { t } from 'svelte-i18n'; + import type { Snippet } from 'svelte'; - export let asset: AssetResponseDto; - export let album: AlbumResponseDto | null = null; - export let stack: StackResponseDto | null = null; - export let showDetailButton: boolean; - export let showSlideshow = false; - export let onZoomImage: () => void; - export let onCopyImage: () => void; - export let onAction: OnAction; - export let onRunJob: (name: AssetJobName) => void; - export let onPlaySlideshow: () => void; - export let onShowDetail: () => void; - // export let showEditorHandler: () => void; - export let onClose: () => void; + interface Props { + asset: AssetResponseDto; + album?: AlbumResponseDto | null; + stack?: StackResponseDto | null; + showDetailButton: boolean; + showSlideshow?: boolean; + onZoomImage: () => void; + onCopyImage?: () => Promise<void>; + onAction: OnAction; + onRunJob: (name: AssetJobName) => void; + onPlaySlideshow: () => void; + onShowDetail: () => void; + // export let showEditorHandler: () => void; + onClose: () => void; + motionPhoto?: Snippet; + } + + let { + asset, + album = null, + stack = null, + showDetailButton, + showSlideshow = false, + onZoomImage, + onCopyImage, + onAction, + onRunJob, + onPlaySlideshow, + onShowDetail, + onClose, + motionPhoto, + }: Props = $props(); const sharedLink = getSharedLink(); - $: isOwner = $user && asset.ownerId === $user?.id; - // svelte-ignore reactive_declaration_non_reactive_property - $: showDownloadButton = sharedLink ? sharedLink.allowDownload : !asset.isOffline; + let isOwner = $derived($user && asset.ownerId === $user?.id); + let showDownloadButton = $derived(sharedLink ? sharedLink.allowDownload : !asset.isOffline); // $: showEditorButton = // isOwner && // asset.type === AssetTypeEnum.Image && @@ -88,10 +107,10 @@ <ShareAction {asset} /> {/if} {#if asset.isOffline} - <CircleIconButton color="alert" icon={mdiAlertOutline} on:click={onShowDetail} title={$t('asset_offline')} /> + <CircleIconButton color="alert" icon={mdiAlertOutline} onclick={onShowDetail} title={$t('asset_offline')} /> {/if} {#if asset.livePhotoVideoId} - <slot name="motion-photo" /> + {@render motionPhoto?.()} {/if} {#if asset.type === AssetTypeEnum.Image} <CircleIconButton @@ -99,11 +118,11 @@ hideMobile={true} icon={$photoZoomState && $photoZoomState.currentZoom > 1 ? mdiMagnifyMinusOutline : mdiMagnifyPlusOutline} title={$t('zoom_image')} - on:click={onZoomImage} + onclick={onZoomImage} /> {/if} {#if canCopyImageToClipboard() && asset.type === AssetTypeEnum.Image} - <CircleIconButton color="opaque" icon={mdiContentCopy} title={$t('copy_image')} on:click={onCopyImage} /> + <CircleIconButton color="opaque" icon={mdiContentCopy} title={$t('copy_image')} onclick={() => onCopyImage?.()} /> {/if} {#if !isOwner && showDownloadButton} @@ -122,7 +141,7 @@ color="opaque" hideMobile={true} icon={mdiImageEditOutline} - on:click={showEditorHandler} + onclick={showEditorHandler} title={$t('editor')} /> {/if} --> diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index 4caeab6dd4..988707cfa7 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -48,18 +48,37 @@ import SlideshowBar from './slideshow-bar.svelte'; import VideoViewer from './video-wrapper-viewer.svelte'; - export let assetStore: AssetStore | null = null; - export let asset: AssetResponseDto; - export let preloadAssets: AssetResponseDto[] = []; - export let showNavigation = true; - export let withStacked = false; - export let isShared = false; - export let album: AlbumResponseDto | null = null; - export let onAction: OnAction | undefined = undefined; - export let reactions: ActivityResponseDto[] = []; - export let onClose: (dto: { asset: AssetResponseDto }) => void; - export let onNext: () => void; - export let onPrevious: () => void; + interface Props { + assetStore?: AssetStore | null; + asset: AssetResponseDto; + preloadAssets?: AssetResponseDto[]; + showNavigation?: boolean; + withStacked?: boolean; + isShared?: boolean; + album?: AlbumResponseDto | null; + onAction?: OnAction | undefined; + reactions?: ActivityResponseDto[]; + onClose: (dto: { asset: AssetResponseDto }) => void; + onNext: () => void; + onPrevious: () => void; + copyImage?: () => Promise<void>; + } + + let { + assetStore = null, + asset = $bindable(), + preloadAssets = $bindable([]), + showNavigation = true, + withStacked = false, + isShared = false, + album = null, + onAction = undefined, + reactions = $bindable([]), + onClose, + onNext, + onPrevious, + copyImage = $bindable(), + }: Props = $props(); const { setAsset } = assetViewingStore; const { @@ -70,26 +89,23 @@ slideshowTransition, } = slideshowStore; - let appearsInAlbums: AlbumResponseDto[] = []; - let shouldPlayMotionPhoto = false; + let appearsInAlbums: AlbumResponseDto[] = $state([]); + let shouldPlayMotionPhoto = $state(false); let sharedLink = getSharedLink(); let enableDetailPanel = asset.hasMetadata; let slideshowStateUnsubscribe: () => void; let shuffleSlideshowUnsubscribe: () => void; - let previewStackedAsset: AssetResponseDto | undefined; - let isShowActivity = false; - let isShowEditor = false; - let isLiked: ActivityResponseDto | null = null; - let numberOfComments: number; - let fullscreenElement: Element; + let previewStackedAsset: AssetResponseDto | undefined = $state(); + let isShowActivity = $state(false); + let isShowEditor = $state(false); + let isLiked: ActivityResponseDto | null = $state(null); + let numberOfComments = $state(0); + let fullscreenElement = $state<Element>(); let unsubscribes: (() => void)[] = []; - let selectedEditType: string = ''; - let stack: StackResponseDto | null = null; + let selectedEditType: string = $state(''); + let stack: StackResponseDto | null = $state(null); - let zoomToggle = () => void 0; - let copyImage: () => Promise<void>; - - $: isFullScreen = fullscreenElement !== null; + let zoomToggle = $state(() => void 0); const refreshStack = async () => { if (isSharedLink()) { @@ -109,16 +125,6 @@ } }; - $: if (asset) { - handlePromiseError(refreshStack()); - } - - $: { - if (album && !album.isActivityEnabled && numberOfComments === 0) { - isShowActivity = false; - } - } - const handleAddComment = () => { numberOfComments++; updateNumberOfComments(1); @@ -184,13 +190,6 @@ } }; - $: { - if (isShared && asset.id) { - handlePromiseError(getFavorite()); - handlePromiseError(getNumberOfComments()); - } - } - onMount(async () => { unsubscribes.push( websocketEvents.on('on_upload_success', onAssetUpdate), @@ -233,12 +232,6 @@ } }); - $: { - if (asset.id && !sharedLink) { - handlePromiseError(handleGetAllAlbums()); - } - } - const handleGetAllAlbums = async () => { if (isSharedLink()) { return; @@ -337,7 +330,7 @@ * Slide show mode */ - let assetViewerHtmlElement: HTMLElement; + let assetViewerHtmlElement = $state<HTMLElement>(); const slideshowHistory = new SlideshowHistory((asset) => { setAsset(asset); @@ -352,7 +345,7 @@ const handlePlaySlideshow = async () => { try { - await assetViewerHtmlElement.requestFullscreen?.(); + await assetViewerHtmlElement?.requestFullscreen?.(); } catch (error) { handleError(error, $t('errors.unable_to_enter_fullscreen')); $slideshowState = SlideshowState.StopSlideshow; @@ -395,6 +388,28 @@ const handleUpdateSelectedEditType = (type: string) => { selectedEditType = type; }; + let isFullScreen = $derived(fullscreenElement !== null); + $effect(() => { + if (asset) { + handlePromiseError(refreshStack()); + } + }); + $effect(() => { + if (album && !album.isActivityEnabled && numberOfComments === 0) { + isShowActivity = false; + } + }); + $effect(() => { + if (isShared && asset.id) { + handlePromiseError(getFavorite()); + handlePromiseError(getNumberOfComments()); + } + }); + $effect(() => { + if (asset.id && !sharedLink) { + handlePromiseError(handleGetAllAlbums()); + } + }); </script> <svelte:document bind:fullscreenElement /> @@ -421,11 +436,12 @@ onShowDetail={toggleDetailPanel} onClose={closeViewer} > - <MotionPhotoAction - slot="motion-photo" - isPlaying={shouldPlayMotionPhoto} - onClick={(shouldPlay) => (shouldPlayMotionPhoto = shouldPlay)} - /> + {#snippet motionPhoto()} + <MotionPhotoAction + isPlaying={shouldPlayMotionPhoto} + onClick={(shouldPlay) => (shouldPlayMotionPhoto = shouldPlay)} + /> + {/snippet} </AssetViewerNavBar> </div> {/if} @@ -442,7 +458,7 @@ <div class="z-[1000] absolute w-full flex"> <SlideshowBar {isFullScreen} - onSetToFullScreen={() => assetViewerHtmlElement.requestFullscreen?.()} + onSetToFullScreen={() => assetViewerHtmlElement?.requestFullscreen?.()} onPrevious={() => navigateAsset('previous')} onNext={() => navigateAsset('next')} onClose={() => ($slideshowState = SlideshowState.StopSlideshow)} @@ -460,7 +476,7 @@ {preloadAssets} onPreviousAsset={() => navigateAsset('previous')} onNextAsset={() => navigateAsset('next')} - on:close={closeViewer} + onClose={closeViewer} haveFadeTransition={false} {sharedLink} /> @@ -472,9 +488,9 @@ loopVideo={true} onPreviousAsset={() => navigateAsset('previous')} onNextAsset={() => navigateAsset('next')} - on:close={closeViewer} - on:onVideoEnded={() => navigateAsset()} - on:onVideoStarted={handleVideoStarted} + onClose={closeViewer} + onVideoEnded={() => navigateAsset()} + onVideoStarted={handleVideoStarted} /> {/if} {/key} @@ -489,8 +505,7 @@ loopVideo={$slideshowState !== SlideshowState.PlaySlideshow} onPreviousAsset={() => navigateAsset('previous')} onNextAsset={() => navigateAsset('next')} - on:close={closeViewer} - on:onVideoEnded={() => (shouldPlayMotionPhoto = false)} + onVideoEnded={() => (shouldPlayMotionPhoto = false)} /> {:else if asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR || (asset.originalPath && asset.originalPath .toLowerCase() @@ -506,7 +521,7 @@ {preloadAssets} onPreviousAsset={() => navigateAsset('previous')} onNextAsset={() => navigateAsset('next')} - on:close={closeViewer} + onClose={closeViewer} {sharedLink} haveFadeTransition={$slideshowState === SlideshowState.None || $slideshowTransition} /> @@ -519,9 +534,9 @@ loopVideo={$slideshowState !== SlideshowState.PlaySlideshow} onPreviousAsset={() => navigateAsset('previous')} onNextAsset={() => navigateAsset('next')} - on:close={closeViewer} - on:onVideoEnded={() => navigateAsset()} - on:onVideoStarted={handleVideoStarted} + onClose={closeViewer} + onVideoEnded={() => navigateAsset()} + onVideoStarted={handleVideoStarted} /> {/if} {#if $slideshowState === SlideshowState.None && isShared && ((album && album.isActivityEnabled) || numberOfComments > 0)} @@ -574,7 +589,7 @@ class="z-[1002] flex place-item-center place-content-center absolute bottom-0 w-full col-span-4 col-start-1 overflow-x-auto horizontal-scrollbar" > <div class="relative w-full whitespace-nowrap transition-all"> - {#each stackedAssets as stackedAsset, index (stackedAsset.id)} + {#each stackedAssets as stackedAsset (stackedAsset.id)} <div class="{stackedAsset.id == asset.id ? '-translate-y-[1px]' @@ -587,7 +602,6 @@ asset={stackedAsset} onClick={(stackedAsset) => { asset = stackedAsset; - preloadAssets = index + 1 >= stackedAssets.length ? [] : [stackedAssets[index + 1]]; }} onMouseEvent={({ isMouseOver }) => handleStackedAssetMouseEvent(isMouseOver, stackedAsset)} disableMouseOver diff --git a/web/src/lib/components/asset-viewer/detail-panel-description.svelte b/web/src/lib/components/asset-viewer/detail-panel-description.svelte index b916733476..0eba78b0c0 100644 --- a/web/src/lib/components/asset-viewer/detail-panel-description.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel-description.svelte @@ -8,14 +8,21 @@ import AutogrowTextarea from '$lib/components/shared-components/autogrow-textarea.svelte'; import { t } from 'svelte-i18n'; - export let asset: AssetResponseDto; - export let isOwner: boolean; + interface Props { + asset: AssetResponseDto; + isOwner: boolean; + } - $: description = asset.exifInfo?.description || ''; + let { asset, isOwner }: Props = $props(); + + let description = $derived(asset.exifInfo?.description || ''); const handleFocusOut = async (newDescription: string) => { try { await updateAsset({ id: asset.id, updateAssetDto: { description: newDescription } }); + + asset.exifInfo = { ...asset.exifInfo, description: newDescription }; + notificationController.show({ type: NotificationType.Info, message: $t('asset_description_updated'), @@ -23,7 +30,6 @@ } catch (error) { handleError(error, $t('cannot_update_the_description')); } - description = newDescription; }; </script> diff --git a/web/src/lib/components/asset-viewer/detail-panel-location.svelte b/web/src/lib/components/asset-viewer/detail-panel-location.svelte index 7d5d86b443..9e59243aa1 100644 --- a/web/src/lib/components/asset-viewer/detail-panel-location.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel-location.svelte @@ -7,10 +7,14 @@ import { mdiMapMarkerOutline, mdiPencil } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let isOwner: boolean; - export let asset: AssetResponseDto; + interface Props { + isOwner: boolean; + asset: AssetResponseDto; + } - let isShowChangeLocation = false; + let { isOwner, asset = $bindable() }: Props = $props(); + + let isShowChangeLocation = $state(false); async function handleConfirmChangeLocation(gps: { lng: number; lat: number }) { isShowChangeLocation = false; @@ -30,7 +34,7 @@ <button type="button" class="flex w-full text-left justify-between place-items-start gap-4 py-4" - on:click={() => (isOwner ? (isShowChangeLocation = true) : null)} + onclick={() => (isOwner ? (isShowChangeLocation = true) : null)} title={isOwner ? $t('edit_location') : ''} class:hover:dark:text-immich-dark-primary={isOwner} class:hover:text-immich-primary={isOwner} @@ -65,7 +69,7 @@ <button type="button" class="flex w-full text-left justify-between place-items-start gap-4 py-4 rounded-lg hover:dark:text-immich-dark-primary hover:text-immich-primary" - on:click={() => (isShowChangeLocation = true)} + onclick={() => (isShowChangeLocation = true)} title={$t('add_location')} > <div class="flex gap-4"> diff --git a/web/src/lib/components/asset-viewer/detail-panel-star-rating.svelte b/web/src/lib/components/asset-viewer/detail-panel-star-rating.svelte index b73fe71716..4c5bfd71a8 100644 --- a/web/src/lib/components/asset-viewer/detail-panel-star-rating.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel-star-rating.svelte @@ -6,10 +6,14 @@ import { handlePromiseError, isSharedLink } from '$lib/utils'; import { preferences } from '$lib/stores/user.store'; - export let asset: AssetResponseDto; - export let isOwner: boolean; + interface Props { + asset: AssetResponseDto; + isOwner: boolean; + } - $: rating = asset.exifInfo?.rating || 0; + let { asset, isOwner }: Props = $props(); + + let rating = $derived(asset.exifInfo?.rating || 0); const handleChangeRating = async (rating: number) => { try { diff --git a/web/src/lib/components/asset-viewer/detail-panel-tags.svelte b/web/src/lib/components/asset-viewer/detail-panel-tags.svelte index 449f61183f..c1175f5eb4 100644 --- a/web/src/lib/components/asset-viewer/detail-panel-tags.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel-tags.svelte @@ -9,12 +9,16 @@ import { mdiClose, mdiPlus } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let asset: AssetResponseDto; - export let isOwner: boolean; + interface Props { + asset: AssetResponseDto; + isOwner: boolean; + } - $: tags = asset.tags || []; + let { asset = $bindable(), isOwner }: Props = $props(); - let isOpen = false; + let tags = $derived(asset.tags || []); + + let isOpen = $state(false); const handleAdd = () => (isOpen = true); @@ -58,7 +62,7 @@ type="button" class="text-gray-100 dark:text-immich-dark-gray bg-immich-primary/95 dark:bg-immich-dark-primary/95 rounded-tr-full rounded-br-full place-items-center place-content-center pr-2 pl-1 py-1 hover:bg-immich-primary/80 dark:hover:bg-immich-dark-primary/80 transition-all" title="Remove tag" - on:click={() => handleRemove(tag.id)} + onclick={() => handleRemove(tag.id)} > <Icon path={mdiClose} /> </button> @@ -68,7 +72,7 @@ type="button" class="rounded-full bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 hover:text-gray-700 dark:hover:text-gray-200 flex place-items-center place-content-center gap-1 px-2 py-1" title="Add tag" - on:click={handleAdd} + onclick={handleAdd} > <span class="text-sm px-1 flex place-items-center place-content-center gap-1"><Icon path={mdiPlus} />Add</span> </button> diff --git a/web/src/lib/components/asset-viewer/detail-panel.svelte b/web/src/lib/components/asset-viewer/detail-panel.svelte index ab84896b7b..9908630233 100644 --- a/web/src/lib/components/asset-viewer/detail-panel.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel.svelte @@ -46,10 +46,14 @@ import AlbumListItemDetails from './album-list-item-details.svelte'; import Portal from '$lib/components/shared-components/portal/portal.svelte'; - export let asset: AssetResponseDto; - export let albums: AlbumResponseDto[] = []; - export let currentAlbum: AlbumResponseDto | null = null; - export let onClose: () => void; + interface Props { + asset: AssetResponseDto; + albums?: AlbumResponseDto[]; + currentAlbum?: AlbumResponseDto | null; + onClose: () => void; + } + + let { asset, albums = [], currentAlbum = null, onClose }: Props = $props(); const getDimensions = (exifInfo: ExifResponseDto) => { const { exifImageWidth: width, exifImageHeight: height } = exifInfo; @@ -60,11 +64,11 @@ return { width, height }; }; - let showAssetPath = false; - let showEditFaces = false; - let previousId: string; + let showAssetPath = $state(false); + let showEditFaces = $state(false); + let previousId: string | undefined = $state(); - $: { + $effect(() => { if (!previousId) { previousId = asset.id; } @@ -72,9 +76,9 @@ showEditFaces = false; previousId = asset.id; } - } + }); - $: isOwner = $user?.id === asset.ownerId; + let isOwner = $derived($user?.id === asset.ownerId); const handleNewAsset = async (newAsset: AssetResponseDto) => { // TODO: check if reloading asset data is necessary @@ -85,27 +89,30 @@ } }; - $: handlePromiseError(handleNewAsset(asset)); + $effect(() => { + handlePromiseError(handleNewAsset(asset)); + }); - $: latlng = (() => { - const lat = asset.exifInfo?.latitude; - const lng = asset.exifInfo?.longitude; + let latlng = $derived( + (() => { + const lat = asset.exifInfo?.latitude; + const lng = asset.exifInfo?.longitude; - if (lat && lng) { - return { lat: Number(lat.toFixed(7)), lng: Number(lng.toFixed(7)) }; - } - })(); + if (lat && lng) { + return { lat: Number(lat.toFixed(7)), lng: Number(lng.toFixed(7)) }; + } + })(), + ); - $: people = asset.people || []; - $: showingHiddenPeople = false; - - $: unassignedFaces = asset.unassignedFaces || []; - - $: timeZone = asset.exifInfo?.timeZone; - $: dateTime = + let people = $state(asset.people || []); + let unassignedFaces = $state(asset.unassignedFaces || []); + let showingHiddenPeople = $state(false); + let timeZone = $derived(asset.exifInfo?.timeZone); + let dateTime = $derived( timeZone && asset.exifInfo?.dateTimeOriginal ? fromDateTimeOriginal(asset.exifInfo.dateTimeOriginal, timeZone) - : fromLocalDateTime(asset.localDateTime); + : fromLocalDateTime(asset.localDateTime), + ); const getMegapixel = (width: number, height: number): number | undefined => { const megapixel = Math.round((height * width) / 1_000_000); @@ -127,7 +134,7 @@ const toggleAssetPath = () => (showAssetPath = !showAssetPath); - let isShowChangeDate = false; + let isShowChangeDate = $state(false); async function handleConfirmChangeDate(dateTimeOriginal: string) { isShowChangeDate = false; @@ -141,7 +148,7 @@ <section class="relative p-2 dark:bg-immich-dark-bg dark:text-immich-dark-fg"> <div class="flex place-items-center gap-2"> - <CircleIconButton icon={mdiClose} title={$t('close')} on:click={onClose} /> + <CircleIconButton icon={mdiClose} title={$t('close')} onclick={onClose} /> <p class="text-lg text-immich-fg dark:text-immich-dark-fg">{$t('info')}</p> </div> @@ -190,7 +197,7 @@ icon={showingHiddenPeople ? mdiEyeOff : mdiEye} padding="1" buttonSize="32" - on:click={() => (showingHiddenPeople = !showingHiddenPeople)} + onclick={() => (showingHiddenPeople = !showingHiddenPeople)} /> {/if} <CircleIconButton @@ -199,7 +206,7 @@ padding="1" size="20" buttonSize="32" - on:click={() => (showEditFaces = true)} + onclick={() => (showEditFaces = true)} /> </div> </div> @@ -212,10 +219,10 @@ href="{AppRoute.PEOPLE}/{person.id}?{QueryParameter.PREVIOUS_ROUTE}={currentAlbum?.id ? `${AppRoute.ALBUMS}/${currentAlbum?.id}` : AppRoute.PHOTOS}" - on:focus={() => ($boundingBoxesArray = people[index].faces)} - on:blur={() => ($boundingBoxesArray = [])} - on:mouseover={() => ($boundingBoxesArray = people[index].faces)} - on:mouseleave={() => ($boundingBoxesArray = [])} + onfocus={() => ($boundingBoxesArray = people[index].faces)} + onblur={() => ($boundingBoxesArray = [])} + onmouseover={() => ($boundingBoxesArray = people[index].faces)} + onmouseleave={() => ($boundingBoxesArray = [])} > <div class="relative"> <ImageThumbnail @@ -278,7 +285,7 @@ <button type="button" class="flex w-full text-left justify-between place-items-start gap-4 py-4" - on:click={() => (isOwner ? (isShowChangeDate = true) : null)} + onclick={() => (isOwner ? (isShowChangeDate = true) : null)} title={isOwner ? $t('edit_date') : ''} class:hover:dark:text-immich-dark-primary={isOwner} class:hover:text-immich-primary={isOwner} @@ -357,7 +364,7 @@ title={$t('show_file_location')} size="16" padding="2" - on:click={toggleAssetPath} + onclick={toggleAssetPath} /> {/if} </p> @@ -428,8 +435,7 @@ </div> {/await} {:then component} - <svelte:component - this={component.default} + <component.default mapMarkers={[ { lat: latlng.lat, @@ -446,7 +452,7 @@ useLocationPin onOpenInMapView={() => goto(`${AppRoute.MAP}#12.5/${latlng.lat}/${latlng.lng}`)} > - <svelte:fragment slot="popup" let:marker> + {#snippet popup({ marker })} {@const { lat, lon } = marker} <div class="flex flex-col items-center gap-1"> <p class="font-bold">{lat.toPrecision(6)}, {lon.toPrecision(6)}</p> @@ -458,8 +464,8 @@ {$t('open_in_openstreetmap')} </a> </div> - </svelte:fragment> - </svelte:component> + {/snippet} + </component.default> {/await} </div> {/if} diff --git a/web/src/lib/components/asset-viewer/download-panel.svelte b/web/src/lib/components/asset-viewer/download-panel.svelte index db46e1eff0..17f5e7e6a8 100644 --- a/web/src/lib/components/asset-viewer/download-panel.svelte +++ b/web/src/lib/components/asset-viewer/download-panel.svelte @@ -44,7 +44,7 @@ <div class="absolute right-2"> <CircleIconButton title={$t('close')} - on:click={() => abort(downloadKey, download)} + onclick={() => abort(downloadKey, download)} size="20" icon={mdiClose} class="dark:text-immich-dark-gray" diff --git a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-area.svelte b/web/src/lib/components/asset-viewer/editor/crop-tool/crop-area.svelte index c35fd91519..2b7153ed4e 100644 --- a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-area.svelte +++ b/web/src/lib/components/asset-viewer/editor/crop-tool/crop-area.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { onMount, afterUpdate, onDestroy, tick } from 'svelte'; + import { onMount, onDestroy, tick } from 'svelte'; import { t } from 'svelte-i18n'; import { getAssetOriginalUrl } from '$lib/utils'; import { handleError } from '$lib/utils/handle-error'; @@ -17,11 +17,23 @@ resetGlobalCropStore, rotateDegrees, } from '$lib/stores/asset-editor.store'; + import type { AssetResponseDto } from '@immich/sdk'; - export let asset; - let img: HTMLImageElement; + interface Props { + asset: AssetResponseDto; + } - $: imgElement.set(img); + let { asset }: Props = $props(); + + let img = $state<HTMLImageElement>(); + + $effect(() => { + if (!img) { + return; + } + + imgElement.set(img); + }); cropAspectRatio.subscribe((value) => { if (!img || !$cropAreaEl) { @@ -54,7 +66,7 @@ resetGlobalCropStore(); }); - afterUpdate(() => { + $effect(() => { resizeCanvas(); }); </script> @@ -64,8 +76,8 @@ class={`crop-area ${$changedOriention ? 'changedOriention' : ''}`} style={`rotate:${$rotateDegrees}deg`} bind:this={$cropAreaEl} - on:mousedown={handleMouseDown} - on:mouseup={handleMouseUp} + onmousedown={handleMouseDown} + onmouseup={handleMouseUp} aria-label="Crop area" type="button" > diff --git a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-preset.svelte b/web/src/lib/components/asset-viewer/editor/crop-tool/crop-preset.svelte index 667191274f..eb788b2d16 100644 --- a/web/src/lib/components/asset-viewer/editor/crop-tool/crop-preset.svelte +++ b/web/src/lib/components/asset-viewer/editor/crop-tool/crop-preset.svelte @@ -3,37 +3,41 @@ import Icon from '$lib/components/elements/icon.svelte'; import type { CropAspectRatio } from '$lib/stores/asset-editor.store'; - export let size: { - icon: string; - name: CropAspectRatio; - viewBox: string; - rotate?: boolean; - }; - export let selectedSize: CropAspectRatio; - export let rotateHorizontal: boolean; - export let selectType: (size: CropAspectRatio) => void; + interface Props { + size: { + icon: string; + name: CropAspectRatio; + viewBox: string; + rotate?: boolean; + }; + selectedSize: CropAspectRatio; + rotateHorizontal: boolean; + selectType: (size: CropAspectRatio) => void; + } - $: isSelected = selectedSize === size.name; - $: buttonColor = (isSelected ? 'primary' : 'transparent-gray') as Color; + let { size, selectedSize, rotateHorizontal, selectType }: Props = $props(); - $: rotatedTitle = (title: string, toRotate: boolean) => { + let isSelected = $derived(selectedSize === size.name); + let buttonColor = $derived((isSelected ? 'primary' : 'transparent-gray') as Color); + + let rotatedTitle = $derived((title: string, toRotate: boolean) => { let sides = title.split(':'); if (toRotate) { sides.reverse(); } return sides.join(':'); - }; + }); - $: toRotate = (def: boolean | undefined) => { + let toRotate = $derived((def: boolean | undefined) => { if (def === false) { return false; } return (def && !rotateHorizontal) || (!def && rotateHorizontal); - }; + }); </script> <li> - <Button color={buttonColor} class="flex-col gap-1" size="sm" rounded="lg" on:click={() => selectType(size.name)}> + <Button color={buttonColor} class="flex-col gap-1" size="sm" rounded="lg" onclick={() => selectType(size.name)}> <Icon size="1.75em" path={size.icon} viewBox={size.viewBox} class={toRotate(size.rotate) ? 'rotate-90' : ''} /> <span>{rotatedTitle(size.name, rotateHorizontal)}</span> </Button> 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 dba3be5d67..363bec7c1f 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 @@ -16,7 +16,7 @@ import { tick } from 'svelte'; import CropPreset from './crop-preset.svelte'; - $: rotateHorizontal = [90, 270].includes($normaizedRorateDegrees); + let rotateHorizontal = $derived([90, 270].includes($normaizedRorateDegrees)); const icon_16_9 = `M200-280q-33 0-56.5-23.5T120-360v-240q0-33 23.5-56.5T200-680h560q33 0 56.5 23.5T840-600v240q0 33-23.5 56.5T760-280H200Zm0-80h560v-240H200v240Zm0 0v-240 240Z`; const icon_4_3 = `M19 5H5c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 12H5V7h14v10z`; const icon_3_2 = `M200-240q-33 0-56.5-23.5T120-320v-320q0-33 23.5-56.5T200-720h560q33 0 56.5 23.5T840-640v320q0 33-23.5 56.5T760-240H200Zm0-80h560v-320H200v320Zm0 0v-320 320Z`; @@ -92,14 +92,17 @@ }, ]; - let selectedSize: CropAspectRatio = 'free'; - $cropAspectRatio = selectedSize; + let selectedSize: CropAspectRatio = $state('free'); - $: sizesRows = [ + $effect(() => { + $cropAspectRatio = selectedSize; + }); + + let sizesRows = $derived([ sizes.filter((s) => s.rotate === false), sizes.filter((s) => s.rotate === undefined), sizes.filter((s) => s.rotate === true), - ]; + ]); async function rotate(clock: boolean) { rotateDegrees.update((v) => { @@ -145,7 +148,7 @@ <h2>{$t('editor_crop_tool_h2_rotation').toUpperCase()}</h2> </div> <ul class="flex-wrap flex-row flex gap-x-6 gap-y-4 justify-center"> - <li><CircleIconButton title={$t('anti_clockwise')} on:click={() => rotate(false)} icon={mdiRotateLeft} /></li> - <li><CircleIconButton title={$t('clockwise')} on:click={() => rotate(true)} icon={mdiRotateRight} /></li> + <li><CircleIconButton title={$t('anti_clockwise')} onclick={() => rotate(false)} icon={mdiRotateLeft} /></li> + <li><CircleIconButton title={$t('clockwise')} onclick={() => rotate(true)} icon={mdiRotateRight} /></li> </ul> </div> diff --git a/web/src/lib/components/asset-viewer/editor/editor-panel.svelte b/web/src/lib/components/asset-viewer/editor/editor-panel.svelte index 78d5ca26e0..133d9c9021 100644 --- a/web/src/lib/components/asset-viewer/editor/editor-panel.svelte +++ b/web/src/lib/components/asset-viewer/editor/editor-panel.svelte @@ -9,8 +9,6 @@ import ConfirmDialog from '$lib/components/shared-components/dialog/confirm-dialog.svelte'; import { shortcut } from '$lib/actions/shortcut'; - export let asset: AssetResponseDto; - onMount(() => { return websocketEvents.on('on_asset_update', (assetUpdate) => { if (assetUpdate.id === asset.id) { @@ -19,12 +17,16 @@ }); }); - export let onUpdateSelectedType: (type: string) => void; - export let onClose: () => void; + interface Props { + asset: AssetResponseDto; + onUpdateSelectedType: (type: string) => void; + onClose: () => void; + } - let selectedType: string = editTypes[0].name; - // svelte-ignore reactive_declaration_non_reactive_property - $: selectedTypeObj = editTypes.find((t) => t.name === selectedType) || editTypes[0]; + let { asset = $bindable(), onUpdateSelectedType, onClose }: Props = $props(); + + let selectedType: string = $state(editTypes[0].name); + let selectedTypeObj = $derived(editTypes.find((t) => t.name === selectedType) || editTypes[0]); setTimeout(() => { onUpdateSelectedType(selectedType); @@ -39,7 +41,7 @@ <section class="relative p-2 dark:bg-immich-dark-bg dark:text-immich-dark-fg"> <div class="flex place-items-center gap-2"> - <CircleIconButton icon={mdiClose} title={$t('close')} on:click={onClose} /> + <CircleIconButton icon={mdiClose} title={$t('close')} onclick={onClose} /> <p class="text-lg text-immich-fg dark:text-immich-dark-fg capitalize">{$t('editor')}</p> </div> <section class="px-4 py-4"> @@ -50,14 +52,14 @@ color={etype.name === selectedType ? 'primary' : 'opaque'} icon={etype.icon} title={etype.name} - on:click={() => selectType(etype.name)} + onclick={() => selectType(etype.name)} /> </li> {/each} </ul> </section> <section> - <svelte:component this={selectedTypeObj.component} /> + <selectedTypeObj.component /> </section> </section> diff --git a/web/src/lib/components/asset-viewer/navigation-area.svelte b/web/src/lib/components/asset-viewer/navigation-area.svelte index e69d93b6b6..88f0baf0bc 100644 --- a/web/src/lib/components/asset-viewer/navigation-area.svelte +++ b/web/src/lib/components/asset-viewer/navigation-area.svelte @@ -1,13 +1,20 @@ <script lang="ts"> - export let onClick: (e: MouseEvent) => void; - export let label: string; + import type { Snippet } from 'svelte'; + + interface Props { + onClick: (e: MouseEvent) => void; + label: string; + children?: Snippet; + } + + let { onClick, label, children }: Props = $props(); </script> <button type="button" class="my-auto mx-4 rounded-full p-3 text-gray-500 transition hover:bg-gray-500 hover:text-white" aria-label={label} - on:click={onClick} + onclick={onClick} > - <slot /> + {@render children?.()} </button> diff --git a/web/src/lib/components/asset-viewer/panorama-viewer.svelte b/web/src/lib/components/asset-viewer/panorama-viewer.svelte index 396685e351..b17f9fdea7 100644 --- a/web/src/lib/components/asset-viewer/panorama-viewer.svelte +++ b/web/src/lib/components/asset-viewer/panorama-viewer.svelte @@ -8,7 +8,11 @@ import { fade } from 'svelte/transition'; import LoadingSpinner from '../shared-components/loading-spinner.svelte'; - export let asset: { id: string; type: AssetTypeEnum.Video } | AssetResponseDto; + interface Props { + asset: { id: string; type: AssetTypeEnum.Video } | AssetResponseDto; + } + + let { asset }: Props = $props(); const photoSphereConfigs = asset.type === AssetTypeEnum.Video @@ -43,14 +47,7 @@ {#await Promise.all([loadAssetData(), import('./photo-sphere-viewer-adapter.svelte'), ...photoSphereConfigs])} <LoadingSpinner /> {:then [data, module, adapter, plugins, navbar]} - <svelte:component - this={module.default} - panorama={data} - plugins={plugins ?? undefined} - {navbar} - {adapter} - {originalImageUrl} - /> + <module.default panorama={data} plugins={plugins ?? undefined} {navbar} {adapter} {originalImageUrl} /> {:catch} {$t('errors.failed_to_load_asset')} {/await} diff --git a/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte b/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte index 1745cd66b6..c18e6bd14b 100644 --- a/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte +++ b/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte @@ -10,16 +10,24 @@ import '@photo-sphere-viewer/core/index.css'; import { onDestroy, onMount } from 'svelte'; - export let panorama: string | { source: string }; - export let originalImageUrl: string | null; - export let adapter: AdapterConstructor | [AdapterConstructor, unknown] = EquirectangularAdapter; - export let plugins: (PluginConstructor | [PluginConstructor, unknown])[] = []; - export let navbar = false; + interface Props { + panorama: string | { source: string }; + originalImageUrl: string | null; + adapter?: AdapterConstructor | [AdapterConstructor, unknown]; + plugins?: (PluginConstructor | [PluginConstructor, unknown])[]; + navbar?: boolean; + } - let container: HTMLDivElement; + let { panorama, originalImageUrl, adapter = EquirectangularAdapter, plugins = [], navbar = false }: Props = $props(); + + let container: HTMLDivElement | undefined = $state(); let viewer: Viewer; onMount(() => { + if (!container) { + return; + } + viewer = new Viewer({ adapter, plugins, diff --git a/web/src/lib/components/asset-viewer/photo-viewer.svelte b/web/src/lib/components/asset-viewer/photo-viewer.svelte index d7595f6b7e..e24751b3c8 100644 --- a/web/src/lib/components/asset-viewer/photo-viewer.svelte +++ b/web/src/lib/components/asset-viewer/photo-viewer.svelte @@ -20,33 +20,38 @@ import { NotificationType, notificationController } from '../shared-components/notification/notification'; import { handleError } from '$lib/utils/handle-error'; - export let asset: AssetResponseDto; - export let preloadAssets: AssetResponseDto[] | undefined = undefined; - export let element: HTMLDivElement | undefined = undefined; - export let haveFadeTransition = true; - export let sharedLink: SharedLinkResponseDto | undefined = undefined; - export let onPreviousAsset: (() => void) | null = null; - export let onNextAsset: (() => void) | null = null; - export let copyImage: (() => Promise<void>) | null = null; - export let zoomToggle: (() => void) | null = null; + interface Props { + asset: AssetResponseDto; + preloadAssets?: AssetResponseDto[] | undefined; + element?: HTMLDivElement | undefined; + haveFadeTransition?: boolean; + sharedLink?: SharedLinkResponseDto | undefined; + onPreviousAsset?: (() => void) | null; + onNextAsset?: (() => void) | null; + copyImage?: () => Promise<void>; + zoomToggle?: (() => void) | null; + onClose?: () => void; + } + + let { + asset, + preloadAssets = undefined, + element = $bindable(), + haveFadeTransition = true, + sharedLink = undefined, + onPreviousAsset = null, + onNextAsset = null, + copyImage = $bindable(), + zoomToggle = $bindable(), + }: Props = $props(); const { slideshowState, slideshowLook } = slideshowStore; - let assetFileUrl: string = ''; - let imageLoaded: boolean = false; - let imageError: boolean = false; - let forceUseOriginal: boolean = false; - let loader: HTMLImageElement; + let assetFileUrl: string = $state(''); + let imageLoaded: boolean = $state(false); + let imageError: boolean = $state(false); - $: isWebCompatible = isWebCompatibleImage(asset); - $: useOriginalByDefault = isWebCompatible && $alwaysLoadOriginalFile; - $: useOriginalImage = useOriginalByDefault || forceUseOriginal; - // when true, will force loading of the original image - $: forceUseOriginal = - forceUseOriginal || asset.originalMimeType === 'image/gif' || ($photoZoomState.currentZoom > 1 && isWebCompatible); - - $: preload(useOriginalImage, preloadAssets); - $: imageLoaderUrl = getAssetUrl(asset.id, useOriginalImage, asset.checksum); + let loader = $state<HTMLImageElement>(); photoZoomState.set({ currentRotation: 0, @@ -129,16 +134,31 @@ const onerror = () => { imageError = imageLoaded = true; }; - if (loader.complete) { + if (loader?.complete) { onload(); } - loader.addEventListener('load', onload); - loader.addEventListener('error', onerror); + loader?.addEventListener('load', onload); + loader?.addEventListener('error', onerror); return () => { loader?.removeEventListener('load', onload); loader?.removeEventListener('error', onerror); }; }); + let isWebCompatible = $derived(isWebCompatibleImage(asset)); + let useOriginalByDefault = $derived(isWebCompatible && $alwaysLoadOriginalFile); + // when true, will force loading of the original image + + let forceUseOriginal: boolean = $derived( + asset.originalMimeType === 'image/gif' || ($photoZoomState.currentZoom > 1 && isWebCompatible), + ); + + let useOriginalImage = $derived(useOriginalByDefault || forceUseOriginal); + + $effect(() => { + preload(useOriginalImage, preloadAssets); + }); + + let imageLoaderUrl = $derived(getAssetUrl(asset.id, useOriginalImage, asset.checksum)); </script> <svelte:window @@ -150,15 +170,15 @@ {#if imageError} <BrokenAsset class="text-xl" /> {/if} -<!-- svelte-ignore a11y-missing-attribute --> +<!-- svelte-ignore a11y_missing_attribute --> <img bind:this={loader} style="display:none" src={imageLoaderUrl} aria-hidden="true" /> <div bind:this={element} class="relative h-full select-none"> <img style="display:none" src={imageLoaderUrl} alt={$getAltText(asset)} - on:load={() => ((imageLoaded = true), (assetFileUrl = imageLoaderUrl))} - on:error={() => (imageError = imageLoaded = true)} + onload={() => ((imageLoaded = true), (assetFileUrl = imageLoaderUrl))} + onerror={() => (imageError = imageLoaded = true)} /> {#if !imageLoaded} <div id="spinner" class="flex h-full items-center justify-center"> @@ -168,7 +188,7 @@ <div use:zoomImageAction use:swipe - on:swipe={onSwipe} + onswipe={onSwipe} class="h-full w-full" transition:fade={{ duration: haveFadeTransition ? 150 : 0 }} > diff --git a/web/src/lib/components/asset-viewer/slideshow-bar.svelte b/web/src/lib/components/asset-viewer/slideshow-bar.svelte index 1acc06f21b..95e08cb310 100644 --- a/web/src/lib/components/asset-viewer/slideshow-bar.svelte +++ b/web/src/lib/components/asset-viewer/slideshow-bar.svelte @@ -9,20 +9,30 @@ import { t } from 'svelte-i18n'; import { fly } from 'svelte/transition'; - export let isFullScreen: boolean; - export let onNext = () => {}; - export let onPrevious = () => {}; - export let onClose = () => {}; - export let onSetToFullScreen = () => {}; + interface Props { + isFullScreen: boolean; + onNext?: () => void; + onPrevious?: () => void; + onClose?: () => void; + onSetToFullScreen?: () => void; + } + + let { + isFullScreen, + onNext = () => {}, + onPrevious = () => {}, + onClose = () => {}, + onSetToFullScreen = () => {}, + }: Props = $props(); const { restartProgress, stopProgress, slideshowDelay, showProgressBar, slideshowNavigation } = slideshowStore; - let progressBarStatus: ProgressBarStatus; - let progressBar: ProgressBar; - let showSettings = false; - let showControls = true; + let progressBarStatus: ProgressBarStatus | undefined = $state(); + let progressBar = $state<ReturnType<typeof ProgressBar>>(); + let showSettings = $state(false); + let showControls = $state(true); let timer: NodeJS.Timeout; - let isOverControls = false; + let isOverControls = $state(false); let unsubscribeRestart: () => void; let unsubscribeStop: () => void; @@ -55,13 +65,13 @@ hideControlsAfterDelay(); unsubscribeRestart = restartProgress.subscribe((value) => { if (value) { - progressBar.restart(value); + progressBar?.restart(value); } }); unsubscribeStop = stopProgress.subscribe((value) => { if (value) { - progressBar.restart(false); + progressBar?.restart(false); stopControlsHideTimer(); } }); @@ -77,7 +87,9 @@ } }); - const handleDone = () => { + const handleDone = async () => { + await progressBar?.reset(); + if ($slideshowNavigation === SlideshowNavigation.AscendingOrder) { onPrevious(); return; @@ -87,7 +99,7 @@ </script> <svelte:window - on:mousemove={showControlBar} + onmousemove={showControlBar} use:shortcuts={[ { shortcut: { key: 'Escape' }, onShortcut: onClose }, { shortcut: { key: 'ArrowLeft' }, onShortcut: onPrevious }, @@ -98,32 +110,32 @@ {#if showControls} <div class="m-4 flex gap-2" - on:mouseenter={() => (isOverControls = true)} - on:mouseleave={() => (isOverControls = false)} + onmouseenter={() => (isOverControls = true)} + onmouseleave={() => (isOverControls = false)} transition:fly={{ duration: 150 }} role="navigation" > - <CircleIconButton buttonSize="50" icon={mdiClose} on:click={onClose} title={$t('exit_slideshow')} /> + <CircleIconButton buttonSize="50" icon={mdiClose} onclick={onClose} title={$t('exit_slideshow')} /> <CircleIconButton buttonSize="50" icon={progressBarStatus === ProgressBarStatus.Paused ? mdiPlay : mdiPause} - on:click={() => (progressBarStatus === ProgressBarStatus.Paused ? progressBar.play() : progressBar.pause())} + onclick={() => (progressBarStatus === ProgressBarStatus.Paused ? progressBar?.play() : progressBar?.pause())} title={progressBarStatus === ProgressBarStatus.Paused ? $t('play') : $t('pause')} /> - <CircleIconButton buttonSize="50" icon={mdiChevronLeft} on:click={onPrevious} title={$t('previous')} /> - <CircleIconButton buttonSize="50" icon={mdiChevronRight} on:click={onNext} title={$t('next')} /> + <CircleIconButton buttonSize="50" icon={mdiChevronLeft} onclick={onPrevious} title={$t('previous')} /> + <CircleIconButton buttonSize="50" icon={mdiChevronRight} onclick={onNext} title={$t('next')} /> <CircleIconButton buttonSize="50" icon={mdiCog} - on:click={() => (showSettings = !showSettings)} + onclick={() => (showSettings = !showSettings)} title={$t('slideshow_settings')} /> {#if !isFullScreen} <CircleIconButton buttonSize="50" icon={mdiFullscreen} - on:click={onSetToFullScreen} + onclick={onSetToFullScreen} title={$t('set_slideshow_to_fullscreen')} /> {/if} diff --git a/web/src/lib/components/asset-viewer/video-native-viewer.svelte b/web/src/lib/components/asset-viewer/video-native-viewer.svelte index 58012ccfce..d019ef273f 100644 --- a/web/src/lib/components/asset-viewer/video-native-viewer.svelte +++ b/web/src/lib/components/asset-viewer/video-native-viewer.svelte @@ -4,31 +4,53 @@ import { getAssetPlaybackUrl, getAssetThumbnailUrl } from '$lib/utils'; import { handleError } from '$lib/utils/handle-error'; import { AssetMediaSize } from '@immich/sdk'; - import { tick } from 'svelte'; + import { onDestroy, onMount } from 'svelte'; import { swipe } from 'svelte-gestures'; import type { SwipeCustomEvent } from 'svelte-gestures'; import { fade } from 'svelte/transition'; import { t } from 'svelte-i18n'; - export let assetId: string; - export let loopVideo: boolean; - export let checksum: string; - export let onPreviousAsset: () => void = () => {}; - export let onNextAsset: () => void = () => {}; - export let onVideoEnded: () => void = () => {}; - export let onVideoStarted: () => void = () => {}; - - let element: HTMLVideoElement | undefined = undefined; - let isVideoLoading = true; - let assetFileUrl: string; - let forceMuted = false; - - $: if (element) { - assetFileUrl = getAssetPlaybackUrl({ id: assetId, checksum }); - forceMuted = false; - element.load(); + interface Props { + assetId: string; + loopVideo: boolean; + checksum: string; + onPreviousAsset?: () => void; + onNextAsset?: () => void; + onVideoEnded?: () => void; + onVideoStarted?: () => void; + onClose?: () => void; } + let { + assetId, + loopVideo, + checksum, + onPreviousAsset = () => {}, + onNextAsset = () => {}, + onVideoEnded = () => {}, + onVideoStarted = () => {}, + onClose = () => {}, + }: Props = $props(); + + let videoPlayer: HTMLVideoElement | undefined = $state(); + let isLoading = $state(true); + let assetFileUrl = $state(''); + let forceMuted = $state(false); + + onMount(() => { + if (videoPlayer) { + assetFileUrl = getAssetPlaybackUrl({ id: assetId, checksum }); + forceMuted = false; + videoPlayer.load(); + } + }); + + onDestroy(() => { + if (videoPlayer) { + videoPlayer.src = ''; + } + }); + const handleCanPlay = async (video: HTMLVideoElement) => { try { await video.play(); @@ -38,16 +60,16 @@ await tryForceMutedPlay(video); return; } + handleError(error, $t('errors.unable_to_play_video')); } finally { - isVideoLoading = false; + isLoading = false; } }; const tryForceMutedPlay = async (video: HTMLVideoElement) => { try { - forceMuted = true; - await tick(); + video.muted = true; await handleCanPlay(video); } catch (error) { handleError(error, $t('errors.unable_to_play_video')); @@ -66,21 +88,22 @@ <div transition:fade={{ duration: 150 }} class="flex h-full select-none place-content-center place-items-center"> <video - bind:this={element} + bind:this={videoPlayer} loop={$loopVideoPreference && loopVideo} autoplay playsinline controls class="h-full object-contain" use:swipe - on:swipe={onSwipe} - on:canplay={(e) => handleCanPlay(e.currentTarget)} - on:ended={onVideoEnded} - on:volumechange={(e) => { + onswipe={onSwipe} + oncanplay={(e) => handleCanPlay(e.currentTarget)} + onended={onVideoEnded} + onvolumechange={(e) => { if (!forceMuted) { $videoViewerMuted = e.currentTarget.muted; } }} + onclose={() => onClose()} muted={forceMuted || $videoViewerMuted} bind:volume={$videoViewerVolume} poster={getAssetThumbnailUrl({ id: assetId, size: AssetMediaSize.Preview, checksum })} @@ -88,7 +111,7 @@ > </video> - {#if isVideoLoading} + {#if isLoading} <div class="absolute flex place-content-center place-items-center"> <LoadingSpinner /> </div> diff --git a/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte b/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte index 5f03784c42..3ee4791b07 100644 --- a/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte +++ b/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte @@ -4,12 +4,29 @@ import VideoNativeViewer from '$lib/components/asset-viewer/video-native-viewer.svelte'; import PanoramaViewer from '$lib/components/asset-viewer/panorama-viewer.svelte'; - export let assetId: string; - export let projectionType: string | null | undefined; - export let checksum: string; - export let loopVideo: boolean; - export let onPreviousAsset: () => void; - export let onNextAsset: () => void; + interface Props { + assetId: string; + projectionType: string | null | undefined; + checksum: string; + loopVideo: boolean; + onClose?: () => void; + onPreviousAsset?: () => void; + onNextAsset?: () => void; + onVideoEnded?: () => void; + onVideoStarted?: () => void; + } + + let { + assetId, + projectionType, + checksum, + loopVideo, + onPreviousAsset, + onClose, + onNextAsset, + onVideoEnded, + onVideoStarted, + }: Props = $props(); </script> {#if projectionType === ProjectionType.EQUIRECTANGULAR} @@ -21,7 +38,8 @@ {assetId} {onPreviousAsset} {onNextAsset} - on:onVideoEnded - on:onVideoStarted + {onVideoEnded} + {onVideoStarted} + {onClose} /> {/if} diff --git a/web/src/lib/components/assets/broken-asset.svelte b/web/src/lib/components/assets/broken-asset.svelte index dd54afba01..31acb832e5 100644 --- a/web/src/lib/components/assets/broken-asset.svelte +++ b/web/src/lib/components/assets/broken-asset.svelte @@ -3,11 +3,14 @@ import { mdiImageBrokenVariant } from '@mdi/js'; import { t } from 'svelte-i18n'; - let className = ''; - export { className as class }; - export let hideMessage = false; - export let width: string | undefined = undefined; - export let height: string | undefined = undefined; + interface Props { + class?: string; + hideMessage?: boolean; + width?: string | undefined; + height?: string | undefined; + } + + let { class: className = '', hideMessage = false, width = undefined, height = undefined }: Props = $props(); </script> <div diff --git a/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte b/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte index 282d152e90..9d69bdeeb2 100644 --- a/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte @@ -7,29 +7,49 @@ import { onMount } from 'svelte'; import { fade } from 'svelte/transition'; - export let url: string; - export let altText: string | undefined; - export let title: string | null = null; - export let heightStyle: string | undefined = undefined; - export let widthStyle: string; - export let base64ThumbHash: string | null = null; - export let curve = false; - export let shadow = false; - export let circle = false; - export let hidden = false; - export let border = false; - export let preload = true; - export let hiddenIconClass = 'text-white'; - export let onComplete: (() => void) | undefined = undefined; + interface Props { + url: string; + altText: string | undefined; + title?: string | null; + heightStyle?: string | undefined; + widthStyle: string; + base64ThumbHash?: string | null; + curve?: boolean; + shadow?: boolean; + circle?: boolean; + hidden?: boolean; + border?: boolean; + preload?: boolean; + hiddenIconClass?: string; + onComplete?: (() => void) | undefined; + onClick?: (() => void) | undefined; + } + + let { + url, + altText, + title = null, + heightStyle = undefined, + widthStyle, + base64ThumbHash = null, + curve = false, + shadow = false, + circle = false, + hidden = false, + border = false, + preload = true, + hiddenIconClass = 'text-white', + onComplete = undefined, + }: Props = $props(); let { IMAGE_THUMBNAIL: { THUMBHASH_FADE_DURATION }, } = TUNABLES; - let loaded = false; - let errored = false; + let loaded = $state(false); + let errored = $state(false); - let img: HTMLImageElement; + let img = $state<HTMLImageElement>(); const setLoaded = () => { loaded = true; @@ -40,20 +60,22 @@ onComplete?.(); }; onMount(() => { - if (img.complete) { + if (img?.complete) { setLoaded(); } }); - $: optionalClasses = [ - curve && 'rounded-xl', - circle && 'rounded-full', - shadow && 'shadow-lg', - (circle || !heightStyle) && 'aspect-square', - border && 'border-[3px] border-immich-dark-primary/80 hover:border-immich-primary', - ] - .filter(Boolean) - .join(' '); + let optionalClasses = $derived( + [ + curve && 'rounded-xl', + circle && 'rounded-full', + shadow && 'shadow-lg', + (circle || !heightStyle) && 'aspect-square', + border && 'border-[3px] border-immich-dark-primary/80 hover:border-immich-primary', + ] + .filter(Boolean) + .join(' '), + ); </script> {#if errored} @@ -61,8 +83,8 @@ {:else} <img bind:this={img} - on:load={setLoaded} - on:error={setErrored} + onload={setLoaded} + onerror={setErrored} loading={preload ? 'eager' : 'lazy'} style:width={widthStyle} style:height={heightStyle} diff --git a/web/src/lib/components/assets/thumbnail/thumbnail.svelte b/web/src/lib/components/assets/thumbnail/thumbnail.svelte index 4c2cf74518..536ea90163 100644 --- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte @@ -31,62 +31,89 @@ import { TUNABLES } from '$lib/utils/tunables'; import { thumbhash } from '$lib/actions/thumbhash'; - export let asset: AssetResponseDto; - export let dateGroup: DateGroup | undefined = undefined; - export let assetStore: AssetStore | undefined = undefined; - export let groupIndex = 0; - export let thumbnailSize: number | undefined = undefined; - export let thumbnailWidth: number | undefined = undefined; - export let thumbnailHeight: number | undefined = undefined; - export let selected = false; - export let selectionCandidate = false; - export let disabled = false; - export let readonly = false; - export let showArchiveIcon = false; - export let showStackedIcon = true; - export let disableMouseOver = false; - export let intersectionConfig: { - root?: HTMLElement; - bottom?: string; - top?: string; - left?: string; - priority?: number; + interface Props { + asset: AssetResponseDto; + dateGroup?: DateGroup | undefined; + assetStore?: AssetStore | undefined; + groupIndex?: number; + thumbnailSize?: number | undefined; + thumbnailWidth?: number | undefined; + thumbnailHeight?: number | undefined; + selected?: boolean; + selectionCandidate?: boolean; disabled?: boolean; - } = {}; + readonly?: boolean; + showArchiveIcon?: boolean; + showStackedIcon?: boolean; + disableMouseOver?: boolean; + intersectionConfig?: { + root?: HTMLElement; + bottom?: string; + top?: string; + left?: string; + priority?: number; + disabled?: boolean; + }; + retrieveElement?: boolean; + onIntersected?: (() => void) | undefined; + onClick?: ((asset: AssetResponseDto) => void) | undefined; + onRetrieveElement?: ((elment: HTMLElement) => void) | undefined; + onSelect?: ((asset: AssetResponseDto) => void) | undefined; + onMouseEvent?: ((event: { isMouseOver: boolean; selectedGroupIndex: number }) => void) | undefined; + class?: string; + } - export let retrieveElement: boolean = false; - export let onIntersected: (() => void) | undefined = undefined; - export let onClick: ((asset: AssetResponseDto) => void) | undefined = undefined; - export let onRetrieveElement: ((elment: HTMLElement) => void) | undefined = undefined; - export let onSelect: ((asset: AssetResponseDto) => void) | undefined = undefined; - export let onMouseEvent: ((event: { isMouseOver: boolean; selectedGroupIndex: number }) => void) | undefined = - undefined; - - let className = ''; - export { className as class }; + let { + asset, + dateGroup = undefined, + assetStore = undefined, + groupIndex = 0, + thumbnailSize = undefined, + thumbnailWidth = undefined, + thumbnailHeight = undefined, + selected = false, + selectionCandidate = false, + disabled = false, + readonly = false, + showArchiveIcon = false, + showStackedIcon = true, + disableMouseOver = false, + intersectionConfig = {}, + retrieveElement = false, + onIntersected = undefined, + onClick = undefined, + onRetrieveElement = undefined, + onSelect = undefined, + onMouseEvent = undefined, + class: className = '', + }: Props = $props(); let { IMAGE_THUMBNAIL: { THUMBHASH_FADE_DURATION }, } = TUNABLES; const componentId = generateId(); - let element: HTMLElement | undefined; - let mouseOver = false; - let intersecting = false; - let lastRetrievedElement: HTMLElement | undefined; - let loaded = false; + let element: HTMLElement | undefined = $state(); + let mouseOver = $state(false); + let intersecting = $state(false); + let lastRetrievedElement: HTMLElement | undefined = $state(); + let loaded = $state(false); - $: if (!retrieveElement) { - lastRetrievedElement = undefined; - } - $: if (retrieveElement && element && lastRetrievedElement !== element) { - lastRetrievedElement = element; - onRetrieveElement?.(element); - } + $effect(() => { + if (!retrieveElement) { + lastRetrievedElement = undefined; + } + }); + $effect(() => { + if (retrieveElement && element && lastRetrievedElement !== element) { + lastRetrievedElement = element; + onRetrieveElement?.(element); + } + }); - $: width = thumbnailSize || thumbnailWidth || 235; - $: height = thumbnailSize || thumbnailHeight || 235; - $: display = intersecting; + let width = $derived(thumbnailSize || thumbnailWidth || 235); + let height = $derived(thumbnailSize || thumbnailHeight || 235); + let display = $derived(intersecting); const onIconClickedHandler = (e?: MouseEvent) => { e?.stopPropagation(); @@ -197,15 +224,15 @@ class="group" class:cursor-not-allowed={disabled} class:cursor-pointer={!disabled} - on:mouseenter={onMouseEnter} - on:mouseleave={onMouseLeave} - on:keypress={(evt) => { + onmouseenter={onMouseEnter} + onmouseleave={onMouseLeave} + onkeypress={(evt) => { if (evt.key === 'Enter') { callClickHandlers(); } }} tabindex={0} - on:click={handleClick} + onclick={handleClick} role="link" > {#if mouseOver && !disableMouseOver} @@ -216,7 +243,7 @@ style:width="{width}px" style:height="{height}px" href={currentUrlReplaceAssetId(asset.id)} - on:click={(evt) => evt.preventDefault()} + onclick={(evt) => evt.preventDefault()} tabindex={0} aria-label="Thumbnail URL" > @@ -227,7 +254,7 @@ {#if !readonly && (mouseOver || selected || selectionCandidate)} <button type="button" - on:click={onIconClickedHandler} + onclick={onIconClickedHandler} class="absolute p-2 focus:outline-none" class:cursor-not-allowed={disabled} role="checkbox" diff --git a/web/src/lib/components/assets/thumbnail/video-thumbnail.svelte b/web/src/lib/components/assets/thumbnail/video-thumbnail.svelte index 14f99ac331..9188ab9a4f 100644 --- a/web/src/lib/components/assets/thumbnail/video-thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/video-thumbnail.svelte @@ -7,31 +7,47 @@ import { generateId } from '$lib/utils/generate-id'; import { onDestroy } from 'svelte'; - export let assetStore: AssetStore | undefined = undefined; - export let url: string; - export let durationInSeconds = 0; - export let enablePlayback = false; - export let playbackOnIconHover = false; - export let showTime = true; - export let curve = false; - export let playIcon = mdiPlayCircleOutline; - export let pauseIcon = mdiPauseCircleOutline; + interface Props { + assetStore?: AssetStore | undefined; + url: string; + durationInSeconds?: number; + enablePlayback?: boolean; + playbackOnIconHover?: boolean; + showTime?: boolean; + curve?: boolean; + playIcon?: string; + pauseIcon?: string; + } + + let { + assetStore = undefined, + url, + durationInSeconds = 0, + enablePlayback = $bindable(false), + playbackOnIconHover = false, + showTime = true, + curve = false, + playIcon = mdiPlayCircleOutline, + pauseIcon = mdiPauseCircleOutline, + }: Props = $props(); const componentId = generateId(); - let remainingSeconds = durationInSeconds; - let loading = true; - let error = false; - let player: HTMLVideoElement; + let remainingSeconds = $state(durationInSeconds); + let loading = $state(true); + let error = $state(false); + let player: HTMLVideoElement | undefined = $state(); - $: if (!enablePlayback) { - // Reset remaining time when playback is disabled. - remainingSeconds = durationInSeconds; + $effect(() => { + if (!enablePlayback) { + // Reset remaining time when playback is disabled. + remainingSeconds = durationInSeconds; - if (player) { - // Cancel video buffering. - player.src = ''; + if (player) { + // Cancel video buffering. + player.src = ''; + } } - } + }); const onMouseEnter = () => { if (assetStore) { assetStore.taskManager.queueScrollSensitiveTask({ @@ -78,8 +94,8 @@ </span> {/if} - <!-- svelte-ignore a11y-no-static-element-interactions --> - <span class="pr-2 pt-2" on:mouseenter={onMouseEnter} on:mouseleave={onMouseLeave}> + <!-- svelte-ignore a11y_no_static_element_interactions --> + <span class="pr-2 pt-2" onmouseenter={onMouseEnter} onmouseleave={onMouseLeave}> {#if enablePlayback} {#if loading} <LoadingSpinner /> @@ -103,15 +119,19 @@ autoplay loop src={url} - on:play={() => { + onplay={() => { loading = false; error = false; }} - on:error={() => { + onerror={() => { + if (!player?.src) { + // Do not show error when the URL is empty. + return; + } error = true; loading = false; }} - on:timeupdate={({ currentTarget }) => { + ontimeupdate={({ currentTarget }) => { const remaining = currentTarget.duration - currentTarget.currentTime; remainingSeconds = Math.min( Math.ceil(Number.isNaN(remaining) ? Number.POSITIVE_INFINITY : remaining), diff --git a/web/src/lib/components/elements/badge.svelte b/web/src/lib/components/elements/badge.svelte index da305e40f9..0db6e3fa40 100644 --- a/web/src/lib/components/elements/badge.svelte +++ b/web/src/lib/components/elements/badge.svelte @@ -1,11 +1,18 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export type Color = 'primary' | 'secondary'; export type Rounded = false | true | 'full'; </script> <script lang="ts"> - export let color: Color = 'primary'; - export let rounded: Rounded = true; + import type { Snippet } from 'svelte'; + + interface Props { + color?: Color; + rounded?: Rounded; + children?: Snippet; + } + + let { color = 'primary', rounded = true, children }: Props = $props(); const colorClasses: Record<Color, string> = { primary: 'text-gray-100 dark:text-immich-dark-gray bg-immich-primary dark:bg-immich-dark-primary', @@ -20,5 +27,5 @@ class:rounded-md={rounded === true} class:rounded-full={rounded === 'full'} > - <slot /> + {@render children?.()} </span> diff --git a/web/src/lib/components/elements/buttons/button.svelte b/web/src/lib/components/elements/buttons/button.svelte index cdd7463445..7e8418e2f5 100644 --- a/web/src/lib/components/elements/buttons/button.svelte +++ b/web/src/lib/components/elements/buttons/button.svelte @@ -1,6 +1,4 @@ -<script lang="ts" context="module"> - import type { HTMLButtonAttributes, HTMLLinkAttributes } from 'svelte/elements'; - +<script lang="ts" module> export type Color = | 'primary' | 'primary-inversed' @@ -17,44 +15,47 @@ export type Size = 'tiny' | 'icon' | 'link' | 'sm' | 'base' | 'lg'; export type Rounded = 'lg' | '3xl' | 'full' | 'none'; export type Shadow = 'md' | false; +</script> - type BaseProps = { - class?: string; +<script lang="ts"> + import type { Snippet } from 'svelte'; + + interface Props { + type?: string; + href?: string; color?: Color; size?: Size; rounded?: Rounded; shadow?: Shadow; fullwidth?: boolean; border?: boolean; - }; + class?: string; + children?: Snippet; + onclick?: (event: MouseEvent) => void; + onfocus?: () => void; + onblur?: () => void; + form?: string; + disabled?: boolean; + title?: string; + 'aria-current'?: 'page' | 'step' | 'location' | 'date' | 'time' | undefined | null; + } - export type ButtonProps = HTMLButtonAttributes & - BaseProps & { - href?: never; - }; - - export type LinkProps = HTMLLinkAttributes & - BaseProps & { - type?: never; - }; - - export type Props = ButtonProps | LinkProps; -</script> - -<script lang="ts"> - type $$Props = Props; - - export let type: $$Props['type'] = 'button'; - export let href: $$Props['href'] = undefined; - export let color: Color = 'primary'; - export let size: Size = 'base'; - export let rounded: Rounded = '3xl'; - export let shadow: Shadow = 'md'; - export let fullwidth = false; - export let border = false; - - let className = ''; - export { className as class }; + let { + type = 'button', + href = undefined, + color = 'primary', + size = 'base', + rounded = '3xl', + shadow = 'md', + fullwidth = false, + border = false, + class: className = '', + children, + onclick, + onfocus, + onblur, + ...rest + }: Props = $props(); const colorClasses: Record<Color, string> = { primary: @@ -93,29 +94,31 @@ full: 'rounded-full', }; - $: computedClass = [ - className, - colorClasses[color], - sizeClasses[size], - roundedClasses[rounded], - shadow === 'md' && 'shadow-md', - fullwidth && 'w-full', - border && 'border', - ] - .filter(Boolean) - .join(' '); + let computedClass = $derived( + [ + className, + colorClasses[color], + sizeClasses[size], + roundedClasses[rounded], + shadow === 'md' && 'shadow-md', + fullwidth && 'w-full', + border && 'border', + ] + .filter(Boolean) + .join(' '), + ); </script> -<!-- svelte-ignore a11y-no-static-element-interactions --> +<!-- svelte-ignore a11y_no_static_element_interactions --> <svelte:element this={href ? 'a' : 'button'} type={href ? undefined : type} {href} - on:click - on:focus - on:blur + {onclick} + {onfocus} + {onblur} class="inline-flex items-center justify-center transition-colors disabled:cursor-not-allowed disabled:opacity-60 disabled:pointer-events-none {computedClass}" - {...$$restProps} + {...rest} > - <slot /> + {@render children?.()} </svelte:element> diff --git a/web/src/lib/components/elements/buttons/circle-icon-button.svelte b/web/src/lib/components/elements/buttons/circle-icon-button.svelte index 8af3f75ade..4b984154f3 100644 --- a/web/src/lib/components/elements/buttons/circle-icon-button.svelte +++ b/web/src/lib/components/elements/buttons/circle-icon-button.svelte @@ -1,64 +1,64 @@ -<script lang="ts" context="module"> - import type { HTMLButtonAttributes, HTMLLinkAttributes } from 'svelte/elements'; - +<script lang="ts" module> export type Color = 'transparent' | 'light' | 'dark' | 'gray' | 'primary' | 'opaque' | 'alert'; export type Padding = '1' | '2' | '3'; - - type BaseProps = { - icon: string; - title: string; - class?: string; - color?: Color; - padding?: Padding; - size?: string; - hideMobile?: true; - buttonSize?: string; - viewBox?: string; - }; - - export type ButtonProps = HTMLButtonAttributes & - BaseProps & { - href?: never; - }; - - export type LinkProps = HTMLLinkAttributes & - BaseProps & { - type?: never; - }; - - export type Props = ButtonProps | LinkProps; </script> <script lang="ts"> import Icon from '$lib/components/elements/icon.svelte'; - type $$Props = Props; - - export let type: $$Props['type'] = 'button'; - export let href: $$Props['href'] = undefined; - export let icon: string; - export let color: Color = 'transparent'; - export let title: string; - /** - * The padding of the button, used by the `p-{padding}` Tailwind CSS class. - */ - export let padding: Padding = '3'; - /** - * Size of the button, used for a CSS value. - */ - export let size = '24'; - export let hideMobile = false; - export let buttonSize: string | undefined = undefined; - /** - * viewBox attribute for the SVG icon. - */ - export let viewBox: string | undefined = undefined; - /** * Override the default styling of the button for specific use cases, such as the icon color. */ - let className = ''; - export { className as class }; + interface Props { + id?: string; + type?: string; + href?: string; + icon: string; + color?: Color; + title: string; + /** + * The padding of the button, used by the `p-{padding}` Tailwind CSS class. + */ + padding?: Padding; + /** + * Size of the button, used for a CSS value. + */ + size?: string; + hideMobile?: boolean; + buttonSize?: string | undefined; + /** + * viewBox attribute for the SVG icon. + */ + viewBox?: string | undefined; + class?: string; + + 'aria-hidden'?: boolean | undefined | null; + 'aria-checked'?: 'true' | 'false' | undefined | null; + 'aria-current'?: 'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false' | undefined | null; + 'aria-controls'?: string | undefined | null; + 'aria-expanded'?: boolean; + 'aria-haspopup'?: boolean; + tabindex?: number | undefined | null; + role?: string | undefined | null; + onclick: (e: MouseEvent) => void; + disabled?: boolean; + } + + let { + type = 'button', + href = undefined, + icon, + color = 'transparent', + title, + padding = '3', + size = '24', + hideMobile = false, + buttonSize = undefined, + viewBox = undefined, + class: className = '', + onclick, + ...rest + }: Props = $props(); const colorClasses: Record<Color, string> = { transparent: 'bg-transparent hover:bg-[#d3d3d3] dark:text-immich-dark-fg', @@ -77,12 +77,12 @@ '3': 'p-3', }; - $: colorClass = colorClasses[color]; - $: mobileClass = hideMobile ? 'hidden sm:flex' : ''; - $: paddingClass = paddingClasses[padding]; + let colorClass = $derived(colorClasses[color]); + let mobileClass = $derived(hideMobile ? 'hidden sm:flex' : ''); + let paddingClass = $derived(paddingClasses[padding]); </script> -<!-- svelte-ignore a11y-no-static-element-interactions --> +<!-- svelte-ignore a11y_no_static_element_interactions --> <svelte:element this={href ? 'a' : 'button'} type={href ? undefined : type} @@ -91,8 +91,8 @@ style:width={buttonSize ? buttonSize + 'px' : ''} style:height={buttonSize ? buttonSize + 'px' : ''} class="flex place-content-center place-items-center rounded-full {colorClass} {paddingClass} transition-all disabled:cursor-default hover:dark:text-immich-dark-gray {className} {mobileClass}" - on:click - {...$$restProps} + {onclick} + {...rest} > <Icon path={icon} {size} ariaLabel={title} {viewBox} color="currentColor" /> </svelte:element> diff --git a/web/src/lib/components/elements/buttons/link-button.svelte b/web/src/lib/components/elements/buttons/link-button.svelte index b8e81f4469..a39e2608cf 100644 --- a/web/src/lib/components/elements/buttons/link-button.svelte +++ b/web/src/lib/components/elements/buttons/link-button.svelte @@ -1,22 +1,25 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export type Color = 'transparent-primary' | 'transparent-gray'; - - type BaseProps = { - color?: Color; - }; - - export type Props = (LinkProps & BaseProps) | (ButtonProps & BaseProps); </script> <script lang="ts"> - import Button, { type ButtonProps, type LinkProps } from '$lib/components/elements/buttons/button.svelte'; + import Button from '$lib/components/elements/buttons/button.svelte'; + import type { Snippet } from 'svelte'; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - type $$Props = Props; + interface Props { + href?: string; + color?: Color; + children?: Snippet; + onclick?: (e: MouseEvent) => void; + title?: string; + disabled?: boolean; + fullwidth?: boolean; + class?: string; + } - export let color: Color = 'transparent-gray'; + let { color = 'transparent-gray', children, ...rest }: Props = $props(); </script> -<Button size="link" {color} shadow={false} rounded="lg" on:click {...$$restProps}> - <slot /> +<Button size="link" {color} shadow={false} rounded="lg" {...rest}> + {@render children?.()} </Button> diff --git a/web/src/lib/components/elements/buttons/skip-link.svelte b/web/src/lib/components/elements/buttons/skip-link.svelte index d1ad667379..858d296c30 100644 --- a/web/src/lib/components/elements/buttons/skip-link.svelte +++ b/web/src/lib/components/elements/buttons/skip-link.svelte @@ -2,13 +2,17 @@ import { t } from 'svelte-i18n'; import Button from './button.svelte'; - /** - * Target for the skip link to move focus to. - */ - export let target: string = 'main'; - export let text: string = $t('skip_to_content'); + interface Props { + /** + * Target for the skip link to move focus to. + */ + target?: string; + text?: string; + } - let isFocused = false; + let { target = 'main', text = $t('skip_to_content') }: Props = $props(); + + let isFocused = $state(false); const moveFocus = () => { const targetEl = document.querySelector<HTMLElement>(target); @@ -20,9 +24,9 @@ <Button size={'sm'} rounded="none" - on:click={moveFocus} - on:focus={() => (isFocused = true)} - on:blur={() => (isFocused = false)} + onclick={moveFocus} + onfocus={() => (isFocused = true)} + onblur={() => (isFocused = false)} > {text} </Button> diff --git a/web/src/lib/components/elements/checkbox.svelte b/web/src/lib/components/elements/checkbox.svelte index 3407262551..4595c06bfb 100644 --- a/web/src/lib/components/elements/checkbox.svelte +++ b/web/src/lib/components/elements/checkbox.svelte @@ -1,11 +1,25 @@ <script lang="ts"> - export let id: string; - export let label: string; - export let checked: boolean | undefined = undefined; - export let disabled: boolean = false; - export let labelClass: string | undefined = undefined; - export let name: string | undefined = undefined; - export let value: string | undefined = undefined; + interface Props { + id: string; + label: string; + checked?: boolean | undefined; + disabled?: boolean; + labelClass?: string | undefined; + name?: string | undefined; + value?: string | undefined; + onchange?: () => void; + } + + let { + id, + label, + checked = $bindable(), + disabled = false, + labelClass = undefined, + name = undefined, + value = undefined, + onchange = () => {}, + }: Props = $props(); </script> <div class="flex items-center space-x-2"> @@ -17,7 +31,7 @@ {disabled} class="size-5 flex-shrink-0 focus-visible:ring" bind:checked - on:change + {onchange} /> <label class={labelClass} for={id}>{label}</label> </div> diff --git a/web/src/lib/components/elements/date-input.svelte b/web/src/lib/components/elements/date-input.svelte index f42fff4359..687e9442e7 100644 --- a/web/src/lib/components/elements/date-input.svelte +++ b/web/src/lib/components/elements/date-input.svelte @@ -1,29 +1,35 @@ <script lang="ts"> - import type { HTMLInputAttributes } from 'svelte/elements'; - - interface $$Props extends HTMLInputAttributes { + interface Props { type: 'date' | 'datetime-local'; + value?: string; + min?: string; + max?: string; + class?: string; + id?: string; + name?: string; + placeholder?: string; } - export let type: $$Props['type']; - export let value: $$Props['value'] = undefined; - export let max: $$Props['max'] = undefined; + let { type, value = $bindable(), max = undefined, ...rest }: Props = $props(); - $: fallbackMax = type === 'date' ? '9999-12-31' : '9999-12-31T23:59'; + let fallbackMax = $derived(type === 'date' ? '9999-12-31' : '9999-12-31T23:59'); // Updating `value` directly causes the date input to reset itself or // interfere with user changes. - $: updatedValue = value; + let updatedValue = $state<string>(); + $effect(() => { + updatedValue = value; + }); </script> <input - {...$$restProps} + {...rest} {type} {value} max={max || fallbackMax} - on:input={(e) => (updatedValue = e.currentTarget.value)} - on:blur={() => (value = updatedValue)} - on:keydown={(e) => { + oninput={(e) => (updatedValue = e.currentTarget.value)} + onblur={() => (value = updatedValue)} + onkeydown={(e) => { if (e.key === 'Enter') { value = updatedValue; } diff --git a/web/src/lib/components/elements/dropdown.svelte b/web/src/lib/components/elements/dropdown.svelte index 80689ef1fe..b146f347dc 100644 --- a/web/src/lib/components/elements/dropdown.svelte +++ b/web/src/lib/components/elements/dropdown.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> // Necessary for eslint /* eslint-disable @typescript-eslint/no-explicit-any */ type T = any; @@ -20,19 +20,31 @@ import { clickOutside } from '$lib/actions/click-outside'; import { fly } from 'svelte/transition'; - let className = ''; - export { className as class }; + interface Props { + class?: string; + options: T[]; + selectedOption?: any; + showMenu?: boolean; + controlable?: boolean; + hideTextOnSmallScreen?: boolean; + title?: string | undefined; + onSelect: (option: T) => void; + onClickOutside?: () => void; + render?: (item: T) => string | RenderedOption; + } - export let options: T[]; - export let selectedOption = options[0]; - export let showMenu = false; - export let controlable = false; - export let hideTextOnSmallScreen = true; - export let title: string | undefined = undefined; - export let onSelect: (option: T) => void; - export let onClickOutside: () => void = () => {}; - - export let render: (item: T) => string | RenderedOption = String; + let { + class: className = '', + options, + selectedOption = $bindable(options[0]), + showMenu = $bindable(false), + controlable = false, + hideTextOnSmallScreen = true, + title = undefined, + onSelect, + onClickOutside = () => {}, + render = String, + }: Props = $props(); const handleClickOutside = () => { if (!controlable) { @@ -65,12 +77,12 @@ } }; - $: renderedSelectedOption = renderOption(selectedOption); + let renderedSelectedOption = $derived(renderOption(selectedOption)); </script> <div use:clickOutside={{ onOutclick: handleClickOutside, onEscape: handleClickOutside }}> <!-- BUTTON TITLE --> - <LinkButton on:click={() => (showMenu = true)} fullwidth {title}> + <LinkButton onclick={() => (showMenu = true)} fullwidth {title}> <div class="flex place-items-center gap-2 text-sm"> {#if renderedSelectedOption?.icon} <Icon path={renderedSelectedOption.icon} size="18" /> @@ -92,7 +104,7 @@ type="button" class="grid grid-cols-[36px,1fr] place-items-center p-2 disabled:opacity-40 {buttonStyle}" disabled={renderedOption.disabled} - on:click={() => !renderedOption.disabled && handleSelectOption(option)} + onclick={() => !renderedOption.disabled && handleSelectOption(option)} > {#if isEqual(selectedOption, option)} <div class="text-immich-primary dark:text-immich-dark-primary"> diff --git a/web/src/lib/components/elements/group-tab.svelte b/web/src/lib/components/elements/group-tab.svelte index f5e2f79350..021d5ca96f 100644 --- a/web/src/lib/components/elements/group-tab.svelte +++ b/web/src/lib/components/elements/group-tab.svelte @@ -1,10 +1,14 @@ <script lang="ts"> import { generateId } from '$lib/utils/generate-id'; - export let filters: string[]; - export let selected: string; - export let label: string; - export let onSelect: (selected: string) => void; + interface Props { + filters: string[]; + selected: string; + label: string; + onSelect: (selected: string) => void; + } + + let { filters, selected, label, onSelect }: Props = $props(); const id = `group-tab-${generateId()}`; </script> @@ -22,7 +26,7 @@ class="peer sr-only" value={filter} checked={filter === selected} - on:change={() => onSelect(filter)} + onchange={() => onSelect(filter)} /> <label for="{id}-{index}" diff --git a/web/src/lib/components/elements/icon.svelte b/web/src/lib/components/elements/icon.svelte index 5965928718..4bc55b3247 100644 --- a/web/src/lib/components/elements/icon.svelte +++ b/web/src/lib/components/elements/icon.svelte @@ -1,22 +1,41 @@ <script lang="ts"> import type { AriaRole } from 'svelte/elements'; - export let size: string | number = '1em'; - export let color = 'currentColor'; - export let path: string; - export let title: string | null = null; - export let desc = ''; - export let flipped = false; - let className = ''; - export { className as class }; - export let viewBox = '0 0 24 24'; - export let role: AriaRole = 'img'; - export let ariaHidden: boolean | undefined = undefined; - export let ariaLabel: string | undefined = undefined; - export let ariaLabelledby: string | undefined = undefined; - export let strokeWidth: number = 0; - export let strokeColor: string = 'currentColor'; - export let spin = false; + interface Props { + size?: string | number; + color?: string; + path: string; + title?: string | null; + desc?: string; + flipped?: boolean; + class?: string; + viewBox?: string; + role?: AriaRole; + ariaHidden?: boolean | undefined; + ariaLabel?: string | undefined; + ariaLabelledby?: string | undefined; + strokeWidth?: number; + strokeColor?: string; + spin?: boolean; + } + + let { + size = '1em', + color = 'currentColor', + path, + title = null, + desc = '', + flipped = false, + class: className = '', + viewBox = '0 0 24 24', + role = 'img', + ariaHidden = undefined, + ariaLabel = undefined, + ariaLabelledby = undefined, + strokeWidth = 0, + strokeColor = 'currentColor', + spin = false, + }: Props = $props(); </script> <svg diff --git a/web/src/lib/components/elements/radio-button.svelte b/web/src/lib/components/elements/radio-button.svelte index a3c47e5fbc..1d110ff644 100644 --- a/web/src/lib/components/elements/radio-button.svelte +++ b/web/src/lib/components/elements/radio-button.svelte @@ -1,9 +1,13 @@ <script lang="ts"> - export let id: string; - export let label: string; - export let name: string; - export let value: string; - export let group: string | undefined = undefined; + interface Props { + id: string; + label: string; + name: string; + value: string; + group?: string | undefined; + } + + let { id, label, name, value, group = $bindable(undefined) }: Props = $props(); </script> <div class="flex items-center space-x-2"> diff --git a/web/src/lib/components/elements/search-bar.svelte b/web/src/lib/components/elements/search-bar.svelte index 7668152d35..c852be3b68 100644 --- a/web/src/lib/components/elements/search-bar.svelte +++ b/web/src/lib/components/elements/search-bar.svelte @@ -5,14 +5,25 @@ import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; import { t } from 'svelte-i18n'; - export let name: string; - export let roundedBottom = true; - export let showLoadingSpinner: boolean; - export let placeholder: string; - export let onSearch: (options: SearchOptions) => void = () => {}; - export let onReset: () => void = () => {}; + interface Props { + name: string; + roundedBottom?: boolean; + showLoadingSpinner: boolean; + placeholder: string; + onSearch?: (options: SearchOptions) => void; + onReset?: () => void; + } - let inputRef: HTMLElement; + let { + name = $bindable(), + roundedBottom = true, + showLoadingSpinner, + placeholder, + onSearch = () => {}, + onReset = () => {}, + }: Props = $props(); + + let inputRef = $state<HTMLElement>(); const resetSearch = () => { name = ''; @@ -37,7 +48,7 @@ title={$t('search')} size="16" padding="2" - on:click={() => onSearch({ force: true })} + onclick={() => onSearch({ force: true })} /> <input class="w-full gap-2 bg-gray-200 dark:bg-immich-dark-gray dark:text-white" @@ -45,8 +56,8 @@ {placeholder} bind:value={name} bind:this={inputRef} - on:keydown={handleSearch} - on:input={() => onSearch({ force: false })} + onkeydown={handleSearch} + oninput={() => onSearch({ force: false })} /> {#if showLoadingSpinner} <div class="flex place-items-center"> @@ -54,6 +65,6 @@ </div> {/if} {#if name} - <CircleIconButton icon={mdiClose} title={$t('clear_value')} size="16" padding="2" on:click={resetSearch} /> + <CircleIconButton icon={mdiClose} title={$t('clear_value')} size="16" padding="2" onclick={resetSearch} /> {/if} </div> diff --git a/web/src/lib/components/elements/slider.svelte b/web/src/lib/components/elements/slider.svelte index 4c19696372..5c80eb2a9e 100644 --- a/web/src/lib/components/elements/slider.svelte +++ b/web/src/lib/components/elements/slider.svelte @@ -1,15 +1,25 @@ <script lang="ts"> - /** - * Unique identifier for the checkbox element, used to associate labels with the input element. - */ - export let id: string; - /** - * Optional aria-describedby attribute to associate the checkbox with a description. - */ - export let ariaDescribedBy: string | undefined = undefined; - export let checked = false; - export let disabled = false; - export let onToggle: ((checked: boolean) => void) | undefined = undefined; + interface Props { + /** + * Unique identifier for the checkbox element, used to associate labels with the input element. + */ + id: string; + /** + * Optional aria-describedby attribute to associate the checkbox with a description. + */ + ariaDescribedBy?: string | undefined; + checked?: boolean; + disabled?: boolean; + onToggle?: ((checked: boolean) => void) | undefined; + } + + let { + id, + ariaDescribedBy = undefined, + checked = $bindable(false), + disabled = false, + onToggle = undefined, + }: Props = $props(); const handleToggle = (event: Event) => onToggle?.((event.target as HTMLInputElement).checked); </script> @@ -20,7 +30,7 @@ class="disabled::cursor-not-allowed h-0 w-0 opacity-0 peer" type="checkbox" bind:checked - on:click={handleToggle} + onclick={handleToggle} {disabled} aria-describedby={ariaDescribedBy} /> diff --git a/web/src/lib/components/error.svelte b/web/src/lib/components/error.svelte index cbc8c26bd8..54466b5a55 100644 --- a/web/src/lib/components/error.svelte +++ b/web/src/lib/components/error.svelte @@ -6,7 +6,11 @@ import { mdiCodeTags, mdiContentCopy, mdiMessage, mdiPartyPopper } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let error: { message: string; code?: string | number; stack?: string } | undefined | null = undefined; + interface Props { + error?: { message: string; code?: string | number; stack?: string } | undefined | null; + } + + let { error = undefined }: Props = $props(); const handleCopy = async () => { if (!error) { @@ -41,7 +45,7 @@ color="primary" icon={mdiContentCopy} title={$t('copy_error')} - on:click={() => handleCopy()} + onclick={() => handleCopy()} /> </div> </div> diff --git a/web/src/lib/components/faces-page/assign-face-side-panel.svelte b/web/src/lib/components/faces-page/assign-face-side-panel.svelte index ce184321e3..b6c9beb43a 100644 --- a/web/src/lib/components/faces-page/assign-face-side-panel.svelte +++ b/web/src/lib/components/faces-page/assign-face-side-panel.svelte @@ -14,24 +14,28 @@ import { zoomImageToBase64 } from '$lib/utils/people-utils'; import { t } from 'svelte-i18n'; - export let allPeople: PersonResponseDto[]; - export let editedFace: AssetFaceResponseDto; - export let assetId: string; - export let assetType: AssetTypeEnum; - export let onClose: () => void; - export let onCreatePerson: (featurePhoto: string | null) => void; - export let onReassign: (person: PersonResponseDto) => void; + interface Props { + allPeople: PersonResponseDto[]; + editedFace: AssetFaceResponseDto; + assetId: string; + assetType: AssetTypeEnum; + onClose: () => void; + onCreatePerson: (featurePhoto: string | null) => void; + onReassign: (person: PersonResponseDto) => void; + } + + let { allPeople, editedFace, assetId, assetType, onClose, onCreatePerson, onReassign }: Props = $props(); // loading spinners - let isShowLoadingNewPerson = false; - let isShowLoadingSearch = false; + let isShowLoadingNewPerson = $state(false); + let isShowLoadingSearch = $state(false); // search people - let searchedPeople: PersonResponseDto[] = []; - let searchFaces = false; - let searchName = ''; + let searchedPeople: PersonResponseDto[] = $state([]); + let searchFaces = $state(false); + let searchName = $state(''); - $: showPeople = searchName ? searchedPeople : allPeople.filter((person) => !person.isHidden); + let showPeople = $derived(searchName ? searchedPeople : allPeople.filter((person) => !person.isHidden)); const handleCreatePerson = async () => { const timeout = setTimeout(() => (isShowLoadingNewPerson = true), timeBeforeShowLoadingSpinner); @@ -53,19 +57,19 @@ <div class="flex place-items-center justify-between gap-2"> {#if !searchFaces} <div class="flex items-center gap-2"> - <CircleIconButton icon={mdiArrowLeftThin} title={$t('back')} on:click={onClose} /> + <CircleIconButton icon={mdiArrowLeftThin} title={$t('back')} onclick={onClose} /> <p class="flex text-lg text-immich-fg dark:text-immich-dark-fg">{$t('select_face')}</p> </div> <div class="flex justify-end gap-2"> <CircleIconButton icon={mdiMagnify} title={$t('search_for_existing_person')} - on:click={() => { + onclick={() => { searchFaces = true; }} /> {#if !isShowLoadingNewPerson} - <CircleIconButton icon={mdiPlus} title={$t('create_new_person')} on:click={handleCreatePerson} /> + <CircleIconButton icon={mdiPlus} title={$t('create_new_person')} onclick={handleCreatePerson} /> {:else} <div class="flex place-content-center place-items-center"> <LoadingSpinner /> @@ -73,7 +77,7 @@ {/if} </div> {:else} - <CircleIconButton icon={mdiArrowLeftThin} title={$t('back')} on:click={onClose} /> + <CircleIconButton icon={mdiArrowLeftThin} title={$t('back')} onclick={onClose} /> <div class="w-full flex"> <SearchPeople type="input" @@ -87,7 +91,7 @@ </div> {/if} </div> - <CircleIconButton icon={mdiClose} title={$t('cancel_search')} on:click={() => (searchFaces = false)} /> + <CircleIconButton icon={mdiClose} title={$t('cancel_search')} onclick={() => (searchFaces = false)} /> {/if} </div> <div class="px-4 py-4 text-sm"> @@ -96,7 +100,7 @@ {#each showPeople as person (person.id)} {#if !editedFace.person || person.id !== editedFace.person.id} <div class="w-fit"> - <button type="button" class="w-[90px]" on:click={() => onReassign(person)}> + <button type="button" class="w-[90px]" onclick={() => onReassign(person)}> <div class="relative"> <ImageThumbnail curve diff --git a/web/src/lib/components/faces-page/edit-name-input.svelte b/web/src/lib/components/faces-page/edit-name-input.svelte index d9e961c13f..ebb44c4008 100644 --- a/web/src/lib/components/faces-page/edit-name-input.svelte +++ b/web/src/lib/components/faces-page/edit-name-input.svelte @@ -5,25 +5,37 @@ import SearchPeople from '$lib/components/faces-page/people-search.svelte'; import { t } from 'svelte-i18n'; - export let person: PersonResponseDto; - export let name: string; - export let suggestedPeople: PersonResponseDto[]; - export let thumbnailData: string; - export let isSearchingPeople: boolean; - export let onChange: (name: string) => void; + interface Props { + person: PersonResponseDto; + name: string; + suggestedPeople: PersonResponseDto[]; + thumbnailData: string; + isSearchingPeople: boolean; + onChange: (name: string) => void; + } + + let { + person, + name = $bindable(), + suggestedPeople = $bindable(), + thumbnailData, + isSearchingPeople = $bindable(), + onChange, + }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + onChange(name); + }; </script> <div class="flex w-full h-14 place-items-center {suggestedPeople.length > 0 ? 'rounded-t-lg dark:border-immich-dark-gray' - : 'rounded-lg'} bg-gray-100 p-2 dark:bg-gray-700" + : 'rounded-lg'} bg-gray-100 p-2 dark:bg-gray-700 border border-gray-200 dark:border-immich-dark-gray" > <ImageThumbnail circle shadow url={thumbnailData} altText={person.name} widthStyle="2rem" heightStyle="2rem" /> - <form - class="ml-4 flex w-full justify-between gap-16" - autocomplete="off" - on:submit|preventDefault={() => onChange(name)} - > + <form class="ml-4 flex w-full justify-between gap-16" autocomplete="off" {onsubmit}> <SearchPeople bind:searchName={name} bind:searchedPeopleLocal={suggestedPeople} diff --git a/web/src/lib/components/faces-page/face-thumbnail.svelte b/web/src/lib/components/faces-page/face-thumbnail.svelte index cce91b4669..cc3fffe5d7 100644 --- a/web/src/lib/components/faces-page/face-thumbnail.svelte +++ b/web/src/lib/components/faces-page/face-thumbnail.svelte @@ -3,19 +3,31 @@ import { type PersonResponseDto } from '@immich/sdk'; import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte'; - export let person: PersonResponseDto; - export let selectable = false; - export let selected = false; - export let thumbnailSize: number | null = null; - export let circle = false; - export let border = false; - export let onClick: (person: PersonResponseDto) => void = () => {}; + interface Props { + person: PersonResponseDto; + selectable?: boolean; + selected?: boolean; + thumbnailSize?: number | null; + circle?: boolean; + border?: boolean; + onClick?: (person: PersonResponseDto) => void; + } + + let { + person, + selectable = false, + selected = false, + thumbnailSize = null, + circle = false, + border = false, + onClick = () => {}, + }: Props = $props(); </script> <button type="button" class="relative rounded-lg transition-all" - on:click={() => onClick(person)} + onclick={() => onClick(person)} disabled={!selectable} style:width={thumbnailSize ? thumbnailSize + 'px' : '100%'} style:height={thumbnailSize ? thumbnailSize + 'px' : '100%'} diff --git a/web/src/lib/components/faces-page/manage-people-visibility.svelte b/web/src/lib/components/faces-page/manage-people-visibility.svelte index 90e20a1e5b..295f629736 100644 --- a/web/src/lib/components/faces-page/manage-people-visibility.svelte +++ b/web/src/lib/components/faces-page/manage-people-visibility.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> const enum ToggleVisibility { HIDE_ALL = 'hide-all', HIDE_UNNANEMD = 'hide-unnamed', @@ -24,17 +24,18 @@ import { t } from 'svelte-i18n'; import CircleIconButton from '../elements/buttons/circle-icon-button.svelte'; - export let people: PersonResponseDto[]; - export let totalPeopleCount: number; - export let titleId: string | undefined = undefined; - export let onClose: () => void; - export let loadNextPage: () => void; + interface Props { + people: PersonResponseDto[]; + totalPeopleCount: number; + titleId?: string | undefined; + onClose: () => void; + loadNextPage: () => void; + } - let toggleVisibility = ToggleVisibility.SHOW_ALL; - let showLoadingSpinner = false; + let { people = $bindable(), totalPeopleCount, titleId = undefined, onClose, loadNextPage }: Props = $props(); - $: personIsHidden = getPersonIsHidden(people); - $: toggleButton = toggleButtonOptions[getNextVisibility(toggleVisibility)]; + let toggleVisibility = $state(ToggleVisibility.SHOW_ALL); + let showLoadingSpinner = $state(false); const getPersonIsHidden = (people: PersonResponseDto[]) => { const personIsHidden: Record<string, boolean> = {}; @@ -44,16 +45,6 @@ return personIsHidden; }; - // svelte-ignore reactive_declaration_non_reactive_property - // svelte-ignore reactive_declaration_module_script_dependency - $: toggleButtonOptions = ((): Record<ToggleVisibility, { icon: string; label: string }> => { - return { - [ToggleVisibility.HIDE_ALL]: { icon: mdiEyeOff, label: $t('hide_all_people') }, - [ToggleVisibility.HIDE_UNNANEMD]: { icon: mdiEyeSettings, label: $t('hide_unnamed_people') }, - [ToggleVisibility.SHOW_ALL]: { icon: mdiEye, label: $t('show_all_people') }, - }; - })(); - const getNextVisibility = (toggleVisibility: ToggleVisibility) => { if (toggleVisibility === ToggleVisibility.SHOW_ALL) { return ToggleVisibility.HIDE_UNNANEMD; @@ -115,6 +106,15 @@ showLoadingSpinner = false; } }; + + let personIsHidden = $state(getPersonIsHidden(people)); + + let toggleButtonOptions: Record<ToggleVisibility, { icon: string; label: string }> = $derived({ + [ToggleVisibility.HIDE_ALL]: { icon: mdiEyeOff, label: $t('hide_all_people') }, + [ToggleVisibility.HIDE_UNNANEMD]: { icon: mdiEyeSettings, label: $t('hide_unnamed_people') }, + [ToggleVisibility.SHOW_ALL]: { icon: mdiEye, label: $t('show_all_people') }, + }); + let toggleButton = $derived(toggleButtonOptions[getNextVisibility(toggleVisibility)]); </script> <svelte:window use:shortcut={{ shortcut: { key: 'Escape' }, onShortcut: onClose }} /> @@ -123,7 +123,7 @@ class="fixed top-0 z-10 flex h-16 w-full items-center justify-between border-b bg-white p-1 dark:border-immich-dark-gray dark:bg-black dark:text-immich-dark-fg md:p-8" > <div class="flex items-center"> - <CircleIconButton title={$t('close')} icon={mdiClose} on:click={onClose} /> + <CircleIconButton title={$t('close')} icon={mdiClose} onclick={onClose} /> <div class="flex gap-2 items-center"> <p id={titleId} class="ml-2">{$t('show_and_hide_people')}</p> <p class="text-sm text-gray-400 dark:text-gray-600">({totalPeopleCount.toLocaleString($locale)})</p> @@ -131,11 +131,11 @@ </div> <div class="flex items-center justify-end"> <div class="flex items-center md:mr-4"> - <CircleIconButton title={$t('reset_people_visibility')} icon={mdiRestart} on:click={handleResetVisibility} /> - <CircleIconButton title={toggleButton.label} icon={toggleButton.icon} on:click={handleToggleVisibility} /> + <CircleIconButton title={$t('reset_people_visibility')} icon={mdiRestart} onclick={handleResetVisibility} /> + <CircleIconButton title={toggleButton.label} icon={toggleButton.icon} onclick={handleToggleVisibility} /> </div> {#if !showLoadingSpinner} - <Button on:click={handleSaveVisibility} size="sm" rounded="lg">{$t('done')}</Button> + <Button onclick={handleSaveVisibility} size="sm" rounded="lg">{$t('done')}</Button> {:else} <LoadingSpinner /> {/if} @@ -143,29 +143,31 @@ </div> <div class="flex flex-wrap gap-1 bg-immich-bg p-2 pb-8 dark:bg-immich-dark-bg md:px-8 mt-16"> - <PeopleInfiniteScroll {people} hasNextPage={true} {loadNextPage} let:person let:index> - {@const hidden = personIsHidden[person.id]} - <button - type="button" - class="group relative w-full h-full" - on:click={() => (personIsHidden[person.id] = !hidden)} - aria-pressed={hidden} - aria-label={person.name ? $t('hide_named_person', { values: { name: person.name } }) : $t('hide_person')} - > - <ImageThumbnail - preload={index < 20} - {hidden} - shadow - url={getPeopleThumbnailUrl(person)} - altText={person.name} - widthStyle="100%" - hiddenIconClass="text-white group-hover:text-black transition-colors" - /> - {#if person.name} - <span class="absolute bottom-2 left-0 w-full select-text px-1 text-center font-medium text-white"> - {person.name} - </span> - {/if} - </button> + <PeopleInfiniteScroll {people} hasNextPage={true} {loadNextPage}> + {#snippet children({ person, index })} + {@const hidden = personIsHidden[person.id]} + <button + type="button" + class="group relative w-full h-full" + onclick={() => (personIsHidden[person.id] = !hidden)} + aria-pressed={hidden} + aria-label={person.name ? $t('hide_named_person', { values: { name: person.name } }) : $t('hide_person')} + > + <ImageThumbnail + preload={index < 20} + {hidden} + shadow + url={getPeopleThumbnailUrl(person)} + altText={person.name} + widthStyle="100%" + hiddenIconClass="text-white group-hover:text-black transition-colors" + /> + {#if person.name} + <span class="absolute bottom-2 left-0 w-full select-text px-1 text-center font-medium text-white"> + {person.name} + </span> + {/if} + </button> + {/snippet} </PeopleInfiniteScroll> </div> 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 52daa36a99..c638691080 100644 --- a/web/src/lib/components/faces-page/merge-face-selector.svelte +++ b/web/src/lib/components/faces-page/merge-face-selector.svelte @@ -19,16 +19,20 @@ import { dialogController } from '$lib/components/shared-components/dialog/dialog'; import { t } from 'svelte-i18n'; - export let person: PersonResponseDto; - export let onBack: () => void; - export let onMerge: (mergedPerson: PersonResponseDto) => void; + interface Props { + person: PersonResponseDto; + onBack: () => void; + onMerge: (mergedPerson: PersonResponseDto) => void; + } - let people: PersonResponseDto[] = []; - let selectedPeople: PersonResponseDto[] = []; - let screenHeight: number; + let { person = $bindable(), onBack, onMerge }: Props = $props(); - $: hasSelection = selectedPeople.length > 0; - $: peopleToNotShow = [...selectedPeople, person]; + let people: PersonResponseDto[] = $state([]); + let selectedPeople: PersonResponseDto[] = $state([]); + let screenHeight: number = $state(0); + + let hasSelection = $derived(selectedPeople.length > 0); + let peopleToNotShow = $derived([...selectedPeople, person]); onMount(async () => { const data = await getAllPeople({ withHidden: false }); @@ -96,20 +100,20 @@ class="absolute left-0 top-0 z-[9999] h-full w-full bg-immich-bg dark:bg-immich-dark-bg" > <ControlAppBar onClose={onBack}> - <svelte:fragment slot="leading"> + {#snippet leading()} {#if hasSelection} {$t('selected_count', { values: { count: selectedPeople.length } })} {:else} {$t('merge_people')} {/if} <div></div> - </svelte:fragment> - <svelte:fragment slot="trailing"> - <Button size={'sm'} disabled={!hasSelection} on:click={handleMerge}> + {/snippet} + {#snippet trailing()} + <Button size={'sm'} disabled={!hasSelection} onclick={handleMerge}> <Icon path={mdiMerge} size={18} /> <span class="ml-2">{$t('merge')}</span></Button > - </svelte:fragment> + {/snippet} </ControlAppBar> <section class="bg-immich-bg px-[70px] pt-[100px] dark:bg-immich-dark-bg"> <section id="merge-face-selector relative"> @@ -135,7 +139,7 @@ title={$t('swap_merge_direction')} icon={mdiSwapHorizontal} size="24" - on:click={handleSwapPeople} + onclick={handleSwapPeople} /> </div> {/if} diff --git a/web/src/lib/components/faces-page/merge-suggestion-modal.svelte b/web/src/lib/components/faces-page/merge-suggestion-modal.svelte index f869790eba..a4ac76f198 100644 --- a/web/src/lib/components/faces-page/merge-suggestion-modal.svelte +++ b/web/src/lib/components/faces-page/merge-suggestion-modal.svelte @@ -9,14 +9,25 @@ import CircleIconButton from '../elements/buttons/circle-icon-button.svelte'; import { t } from 'svelte-i18n'; - export let personMerge1: PersonResponseDto; - export let personMerge2: PersonResponseDto; - export let potentialMergePeople: PersonResponseDto[]; - export let onReject: () => void; - export let onConfirm: ([personMerge1, personMerge2]: [PersonResponseDto, PersonResponseDto]) => void; - export let onClose: () => void; + interface Props { + personMerge1: PersonResponseDto; + personMerge2: PersonResponseDto; + potentialMergePeople: PersonResponseDto[]; + onReject: () => void; + onConfirm: ([personMerge1, personMerge2]: [PersonResponseDto, PersonResponseDto]) => void; + onClose: () => void; + } - let choosePersonToMerge = false; + let { + personMerge1 = $bindable(), + personMerge2 = $bindable(), + potentialMergePeople = $bindable(), + onReject, + onConfirm, + onClose, + }: Props = $props(); + + let choosePersonToMerge = $state(false); const title = personMerge2.name; @@ -43,7 +54,7 @@ <CircleIconButton title={$t('swap_merge_direction')} icon={mdiMerge} - on:click={() => ([personMerge1, personMerge2] = [personMerge2, personMerge1])} + onclick={() => ([personMerge1, personMerge2] = [personMerge2, personMerge1])} /> </div> @@ -51,7 +62,7 @@ type="button" disabled={potentialMergePeople.length === 0} class="flex h-28 w-28 items-center rounded-full border-2 border-immich-primary px-1 dark:border-immich-dark-primary md:h-32 md:w-32 md:px-2" - on:click={() => { + onclick={() => { if (potentialMergePeople.length > 0) { choosePersonToMerge = !choosePersonToMerge; } @@ -69,13 +80,13 @@ {:else} <div class="grid w-full grid-cols-1 gap-2"> <div class="px-2"> - <button type="button" on:click={() => (choosePersonToMerge = false)}> <Icon path={mdiArrowLeft} /></button> + <button type="button" onclick={() => (choosePersonToMerge = false)}> <Icon path={mdiArrowLeft} /></button> </div> <div class="flex items-center justify-center"> <div class="flex flex-wrap justify-center md:grid md:grid-cols-{potentialMergePeople.length}"> {#each potentialMergePeople as person (person.id)} <div class="h-24 w-24 md:h-28 md:w-28"> - <button type="button" class="p-2 w-full" on:click={() => changePersonToMerge(person)}> + <button type="button" class="p-2 w-full" onclick={() => changePersonToMerge(person)}> <ImageThumbnail border={true} circle @@ -83,7 +94,7 @@ url={getPeopleThumbnailUrl(person)} altText={person.name} widthStyle="100%" - on:click={() => changePersonToMerge(person)} + onClick={() => changePersonToMerge(person)} /> </button> </div> @@ -100,8 +111,9 @@ <div class="flex px-4 pt-2"> <p class="text-sm text-gray-500 dark:text-gray-300">{$t('they_will_be_merged_together')}</p> </div> - <svelte:fragment slot="sticky-bottom"> - <Button fullwidth color="gray" on:click={onReject}>{$t('no')}</Button> - <Button fullwidth on:click={() => onConfirm([personMerge1, personMerge2])}>{$t('yes')}</Button> - </svelte:fragment> + + {#snippet stickyBottom()} + <Button fullwidth color="gray" onclick={onReject}>{$t('no')}</Button> + <Button fullwidth onclick={() => onConfirm([personMerge1, personMerge2])}>{$t('yes')}</Button> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/faces-page/people-card.svelte b/web/src/lib/components/faces-page/people-card.svelte index 6791a26232..a83d1180f9 100644 --- a/web/src/lib/components/faces-page/people-card.svelte +++ b/web/src/lib/components/faces-page/people-card.svelte @@ -15,28 +15,32 @@ import { focusOutside } from '$lib/actions/focus-outside'; import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte'; - export let person: PersonResponseDto; - export let preload = false; - export let onChangeName: () => void; - export let onSetBirthDate: () => void; - export let onMergePeople: () => void; - export let onHidePerson: () => void; + interface Props { + person: PersonResponseDto; + preload?: boolean; + onChangeName: () => void; + onSetBirthDate: () => void; + onMergePeople: () => void; + onHidePerson: () => void; + } - let showVerticalDots = false; + let { person, preload = false, onChangeName, onSetBirthDate, onMergePeople, onHidePerson }: Props = $props(); + + let showVerticalDots = $state(false); </script> <div id="people-card" class="relative" - on:mouseenter={() => (showVerticalDots = true)} - on:mouseleave={() => (showVerticalDots = false)} + onmouseenter={() => (showVerticalDots = true)} + onmouseleave={() => (showVerticalDots = false)} role="group" use:focusOutside={{ onFocusOut: () => (showVerticalDots = false) }} > <a href="{AppRoute.PEOPLE}/{person.id}?{QueryParameter.PREVIOUS_ROUTE}={AppRoute.PEOPLE}" draggable="false" - on:focus={() => (showVerticalDots = true)} + onfocus={() => (showVerticalDots = true)} > <div class="w-full h-full rounded-xl brightness-95 filter"> <ImageThumbnail diff --git a/web/src/lib/components/faces-page/people-infinite-scroll.svelte b/web/src/lib/components/faces-page/people-infinite-scroll.svelte index aefd6fe957..0de084c4b2 100644 --- a/web/src/lib/components/faces-page/people-infinite-scroll.svelte +++ b/web/src/lib/components/faces-page/people-infinite-scroll.svelte @@ -1,11 +1,16 @@ <script lang="ts"> import type { PersonResponseDto } from '@immich/sdk'; - export let people: PersonResponseDto[]; - export let hasNextPage: boolean | undefined = undefined; - export let loadNextPage: () => void; + interface Props { + people: PersonResponseDto[]; + hasNextPage?: boolean | undefined; + loadNextPage: () => void; + children?: import('svelte').Snippet<[{ person: PersonResponseDto; index: number }]>; + } - let lastPersonContainer: HTMLElement | undefined; + let { people, hasNextPage = undefined, loadNextPage, children }: Props = $props(); + + let lastPersonContainer: HTMLElement | undefined = $state(); const intersectionObserver = new IntersectionObserver((entries) => { const entry = entries.find((entry) => entry.target === lastPersonContainer); @@ -14,20 +19,22 @@ } }); - $: if (lastPersonContainer) { - intersectionObserver.disconnect(); - intersectionObserver.observe(lastPersonContainer); - } + $effect(() => { + if (lastPersonContainer) { + intersectionObserver.disconnect(); + intersectionObserver.observe(lastPersonContainer); + } + }); </script> <div class="w-full grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-7 2xl:grid-cols-9 gap-1"> {#each people as person, index (person.id)} {#if hasNextPage && index === people.length - 1} <div bind:this={lastPersonContainer}> - <slot {person} {index} /> + {@render children?.({ person, index })} </div> {:else} - <slot {person} {index} /> + {@render children?.({ person, index })} {/if} {/each} </div> diff --git a/web/src/lib/components/faces-page/people-list.svelte b/web/src/lib/components/faces-page/people-list.svelte index 10626a6a93..511792e536 100644 --- a/web/src/lib/components/faces-page/people-list.svelte +++ b/web/src/lib/components/faces-page/people-list.svelte @@ -4,22 +4,24 @@ import SearchPeople from '$lib/components/faces-page/people-search.svelte'; import { t } from 'svelte-i18n'; - export let screenHeight: number; - export let people: PersonResponseDto[]; - export let peopleToNotShow: PersonResponseDto[]; - export let onSelect: (person: PersonResponseDto) => void; - - let searchedPeopleLocal: PersonResponseDto[] = []; - - let name = ''; - let showPeople: PersonResponseDto[]; - - $: { - showPeople = name ? searchedPeopleLocal : people; - showPeople = showPeople.filter( - (person) => !peopleToNotShow.some((unselectedPerson) => unselectedPerson.id === person.id), - ); + interface Props { + screenHeight: number; + people: PersonResponseDto[]; + peopleToNotShow: PersonResponseDto[]; + onSelect: (person: PersonResponseDto) => void; } + + let { screenHeight, people, peopleToNotShow, onSelect }: Props = $props(); + + let searchedPeopleLocal: PersonResponseDto[] = $state([]); + + let name = $state(''); + + const showPeople = $derived( + (name ? searchedPeopleLocal : people).filter( + (person) => !peopleToNotShow.some((unselectedPerson) => unselectedPerson.id === person.id), + ), + ); </script> <div class=" w-40 sm:w-48 md:w-96 h-14 mb-8"> diff --git a/web/src/lib/components/faces-page/people-search.svelte b/web/src/lib/components/faces-page/people-search.svelte index 2a952b8145..835f4188c4 100644 --- a/web/src/lib/components/faces-page/people-search.svelte +++ b/web/src/lib/components/faces-page/people-search.svelte @@ -7,16 +7,6 @@ import { searchPerson, type PersonResponseDto } from '@immich/sdk'; import { t } from 'svelte-i18n'; - export let searchName: string; - export let searchedPeopleLocal: PersonResponseDto[]; - export let type: 'searchBar' | 'input'; - export let numberPeopleToSearch: number = maximumLengthSearchPeople; - export let inputClass: string = 'w-full gap-2 bg-immich-bg dark:bg-immich-dark-bg'; - export let showLoadingSpinner: boolean = false; - export let placeholder: string = $t('name_or_nickname'); - export let onReset = () => {}; - export let onSearch = () => {}; - let searchedPeople: PersonResponseDto[] = []; let searchWord: string; let abortController: AbortController | null = null; @@ -43,7 +33,36 @@ } }; - export let handleSearch = async (force?: boolean, name?: string) => { + interface Props { + searchName: string; + searchedPeopleLocal: PersonResponseDto[]; + type: 'searchBar' | 'input'; + numberPeopleToSearch?: number; + inputClass?: string; + showLoadingSpinner?: boolean; + placeholder?: string; + onReset?: () => void; + onSearch?: () => void; + } + + let { + searchName = $bindable(), + searchedPeopleLocal = $bindable(), + type, + numberPeopleToSearch = maximumLengthSearchPeople, + inputClass = 'w-full gap-2 bg-immich-bg dark:bg-immich-dark-bg', + showLoadingSpinner = $bindable(false), + placeholder = $t('name_or_nickname'), + onReset = () => {}, + onSearch = () => {}, + }: Props = $props(); + + const handleReset = () => { + reset(); + onReset(); + }; + + export async function searchPeople(force?: boolean, name?: string) { searchName = name ?? searchName; onSearch(); if (searchName === '') { @@ -70,12 +89,7 @@ showLoadingSpinner = false; search(); } - }; - - const handleReset = () => { - reset(); - onReset(); - }; + } </script> {#if type === 'searchBar'} @@ -84,7 +98,7 @@ {showLoadingSpinner} {placeholder} onReset={handleReset} - onSearch={({ force }) => handleSearch(force ?? false)} + onSearch={({ force }) => searchPeople(force ?? false)} /> {:else} <input @@ -92,7 +106,7 @@ type="text" {placeholder} bind:value={searchName} - on:input={() => handleSearch(false)} + oninput={() => searchPeople(false)} use:initInput /> {/if} 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 13f356dfc0..8bbfaaafcf 100644 --- a/web/src/lib/components/faces-page/person-side-panel.svelte +++ b/web/src/lib/components/faces-page/person-side-panel.svelte @@ -28,28 +28,32 @@ import { photoViewer } from '$lib/stores/assets.store'; import { t } from 'svelte-i18n'; - export let assetId: string; - export let assetType: AssetTypeEnum; - export let onClose: () => void; - export let onRefresh: () => void; + interface Props { + assetId: string; + assetType: AssetTypeEnum; + onClose: () => void; + onRefresh: () => void; + } + + let { assetId, assetType, onClose, onRefresh }: Props = $props(); // keep track of the changes let peopleToCreate: string[] = []; let assetFaceGenerated: string[] = []; // faces - let peopleWithFaces: AssetFaceResponseDto[] = []; - let selectedPersonToReassign: Record<string, PersonResponseDto> = {}; - let selectedPersonToCreate: Record<string, string> = {}; - let editedFace: AssetFaceResponseDto; + let peopleWithFaces: AssetFaceResponseDto[] = $state([]); + let selectedPersonToReassign: Record<string, PersonResponseDto> = $state({}); + let selectedPersonToCreate: Record<string, string> = $state({}); + let editedFace: AssetFaceResponseDto | undefined = $state(); // loading spinners - let isShowLoadingDone = false; - let isShowLoadingPeople = false; + let isShowLoadingDone = $state(false); + let isShowLoadingPeople = $state(false); // search people - let showSelectedFaces = false; - let allPeople: PersonResponseDto[] = []; + let showSelectedFaces = $state(false); + let allPeople: PersonResponseDto[] = $state([]); // timers let loaderLoadingDoneTimeout: ReturnType<typeof setTimeout>; @@ -152,14 +156,14 @@ }; const handleCreatePerson = (newFeaturePhoto: string | null) => { - if (newFeaturePhoto) { + if (newFeaturePhoto && editedFace) { selectedPersonToCreate[editedFace.id] = newFeaturePhoto; } showSelectedFaces = false; }; const handleReassignFace = (person: PersonResponseDto | null) => { - if (person) { + if (person && editedFace) { selectedPersonToReassign[editedFace.id] = person; } showSelectedFaces = false; @@ -177,14 +181,14 @@ > <div class="flex place-items-center justify-between gap-2"> <div class="flex items-center gap-2"> - <CircleIconButton icon={mdiArrowLeftThin} title={$t('back')} on:click={onClose} /> + <CircleIconButton icon={mdiArrowLeftThin} title={$t('back')} onclick={onClose} /> <p class="flex text-lg text-immich-fg dark:text-immich-dark-fg">{$t('edit_faces')}</p> </div> {#if !isShowLoadingDone} <button type="button" class="justify-self-end rounded-lg p-2 hover:bg-immich-dark-primary hover:dark:bg-immich-dark-primary/50" - on:click={() => handleEditFaces()} + onclick={() => handleEditFaces()} > {$t('done')} </button> @@ -207,9 +211,9 @@ role="button" tabindex={index} class="absolute left-0 top-0 h-[90px] w-[90px] cursor-default" - on:focus={() => ($boundingBoxesArray = [peopleWithFaces[index]])} - on:mouseover={() => ($boundingBoxesArray = [peopleWithFaces[index]])} - on:mouseleave={() => ($boundingBoxesArray = [])} + onfocus={() => ($boundingBoxesArray = [peopleWithFaces[index]])} + onmouseover={() => ($boundingBoxesArray = [peopleWithFaces[index]])} + onmouseleave={() => ($boundingBoxesArray = [])} > <div class="relative"> {#if selectedPersonToCreate[face.id]} @@ -291,7 +295,7 @@ size="18" padding="1" class="absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform" - on:click={() => handleReset(face.id)} + onclick={() => handleReset(face.id)} /> {:else} <CircleIconButton @@ -301,7 +305,7 @@ size="18" padding="1" class="absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform" - on:click={() => handleFacePicker(face)} + onclick={() => handleFacePicker(face)} /> {/if} </div> @@ -322,7 +326,7 @@ </div> </section> -{#if showSelectedFaces} +{#if showSelectedFaces && editedFace} <AssignFaceSidePanel {allPeople} {editedFace} diff --git a/web/src/lib/components/faces-page/set-birth-date-modal.svelte b/web/src/lib/components/faces-page/set-birth-date-modal.svelte index d38c519911..f5ecbfabf0 100644 --- a/web/src/lib/components/faces-page/set-birth-date-modal.svelte +++ b/web/src/lib/components/faces-page/set-birth-date-modal.svelte @@ -5,11 +5,20 @@ import DateInput from '../elements/date-input.svelte'; import { t } from 'svelte-i18n'; - export let birthDate: string; - export let onClose: () => void; - export let onUpdate: (birthDate: string) => void; + interface Props { + birthDate: string; + onClose: () => void; + onUpdate: (birthDate: string) => void; + } + + let { birthDate = $bindable(), onClose, onUpdate }: Props = $props(); const todayFormatted = new Date().toISOString().split('T')[0]; + + const onSubmit = (event: Event) => { + event.preventDefault(); + onUpdate(birthDate); + }; </script> <FullScreenModal title={$t('set_date_of_birth')} icon={mdiCake} {onClose}> @@ -19,7 +28,7 @@ </p> </div> - <form on:submit|preventDefault={() => onUpdate(birthDate)} autocomplete="off" id="set-birth-date-form"> + <form onsubmit={(e) => onSubmit(e)} autocomplete="off" id="set-birth-date-form"> <div class="my-4 flex flex-col gap-2"> <DateInput class="immich-form-input" @@ -31,8 +40,9 @@ /> </div> </form> - <svelte:fragment slot="sticky-bottom"> - <Button color="gray" fullwidth on:click={onClose}>{$t('cancel')}</Button> + + {#snippet stickyBottom()} + <Button color="gray" fullwidth onclick={onClose}>{$t('cancel')}</Button> <Button type="submit" fullwidth form="set-birth-date-form">{$t('set')}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> 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 70a360bea0..06c53f3618 100644 --- a/web/src/lib/components/faces-page/unmerge-face-selector.svelte +++ b/web/src/lib/components/faces-page/unmerge-face-selector.svelte @@ -10,7 +10,7 @@ type PersonResponseDto, } from '@immich/sdk'; import { mdiMerge, mdiPlus } from '@mdi/js'; - import { onMount } from 'svelte'; + import { onMount, type Snippet } from 'svelte'; import { quintOut } from 'svelte/easing'; import { fly } from 'svelte/transition'; import Button from '../elements/buttons/button.svelte'; @@ -21,20 +21,26 @@ import PeopleList from './people-list.svelte'; import { t } from 'svelte-i18n'; - export let assetIds: string[]; - export let personAssets: PersonResponseDto; - export let onConfirm: () => void; - export let onClose: () => void; + interface Props { + assetIds: string[]; + personAssets: PersonResponseDto; + onConfirm: () => void; + onClose: () => void; + header?: Snippet; + merge?: Snippet; + } - let people: PersonResponseDto[] = []; - let selectedPerson: PersonResponseDto | null = null; - let disableButtons = false; - let showLoadingSpinnerCreate = false; - let showLoadingSpinnerReassign = false; - let hasSelection = false; - let screenHeight: number; + let { assetIds, personAssets, onConfirm, onClose, header, merge }: Props = $props(); - $: peopleToNotShow = selectedPerson ? [personAssets, selectedPerson] : [personAssets]; + let people: PersonResponseDto[] = $state([]); + let selectedPerson: PersonResponseDto | null = $state(null); + let disableButtons = $state(false); + let showLoadingSpinnerCreate = $state(false); + let showLoadingSpinnerReassign = $state(false); + let hasSelection = $state(false); + let screenHeight: number = $state(0); + + let peopleToNotShow = $derived(selectedPerson ? [personAssets, selectedPerson] : [personAssets]); const selectedPeople: AssetFaceUpdateItem[] = []; @@ -117,17 +123,17 @@ class="absolute left-0 top-0 z-[9999] h-full w-full bg-immich-bg dark:bg-immich-dark-bg" > <ControlAppBar {onClose}> - <svelte:fragment slot="leading"> - <slot name="header" /> + {#snippet leading()} + {@render header?.()} <div></div> - </svelte:fragment> - <svelte:fragment slot="trailing"> + {/snippet} + {#snippet trailing()} <div class="flex gap-4"> <Button title={$t('create_new_person_hint')} size={'sm'} disabled={disableButtons || hasSelection} - on:click={handleCreate} + onclick={handleCreate} > {#if !showLoadingSpinnerCreate} <Icon path={mdiPlus} size={18} /> @@ -140,7 +146,7 @@ size={'sm'} title={$t('reassing_hint')} disabled={disableButtons || !hasSelection} - on:click={handleReassign} + onclick={handleReassign} > {#if !showLoadingSpinnerReassign} <div> @@ -152,9 +158,9 @@ <span class="ml-2"> {$t('reassign')}</span></Button > </div> - </svelte:fragment> + {/snippet} </ControlAppBar> - <slot name="merge" /> + {@render merge?.()} <section class="bg-immich-bg px-[70px] pt-[100px] dark:bg-immich-dark-bg"> <section id="merge-face-selector relative"> {#if selectedPerson !== null} diff --git a/web/src/lib/components/forms/admin-registration-form.svelte b/web/src/lib/components/forms/admin-registration-form.svelte index d49ab55439..b4ecd56283 100644 --- a/web/src/lib/components/forms/admin-registration-form.svelte +++ b/web/src/lib/components/forms/admin-registration-form.svelte @@ -8,15 +8,15 @@ import { t } from 'svelte-i18n'; import { retrieveServerConfig } from '$lib/stores/server-config.store'; - let email = ''; - let password = ''; - let confirmPassword = ''; - let name = ''; + let email = $state(''); + let password = $state(''); + let confirmPassword = $state(''); + let name = $state(''); - let errorMessage: string; - let canRegister = false; + let errorMessage: string = $state(''); + let canRegister = $state(false); - $: { + $effect(() => { if (password !== confirmPassword && confirmPassword.length > 0) { errorMessage = $t('password_does_not_match'); canRegister = false; @@ -24,7 +24,7 @@ errorMessage = ''; canRegister = true; } - } + }); async function registerAdmin() { if (canRegister) { @@ -40,9 +40,14 @@ } } } + + const onsubmit = async (event: Event) => { + event.preventDefault(); + await registerAdmin(); + }; </script> -<form on:submit|preventDefault={registerAdmin} method="post" class="mt-5 flex flex-col gap-5"> +<form {onsubmit} method="post" class="mt-5 flex flex-col gap-5"> <div class="flex flex-col gap-2"> <label class="immich-form-label" for="email">{$t('admin_email')}</label> <input class="immich-form-input" id="email" bind:value={email} type="email" autocomplete="email" required /> diff --git a/web/src/lib/components/forms/api-key-form.svelte b/web/src/lib/components/forms/api-key-form.svelte index 5b1341db44..086d7708c3 100644 --- a/web/src/lib/components/forms/api-key-form.svelte +++ b/web/src/lib/components/forms/api-key-form.svelte @@ -5,13 +5,23 @@ import FullScreenModal from '../shared-components/full-screen-modal.svelte'; import { NotificationType, notificationController } from '../shared-components/notification/notification'; - export let apiKey: { name: string }; - export let title: string; - export let cancelText = $t('cancel'); - export let submitText = $t('save'); + interface Props { + apiKey: { name: string }; + title: string; + cancelText?: string; + submitText?: string; + onSubmit: (apiKey: { name: string }) => void; + onCancel: () => void; + } - export let onSubmit: (apiKey: { name: string }) => void; - export let onCancel: () => void; + let { + apiKey = $bindable(), + title, + cancelText = $t('cancel'), + submitText = $t('save'), + onSubmit, + onCancel, + }: Props = $props(); const handleSubmit = () => { if (apiKey.name) { @@ -23,17 +33,23 @@ }); } }; + + const onsubmit = (event: Event) => { + event.preventDefault(); + handleSubmit(); + }; </script> <FullScreenModal {title} icon={mdiKeyVariant} onClose={() => onCancel()}> - <form on:submit|preventDefault={handleSubmit} autocomplete="off" id="api-key-form"> + <form {onsubmit} autocomplete="off" id="api-key-form"> <div class="mb-4 flex flex-col gap-2"> <label class="immich-form-label" for="name">{$t('name')}</label> <input class="immich-form-input" id="name" name="name" type="text" bind:value={apiKey.name} /> </div> </form> - <svelte:fragment slot="sticky-bottom"> - <Button color="gray" fullwidth on:click={() => onCancel()}>{cancelText}</Button> + + {#snippet stickyBottom()} + <Button color="gray" fullwidth onclick={() => onCancel()}>{cancelText}</Button> <Button type="submit" fullwidth form="api-key-form">{submitText}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/forms/api-key-secret.svelte b/web/src/lib/components/forms/api-key-secret.svelte index dbbefe0d71..fd0503e850 100644 --- a/web/src/lib/components/forms/api-key-secret.svelte +++ b/web/src/lib/components/forms/api-key-secret.svelte @@ -5,8 +5,12 @@ import FullScreenModal from '../shared-components/full-screen-modal.svelte'; import { t } from 'svelte-i18n'; - export let secret = ''; - export let onDone: () => void; + interface Props { + secret?: string; + onDone: () => void; + } + + let { secret = '', onDone }: Props = $props(); </script> <FullScreenModal title={$t('api_key')} icon={mdiKeyVariant} onClose={onDone}> @@ -21,8 +25,8 @@ <textarea class="immich-form-input" id="secret" name="secret" readonly={true} value={secret}></textarea> </div> - <svelte:fragment slot="sticky-bottom"> - <Button on:click={() => copyToClipboard(secret)} fullwidth>{$t('copy_to_clipboard')}</Button> - <Button on:click={onDone} fullwidth>{$t('done')}</Button> - </svelte:fragment> + {#snippet stickyBottom()} + <Button onclick={() => copyToClipboard(secret)} fullwidth>{$t('copy_to_clipboard')}</Button> + <Button onclick={onDone} fullwidth>{$t('done')}</Button> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/forms/change-password-form.svelte b/web/src/lib/components/forms/change-password-form.svelte index cbf2ff07f0..94dbb5841f 100644 --- a/web/src/lib/components/forms/change-password-form.svelte +++ b/web/src/lib/components/forms/change-password-form.svelte @@ -4,17 +4,21 @@ import { updateMyUser } from '@immich/sdk'; import { t } from 'svelte-i18n'; - export let onSuccess: () => void; + interface Props { + onSuccess: () => void; + } - let errorMessage: string; + let { onSuccess }: Props = $props(); + + let errorMessage: string = $state(''); let success: string; - let password = ''; - let passwordConfirm = ''; + let password = $state(''); + let passwordConfirm = $state(''); - let valid = false; + let valid = $state(false); - $: { + $effect(() => { if (password !== passwordConfirm && passwordConfirm.length > 0) { errorMessage = $t('password_does_not_match'); valid = false; @@ -22,7 +26,7 @@ errorMessage = ''; valid = true; } - } + }); async function changePassword() { if (valid) { @@ -33,9 +37,14 @@ onSuccess(); } } + + const onsubmit = async (event: Event) => { + event.preventDefault(); + await changePassword(); + }; </script> -<form on:submit|preventDefault={changePassword} method="post" class="mt-5 flex flex-col gap-5"> +<form {onsubmit} method="post" class="mt-5 flex flex-col gap-5"> <div class="flex flex-col gap-2"> <label class="immich-form-label" for="password">{$t('new_password')}</label> <PasswordField id="password" bind:password autocomplete="new-password" /> diff --git a/web/src/lib/components/forms/create-user-form.svelte b/web/src/lib/components/forms/create-user-form.svelte index 0687912542..b1599a24b2 100644 --- a/web/src/lib/components/forms/create-user-form.svelte +++ b/web/src/lib/components/forms/create-user-form.svelte @@ -10,29 +10,33 @@ import Slider from '../elements/slider.svelte'; import PasswordField from '../shared-components/password-field.svelte'; - export let onClose: () => void; - export let onSubmit: () => void; - export let onCancel: () => void; - export let oauthEnabled = false; + interface Props { + onClose: () => void; + onSubmit: () => void; + onCancel: () => void; + oauthEnabled?: boolean; + } - let error: string; - let success: string; + let { onClose, onSubmit, onCancel, oauthEnabled = false }: Props = $props(); - let email = ''; - let password = ''; - let confirmPassword = ''; - let name = ''; - let shouldChangePassword = true; - let notify = true; + let error = $state(''); + let success = $state(''); - let canCreateUser = false; - let quotaSize: number | undefined; - let isCreatingUser = false; + let email = $state(''); + let password = $state(''); + let confirmPassword = $state(''); + let name = $state(''); + let shouldChangePassword = $state(true); + let notify = $state(true); - $: quotaSizeInBytes = quotaSize ? convertToBytes(quotaSize, ByteUnit.GiB) : null; - $: quotaSizeWarning = quotaSizeInBytes && quotaSizeInBytes > $serverInfo.diskSizeRaw; + let canCreateUser = $state(false); + let quotaSize: number | undefined = $state(); + let isCreatingUser = $state(false); - $: { + let quotaSizeInBytes = $derived(quotaSize ? convertToBytes(quotaSize, ByteUnit.GiB) : null); + let quotaSizeWarning = $derived(quotaSizeInBytes && quotaSizeInBytes > $serverInfo.diskSizeRaw); + + $effect(() => { if (password !== confirmPassword && confirmPassword.length > 0) { error = $t('password_does_not_match'); canCreateUser = false; @@ -40,7 +44,7 @@ error = ''; canCreateUser = true; } - } + }); async function registerUser() { if (canCreateUser && !isCreatingUser) { @@ -71,10 +75,15 @@ } } } + + const onsubmit = async (event: Event) => { + event.preventDefault(); + await registerUser(); + }; </script> <FullScreenModal title={$t('create_new_user')} showLogo {onClose}> - <form on:submit|preventDefault={registerUser} autocomplete="off" id="create-new-user-form"> + <form {onsubmit} autocomplete="off" id="create-new-user-form"> <div class="my-4 flex flex-col gap-2"> <label class="immich-form-label" for="email">{$t('email')}</label> <input class="immich-form-input" id="email" bind:value={email} type="email" required /> @@ -134,8 +143,9 @@ <p class="text-sm text-immich-primary">{success}</p> {/if} </form> - <svelte:fragment slot="sticky-bottom"> - <Button color="gray" fullwidth on:click={onCancel}>{$t('cancel')}</Button> + + {#snippet stickyBottom()} + <Button color="gray" fullwidth onclick={onCancel}>{$t('cancel')}</Button> <Button type="submit" disabled={isCreatingUser} fullwidth form="create-new-user-form">{$t('create')}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/forms/edit-album-form.svelte b/web/src/lib/components/forms/edit-album-form.svelte index e33774245b..bd61cd2068 100644 --- a/web/src/lib/components/forms/edit-album-form.svelte +++ b/web/src/lib/components/forms/edit-album-form.svelte @@ -6,15 +6,19 @@ import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte'; import { t } from 'svelte-i18n'; - export let album: AlbumResponseDto; - export let onEditSuccess: ((album: AlbumResponseDto) => unknown) | undefined = undefined; - export let onCancel: (() => unknown) | undefined = undefined; - export let onClose: () => void; + interface Props { + album: AlbumResponseDto; + onEditSuccess?: ((album: AlbumResponseDto) => unknown) | undefined; + onCancel?: (() => unknown) | undefined; + onClose: () => void; + } - let albumName = album.albumName; - let description = album.description; + let { album = $bindable(), onEditSuccess = undefined, onCancel = undefined, onClose }: Props = $props(); - let isSubmitting = false; + let albumName = $state(album.albumName); + let description = $state(album.description); + + let isSubmitting = $state(false); const handleUpdateAlbumInfo = async () => { isSubmitting = true; @@ -35,10 +39,15 @@ isSubmitting = false; } }; + + const onsubmit = async (event: Event) => { + event.preventDefault(); + await handleUpdateAlbumInfo(); + }; </script> <FullScreenModal title={$t('edit_album')} width="wide" {onClose}> - <form on:submit|preventDefault={handleUpdateAlbumInfo} autocomplete="off" id="edit-album-form"> + <form {onsubmit} autocomplete="off" id="edit-album-form"> <div class="flex items-center"> <div class="hidden sm:flex"> <AlbumCover {album} class="h-[200px] w-[200px] m-4 shadow-lg" /> @@ -57,8 +66,9 @@ </div> </div> </form> - <svelte:fragment slot="sticky-bottom"> - <Button color="gray" fullwidth on:click={() => onCancel?.()}>{$t('cancel')}</Button> + + {#snippet stickyBottom()} + <Button color="gray" fullwidth onclick={() => onCancel?.()}>{$t('cancel')}</Button> <Button type="submit" fullwidth disabled={isSubmitting} form="edit-album-form">{$t('ok')}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/forms/edit-user-form.svelte b/web/src/lib/components/forms/edit-user-form.svelte index 0079a695bc..e95ed64135 100644 --- a/web/src/lib/components/forms/edit-user-form.svelte +++ b/web/src/lib/components/forms/edit-user-form.svelte @@ -10,23 +10,35 @@ import { t } from 'svelte-i18n'; import { ByteUnit, convertFromBytes, convertToBytes } from '$lib/utils/byte-units'; - export let user: UserAdminResponseDto; - export let canResetPassword = true; - export let newPassword: string; - export let onClose: () => void; - export let onResetPasswordSuccess: () => void; - export let onEditSuccess: () => void; + interface Props { + user: UserAdminResponseDto; + canResetPassword?: boolean; + newPassword: string; + onClose: () => void; + onResetPasswordSuccess: () => void; + onEditSuccess: () => void; + } + + let { + user, + canResetPassword = true, + newPassword = $bindable(), + onClose, + onResetPasswordSuccess, + onEditSuccess, + }: Props = $props(); let error: string; let success: string; - let quotaSize = user.quotaSizeInBytes ? convertFromBytes(user.quotaSizeInBytes, ByteUnit.GiB) : null; + let quotaSize = $state(user.quotaSizeInBytes ? convertFromBytes(user.quotaSizeInBytes, ByteUnit.GiB) : null); const previousQutoa = user.quotaSizeInBytes; - $: quotaSizeWarning = + let quotaSizeWarning = $derived( previousQutoa !== convertToBytes(Number(quotaSize), ByteUnit.GiB) && - !!quotaSize && - convertToBytes(Number(quotaSize), ByteUnit.GiB) > $serverInfo.diskSizeRaw; + !!quotaSize && + convertToBytes(Number(quotaSize), ByteUnit.GiB) > $serverInfo.diskSizeRaw, + ); const editUser = async () => { try { @@ -89,10 +101,15 @@ return generatedPassword; } + + const onSubmit = async (event: Event) => { + event.preventDefault(); + await editUser(); + }; </script> <FullScreenModal title={$t('edit_user')} icon={mdiAccountEditOutline} {onClose}> - <form on:submit|preventDefault={editUser} autocomplete="off" id="edit-user-form"> + <form onsubmit={onSubmit} autocomplete="off" id="edit-user-form"> <div class="my-4 flex flex-col gap-2"> <label class="immich-form-label" for="email">{$t('email')}</label> <input class="immich-form-input" id="email" name="email" type="email" bind:value={user.email} /> @@ -140,10 +157,11 @@ <p class="ml-4 text-sm text-immich-primary">{success}</p> {/if} </form> - <svelte:fragment slot="sticky-bottom"> + + {#snippet stickyBottom()} {#if canResetPassword} - <Button color="light-red" fullwidth on:click={resetPassword}>{$t('reset_password')}</Button> + <Button color="light-red" fullwidth onclick={resetPassword}>{$t('reset_password')}</Button> {/if} <Button type="submit" fullwidth form="edit-user-form">{$t('confirm')}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/forms/library-exclusion-pattern-form.svelte b/web/src/lib/components/forms/library-exclusion-pattern-form.svelte index 05d47c0a0f..e79b60d265 100644 --- a/web/src/lib/components/forms/library-exclusion-pattern-form.svelte +++ b/web/src/lib/components/forms/library-exclusion-pattern-form.svelte @@ -5,13 +5,25 @@ import { onMount } from 'svelte'; import { t } from 'svelte-i18n'; - export let exclusionPattern: string; - export let exclusionPatterns: string[] = []; - export let isEditing = false; - export let submitText = $t('submit'); - export let onCancel: () => void; - export let onSubmit: (exclusionPattern: string) => void; - export let onDelete: () => void = () => {}; + interface Props { + exclusionPattern: string; + exclusionPatterns?: string[]; + isEditing?: boolean; + submitText?: string; + onCancel: () => void; + onSubmit: (exclusionPattern: string) => void; + onDelete?: () => void; + } + + let { + exclusionPattern = $bindable(), + exclusionPatterns = $bindable([]), + isEditing = false, + submitText = $t('submit'), + onCancel, + onSubmit, + onDelete, + }: Props = $props(); onMount(() => { if (isEditing) { @@ -19,12 +31,19 @@ } }); - $: isDuplicate = exclusionPattern !== null && exclusionPatterns.includes(exclusionPattern); - $: canSubmit = exclusionPattern && !exclusionPatterns.includes(exclusionPattern); + let isDuplicate = $derived(exclusionPattern !== null && exclusionPatterns.includes(exclusionPattern)); + let canSubmit = $derived(exclusionPattern && !exclusionPatterns.includes(exclusionPattern)); + + const onsubmit = (event: Event) => { + event.preventDefault(); + if (canSubmit) { + onSubmit(exclusionPattern); + } + }; </script> <FullScreenModal title={$t('add_exclusion_pattern')} icon={mdiFolderRemove} onClose={onCancel}> - <form on:submit|preventDefault={() => onSubmit(exclusionPattern)} autocomplete="off" id="add-exclusion-pattern-form"> + <form {onsubmit} autocomplete="off" id="add-exclusion-pattern-form"> <p class="py-5 text-sm"> {$t('admin.exclusion_pattern_description')} <br /><br /> @@ -46,11 +65,12 @@ {/if} </div> </form> - <svelte:fragment slot="sticky-bottom"> - <Button color="gray" fullwidth on:click={onCancel}>{$t('cancel')}</Button> + + {#snippet stickyBottom()} + <Button color="gray" fullwidth onclick={onCancel}>{$t('cancel')}</Button> {#if isEditing} - <Button color="red" fullwidth on:click={onDelete}>{$t('delete')}</Button> + <Button color="red" fullwidth onclick={onDelete}>{$t('delete')}</Button> {/if} <Button type="submit" disabled={!canSubmit} fullwidth form="add-exclusion-pattern-form">{submitText}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/forms/library-import-path-form.svelte b/web/src/lib/components/forms/library-import-path-form.svelte index 8bfca80aec..33e763f0f0 100644 --- a/web/src/lib/components/forms/library-import-path-form.svelte +++ b/web/src/lib/components/forms/library-import-path-form.svelte @@ -5,15 +5,29 @@ import { onMount } from 'svelte'; import { t } from 'svelte-i18n'; - export let importPath: string | null; - export let importPaths: string[] = []; - export let title = $t('import_path'); - export let cancelText = $t('cancel'); - export let submitText = $t('save'); - export let isEditing = false; - export let onCancel: () => void; - export let onSubmit: (importPath: string | null) => void; - export let onDelete: () => void = () => {}; + interface Props { + importPath: string | null; + importPaths?: string[]; + title?: string; + cancelText?: string; + submitText?: string; + isEditing?: boolean; + onCancel: () => void; + onSubmit: (importPath: string | null) => void; + onDelete?: () => void; + } + + let { + importPath = $bindable(), + importPaths = $bindable([]), + title = $t('import_path'), + cancelText = $t('cancel'), + submitText = $t('save'), + isEditing = false, + onCancel, + onSubmit, + onDelete, + }: Props = $props(); onMount(() => { if (isEditing) { @@ -21,12 +35,19 @@ } }); - $: isDuplicate = importPath !== null && importPaths.includes(importPath); - $: canSubmit = importPath !== '' && importPath !== null && !importPaths.includes(importPath); + let isDuplicate = $derived(importPath !== null && importPaths.includes(importPath)); + let canSubmit = $derived(importPath !== '' && importPath !== null && !importPaths.includes(importPath)); + + const onsubmit = (event: Event) => { + event.preventDefault(); + if (canSubmit) { + onSubmit(importPath); + } + }; </script> <FullScreenModal {title} icon={mdiFolderSync} onClose={onCancel}> - <form on:submit|preventDefault={() => onSubmit(importPath)} autocomplete="off" id="library-import-path-form"> + <form {onsubmit} autocomplete="off" id="library-import-path-form"> <p class="py-5 text-sm">{$t('admin.library_import_path_description')}</p> <div class="my-4 flex flex-col gap-2"> @@ -40,11 +61,12 @@ {/if} </div> </form> - <svelte:fragment slot="sticky-bottom"> - <Button color="gray" fullwidth on:click={onCancel}>{cancelText}</Button> + + {#snippet stickyBottom()} + <Button color="gray" fullwidth onclick={onCancel}>{cancelText}</Button> {#if isEditing} - <Button color="red" fullwidth on:click={onDelete}>{$t('delete')}</Button> + <Button color="red" fullwidth onclick={onDelete}>{$t('delete')}</Button> {/if} <Button type="submit" disabled={!canSubmit} fullwidth form="library-import-path-form">{submitText}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> 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 9e7ae11a63..3acd46520f 100644 --- a/web/src/lib/components/forms/library-import-paths-form.svelte +++ b/web/src/lib/components/forms/library-import-paths-form.svelte @@ -11,19 +11,23 @@ import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; import { t } from 'svelte-i18n'; - export let library: LibraryResponseDto; - export let onCancel: () => void; - export let onSubmit: (library: LibraryResponseDto) => void; + interface Props { + library: LibraryResponseDto; + onCancel: () => void; + onSubmit: (library: LibraryResponseDto) => void; + } - let addImportPath = false; - let editImportPath: number | null = null; + let { library = $bindable(), onCancel, onSubmit }: Props = $props(); - let importPathToAdd: string | null = null; - let editedImportPath: string; + let addImportPath = $state(false); + let editImportPath: number | null = $state(null); - let validatedPaths: ValidateLibraryImportPathResponseDto[] = []; + let importPathToAdd: string | null = $state(null); + let editedImportPath: string = $state(''); - $: importPaths = validatedPaths.map((validatedPath) => validatedPath.importPath); + let validatedPaths: ValidateLibraryImportPathResponseDto[] = $state([]); + + let importPaths = $derived(validatedPaths.map((validatedPath) => validatedPath.importPath)); onMount(async () => { if (library.importPaths) { @@ -134,6 +138,11 @@ editImportPath = null; } }; + + const onsubmit = (event: Event) => { + event.preventDefault(); + onSubmit({ ...library }); + }; </script> {#if addImportPath} @@ -163,7 +172,7 @@ /> {/if} -<form on:submit|preventDefault={() => onSubmit({ ...library })} autocomplete="off" class="m-4 flex flex-col gap-4"> +<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} @@ -199,7 +208,7 @@ icon={mdiPencilOutline} title={$t('edit_import_path')} size="16" - on:click={() => { + onclick={() => { editImportPath = listIndex; editedImportPath = validatedPath.importPath; }} @@ -223,7 +232,7 @@ ><Button type="button" size="sm" - on:click={() => { + onclick={() => { addImportPath = true; }}>{$t('add_path')}</Button ></td @@ -233,12 +242,12 @@ </table> <div class="flex justify-between w-full"> <div class="justify-end gap-2"> - <Button size="sm" color="gray" on:click={() => revalidate()} + <Button size="sm" color="gray" onclick={() => revalidate()} ><Icon path={mdiRefresh} size={20} />{$t('validate')}</Button > </div> <div class="justify-end gap-2"> - <Button size="sm" color="gray" on:click={onCancel}>{$t('cancel')}</Button> + <Button size="sm" color="gray" onclick={onCancel}>{$t('cancel')}</Button> <Button size="sm" type="submit">{$t('save')}</Button> </div> </div> diff --git a/web/src/lib/components/forms/library-rename-form.svelte b/web/src/lib/components/forms/library-rename-form.svelte index 1f93fb028b..3f20709474 100644 --- a/web/src/lib/components/forms/library-rename-form.svelte +++ b/web/src/lib/components/forms/library-rename-form.svelte @@ -3,18 +3,27 @@ import Button from '../elements/buttons/button.svelte'; import { t } from 'svelte-i18n'; - export let library: Partial<LibraryResponseDto>; - export let onCancel: () => void; - export let onSubmit: (library: Partial<LibraryResponseDto>) => void; + interface Props { + library: Partial<LibraryResponseDto>; + onCancel: () => void; + onSubmit: (library: Partial<LibraryResponseDto>) => void; + } + + let { library = $bindable(), onCancel, onSubmit }: Props = $props(); + + const onsubmit = (event: Event) => { + event.preventDefault(); + onSubmit({ ...library }); + }; </script> -<form on:submit|preventDefault={() => onSubmit({ ...library })} autocomplete="off" class="m-4 flex flex-col gap-2"> +<form {onsubmit} autocomplete="off" class="m-4 flex flex-col gap-2"> <div class="flex flex-col gap-2"> <label class="immich-form-label" for="path">{$t('name')}</label> <input class="immich-form-input" id="name" name="name" type="text" bind:value={library.name} /> </div> <div class="flex w-full justify-end gap-2 pt-2"> - <Button size="sm" color="gray" on:click={onCancel}>{$t('cancel')}</Button> + <Button size="sm" color="gray" onclick={onCancel}>{$t('cancel')}</Button> <Button size="sm" type="submit">{$t('save')}</Button> </div> </form> 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 a9a42c31f7..68e99641e8 100644 --- a/web/src/lib/components/forms/library-scan-settings-form.svelte +++ b/web/src/lib/components/forms/library-scan-settings-form.svelte @@ -8,17 +8,21 @@ import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; import { t } from 'svelte-i18n'; - export let library: Partial<LibraryResponseDto>; - export let onCancel: () => void; - export let onSubmit: (library: Partial<LibraryResponseDto>) => void; + interface Props { + library: Partial<LibraryResponseDto>; + onCancel: () => void; + onSubmit: (library: Partial<LibraryResponseDto>) => void; + } - let addExclusionPattern = false; - let editExclusionPattern: number | null = null; + let { library = $bindable(), onCancel, onSubmit }: Props = $props(); - let exclusionPatternToAdd: string; - let editedExclusionPattern: string; + let addExclusionPattern = $state(false); + let editExclusionPattern: number | null = $state(null); - let exclusionPatterns: string[] = []; + let exclusionPatternToAdd: string = $state(''); + let editedExclusionPattern: string = $state(''); + + let exclusionPatterns: string[] = $state([]); onMount(() => { if (library.exclusionPatterns) { @@ -89,6 +93,11 @@ editExclusionPattern = null; } }; + + const onsubmit = (event: Event) => { + event.preventDefault(); + onSubmit(library); + }; </script> {#if addExclusionPattern} @@ -113,7 +122,7 @@ /> {/if} -<form on:submit|preventDefault={() => onSubmit(library)} autocomplete="off" class="m-4 flex flex-col gap-4"> +<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} @@ -131,7 +140,7 @@ icon={mdiPencilOutline} title={$t('edit_exclusion_pattern')} size="16" - on:click={() => { + onclick={() => { editExclusionPattern = listIndex; editedExclusionPattern = exclusionPattern; }} @@ -154,7 +163,7 @@ <td class="w-1/4 text-ellipsis px-4 text-sm" ><Button size="sm" - on:click={() => { + onclick={() => { addExclusionPattern = true; }}>{$t('add_exclusion_pattern')}</Button ></td @@ -164,7 +173,7 @@ </table> <div class="flex w-full justify-end gap-4"> - <Button size="sm" color="gray" on:click={onCancel}>{$t('cancel')}</Button> + <Button size="sm" color="gray" onclick={onCancel}>{$t('cancel')}</Button> <Button size="sm" type="submit">{$t('save')}</Button> </div> </form> diff --git a/web/src/lib/components/forms/library-user-picker-form.svelte b/web/src/lib/components/forms/library-user-picker-form.svelte index e5334ff9e9..137a49921a 100644 --- a/web/src/lib/components/forms/library-user-picker-form.svelte +++ b/web/src/lib/components/forms/library-user-picker-form.svelte @@ -8,27 +8,37 @@ import SettingSelect from '$lib/components/shared-components/settings/setting-select.svelte'; import { t } from 'svelte-i18n'; - export let onCancel: () => void; - export let onSubmit: (ownerId: string) => void; + interface Props { + onCancel: () => void; + onSubmit: (ownerId: string) => void; + } - let ownerId: string = $user.id; + let { onCancel, onSubmit }: Props = $props(); - let userOptions: { value: string; text: string }[] = []; + let ownerId: string = $state($user.id); + + let userOptions: { value: string; text: string }[] = $state([]); onMount(async () => { const users = await searchUsersAdmin({}); userOptions = users.map((user) => ({ value: user.id, text: user.name })); }); + + const onsubmit = (event: Event) => { + event.preventDefault(); + onSubmit(ownerId); + }; </script> <FullScreenModal title={$t('select_library_owner')} icon={mdiFolderSync} onClose={onCancel}> - <form on:submit|preventDefault={() => onSubmit(ownerId)} autocomplete="off" id="select-library-owner-form"> + <form {onsubmit} autocomplete="off" id="select-library-owner-form"> <p class="p-5 text-sm">{$t('admin.note_cannot_be_changed_later')}</p> <SettingSelect bind:value={ownerId} options={userOptions} name="user" /> </form> - <svelte:fragment slot="sticky-bottom"> - <Button color="gray" fullwidth on:click={onCancel}>{$t('cancel')}</Button> + + {#snippet stickyBottom()} + <Button color="gray" fullwidth onclick={onCancel}>{$t('cancel')}</Button> <Button type="submit" fullwidth form="select-library-owner-form">{$t('create')}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/forms/login-form.svelte b/web/src/lib/components/forms/login-form.svelte index b1af7a01f4..be40210e17 100644 --- a/web/src/lib/components/forms/login-form.svelte +++ b/web/src/lib/components/forms/login-form.svelte @@ -12,16 +12,20 @@ import PasswordField from '../shared-components/password-field.svelte'; import { t } from 'svelte-i18n'; - export let onSuccess: () => unknown | Promise<unknown>; - export let onFirstLogin: () => unknown | Promise<unknown>; - export let onOnboarding: () => unknown | Promise<unknown>; + interface Props { + onSuccess: () => unknown | Promise<unknown>; + onFirstLogin: () => unknown | Promise<unknown>; + onOnboarding: () => unknown | Promise<unknown>; + } - let errorMessage: string; - let email = ''; - let password = ''; - let oauthError = ''; - let loading = false; - let oauthLoading = true; + let { onSuccess, onFirstLogin, onOnboarding }: Props = $props(); + + let errorMessage: string = $state(''); + let email = $state(''); + let password = $state(''); + let oauthError = $state(''); + let loading = $state(false); + let oauthLoading = $state(true); onMount(async () => { if (!$featureFlags.oauth) { @@ -87,10 +91,15 @@ oauthError = $t('errors.unable_to_login_with_oauth'); } }; + + const onsubmit = async (event: Event) => { + event.preventDefault(); + await handleLogin(); + }; </script> {#if !oauthLoading && $featureFlags.passwordLogin} - <form on:submit|preventDefault={handleLogin} class="mt-5 flex flex-col gap-5"> + <form {onsubmit} class="mt-5 flex flex-col gap-5"> {#if errorMessage} <p class="text-red-400" transition:fade> {errorMessage} @@ -150,7 +159,7 @@ size="lg" fullwidth color={$featureFlags.passwordLogin ? 'secondary' : 'primary'} - on:click={handleOAuthLogin} + onclick={handleOAuthLogin} > {#if oauthLoading} <span class="h-6"> diff --git a/web/src/lib/components/forms/tag-asset-form.svelte b/web/src/lib/components/forms/tag-asset-form.svelte index b5e358ec96..84a8c1a409 100644 --- a/web/src/lib/components/forms/tag-asset-form.svelte +++ b/web/src/lib/components/forms/tag-asset-form.svelte @@ -9,14 +9,19 @@ import Icon from '$lib/components/elements/icon.svelte'; import { AppRoute } from '$lib/constants'; import FormatMessage from '$lib/components/i18n/format-message.svelte'; + import { SvelteSet } from 'svelte/reactivity'; - export let onTag: (tagIds: string[]) => void; - export let onCancel: () => void; + interface Props { + onTag: (tagIds: string[]) => void; + onCancel: () => void; + } - let allTags: TagResponseDto[] = []; - $: tagMap = Object.fromEntries(allTags.map((tag) => [tag.id, tag])); - let selectedIds = new Set<string>(); - $: disabled = selectedIds.size === 0; + let { onTag, onCancel }: Props = $props(); + + let allTags: TagResponseDto[] = $state([]); + let tagMap = $derived(Object.fromEntries(allTags.map((tag) => [tag.id, tag]))); + let selectedIds = $state(new SvelteSet<string>()); + let disabled = $derived(selectedIds.size === 0); onMount(async () => { allTags = await getAllTags(); @@ -37,19 +42,26 @@ selectedIds.delete(tag); selectedIds = selectedIds; }; + + const onsubmit = (event: Event) => { + event.preventDefault(); + handleSubmit(); + }; </script> <FullScreenModal title={$t('tag_assets')} icon={mdiTag} onClose={onCancel}> <div class="text-sm"> <p> - <FormatMessage key="tag_not_found_question" let:message> - <a href={AppRoute.TAGS} class="text-immich-primary dark:text-immich-dark-primary underline"> - {message} - </a> + <FormatMessage key="tag_not_found_question"> + {#snippet children({ message })} + <a href={AppRoute.TAGS} class="text-immich-primary dark:text-immich-dark-primary underline"> + {message} + </a> + {/snippet} </FormatMessage> </p> </div> - <form on:submit|preventDefault={handleSubmit} autocomplete="off" id="create-tag-form"> + <form {onsubmit} autocomplete="off" id="create-tag-form"> <div class="my-4 flex flex-col gap-2"> <Combobox onSelect={handleSelect} @@ -77,7 +89,7 @@ type="button" class="text-gray-100 dark:text-immich-dark-gray bg-immich-primary/95 dark:bg-immich-dark-primary/95 rounded-tr-full rounded-br-full place-items-center place-content-center pr-2 pl-1 py-1 hover:bg-immich-primary/80 dark:hover:bg-immich-dark-primary/80 transition-all" title="Remove tag" - on:click={() => handleRemove(tagId)} + onclick={() => handleRemove(tagId)} > <Icon path={mdiClose} /> </button> @@ -86,8 +98,8 @@ {/each} </section> - <svelte:fragment slot="sticky-bottom"> - <Button color="gray" fullwidth on:click={onCancel}>{$t('cancel')}</Button> + {#snippet stickyBottom()} + <Button color="gray" fullwidth onclick={onCancel}>{$t('cancel')}</Button> <Button type="submit" fullwidth form="create-tag-form" {disabled}>{$t('tag_assets')}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/i18n/__test__/format-tag-b.svelte b/web/src/lib/components/i18n/__test__/format-tag-b.svelte index 122358c6b7..6e8b2412e1 100644 --- a/web/src/lib/components/i18n/__test__/format-tag-b.svelte +++ b/web/src/lib/components/i18n/__test__/format-tag-b.svelte @@ -3,12 +3,18 @@ import FormatMessage from '../format-message.svelte'; import type { ComponentProps } from 'svelte'; - export let key: Translations; - export let values: ComponentProps<FormatMessage>['values']; + interface Props { + key: Translations; + values: ComponentProps<typeof FormatMessage>['values']; + } + + let { key, values }: Props = $props(); </script> -<FormatMessage {key} {values} let:tag let:message> - {#if tag === 'b'} - <strong>{message}</strong> - {/if} +<FormatMessage {key} {values}> + {#snippet children({ tag, message })} + {#if tag === 'b'} + <strong>{message}</strong> + {/if} + {/snippet} </FormatMessage> diff --git a/web/src/lib/components/i18n/format-bold-message.svelte b/web/src/lib/components/i18n/format-bold-message.svelte index 052b220edc..0381ec5e98 100644 --- a/web/src/lib/components/i18n/format-bold-message.svelte +++ b/web/src/lib/components/i18n/format-bold-message.svelte @@ -3,12 +3,18 @@ import type { InterpolationValues } from '$lib/components/i18n/format-message.svelte'; import type { Translations } from 'svelte-i18n'; - export let key: Translations; - export let values: InterpolationValues = {}; + interface Props { + key: Translations; + values?: InterpolationValues; + } + + let { key, values = {} }: Props = $props(); </script> -<FormatMessage {key} {values} let:message let:tag> - {#if tag === 'b'} - <b>{message}</b> - {/if} +<FormatMessage {key} {values}> + {#snippet children({ message, tag })} + {#if tag === 'b'} + <b>{message}</b> + {/if} + {/snippet} </FormatMessage> diff --git a/web/src/lib/components/i18n/format-message.svelte b/web/src/lib/components/i18n/format-message.svelte index 48c59478c6..b8909e34de 100644 --- a/web/src/lib/components/i18n/format-message.svelte +++ b/web/src/lib/components/i18n/format-message.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> import type { FormatXMLElementFn, PrimitiveType } from 'intl-messageformat'; export type InterpolationValues = Record<string, PrimitiveType | FormatXMLElementFn<unknown>>; </script> @@ -18,8 +18,13 @@ tag?: string; }; - export let key: Translations; - export let values: InterpolationValues = {}; + interface Props { + key: Translations; + values?: InterpolationValues; + children?: import('svelte').Snippet<[{ tag?: string; message?: string }]>; + } + + let { key, values = {}, children }: Props = $props(); const getLocale = (locale?: string | null) => { if (locale == null) { @@ -96,9 +101,9 @@ } }; - $: message = ($json(key) as string) || key; - $: locale = getLocale($i18nLocale); - $: parts = getParts(message, locale); + let message = $derived(($json(key) as string) || key); + let locale = $derived(getLocale($i18nLocale)); + let parts = $derived(getParts(message, locale)); </script> <!-- @@ -130,7 +135,7 @@ Result: Visit <a href="">docs</a> <strong>now</strong> --> {#each parts as { tag, message }} {#if tag} - <slot {tag} {message}>{message}</slot> + {#if children}{@render children({ tag, message })}{:else}{message}{/if} {:else} {message} {/if} diff --git a/web/src/lib/components/layouts/user-page-layout.svelte b/web/src/lib/components/layouts/user-page-layout.svelte index ed232b80cd..9be2db2691 100644 --- a/web/src/lib/components/layouts/user-page-layout.svelte +++ b/web/src/lib/components/layouts/user-page-layout.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export const headerId = 'user-page-header'; </script> @@ -7,16 +7,36 @@ import NavigationBar from '../shared-components/navigation-bar/navigation-bar.svelte'; import SideBar from '../shared-components/side-bar/side-bar.svelte'; import AdminSideBar from '../shared-components/side-bar/admin-side-bar.svelte'; + import type { Snippet } from 'svelte'; - export let hideNavbar = false; - export let showUploadButton = false; - export let title: string | undefined = undefined; - export let description: string | undefined = undefined; - export let scrollbar = true; - export let admin = false; + interface Props { + hideNavbar?: boolean; + showUploadButton?: boolean; + title?: string | undefined; + description?: string | undefined; + scrollbar?: boolean; + admin?: boolean; + header?: Snippet; + sidebar?: Snippet; + buttons?: Snippet; + children?: Snippet; + } - $: scrollbarClass = scrollbar ? 'immich-scrollbar p-2 pb-8' : 'scrollbar-hidden'; - $: hasTitleClass = title ? 'top-16 h-[calc(100%-theme(spacing.16))]' : 'top-0 h-full'; + let { + hideNavbar = false, + showUploadButton = false, + title = undefined, + description = undefined, + scrollbar = true, + admin = false, + header, + sidebar, + buttons, + children, + }: Props = $props(); + + let scrollbarClass = $derived(scrollbar ? 'immich-scrollbar p-2 pb-8' : 'scrollbar-hidden'); + let hasTitleClass = $derived(title ? 'top-16 h-[calc(100%-theme(spacing.16))]' : 'top-0 h-full'); </script> <header> @@ -24,22 +44,20 @@ <NavigationBar {showUploadButton} onUploadClick={() => openFileUploadDialog()} /> {/if} - <slot name="header" /> + {@render header?.()} </header> <main tabindex="-1" class="relative grid h-screen grid-cols-[theme(spacing.18)_auto] overflow-hidden bg-immich-bg pt-[var(--navbar-height)] dark:bg-immich-dark-bg md:grid-cols-[theme(spacing.64)_auto]" > - <slot name="sidebar"> - {#if admin} - <AdminSideBar /> - {:else} - <SideBar /> - {/if} - </slot> + {#if sidebar}{@render sidebar()}{:else if admin} + <AdminSideBar /> + {:else} + <SideBar /> + {/if} <section class="relative"> - {#if title || $$slots.buttons} + {#if title || buttons} <div class="absolute flex h-16 w-full place-items-center justify-between border-b p-4 dark:border-immich-dark-gray dark:text-immich-dark-fg" > @@ -51,12 +69,12 @@ <p class="text-sm text-gray-400 dark:text-gray-600">{description}</p> {/if} </div> - <slot name="buttons" /> + {@render buttons?.()} </div> {/if} <div class="{scrollbarClass} scrollbar-stable absolute {hasTitleClass} w-full overflow-y-auto"> - <slot /> + {@render children?.()} </div> </section> </main> diff --git a/web/src/lib/components/map-page/map-settings-modal.svelte b/web/src/lib/components/map-page/map-settings-modal.svelte index 35df9f2285..270978e120 100644 --- a/web/src/lib/components/map-page/map-settings-modal.svelte +++ b/web/src/lib/components/map-page/map-settings-modal.svelte @@ -10,19 +10,24 @@ import LinkButton from '../elements/buttons/link-button.svelte'; import DateInput from '../elements/date-input.svelte'; - export let settings: MapSettings; - export let onClose: () => void; - export let onSave: (settings: MapSettings) => void; + interface Props { + settings: MapSettings; + onClose: () => void; + onSave: (settings: MapSettings) => void; + } - let customDateRange = !!settings.dateAfter || !!settings.dateBefore; + let { settings = $bindable(), onClose, onSave }: Props = $props(); + + let customDateRange = $state(!!settings.dateAfter || !!settings.dateBefore); + + const onsubmit = (event: Event) => { + event.preventDefault(); + onSave(settings); + }; </script> <FullScreenModal title={$t('map_settings')} {onClose}> - <form - on:submit|preventDefault={() => onSave(settings)} - class="flex flex-col gap-4 text-immich-primary dark:text-immich-dark-primary" - id="map-settings-form" - > + <form {onsubmit} class="flex flex-col gap-4 text-immich-primary dark:text-immich-dark-primary" id="map-settings-form"> <SettingSwitch title={$t('allow_dark_mode')} bind:checked={settings.allowDarkMode} /> <SettingSwitch title={$t('only_favorites')} bind:checked={settings.onlyFavorites} /> <SettingSwitch title={$t('include_archived')} bind:checked={settings.includeArchived} /> @@ -46,7 +51,7 @@ </div> <div class="flex justify-center text-xs"> <LinkButton - on:click={() => { + onclick={() => { customDateRange = false; settings.dateAfter = ''; settings.dateBefore = ''; @@ -91,7 +96,7 @@ /> <div class="text-xs"> <LinkButton - on:click={() => { + onclick={() => { customDateRange = true; settings.relativeDate = ''; }} @@ -102,8 +107,9 @@ </div> {/if} </form> - <svelte:fragment slot="sticky-bottom"> - <Button color="gray" size="sm" fullwidth on:click={onClose}>{$t('cancel')}</Button> + + {#snippet stickyBottom()} + <Button color="gray" size="sm" fullwidth onclick={onClose}>{$t('cancel')}</Button> <Button type="submit" size="sm" fullwidth form="map-settings-form">{$t('save')}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/memory-page/memory-viewer.svelte b/web/src/lib/components/memory-page/memory-viewer.svelte index f4715ce57c..bca3b2024d 100644 --- a/web/src/lib/components/memory-page/memory-viewer.svelte +++ b/web/src/lib/components/memory-page/memory-viewer.svelte @@ -42,8 +42,9 @@ import { onMount } from 'svelte'; import { t } from 'svelte-i18n'; import { tweened } from 'svelte/motion'; - import { derived } from 'svelte/store'; + import { derived as storeDerived } from 'svelte/store'; import { fade } from 'svelte/transition'; + import { SvelteSet } from 'svelte/reactivity'; type MemoryIndex = { memoryIndex: number; @@ -59,19 +60,21 @@ nextMemory?: MemoryLaneResponseDto; }; - let memoryGallery: HTMLElement; - let memoryWrapper: HTMLElement; - let galleryInView = false; - let paused = false; - let selectedAssets: Set<AssetResponseDto> = new Set(); - let current: MemoryAsset | undefined = undefined; + let memoryGallery: HTMLElement | undefined = $state(); + let memoryWrapper: HTMLElement | undefined = $state(); + let galleryInView = $state(false); + let paused = $state(false); + let selectedAssets: SvelteSet<AssetResponseDto> = $state(new SvelteSet()); + let current: MemoryAsset | undefined = $state(undefined); // let memories: MemoryAsset[] = []; - let resetPromise = Promise.resolve(); + let resetPromise = $state(Promise.resolve()); const { isViewing } = assetViewingStore; - const viewport: Viewport = { width: 0, height: 0 }; - const progress = tweened<number>(0, { duration: (from: number, to: number) => (to ? 5000 * (to - from) : 0) }); - const memories = derived(memoryStore, (memories) => { + const viewport: Viewport = $state({ width: 0, height: 0 }); + const progressBarController = tweened<number>(0, { + duration: (from: number, to: number) => (to ? 5000 * (to - from) : 0), + }); + const memories = storeDerived(memoryStore, (memories) => { memories = memories ?? []; const memoryAssets: MemoryAsset[] = []; let previous: MemoryAsset | undefined; @@ -100,13 +103,6 @@ return memoryAssets; }); - $: isMultiSelectionMode = selectedAssets.size > 0; - $: isAllArchived = [...selectedAssets].every((asset) => asset.isArchived); - $: isAllFavorite = [...selectedAssets].every((asset) => asset.isFavorite); - $: selectedAssets = galleryInView ? selectedAssets : new Set(); - $: handlePromiseError(handleProgress($progress)); - $: handlePromiseError(handleAction(galleryInView ? 'pause' : 'play')); - const loadFromParams = (memories: MemoryAsset[], page: typeof $page | NavigationTarget | null) => { const assetId = page?.params?.assetId ?? page?.url.searchParams.get(QueryParameter.ID) ?? undefined; handlePromiseError(handleAction($isViewing ? 'pause' : 'reset')); @@ -130,24 +126,24 @@ const handleNextMemory = () => handleNavigate(current?.nextMemory?.assets[0]); const handlePreviousMemory = () => handleNavigate(current?.previousMemory?.assets[0]); const handleEscape = async () => goto(AppRoute.PHOTOS); - const handleSelectAll = () => (selectedAssets = new Set(current?.memory.assets || [])); + const handleSelectAll = () => (selectedAssets = new SvelteSet(current?.memory.assets || [])); const handleAction = async (action: 'reset' | 'pause' | 'play') => { switch (action) { case 'play': { paused = false; - await progress.set(1); + await progressBarController.set(1); break; } case 'pause': { paused = true; - await progress.set($progress); + await progressBarController.set($progressBarController); break; } case 'reset': { paused = false; - resetPromise = progress.set(0); + resetPromise = progressBarController.set(0); break; } } @@ -159,6 +155,7 @@ } if (progress === 1) { + await progressBarController.set(0); await (current?.next ? handleNextAsset() : handleAction('pause')); } }; @@ -210,6 +207,21 @@ current = loadFromParams($memories, target); }); + $effect(() => { + selectedAssets = galleryInView ? selectedAssets : new SvelteSet(); + }); + + let isMultiSelectionMode = $derived(selectedAssets.size > 0); + let isAllArchived = $derived([...selectedAssets].every((asset) => asset.isArchived)); + let isAllFavorite = $derived([...selectedAssets].every((asset) => asset.isFavorite)); + + $effect(() => { + handlePromiseError(handleProgress($progressBarController)); + }); + + $effect(() => { + handlePromiseError(handleAction(galleryInView ? 'pause' : 'play')); + }); </script> <svelte:window @@ -226,9 +238,9 @@ {#if isMultiSelectionMode} <div class="sticky top-0 z-[90]"> - <AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}> + <AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new SvelteSet())}> <CreateSharedLink /> - <CircleIconButton title={$t('select_all')} icon={mdiSelectAll} on:click={handleSelectAll} /> + <CircleIconButton title={$t('select_all')} icon={mdiSelectAll} onclick={handleSelectAll} /> <ButtonContextMenu icon={mdiPlus} title={$t('add_to')}> <AddToAlbum /> @@ -251,17 +263,19 @@ <section id="memory-viewer" class="w-full bg-immich-dark-gray" bind:this={memoryWrapper}> {#if current && current.memory.assets.length > 0} <ControlAppBar onClose={() => goto(AppRoute.PHOTOS)} forceDark> - <svelte:fragment slot="leading"> - <p class="text-lg"> - {$memoryLaneTitle(current.memory.yearsAgo)} - </p> - </svelte:fragment> + {#snippet leading()} + {#if current} + <p class="text-lg"> + {$memoryLaneTitle(current.memory.yearsAgo)} + </p> + {/if} + {/snippet} <div class="flex place-content-center place-items-center gap-2 overflow-hidden"> <CircleIconButton title={paused ? $t('play_memories') : $t('pause_memories')} icon={paused ? mdiPlay : mdiPause} - on:click={() => handleAction(paused ? 'play' : 'pause')} + onclick={() => handleAction(paused ? 'play' : 'pause')} class="hover:text-black" /> @@ -274,7 +288,7 @@ {:then} <span class="absolute left-0 h-[2px] bg-white" - style:width={`${index < current.assetIndex ? 100 : index > current.assetIndex ? 0 : $progress * 100}%`} + style:width={`${index < current.assetIndex ? 100 : index > current.assetIndex ? 0 : $progressBarController * 100}%`} ></span> {/await} </a> @@ -296,10 +310,10 @@ > <button type="button" - on:click={() => memoryWrapper.scrollIntoView({ behavior: 'smooth' })} + onclick={() => memoryWrapper?.scrollIntoView({ behavior: 'smooth' })} disabled={!galleryInView} > - <CircleIconButton title={$t('hide_gallery')} icon={mdiChevronUp} color="light" /> + <CircleIconButton title={$t('hide_gallery')} icon={mdiChevronUp} color="light" onclick={() => {}} /> </button> </div> {/if} @@ -314,7 +328,7 @@ type="button" class="relative h-full w-full rounded-2xl" disabled={!current.previousMemory} - on:click={handlePreviousMemory} + onclick={handlePreviousMemory} > {#if current.previousMemory && current.previousMemory.assets.length > 0} <img @@ -367,6 +381,7 @@ icon={mdiImageSearch} title={$t('view_in_timeline')} color="light" + onclick={() => {}} /> </div> <!-- CONTROL BUTTONS --> @@ -376,7 +391,7 @@ title={$t('previous_memory')} icon={mdiChevronLeft} color="dark" - on:click={handlePreviousAsset} + onclick={handlePreviousAsset} /> </div> {/if} @@ -387,7 +402,7 @@ title={$t('next_memory')} icon={mdiChevronRight} color="dark" - on:click={handleNextAsset} + onclick={handleNextAsset} /> </div> {/if} @@ -409,7 +424,7 @@ <button type="button" class="relative h-full w-full rounded-2xl" - on:click={handleNextMemory} + onclick={handleNextMemory} disabled={!current.nextMemory} > {#if current.nextMemory && current.nextMemory.assets.length > 0} @@ -451,7 +466,7 @@ title={$t('show_gallery')} icon={mdiChevronDown} color="light" - on:click={() => memoryGallery.scrollIntoView({ behavior: 'smooth' })} + onclick={() => memoryGallery?.scrollIntoView({ behavior: 'smooth' })} /> </div> diff --git a/web/src/lib/components/onboarding-page/onboarding-card.svelte b/web/src/lib/components/onboarding-page/onboarding-card.svelte index 9b2378ccd8..54951dfa09 100644 --- a/web/src/lib/components/onboarding-page/onboarding-card.svelte +++ b/web/src/lib/components/onboarding-page/onboarding-card.svelte @@ -1,9 +1,15 @@ <script lang="ts"> import Icon from '$lib/components/elements/icon.svelte'; + import type { Snippet } from 'svelte'; import { fade } from 'svelte/transition'; - export let title: string | undefined = undefined; - export let icon: string | undefined = undefined; + interface Props { + title?: string | undefined; + icon?: string | undefined; + children?: Snippet; + } + + let { title = undefined, icon = undefined, children }: Props = $props(); </script> <div @@ -23,5 +29,5 @@ {/if} </div> {/if} - <slot /> + {@render children?.()} </div> diff --git a/web/src/lib/components/onboarding-page/onboarding-hello.svelte b/web/src/lib/components/onboarding-page/onboarding-hello.svelte index 466e1d29f7..102465f019 100644 --- a/web/src/lib/components/onboarding-page/onboarding-hello.svelte +++ b/web/src/lib/components/onboarding-page/onboarding-hello.svelte @@ -7,7 +7,11 @@ import { user } from '$lib/stores/user.store'; import { t } from 'svelte-i18n'; - export let onDone: () => void; + interface Props { + onDone: () => void; + } + + let { onDone }: Props = $props(); </script> <OnboardingCard> @@ -18,7 +22,7 @@ <p class="text-3xl pb-6 font-light">{$t('onboarding_welcome_description')}</p> <div class="w-full flex place-content-end"> - <Button class="flex gap-2 place-content-center" on:click={() => onDone()}> + <Button class="flex gap-2 place-content-center" onclick={() => onDone()}> <p>{$t('theme')}</p> <Icon path={mdiArrowRight} size="18" /> </Button> diff --git a/web/src/lib/components/onboarding-page/onboarding-privacy.svelte b/web/src/lib/components/onboarding-page/onboarding-privacy.svelte index da36f741f1..8ff8a9200d 100644 --- a/web/src/lib/components/onboarding-page/onboarding-privacy.svelte +++ b/web/src/lib/components/onboarding-page/onboarding-privacy.svelte @@ -10,10 +10,15 @@ import { t } from 'svelte-i18n'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; - export let onDone: () => void; - export let onPrevious: () => void; + interface Props { + onDone: () => void; + onPrevious: () => void; + } - let config: SystemConfigDto | null = null; + let { onDone, onPrevious }: Props = $props(); + + let config: SystemConfigDto | null = $state(null); + let adminSettingsComponent = $state<ReturnType<typeof AdminSettings>>(); onMount(async () => { config = await getConfig(); @@ -26,38 +31,42 @@ </p> {#if config && $user} - <AdminSettings bind:config let:handleSave> - <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" on:click={() => onPrevious()}> - <Icon path={mdiArrowLeft} size="18" /> - <p>{$t('theme')}</p> - </Button> - </div> - <div class="flex w-full place-content-end"> - <Button - on:click={() => { - 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> + <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> + </div> + {/if} + {/snippet} </AdminSettings> {/if} </OnboardingCard> diff --git a/web/src/lib/components/onboarding-page/onboarding-storage-template.svelte b/web/src/lib/components/onboarding-page/onboarding-storage-template.svelte index 69809dd39d..b692a6f2de 100644 --- a/web/src/lib/components/onboarding-page/onboarding-storage-template.svelte +++ b/web/src/lib/components/onboarding-page/onboarding-storage-template.svelte @@ -12,10 +12,15 @@ import { t } from 'svelte-i18n'; import FormatMessage from '$lib/components/i18n/format-message.svelte'; - export let onDone: () => void; - export let onPrevious: () => void; + interface Props { + onDone: () => void; + onPrevious: () => void; + } - let config: SystemConfigDto | null = null; + let { onDone, onPrevious }: Props = $props(); + + let config: SystemConfigDto | undefined = $state(); + let adminSettingsComponent = $state<ReturnType<typeof AdminSettings>>(); onMount(async () => { config = await getConfig(); @@ -24,45 +29,51 @@ <OnboardingCard title={$t('admin.storage_template_settings')} icon={mdiHarddisk}> <p> - <FormatMessage key="admin.storage_template_onboarding_description" let:message> - <a class="underline" href="https://immich.app/docs/administration/storage-template">{message}</a> + <FormatMessage key="admin.storage_template_onboarding_description"> + {#snippet children({ message })} + <a class="underline" href="https://immich.app/docs/administration/storage-template">{message}</a> + {/snippet} </FormatMessage> </p> {#if config && $user} - <AdminSettings bind:config let:defaultConfig let:savedConfig let:handleSave let:handleReset> - <StorageTemplateSettings - minified - disabled={$featureFlags.configFile} - {config} - {defaultConfig} - {savedConfig} - onSave={(config) => handleSave(config)} - onReset={(options) => handleReset(options)} - duration={0} - > - <div class="flex pt-4"> - <div class="w-full flex place-content-start"> - <Button class="flex gap-2 place-content-center" on:click={() => onPrevious()}> - <Icon path={mdiArrowLeft} size="18" /> - <p>{$t('theme')}</p> - </Button> - </div> - <div class="flex w-full place-content-end"> - <Button - on:click={() => { - handleSave({ storageTemplate: config?.storageTemplate }); - onDone(); - }} - > - <span class="flex place-content-center place-items-center gap-2"> - {$t('done')} - <Icon path={mdiCheck} size="18" /> - </span> - </Button> - </div> - </div> - </StorageTemplateSettings> + <AdminSettings bind:config bind:this={adminSettingsComponent}> + {#snippet children({ defaultConfig, savedConfig })} + {#if config} + <StorageTemplateSettings + minified + disabled={$featureFlags.configFile} + {config} + {defaultConfig} + {savedConfig} + onSave={(config) => adminSettingsComponent?.handleSave(config)} + onReset={(options) => adminSettingsComponent?.handleReset(options)} + duration={0} + > + <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({ storageTemplate: config?.storageTemplate }); + onDone(); + }} + > + <span class="flex place-content-center place-items-center gap-2"> + {$t('done')} + <Icon path={mdiCheck} size="18" /> + </span> + </Button> + </div> + </div> + </StorageTemplateSettings> + {/if} + {/snippet} </AdminSettings> {/if} </OnboardingCard> diff --git a/web/src/lib/components/onboarding-page/onboarding-theme.svelte b/web/src/lib/components/onboarding-page/onboarding-theme.svelte index 975dbd1ec3..4229cf9f67 100644 --- a/web/src/lib/components/onboarding-page/onboarding-theme.svelte +++ b/web/src/lib/components/onboarding-page/onboarding-theme.svelte @@ -8,7 +8,11 @@ import { Theme } from '$lib/constants'; import { t } from 'svelte-i18n'; - export let onDone: () => void; + interface Props { + onDone: () => void; + } + + let { onDone }: Props = $props(); </script> <OnboardingCard icon={mdiThemeLightDark} title={$t('color_theme')}> @@ -20,7 +24,7 @@ <button type="button" class="w-1/2 aspect-square bg-immich-bg rounded-3xl transition-all shadow-sm hover:shadow-xl border-[3px] border-immich-dark-primary/80 border-immich-primary dark:border dark:border-transparent" - on:click={() => ($colorTheme.value = Theme.LIGHT)} + onclick={() => ($colorTheme.value = Theme.LIGHT)} > <div class="flex flex-col place-items-center place-content-center justify-around h-full w-full text-immich-primary" @@ -32,7 +36,7 @@ <button type="button" class="w-1/2 aspect-square bg-immich-dark-bg rounded-3xl dark:border-[3px] dark:border-immich-dark-primary/80 dark:border-immich-dark-primary border border-transparent" - on:click={() => ($colorTheme.value = Theme.DARK)} + onclick={() => ($colorTheme.value = Theme.DARK)} > <div class="flex flex-col place-items-center place-content-center justify-around h-full w-full text-immich-dark-primary" @@ -45,7 +49,7 @@ <div class="flex"> <div class="w-full flex place-content-end"> - <Button class="flex gap-2 place-content-center" on:click={() => onDone()}> + <Button class="flex gap-2 place-content-center" onclick={() => onDone()}> <p>{$t('privacy')}</p> <Icon path={mdiArrowRight} size="18" /> </Button> diff --git a/web/src/lib/components/photos-page/actions/add-to-album.svelte b/web/src/lib/components/photos-page/actions/add-to-album.svelte index 8c46764408..10917a1d90 100644 --- a/web/src/lib/components/photos-page/actions/add-to-album.svelte +++ b/web/src/lib/components/photos-page/actions/add-to-album.svelte @@ -8,10 +8,14 @@ import { t } from 'svelte-i18n'; import type { OnAddToAlbum } from '$lib/utils/actions'; - export let shared = false; - export let onAddToAlbum: OnAddToAlbum = () => {}; + interface Props { + shared?: boolean; + onAddToAlbum?: OnAddToAlbum; + } - let showAlbumPicker = false; + let { shared = false, onAddToAlbum = () => {} }: Props = $props(); + + let showAlbumPicker = $state(false); const { getAssets } = getAssetControlContext(); diff --git a/web/src/lib/components/photos-page/actions/archive-action.svelte b/web/src/lib/components/photos-page/actions/archive-action.svelte index 792b80b702..868a5ddd6d 100644 --- a/web/src/lib/components/photos-page/actions/archive-action.svelte +++ b/web/src/lib/components/photos-page/actions/archive-action.svelte @@ -7,15 +7,18 @@ import { archiveAssets } from '$lib/utils/asset-utils'; import { t } from 'svelte-i18n'; - export let onArchive: OnArchive; + interface Props { + onArchive: OnArchive; + menuItem?: boolean; + unarchive?: boolean; + } - export let menuItem = false; - export let unarchive = false; + let { onArchive, menuItem = false, unarchive = false }: Props = $props(); - $: text = unarchive ? $t('unarchive') : $t('to_archive'); - $: icon = unarchive ? mdiArchiveArrowUpOutline : mdiArchiveArrowDownOutline; + let text = $derived(unarchive ? $t('unarchive') : $t('to_archive')); + let icon = $derived(unarchive ? mdiArchiveArrowUpOutline : mdiArchiveArrowDownOutline); - let loading = false; + let loading = $state(false); const { clearSelect, getOwnedAssets } = getAssetControlContext(); @@ -38,8 +41,8 @@ {#if !menuItem} {#if loading} - <CircleIconButton title={$t('loading')} icon={mdiTimerSand} /> + <CircleIconButton title={$t('loading')} icon={mdiTimerSand} onclick={() => {}} /> {:else} - <CircleIconButton title={text} {icon} on:click={handleArchive} /> + <CircleIconButton title={text} {icon} onclick={handleArchive} /> {/if} {/if} 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 13b51638f4..b383729ecd 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 @@ -10,16 +10,16 @@ import { getAssetControlContext } from '../asset-select-control-bar.svelte'; import { t } from 'svelte-i18n'; - export let jobs: AssetJobName[] = [ - AssetJobName.RegenerateThumbnail, - AssetJobName.RefreshMetadata, - AssetJobName.TranscodeVideo, - ]; + interface Props { + jobs?: AssetJobName[]; + } + + let { jobs = [AssetJobName.RegenerateThumbnail, AssetJobName.RefreshMetadata, AssetJobName.TranscodeVideo] }: Props = + $props(); const { clearSelect, getOwnedAssets } = getAssetControlContext(); - // svelte-ignore reactive_declaration_non_reactive_property - $: isAllVideos = [...getOwnedAssets()].every((asset) => asset.type === AssetTypeEnum.Video); + let isAllVideos = $derived([...getOwnedAssets()].every((asset) => asset.type === AssetTypeEnum.Video)); const handleRunJob = async (name: AssetJobName) => { try { diff --git a/web/src/lib/components/photos-page/actions/change-date-action.svelte b/web/src/lib/components/photos-page/actions/change-date-action.svelte index 114315348d..3232cbd2b4 100644 --- a/web/src/lib/components/photos-page/actions/change-date-action.svelte +++ b/web/src/lib/components/photos-page/actions/change-date-action.svelte @@ -9,10 +9,14 @@ import { getAssetControlContext } from '../asset-select-control-bar.svelte'; import { mdiCalendarEditOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let menuItem = false; + interface Props { + menuItem?: boolean; + } + + let { menuItem = false }: Props = $props(); const { clearSelect, getOwnedAssets } = getAssetControlContext(); - let isShowChangeDate = false; + let isShowChangeDate = $state(false); const handleConfirm = async (dateTimeOriginal: string) => { isShowChangeDate = false; diff --git a/web/src/lib/components/photos-page/actions/change-location-action.svelte b/web/src/lib/components/photos-page/actions/change-location-action.svelte index 3fe1db4327..0ad93e5d81 100644 --- a/web/src/lib/components/photos-page/actions/change-location-action.svelte +++ b/web/src/lib/components/photos-page/actions/change-location-action.svelte @@ -9,10 +9,14 @@ import { mdiMapMarkerMultipleOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let menuItem = false; + interface Props { + menuItem?: boolean; + } + + let { menuItem = false }: Props = $props(); const { clearSelect, getOwnedAssets } = getAssetControlContext(); - let isShowChangeLocation = false; + let isShowChangeLocation = $state(false); async function handleConfirm(point: { lng: number; lat: number }) { isShowChangeLocation = false; diff --git a/web/src/lib/components/photos-page/actions/create-shared-link.svelte b/web/src/lib/components/photos-page/actions/create-shared-link.svelte index 7436ff2177..1b99627ea9 100644 --- a/web/src/lib/components/photos-page/actions/create-shared-link.svelte +++ b/web/src/lib/components/photos-page/actions/create-shared-link.svelte @@ -5,11 +5,11 @@ import { getAssetControlContext } from '../asset-select-control-bar.svelte'; import { t } from 'svelte-i18n'; - let showModal = false; + let showModal = $state(false); const { getAssets } = getAssetControlContext(); </script> -<CircleIconButton title={$t('share')} icon={mdiShareVariantOutline} on:click={() => (showModal = true)} /> +<CircleIconButton title={$t('share')} icon={mdiShareVariantOutline} onclick={() => (showModal = true)} /> {#if showModal} <CreateSharedLinkModal assetIds={[...getAssets()].map(({ id }) => id)} onClose={() => (showModal = false)} /> diff --git a/web/src/lib/components/photos-page/actions/delete-assets.svelte b/web/src/lib/components/photos-page/actions/delete-assets.svelte index 6d3275c74d..bdd442e50c 100644 --- a/web/src/lib/components/photos-page/actions/delete-assets.svelte +++ b/web/src/lib/components/photos-page/actions/delete-assets.svelte @@ -8,16 +8,20 @@ import DeleteAssetDialog from '../delete-asset-dialog.svelte'; import { t } from 'svelte-i18n'; - export let onAssetDelete: OnDelete; - export let menuItem = false; - export let force = !$featureFlags.trash; + interface Props { + onAssetDelete: OnDelete; + menuItem?: boolean; + force?: boolean; + } + + let { onAssetDelete, menuItem = false, force = !$featureFlags.trash }: Props = $props(); const { clearSelect, getOwnedAssets } = getAssetControlContext(); - let isShowConfirmation = false; - let loading = false; + let isShowConfirmation = $state(false); + let loading = $state(false); - $: label = force ? $t('permanently_delete') : $t('delete'); + let label = $derived(force ? $t('permanently_delete') : $t('delete')); const handleTrash = async () => { if (force) { @@ -41,9 +45,9 @@ {#if menuItem} <MenuOption text={label} icon={mdiDeleteOutline} onClick={handleTrash} /> {:else if loading} - <CircleIconButton title={$t('loading')} icon={mdiTimerSand} /> + <CircleIconButton title={$t('loading')} icon={mdiTimerSand} onclick={() => {}} /> {:else} - <CircleIconButton title={label} icon={mdiDeleteForeverOutline} on:click={handleTrash} /> + <CircleIconButton title={label} icon={mdiDeleteForeverOutline} onclick={handleTrash} /> {/if} {#if isShowConfirmation} diff --git a/web/src/lib/components/photos-page/actions/download-action.svelte b/web/src/lib/components/photos-page/actions/download-action.svelte index 7716fbe36d..89eca9c6a8 100644 --- a/web/src/lib/components/photos-page/actions/download-action.svelte +++ b/web/src/lib/components/photos-page/actions/download-action.svelte @@ -7,8 +7,12 @@ import { mdiCloudDownloadOutline, mdiFileDownloadOutline, mdiFolderDownloadOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let filename = 'immich.zip'; - export let menuItem = false; + interface Props { + filename?: string; + menuItem?: boolean; + } + + let { filename = 'immich.zip', menuItem = false }: Props = $props(); const { getAssets, clearSelect } = getAssetControlContext(); @@ -24,7 +28,7 @@ await downloadArchive(filename, { assetIds: assets.map((asset) => asset.id) }); }; - $: menuItemIcon = getAssets().size === 1 ? mdiFileDownloadOutline : mdiFolderDownloadOutline; + let menuItemIcon = $derived(getAssets().size === 1 ? mdiFileDownloadOutline : mdiFolderDownloadOutline); </script> <svelte:window use:shortcut={{ shortcut: { key: 'd', shift: true }, onShortcut: handleDownloadFiles }} /> @@ -32,5 +36,5 @@ {#if menuItem} <MenuOption text={$t('download')} icon={menuItemIcon} onClick={handleDownloadFiles} /> {:else} - <CircleIconButton title={$t('download')} icon={mdiCloudDownloadOutline} on:click={handleDownloadFiles} /> + <CircleIconButton title={$t('download')} icon={mdiCloudDownloadOutline} onclick={handleDownloadFiles} /> {/if} diff --git a/web/src/lib/components/photos-page/actions/favorite-action.svelte b/web/src/lib/components/photos-page/actions/favorite-action.svelte index 1d723b1a9d..1bc6764157 100644 --- a/web/src/lib/components/photos-page/actions/favorite-action.svelte +++ b/web/src/lib/components/photos-page/actions/favorite-action.svelte @@ -12,15 +12,18 @@ import { getAssetControlContext } from '../asset-select-control-bar.svelte'; import { t } from 'svelte-i18n'; - export let onFavorite: OnFavorite; + interface Props { + onFavorite: OnFavorite; + menuItem?: boolean; + removeFavorite: boolean; + } - export let menuItem = false; - export let removeFavorite: boolean; + let { onFavorite, menuItem = false, removeFavorite }: Props = $props(); - $: text = removeFavorite ? $t('remove_from_favorites') : $t('to_favorite'); - $: icon = removeFavorite ? mdiHeartMinusOutline : mdiHeartOutline; + let text = $derived(removeFavorite ? $t('remove_from_favorites') : $t('to_favorite')); + let icon = $derived(removeFavorite ? mdiHeartMinusOutline : mdiHeartOutline); - let loading = false; + let loading = $state(false); const { clearSelect, getOwnedAssets } = getAssetControlContext(); @@ -65,8 +68,8 @@ {#if !menuItem} {#if loading} - <CircleIconButton title={$t('loading')} icon={mdiTimerSand} /> + <CircleIconButton title={$t('loading')} icon={mdiTimerSand} onclick={() => {}} /> {:else} - <CircleIconButton title={text} {icon} on:click={handleFavorite} /> + <CircleIconButton title={text} {icon} onclick={handleFavorite} /> {/if} {/if} diff --git a/web/src/lib/components/photos-page/actions/link-live-photo-action.svelte b/web/src/lib/components/photos-page/actions/link-live-photo-action.svelte index 24107b9f88..27ac6cf042 100644 --- a/web/src/lib/components/photos-page/actions/link-live-photo-action.svelte +++ b/web/src/lib/components/photos-page/actions/link-live-photo-action.svelte @@ -8,15 +8,19 @@ import MenuOption from '../../shared-components/context-menu/menu-option.svelte'; import { getAssetControlContext } from '../asset-select-control-bar.svelte'; - export let onLink: OnLink; - export let onUnlink: OnUnlink; - export let menuItem = false; - export let unlink = false; + interface Props { + onLink: OnLink; + onUnlink: OnUnlink; + menuItem?: boolean; + unlink?: boolean; + } - let loading = false; + let { onLink, onUnlink, menuItem = false, unlink = false }: Props = $props(); - $: text = unlink ? $t('unlink_motion_video') : $t('link_motion_video'); - $: icon = unlink ? mdiLinkOff : mdiMotionPlayOutline; + let loading = $state(false); + + let text = $derived(unlink ? $t('unlink_motion_video') : $t('link_motion_video')); + let icon = $derived(unlink ? mdiLinkOff : mdiMotionPlayOutline); const { clearSelect, getOwnedAssets } = getAssetControlContext(); @@ -68,8 +72,8 @@ {#if !menuItem} {#if loading} - <CircleIconButton title={$t('loading')} icon={mdiTimerSand} /> + <CircleIconButton title={$t('loading')} icon={mdiTimerSand} onclick={() => {}} /> {:else} - <CircleIconButton title={text} {icon} on:click={onClick} /> + <CircleIconButton title={text} {icon} onclick={onClick} /> {/if} {/if} diff --git a/web/src/lib/components/photos-page/actions/remove-from-album.svelte b/web/src/lib/components/photos-page/actions/remove-from-album.svelte index 2384f95d2e..19c1e54cfa 100644 --- a/web/src/lib/components/photos-page/actions/remove-from-album.svelte +++ b/web/src/lib/components/photos-page/actions/remove-from-album.svelte @@ -11,9 +11,13 @@ import { dialogController } from '$lib/components/shared-components/dialog/dialog'; import { t } from 'svelte-i18n'; - export let album: AlbumResponseDto; - export let onRemove: ((assetIds: string[]) => void) | undefined; - export let menuItem = false; + interface Props { + album: AlbumResponseDto; + onRemove: ((assetIds: string[]) => void) | undefined; + menuItem?: boolean; + } + + let { album = $bindable(), onRemove, menuItem = false }: Props = $props(); const { getAssets, clearSelect } = getAssetControlContext(); @@ -57,5 +61,5 @@ {#if menuItem} <MenuOption text={$t('remove_from_album')} icon={mdiImageRemoveOutline} onClick={removeFromAlbum} /> {:else} - <CircleIconButton title={$t('remove_from_album')} icon={mdiDeleteOutline} on:click={removeFromAlbum} /> + <CircleIconButton title={$t('remove_from_album')} icon={mdiDeleteOutline} onclick={removeFromAlbum} /> {/if} diff --git a/web/src/lib/components/photos-page/actions/remove-from-shared-link.svelte b/web/src/lib/components/photos-page/actions/remove-from-shared-link.svelte index e838f0813d..e884a929a3 100644 --- a/web/src/lib/components/photos-page/actions/remove-from-shared-link.svelte +++ b/web/src/lib/components/photos-page/actions/remove-from-shared-link.svelte @@ -9,7 +9,11 @@ import { dialogController } from '$lib/components/shared-components/dialog/dialog'; import { t } from 'svelte-i18n'; - export let sharedLink: SharedLinkResponseDto; + interface Props { + sharedLink: SharedLinkResponseDto; + } + + let { sharedLink = $bindable() }: Props = $props(); const { getAssets, clearSelect } = getAssetControlContext(); @@ -55,4 +59,4 @@ }; </script> -<CircleIconButton title={$t('remove_from_shared_link')} on:click={handleRemove} icon={mdiDeleteOutline} /> +<CircleIconButton title={$t('remove_from_shared_link')} onclick={handleRemove} icon={mdiDeleteOutline} /> diff --git a/web/src/lib/components/photos-page/actions/restore-assets.svelte b/web/src/lib/components/photos-page/actions/restore-assets.svelte index 19e1c206fd..037e3239ef 100644 --- a/web/src/lib/components/photos-page/actions/restore-assets.svelte +++ b/web/src/lib/components/photos-page/actions/restore-assets.svelte @@ -12,11 +12,15 @@ import { getAssetControlContext } from '../asset-select-control-bar.svelte'; import { t } from 'svelte-i18n'; - export let onRestore: OnRestore | undefined; + interface Props { + onRestore: OnRestore | undefined; + } + + let { onRestore }: Props = $props(); const { getAssets, clearSelect } = getAssetControlContext(); - let loading = false; + let loading = $state(false); const handleRestore = async () => { loading = true; @@ -40,7 +44,7 @@ }; </script> -<Button disabled={loading} size="sm" color="transparent-gray" shadow={false} rounded="lg" on:click={handleRestore}> +<Button disabled={loading} size="sm" color="transparent-gray" shadow={false} rounded="lg" onclick={handleRestore}> <Icon path={mdiHistory} size="24" /> <span class="ml-2">{$t('restore')}</span> </Button> diff --git a/web/src/lib/components/photos-page/actions/select-all-assets.svelte b/web/src/lib/components/photos-page/actions/select-all-assets.svelte index 93df51a6a0..cc27f3ebbe 100644 --- a/web/src/lib/components/photos-page/actions/select-all-assets.svelte +++ b/web/src/lib/components/photos-page/actions/select-all-assets.svelte @@ -6,8 +6,12 @@ import { selectAllAssets, cancelMultiselect } from '$lib/utils/asset-utils'; import { t } from 'svelte-i18n'; - export let assetStore: AssetStore; - export let assetInteractionStore: AssetInteractionStore; + interface Props { + assetStore: AssetStore; + assetInteractionStore: AssetInteractionStore; + } + + let { assetStore, assetInteractionStore }: Props = $props(); const handleSelectAll = async () => { await selectAllAssets(assetStore, assetInteractionStore); @@ -19,7 +23,7 @@ </script> {#if $isSelectingAllAssets} - <CircleIconButton title={$t('unselect_all')} icon={mdiSelectRemove} on:click={handleCancel} /> + <CircleIconButton title={$t('unselect_all')} icon={mdiSelectRemove} onclick={handleCancel} /> {:else} - <CircleIconButton title={$t('select_all')} icon={mdiSelectAll} on:click={handleSelectAll} /> + <CircleIconButton title={$t('select_all')} icon={mdiSelectAll} onclick={handleSelectAll} /> {/if} diff --git a/web/src/lib/components/photos-page/actions/stack-action.svelte b/web/src/lib/components/photos-page/actions/stack-action.svelte index c1f2bf212f..fe4f066a0e 100644 --- a/web/src/lib/components/photos-page/actions/stack-action.svelte +++ b/web/src/lib/components/photos-page/actions/stack-action.svelte @@ -6,9 +6,13 @@ import type { OnStack, OnUnstack } from '$lib/utils/actions'; import { t } from 'svelte-i18n'; - export let unstack = false; - export let onStack: OnStack | undefined; - export let onUnstack: OnUnstack | undefined; + interface Props { + unstack?: boolean; + onStack: OnStack | undefined; + onUnstack: OnUnstack | undefined; + } + + let { unstack = false, onStack, onUnstack }: Props = $props(); const { clearSelect, getOwnedAssets } = getAssetControlContext(); diff --git a/web/src/lib/components/photos-page/actions/tag-action.svelte b/web/src/lib/components/photos-page/actions/tag-action.svelte index 77e91d7235..32cdaec16a 100644 --- a/web/src/lib/components/photos-page/actions/tag-action.svelte +++ b/web/src/lib/components/photos-page/actions/tag-action.svelte @@ -7,13 +7,17 @@ import { getAssetControlContext } from '../asset-select-control-bar.svelte'; import TagAssetForm from '$lib/components/forms/tag-asset-form.svelte'; - export let menuItem = false; + interface Props { + menuItem?: boolean; + } + + let { menuItem = false }: Props = $props(); const text = $t('tag'); const icon = mdiTagMultipleOutline; - let loading = false; - let isOpen = false; + let loading = $state(false); + let isOpen = $state(false); const { clearSelect, getOwnedAssets } = getAssetControlContext(); @@ -36,9 +40,9 @@ {#if !menuItem} {#if loading} - <CircleIconButton title={$t('loading')} icon={mdiTimerSand} /> + <CircleIconButton title={$t('loading')} icon={mdiTimerSand} onclick={() => {}} /> {:else} - <CircleIconButton title={text} {icon} on:click={handleOpen} /> + <CircleIconButton title={text} {icon} onclick={handleOpen} /> {/if} {/if} diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte index 6c534e5116..775b2a9282 100644 --- a/web/src/lib/components/photos-page/asset-grid.svelte +++ b/web/src/lib/components/photos-page/asset-grid.svelte @@ -22,7 +22,7 @@ import { TUNABLES } from '$lib/utils/tunables'; import type { AlbumResponseDto, AssetResponseDto } from '@immich/sdk'; import { throttle } from 'lodash-es'; - import { onDestroy, onMount } from 'svelte'; + import { onDestroy, onMount, type Snippet } from 'svelte'; import Portal from '../shared-components/portal/portal.svelte'; import Scrubber from '../shared-components/scrubber/scrubber.svelte'; import ShowShortcuts from '../shared-components/show-shortcuts.svelte'; @@ -38,80 +38,70 @@ import { generateId } from '$lib/utils/generate-id'; import { isTimelineScrolling } from '$lib/stores/timeline.store'; - export let isSelectionMode = false; - export let singleSelect = false; - - /** `true` if this asset grid is responds to navigation events; if `true`, then look at the + interface Props { + isSelectionMode?: boolean; + singleSelect?: boolean; + /** `true` if this asset grid is responds to navigation events; if `true`, then look at the `AssetViewingStore.gridScrollTarget` and load and scroll to the asset specified, and additionally, update the page location/url with the asset as the asset-grid is scrolled */ - export let enableRouting: boolean; + enableRouting: boolean; + assetStore: AssetStore; + assetInteractionStore: AssetInteractionStore; + removeAction?: AssetAction.UNARCHIVE | AssetAction.ARCHIVE | AssetAction.FAVORITE | AssetAction.UNFAVORITE | null; + withStacked?: boolean; + showArchiveIcon?: boolean; + isShared?: boolean; + album?: AlbumResponseDto | null; + isShowDeleteConfirmation?: boolean; + onSelect?: (asset: AssetResponseDto) => void; + onEscape?: () => void; + children?: Snippet; + empty?: Snippet; + } - export let assetStore: AssetStore; - export let assetInteractionStore: AssetInteractionStore; - export let removeAction: - | AssetAction.UNARCHIVE - | AssetAction.ARCHIVE - | AssetAction.FAVORITE - | AssetAction.UNFAVORITE - | null = null; - export let withStacked = false; - export let showArchiveIcon = false; - export let isShared = false; - export let album: AlbumResponseDto | null = null; - export let isShowDeleteConfirmation = false; - export let onSelect: (asset: AssetResponseDto) => void = () => {}; - export let onEscape: () => void = () => {}; + let { + isSelectionMode = false, + singleSelect = false, + enableRouting, + assetStore = $bindable(), + assetInteractionStore, + removeAction = null, + withStacked = false, + showArchiveIcon = false, + isShared = false, + album = null, + isShowDeleteConfirmation = $bindable(false), + onSelect = () => {}, + onEscape = () => {}, + children, + empty, + }: Props = $props(); let { isViewing: showAssetViewer, asset: viewingAsset, preloadAssets, gridScrollTarget } = assetViewingStore; const { assetSelectionCandidates, assetSelectionStart, selectedGroup, selectedAssets, isMultiSelectState } = assetInteractionStore; - const viewport: ViewportXY = { width: 0, height: 0, x: 0, y: 0 }; - const safeViewport: ViewportXY = { width: 0, height: 0, x: 0, y: 0 }; + const viewport: ViewportXY = $state({ width: 0, height: 0, x: 0, y: 0 }); + const safeViewport: ViewportXY = $state({ width: 0, height: 0, x: 0, y: 0 }); const componentId = generateId(); - let element: HTMLElement; - let timelineElement: HTMLElement; - let showShortcuts = false; - let showSkeleton = true; + let element: HTMLElement | undefined = $state(); + let timelineElement: HTMLElement | undefined = $state(); + let showShortcuts = $state(false); + let showSkeleton = $state(true); let internalScroll = false; let navigating = false; - let preMeasure: AssetBucket[] = []; + let preMeasure: AssetBucket[] = $state([]); let lastIntersectedBucketDate: string | undefined; - let scrubBucketPercent = 0; - let scrubBucket: { bucketDate: string | undefined } | undefined; - let scrubOverallPercent: number = 0; - let topSectionHeight = 0; - let topSectionOffset = 0; + let scrubBucketPercent = $state(0); + let scrubBucket: { bucketDate: string | undefined } | undefined = $state(); + let scrubOverallPercent: number = $state(0); + let topSectionHeight = $state(0); + let topSectionOffset = $state(0); // 60 is the bottom spacer element at 60px let bottomSectionHeight = 60; - let leadout = false; + let leadout = $state(false); - $: isTrashEnabled = $featureFlags.loaded && $featureFlags.trash; - $: isEmpty = $assetStore.initialized && $assetStore.buckets.length === 0; - $: idsSelectedAssets = [...$selectedAssets].map(({ id }) => id); - $: isAllArchived = [...$selectedAssets].every((asset) => asset.isArchived); - $: { - if (isEmpty) { - assetInteractionStore.clearMultiselect(); - } - } - $: { - if (element && isViewportOrigin()) { - const rect = element.getBoundingClientRect(); - viewport.height = rect.height; - viewport.width = rect.width; - viewport.x = rect.x; - viewport.y = rect.y; - } - if (!isViewportOrigin() && !isEqual(viewport, safeViewport)) { - safeViewport.height = viewport.height; - safeViewport.width = viewport.width; - safeViewport.x = viewport.x; - safeViewport.y = viewport.y; - updateViewport(); - } - } const { ASSET_GRID: { NAVIGATE_ON_ASSET_IN_VIEW }, BUCKET: { @@ -141,11 +131,11 @@ if ($gridScrollTarget?.at) { void $assetStore.scheduleScrollToAssetId($gridScrollTarget, () => { - element.scrollTo({ top: 0 }); + element?.scrollTo({ top: 0 }); showSkeleton = false; }); } else { - element.scrollTo({ top: 0 }); + element?.scrollTo({ top: 0 }); showSkeleton = false; } }; @@ -185,7 +175,7 @@ { replaceState: true, forceNavigate: true }, ); } else { - element.scrollTo({ top: 0 }); + element?.scrollTo({ top: 0 }); showSkeleton = false; } }, 500); @@ -276,14 +266,24 @@ ($assetStore.timelineHeight + bottomSectionHeight + topSectionHeight - safeViewport.height) / ($assetStore.timelineHeight + bottomSectionHeight + topSectionHeight); - const getMaxScroll = () => - topSectionHeight + bottomSectionHeight + (timelineElement.clientHeight - element.clientHeight); + const getMaxScroll = () => { + if (!element || !timelineElement) { + return 0; + } + + return topSectionHeight + bottomSectionHeight + (timelineElement.clientHeight - element.clientHeight); + }; const scrollToBucketAndOffset = (bucket: AssetBucket, bucketScrollPercent: number) => { const topOffset = getOffset(bucket.bucketDate) + topSectionHeight + topSectionOffset; const maxScrollPercent = getMaxScrollPercent(); const delta = bucket.bucketHeight * bucketScrollPercent; const scrollTop = (topOffset + delta) * maxScrollPercent; + + if (!element) { + return; + } + element.scrollTop = scrollTop; }; @@ -297,6 +297,11 @@ const maxScroll = getMaxScroll(); const offset = maxScroll * scrollPercent; + + if (!element) { + return; + } + element.scrollTop = offset; } else { const bucket = assetStore.buckets.find((b) => b.bucketDate === bucketDate); @@ -344,6 +349,11 @@ }, 1000); leadout = false; + + if (!element) { + return; + } + if ($assetStore.timelineHeight < safeViewport.height * 2) { // edge case - scroll limited due to size of content, must adjust - use the overall percent instead const maxScroll = getMaxScroll(); @@ -409,7 +419,7 @@ : () => void 0; const onScrollTarget: ScrollTargetListener = ({ bucket, offset }) => { - element.scrollTo({ top: offset }); + element?.scrollTo({ top: offset }); if (!bucket.measured) { preMeasure.push(bucket); } @@ -466,37 +476,10 @@ const focusElement = () => { if (document.activeElement === document.body) { - element.focus(); + element?.focus(); } }; - $: shortcutList = (() => { - if ($isSearchEnabled || $showAssetViewer) { - return []; - } - - const shortcuts: ShortcutOptions[] = [ - { shortcut: { key: 'Escape' }, onShortcut: onEscape }, - { shortcut: { key: '?', shift: true }, onShortcut: () => (showShortcuts = !showShortcuts) }, - { shortcut: { key: '/' }, onShortcut: () => goto(AppRoute.EXPLORE) }, - { shortcut: { key: 'A', ctrl: true }, onShortcut: () => selectAllAssets($assetStore, assetInteractionStore) }, - { shortcut: { key: 'PageDown' }, preventDefault: false, onShortcut: focusElement }, - { shortcut: { key: 'PageUp' }, preventDefault: false, onShortcut: focusElement }, - ]; - - if ($isMultiSelectState) { - shortcuts.push( - { shortcut: { key: 'Delete' }, onShortcut: onDelete }, - { shortcut: { key: 'Delete', shift: true }, onShortcut: onForceDelete }, - { shortcut: { key: 'D', ctrl: true }, onShortcut: () => deselectAllAssets() }, - { shortcut: { key: 's' }, onShortcut: () => onStackAssets() }, - { shortcut: { key: 'a', shift: true }, onShortcut: toggleArchive }, - ); - } - - return shortcuts; - })(); - const handleSelectAsset = (asset: AssetResponseDto) => { if (!$assetStore.albumAssets.has(asset.id)) { assetInteractionStore.selectAsset(asset); @@ -585,13 +568,9 @@ } }; - let lastAssetMouseEvent: AssetResponseDto | null = null; + let lastAssetMouseEvent: AssetResponseDto | null = $state(null); - $: if (!lastAssetMouseEvent) { - assetInteractionStore.clearAssetSelectionCandidates(); - } - - let shiftKeyIsDown = false; + let shiftKeyIsDown = $state(false); const deselectAllAssets = () => { cancelMultiselect(assetInteractionStore); @@ -619,14 +598,6 @@ } }; - $: if (!shiftKeyIsDown) { - assetInteractionStore.clearAssetSelectionCandidates(); - } - - $: if (shiftKeyIsDown && lastAssetMouseEvent) { - selectAssetCandidates(lastAssetMouseEvent); - } - const handleSelectAssetCandidates = (asset: AssetResponseDto | null) => { if (asset) { selectAssetCandidates(asset); @@ -655,7 +626,7 @@ onSelect(asset); - if (singleSelect) { + if (singleSelect && element) { element.scrollTop = 0; return; } @@ -723,18 +694,18 @@ assetInteractionStore.setAssetSelectionStart(deselect ? null : asset); }; - const selectAssetCandidates = (asset: AssetResponseDto) => { + const selectAssetCandidates = (endAsset: AssetResponseDto) => { if (!shiftKeyIsDown) { return; } - const rangeStart = $assetSelectionStart; - if (!rangeStart) { + const startAsset = $assetSelectionStart; + if (!startAsset) { return; } - let start = $assetStore.assets.indexOf(rangeStart); - let end = $assetStore.assets.indexOf(asset); + let start = $assetStore.assets.findIndex((a) => a.id === startAsset.id); + let end = $assetStore.assets.findIndex((a) => a.id === endAsset.id); if (start > end) { [start, end] = [end, start]; @@ -751,9 +722,83 @@ onDestroy(() => { assetStore.taskManager.removeAllTasksForComponent(componentId); }); + let isTrashEnabled = $derived($featureFlags.loaded && $featureFlags.trash); + let isEmpty = $derived($assetStore.initialized && $assetStore.buckets.length === 0); + let idsSelectedAssets = $derived([...$selectedAssets].map(({ id }) => id)); + let isAllArchived = $derived([...$selectedAssets].every((asset) => asset.isArchived)); + + $effect(() => { + if (isEmpty) { + assetInteractionStore.clearMultiselect(); + } + }); + + $effect(() => { + if (element && isViewportOrigin()) { + const rect = element.getBoundingClientRect(); + viewport.height = rect.height; + viewport.width = rect.width; + viewport.x = rect.x; + viewport.y = rect.y; + } + if (!isViewportOrigin() && !isEqual(viewport, safeViewport)) { + safeViewport.height = viewport.height; + safeViewport.width = viewport.width; + safeViewport.x = viewport.x; + safeViewport.y = viewport.y; + updateViewport(); + } + }); + + let shortcutList = $derived( + (() => { + if ($isSearchEnabled || $showAssetViewer) { + return []; + } + + const shortcuts: ShortcutOptions[] = [ + { shortcut: { key: 'Escape' }, onShortcut: onEscape }, + { shortcut: { key: '?', shift: true }, onShortcut: () => (showShortcuts = !showShortcuts) }, + { shortcut: { key: '/' }, onShortcut: () => goto(AppRoute.EXPLORE) }, + { shortcut: { key: 'A', ctrl: true }, onShortcut: () => selectAllAssets($assetStore, assetInteractionStore) }, + { shortcut: { key: 'PageDown' }, preventDefault: false, onShortcut: focusElement }, + { shortcut: { key: 'PageUp' }, preventDefault: false, onShortcut: focusElement }, + ]; + + if ($isMultiSelectState) { + shortcuts.push( + { shortcut: { key: 'Delete' }, onShortcut: onDelete }, + { shortcut: { key: 'Delete', shift: true }, onShortcut: onForceDelete }, + { shortcut: { key: 'D', ctrl: true }, onShortcut: () => deselectAllAssets() }, + { shortcut: { key: 's' }, onShortcut: () => onStackAssets() }, + { shortcut: { key: 'a', shift: true }, onShortcut: toggleArchive }, + ); + } + + return shortcuts; + })(), + ); + + $effect(() => { + if (!lastAssetMouseEvent) { + assetInteractionStore.clearAssetSelectionCandidates(); + } + }); + + $effect(() => { + if (!shiftKeyIsDown) { + assetInteractionStore.clearAssetSelectionCandidates(); + } + }); + + $effect(() => { + if (shiftKeyIsDown && lastAssetMouseEvent) { + selectAssetCandidates(lastAssetMouseEvent); + } + }); </script> -<svelte:window on:keydown={onKeyDown} on:keyup={onKeyUp} on:selectstart={onSelectStart} use:shortcuts={shortcutList} /> +<svelte:window onkeydown={onKeyDown} onkeyup={onKeyUp} onselectstart={onSelectStart} use:shortcuts={shortcutList} /> {#if isShowDeleteConfirmation} <DeleteAssetDialog @@ -789,16 +834,16 @@ tabindex="-1" use:resizeObserver={({ height, width }) => ((viewport.width = width), (viewport.height = height))} bind:this={element} - on:scroll={() => ((assetStore.lastScrollTime = Date.now()), handleTimelineScroll())} + onscroll={() => ((assetStore.lastScrollTime = Date.now()), handleTimelineScroll())} > <section use:resizeObserver={({ target, height }) => ((topSectionHeight = height), (topSectionOffset = target.offsetTop))} class:invisible={showSkeleton} > - <slot /> + {@render children?.()} {#if isEmpty} <!-- (optional) empty placeholder --> - <slot name="empty" /> + {@render empty?.()} {/if} </section> diff --git a/web/src/lib/components/photos-page/asset-select-control-bar.svelte b/web/src/lib/components/photos-page/asset-select-control-bar.svelte index 79a0ea75e6..2ab8f1e9c2 100644 --- a/web/src/lib/components/photos-page/asset-select-control-bar.svelte +++ b/web/src/lib/components/photos-page/asset-select-control-bar.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> import { createContext } from '$lib/utils/context'; import { t } from 'svelte-i18n'; @@ -17,10 +17,16 @@ import type { AssetResponseDto } from '@immich/sdk'; import { mdiClose } from '@mdi/js'; import ControlAppBar from '../shared-components/control-app-bar.svelte'; + import type { Snippet } from 'svelte'; - export let assets: Set<AssetResponseDto>; - export let clearSelect: () => void; - export let ownerId: string | undefined = undefined; + interface Props { + assets: Set<AssetResponseDto>; + clearSelect: () => void; + ownerId?: string | undefined; + children?: Snippet; + } + + let { assets, clearSelect, ownerId = undefined, children }: Props = $props(); setContext({ getAssets: () => assets, @@ -31,9 +37,13 @@ </script> <ControlAppBar onClose={clearSelect} backIcon={mdiClose} tailwindClasses="bg-white shadow-md"> - <div class="font-medium text-immich-primary dark:text-immich-dark-primary" slot="leading"> - <p class="block sm:hidden">{assets.size}</p> - <p class="hidden sm:block">{$t('selected_count', { values: { count: assets.size } })}</p> - </div> - <slot slot="trailing" /> + {#snippet leading()} + <div class="font-medium text-immich-primary dark:text-immich-dark-primary"> + <p class="block sm:hidden">{assets.size}</p> + <p class="hidden sm:block">{$t('selected_count', { values: { count: assets.size } })}</p> + </div> + {/snippet} + {#snippet trailing()} + {@render children?.()} + {/snippet} </ControlAppBar> diff --git a/web/src/lib/components/photos-page/delete-asset-dialog.svelte b/web/src/lib/components/photos-page/delete-asset-dialog.svelte index 3eff428a7b..3053600a47 100644 --- a/web/src/lib/components/photos-page/delete-asset-dialog.svelte +++ b/web/src/lib/components/photos-page/delete-asset-dialog.svelte @@ -5,11 +5,15 @@ import { t } from 'svelte-i18n'; import FormatMessage from '$lib/components/i18n/format-message.svelte'; - export let size: number; - export let onConfirm: () => void; - export let onCancel: () => void; + interface Props { + size: number; + onConfirm: () => void; + onCancel: () => void; + } - let checked = false; + let { size, onConfirm, onCancel }: Props = $props(); + + let checked = $state(false); const handleConfirm = () => { if (checked) { @@ -25,10 +29,12 @@ onConfirm={handleConfirm} {onCancel} > - <svelte:fragment slot="prompt"> + {#snippet promptSnippet()} <p> - <FormatMessage key="permanently_delete_assets_prompt" values={{ count: size }} let:message> - <b>{message}</b> + <FormatMessage key="permanently_delete_assets_prompt" values={{ count: size }}> + {#snippet children({ message })} + <b>{message}</b> + {/snippet} </FormatMessage> </p> <p><b>{$t('cannot_undo_this_action')}</b></p> @@ -36,5 +42,5 @@ <div class="pt-4 flex justify-center items-center"> <Checkbox id="confirm-deletion-input" label={$t('do_not_show_again')} bind:checked /> </div> - </svelte:fragment> + {/snippet} </ConfirmDialog> 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 f458fe40dd..80ad7640fb 100644 --- a/web/src/lib/components/photos-page/measure-date-group.svelte +++ b/web/src/lib/components/photos-page/measure-date-group.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> const recentTimes: number[] = []; // TODO: track average time to measure, and use this to populate TUNABLES.ASSETS_STORE.CHECK_INTERVAL_MS // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -20,9 +20,13 @@ import { resizeObserver } from '$lib/actions/resize-observer'; import type { AssetBucket, AssetStore, BucketListener } from '$lib/stores/assets.store'; - export let assetStore: AssetStore; - export let bucket: AssetBucket; - export let onMeasured: () => void; + interface Props { + assetStore: AssetStore; + bucket: AssetBucket; + onMeasured: () => void; + } + + let { assetStore, bucket, onMeasured }: Props = $props(); async function _measure(element: Element) { try { diff --git a/web/src/lib/components/photos-page/memory-lane.svelte b/web/src/lib/components/photos-page/memory-lane.svelte index ed6ef4f3a7..3a6ac7e8cf 100644 --- a/web/src/lib/components/photos-page/memory-lane.svelte +++ b/web/src/lib/components/photos-page/memory-lane.svelte @@ -11,27 +11,29 @@ import { fade } from 'svelte/transition'; import { t } from 'svelte-i18n'; - $: shouldRender = $memoryStore?.length > 0; + let shouldRender = $derived($memoryStore?.length > 0); onMount(async () => { const localTime = new Date(); $memoryStore = await getMemoryLane({ month: localTime.getMonth() + 1, day: localTime.getDate() }); }); - let memoryLaneElement: HTMLElement; - let offsetWidth = 0; - let innerWidth = 0; + let memoryLaneElement: HTMLElement | undefined = $state(); + let offsetWidth = $state(0); + let innerWidth = $state(0); - let scrollLeftPosition = 0; + let scrollLeftPosition = $state(0); - const onScroll = () => (scrollLeftPosition = memoryLaneElement?.scrollLeft); + const onScroll = () => { + scrollLeftPosition = memoryLaneElement?.scrollLeft ?? 0; + }; - $: canScrollLeft = scrollLeftPosition > 0; - $: canScrollRight = Math.ceil(scrollLeftPosition) < innerWidth - offsetWidth; + let canScrollLeft = $derived(scrollLeftPosition > 0); + let canScrollRight = $derived(Math.ceil(scrollLeftPosition) < innerWidth - offsetWidth); const scrollBy = 400; - const scrollLeft = () => memoryLaneElement.scrollBy({ left: -scrollBy, behavior: 'smooth' }); - const scrollRight = () => memoryLaneElement.scrollBy({ left: scrollBy, behavior: 'smooth' }); + const scrollLeft = () => memoryLaneElement?.scrollBy({ left: -scrollBy, behavior: 'smooth' }); + const scrollRight = () => memoryLaneElement?.scrollBy({ left: scrollBy, behavior: 'smooth' }); </script> {#if shouldRender} @@ -40,7 +42,7 @@ bind:this={memoryLaneElement} class="relative mt-5 overflow-x-hidden whitespace-nowrap transition-all" use:resizeObserver={({ width }) => (offsetWidth = width)} - on:scroll={onScroll} + onscroll={onScroll} > {#if canScrollLeft || canScrollRight} <div class="sticky left-0 z-20"> @@ -49,7 +51,7 @@ <button type="button" class="rounded-full border border-gray-500 bg-gray-100 p-2 text-gray-500 opacity-50 hover:opacity-100" - on:click={scrollLeft} + onclick={scrollLeft} > <Icon path={mdiChevronLeft} size="36" /></button > @@ -60,7 +62,7 @@ <button type="button" class="rounded-full border border-gray-500 bg-gray-100 p-2 text-gray-500 opacity-50 hover:opacity-100" - on:click={scrollRight} + onclick={scrollRight} > <Icon path={mdiChevronRight} size="36" /></button > diff --git a/web/src/lib/components/photos-page/skeleton.svelte b/web/src/lib/components/photos-page/skeleton.svelte index 07836eb4db..601a40cce2 100644 --- a/web/src/lib/components/photos-page/skeleton.svelte +++ b/web/src/lib/components/photos-page/skeleton.svelte @@ -1,6 +1,10 @@ <script lang="ts"> - export let title: string | null = null; - export let height: string | null = null; + interface Props { + title?: string | null; + height?: string | null; + } + + let { title = null, height = null }: Props = $props(); </script> <div class="overflow-clip" style={`height: ${height}`}> diff --git a/web/src/lib/components/share-page/individual-shared-viewer.svelte b/web/src/lib/components/share-page/individual-shared-viewer.svelte index 1b5368b133..245a90f9f3 100644 --- a/web/src/lib/components/share-page/individual-shared-viewer.svelte +++ b/web/src/lib/components/share-page/individual-shared-viewer.svelte @@ -19,15 +19,19 @@ import type { Viewport } from '$lib/stores/assets.store'; import { t } from 'svelte-i18n'; - export let sharedLink: SharedLinkResponseDto; - export let isOwned: boolean; + interface Props { + sharedLink: SharedLinkResponseDto; + isOwned: boolean; + } - const viewport: Viewport = { width: 0, height: 0 }; - let selectedAssets: Set<AssetResponseDto> = new Set(); - let innerWidth: number; + let { sharedLink = $bindable(), isOwned }: Props = $props(); - $: assets = sharedLink.assets; - $: isMultiSelectionMode = selectedAssets.size > 0; + const viewport: Viewport = $state({ width: 0, height: 0 }); + let selectedAssets: Set<AssetResponseDto> = $state(new Set()); + let innerWidth: number = $state(0); + + let assets = $derived(sharedLink.assets); + let isMultiSelectionMode = $derived(selectedAssets.size > 0); dragAndDropFilesStore.subscribe((value) => { if (value.isDragging && value.files.length > 0) { @@ -75,7 +79,7 @@ <section class="bg-immich-bg dark:bg-immich-dark-bg"> {#if isMultiSelectionMode} <AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}> - <CircleIconButton title={$t('select_all')} icon={mdiSelectAll} on:click={handleSelectAll} /> + <CircleIconButton title={$t('select_all')} icon={mdiSelectAll} onclick={handleSelectAll} /> {#if sharedLink?.allowDownload} <DownloadAction filename="immich-shared.zip" /> {/if} @@ -85,23 +89,23 @@ </AssetSelectControlBar> {:else} <ControlAppBar onClose={() => goto(AppRoute.PHOTOS)} backIcon={mdiArrowLeft} showBackButton={false}> - <svelte:fragment slot="leading"> + {#snippet leading()} <ImmichLogoSmallLink width={innerWidth} /> - </svelte:fragment> + {/snippet} - <svelte:fragment slot="trailing"> + {#snippet trailing()} {#if sharedLink?.allowUpload} <CircleIconButton title={$t('add_photos')} - on:click={() => handleUploadAssets()} + onclick={() => handleUploadAssets()} icon={mdiFileImagePlusOutline} /> {/if} {#if sharedLink?.allowDownload} - <CircleIconButton title={$t('download')} on:click={downloadAssets} icon={mdiFolderDownloadOutline} /> + <CircleIconButton title={$t('download')} onclick={downloadAssets} icon={mdiFolderDownloadOutline} /> {/if} - </svelte:fragment> + {/snippet} </ControlAppBar> {/if} <section class="my-[160px] mx-4" bind:clientHeight={viewport.height} bind:clientWidth={viewport.width}> diff --git a/web/src/lib/components/shared-components/album-selection-modal.svelte b/web/src/lib/components/shared-components/album-selection-modal.svelte index 65f39ccb16..3400864efd 100644 --- a/web/src/lib/components/shared-components/album-selection-modal.svelte +++ b/web/src/lib/components/shared-components/album-selection-modal.svelte @@ -11,17 +11,19 @@ import { sortAlbums } from '$lib/utils/album-utils'; import { albumViewSettings } from '$lib/stores/preferences.store'; - export let onNewAlbum: (search: string) => void; - export let onAlbumClick: (album: AlbumResponseDto) => void; + let albums: AlbumResponseDto[] = $state([]); + let recentAlbums: AlbumResponseDto[] = $state([]); + let loading = $state(true); + let search = $state(''); - let albums: AlbumResponseDto[] = []; - let recentAlbums: AlbumResponseDto[] = []; - let filteredAlbums: AlbumResponseDto[] = []; - let loading = true; - let search = ''; + interface Props { + onNewAlbum: (search: string) => void; + onAlbumClick: (album: AlbumResponseDto) => void; + shared: boolean; + onClose: () => void; + } - export let shared: boolean; - export let onClose: () => void; + let { onNewAlbum, onAlbumClick, shared, onClose }: Props = $props(); onMount(async () => { albums = await getAllAlbums({ shared: shared || undefined }); @@ -29,13 +31,15 @@ loading = false; }); - $: filteredAlbums = sortAlbums( - search.length > 0 && albums.length > 0 - ? albums.filter((album) => { - return normalizeSearchString(album.albumName).includes(normalizeSearchString(search)); - }) - : albums, - { sortBy: $albumViewSettings.sortBy, orderBy: $albumViewSettings.sortOrder }, + let filteredAlbums = $derived( + sortAlbums( + search.length > 0 && albums.length > 0 + ? albums.filter((album) => { + return normalizeSearchString(album.albumName).includes(normalizeSearchString(search)); + }) + : albums, + { sortBy: $albumViewSettings.sortBy, orderBy: $albumViewSettings.sortOrder }, + ), ); const getTitle = () => { @@ -71,7 +75,7 @@ <div class="immich-scrollbar overflow-y-auto"> <button type="button" - on:click={() => onNewAlbum(search)} + onclick={() => onNewAlbum(search)} class="flex w-full items-center gap-4 px-6 py-2 transition-colors hover:bg-gray-200 dark:hover:bg-gray-700 rounded-xl" > <div class="flex h-12 w-12 items-center justify-center"> diff --git a/web/src/lib/components/shared-components/autogrow-textarea.svelte b/web/src/lib/components/shared-components/autogrow-textarea.svelte index efbcf218e6..5bb4637e05 100644 --- a/web/src/lib/components/shared-components/autogrow-textarea.svelte +++ b/web/src/lib/components/shared-components/autogrow-textarea.svelte @@ -3,23 +3,23 @@ import { shortcut } from '$lib/actions/shortcut'; import { tick } from 'svelte'; - export let content: string = ''; - let className: string = ''; - export { className as class }; - export let onContentUpdate: (newContent: string) => void = () => null; - export let placeholder: string = ''; + interface Props { + content?: string; + class?: string; + onContentUpdate?: (newContent: string) => void; + placeholder?: string; + } - let textarea: HTMLTextAreaElement; - $: newContent = content; + let { content = '', class: className = '', onContentUpdate = () => null, placeholder = '' }: Props = $props(); - $: { - // re-visit with svelte 5. runes will make this better. - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - newContent; + let textarea: HTMLTextAreaElement | undefined = $state(); + let newContent = $state(content); + + $effect(() => { if (textarea && newContent.length > 0) { void tick().then(() => autoGrowHeight(textarea)); } - } + }); const updateContent = () => { if (content === newContent) { @@ -32,8 +32,8 @@ <textarea bind:this={textarea} class="resize-none {className}" - on:focusout={updateContent} - on:input={(e) => (newContent = e.currentTarget.value)} + onfocusout={updateContent} + oninput={(e) => (newContent = e.currentTarget.value)} {placeholder} use:shortcut={{ shortcut: { key: 'Enter', ctrl: true }, diff --git a/web/src/lib/components/shared-components/change-date.spec.ts b/web/src/lib/components/shared-components/change-date.spec.ts index 112e900c02..815acac5ab 100644 --- a/web/src/lib/components/shared-components/change-date.spec.ts +++ b/web/src/lib/components/shared-components/change-date.spec.ts @@ -16,6 +16,16 @@ describe('ChangeDate component', () => { beforeEach(() => { vi.stubGlobal('IntersectionObserver', getIntersectionObserverMock()); + + vi.stubGlobal('visualViewport', { + height: window.innerHeight, + width: window.innerWidth, + scale: 1, + offsetLeft: 0, + offsetTop: 0, + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + }); }); afterEach(() => { diff --git a/web/src/lib/components/shared-components/change-date.svelte b/web/src/lib/components/shared-components/change-date.svelte index 8ceda5f1d6..13b2752f0c 100644 --- a/web/src/lib/components/shared-components/change-date.svelte +++ b/web/src/lib/components/shared-components/change-date.svelte @@ -1,14 +1,18 @@ <script lang="ts"> import { DateTime } from 'luxon'; import ConfirmDialog from './dialog/confirm-dialog.svelte'; - import Combobox from './combobox.svelte'; + import Combobox, { type ComboBoxOption } from './combobox.svelte'; import DateInput from '../elements/date-input.svelte'; import { t } from 'svelte-i18n'; - export let initialDate: DateTime = DateTime.now(); - export let initialTimeZone: string = ''; - export let onCancel: () => void; - export let onConfirm: (date: string) => void; + interface Props { + initialDate?: DateTime; + initialTimeZone?: string; + onCancel: () => void; + onConfirm: (date: string) => void; + } + + let { initialDate = DateTime.now(), initialTimeZone = '', onCancel, onConfirm }: Props = $props(); type ZoneOption = { /** @@ -49,21 +53,15 @@ const knownTimezones = Intl.supportedValuesOf('timeZone'); - let timezones: ZoneOption[]; - $: timezones = knownTimezones + const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; + + let selectedDate = $state(initialDate.toFormat("yyyy-MM-dd'T'HH:mm")); + let timezones: ZoneOption[] = knownTimezones .map((zone) => zoneOptionForDate(zone, selectedDate)) .filter((zone) => zone.valid) .sort((zoneA, zoneB) => sortTwoZones(zoneA, zoneB)); - - const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; // the offsets (and validity) for time zones may change if the date is changed, which is why we recompute the list - let selectedOption: ZoneOption | undefined; - $: selectedOption = getPreferredTimeZone(initialDate, userTimeZone, timezones, selectedOption); - - let selectedDate = initialDate.toFormat("yyyy-MM-dd'T'HH:mm"); - - // when changing the time zone, assume the configured date/time is meant for that time zone (instead of updating it) - $: date = DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true }); + let selectedOption: ZoneOption | undefined = $state(getPreferredTimeZone(initialDate, userTimeZone, timezones)); function zoneOptionForDate(zone: string, date: string) { const dateAtZone: DateTime = DateTime.fromISO(date, { zone }); @@ -125,6 +123,14 @@ onConfirm(value); } }; + + const handleOnSelect = (option?: ComboBoxOption) => { + if (option) { + selectedOption = getPreferredTimeZone(initialDate, userTimeZone, timezones, option as ZoneOption); + } + }; + // when changing the time zone, assume the configured date/time is meant for that time zone (instead of updating it) + let date = $derived(DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true })); </script> <ConfirmDialog @@ -135,13 +141,23 @@ onConfirm={handleConfirm} {onCancel} > - <div class="flex flex-col text-left gap-2" slot="prompt"> - <div class="flex flex-col"> - <label for="datetime">{$t('date_and_time')}</label> - <DateInput class="immich-form-input" id="datetime" type="datetime-local" bind:value={selectedDate} /> + <!-- @migration-task: migrate this slot by hand, `prompt` would shadow a prop on the parent component --> + <!-- @migration-task: migrate this slot by hand, `prompt` would shadow a prop on the parent component --> + {#snippet promptSnippet()} + <div class="flex flex-col text-left gap-2"> + <div class="flex flex-col"> + <label for="datetime">{$t('date_and_time')}</label> + <DateInput class="immich-form-input" id="datetime" type="datetime-local" bind:value={selectedDate} /> + </div> + <div> + <Combobox + bind:selectedOption + label={$t('timezone')} + options={timezones} + placeholder={$t('search_timezone')} + onSelect={(option) => handleOnSelect(option)} + /> + </div> </div> - <div> - <Combobox bind:selectedOption label={$t('timezone')} options={timezones} placeholder={$t('search_timezone')} /> - </div> - </div> + {/snippet} </ConfirmDialog> diff --git a/web/src/lib/components/shared-components/change-location.svelte b/web/src/lib/components/shared-components/change-location.svelte index 573c9ab38b..fa050d39c2 100644 --- a/web/src/lib/components/shared-components/change-location.svelte +++ b/web/src/lib/components/shared-components/change-location.svelte @@ -12,39 +12,44 @@ import { listNavigation } from '$lib/actions/list-navigation'; import { t } from 'svelte-i18n'; import CoordinatesInput from '$lib/components/shared-components/coordinates-input.svelte'; + import Map from '$lib/components/shared-components/map/map.svelte'; interface Point { lng: number; lat: number; } - export let asset: AssetResponseDto | undefined = undefined; - export let onCancel: () => void; - export let onConfirm: (point: Point) => void; + interface Props { + asset?: AssetResponseDto | undefined; + onCancel: () => void; + onConfirm: (point: Point) => void; + } - let places: PlacesResponseDto[] = []; - let suggestedPlaces: PlacesResponseDto[] = []; - let searchWord: string; + let { asset = undefined, onCancel, onConfirm }: Props = $props(); + + let places: PlacesResponseDto[] = $state([]); + let suggestedPlaces: PlacesResponseDto[] = $state([]); + let searchWord: string = $state(''); let latestSearchTimeout: number; - let showLoadingSpinner = false; - let suggestionContainer: HTMLDivElement; - let hideSuggestion = false; - let addClipMapMarker: (long: number, lat: number) => void; + let showLoadingSpinner = $state(false); + let suggestionContainer: HTMLDivElement | undefined = $state(); + let hideSuggestion = $state(false); + let mapElement = $state<ReturnType<typeof Map>>(); - $: lat = asset?.exifInfo?.latitude ?? undefined; - $: lng = asset?.exifInfo?.longitude ?? undefined; - $: zoom = lat !== undefined && lng !== undefined ? 12.5 : 1; + let lat = $derived(asset?.exifInfo?.latitude ?? undefined); + let lng = $derived(asset?.exifInfo?.longitude ?? undefined); + let zoom = $derived(lat !== undefined && lng !== undefined ? 12.5 : 1); - $: { + $effect(() => { if (places) { suggestedPlaces = places.slice(0, 5); } if (searchWord === '') { suggestedPlaces = []; } - } + }); - let point: Point | null = null; + let point: Point | null = $state(null); const handleConfirm = () => { if (point) { @@ -94,88 +99,95 @@ const handleUseSuggested = (latitude: number, longitude: number) => { hideSuggestion = true; point = { lng: longitude, lat: latitude }; - addClipMapMarker(longitude, latitude); + mapElement?.addClipMapMarker(longitude, latitude); }; </script> <ConfirmDialog confirmColor="primary" title={$t('change_location')} width="wide" onConfirm={handleConfirm} {onCancel}> - <div slot="prompt" class="flex flex-col w-full h-full gap-2"> - <div - class="relative w-64 sm:w-96" - use:clickOutside={{ onOutclick: () => (hideSuggestion = true) }} - use:listNavigation={suggestionContainer} - > - <button type="button" class="w-full" on:click={() => (hideSuggestion = false)}> - <SearchBar - placeholder={$t('search_places')} - bind:name={searchWord} - {showLoadingSpinner} - onReset={() => (suggestedPlaces = [])} - onSearch={handleSearchPlaces} - roundedBottom={suggestedPlaces.length === 0 || hideSuggestion} - /> - </button> - <div class="absolute z-[99] w-full" id="suggestion" bind:this={suggestionContainer}> - {#if !hideSuggestion} - {#each suggestedPlaces as place, index} - <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 === - suggestedPlaces.length - 1 - ? 'rounded-b-lg border-b' - : ''}" - on:click={() => handleUseSuggested(place.latitude, place.longitude)} - > - <p class="ml-4 text-sm text-gray-700 dark:text-gray-100 truncate"> - {getLocation(place.name, place.admin1name, place.admin2name)} - </p> + {#snippet promptSnippet()} + <div class="flex flex-col w-full h-full gap-2"> + <div class="relative w-64 sm:w-96"> + {#if suggestionContainer} + <div + use:clickOutside={{ onOutclick: () => (hideSuggestion = true) }} + use:listNavigation={suggestionContainer} + > + <button type="button" class="w-full" onclick={() => (hideSuggestion = false)}> + <SearchBar + placeholder={$t('search_places')} + bind:name={searchWord} + {showLoadingSpinner} + onReset={() => (suggestedPlaces = [])} + onSearch={handleSearchPlaces} + roundedBottom={suggestedPlaces.length === 0 || hideSuggestion} + /> </button> - {/each} + </div> {/if} + + <div class="absolute z-[99] w-full" id="suggestion" bind:this={suggestionContainer}> + {#if !hideSuggestion} + {#each suggestedPlaces as place, index} + <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 === + suggestedPlaces.length - 1 + ? 'rounded-b-lg border-b' + : ''}" + onclick={() => handleUseSuggested(place.latitude, place.longitude)} + > + <p class="ml-4 text-sm text-gray-700 dark:text-gray-100 truncate"> + {getLocation(place.name, place.admin1name, place.admin2name)} + </p> + </button> + {/each} + {/if} + </div> + </div> + + <span>{$t('pick_a_location')}</span> + <div class="h-[500px] min-h-[300px] w-full"> + {#await import('../shared-components/map/map.svelte')} + {#await delay(timeToLoadTheMap) then} + <!-- show the loading spinner only if loading the map takes too much time --> + <div class="flex items-center justify-center h-full w-full"> + <LoadingSpinner /> + </div> + {/await} + {:then { default: Map }} + <Map + bind:this={mapElement} + mapMarkers={lat !== undefined && lng !== undefined && asset + ? [ + { + id: asset.id, + lat, + lon: lng, + city: asset.exifInfo?.city ?? null, + state: asset.exifInfo?.state ?? null, + country: asset.exifInfo?.country ?? null, + }, + ] + : []} + {zoom} + center={lat && lng ? { lat, lng } : undefined} + simplified={true} + clickable={true} + onClickPoint={(selected) => (point = selected)} + /> + {/await} + </div> + + <div class="grid sm:grid-cols-2 gap-4 text-sm text-left mt-4"> + <CoordinatesInput + lat={point ? point.lat : lat} + lng={point ? point.lng : lng} + onUpdate={(lat, lng) => { + point = { lat, lng }; + mapElement?.addClipMapMarker(lng, lat); + }} + /> </div> </div> - <span>{$t('pick_a_location')}</span> - <div class="h-[500px] min-h-[300px] w-full"> - {#await import('../shared-components/map/map.svelte')} - {#await delay(timeToLoadTheMap) then} - <!-- show the loading spinner only if loading the map takes too much time --> - <div class="flex items-center justify-center h-full w-full"> - <LoadingSpinner /> - </div> - {/await} - {:then { default: Map }} - <Map - mapMarkers={lat !== undefined && lng !== undefined && asset - ? [ - { - id: asset.id, - lat, - lon: lng, - city: asset.exifInfo?.city ?? null, - state: asset.exifInfo?.state ?? null, - country: asset.exifInfo?.country ?? null, - }, - ] - : []} - {zoom} - bind:addClipMapMarker - center={lat && lng ? { lat, lng } : undefined} - simplified={true} - clickable={true} - onClickPoint={(selected) => (point = selected)} - /> - {/await} - </div> - - <div class="grid sm:grid-cols-2 gap-4 text-sm text-left mt-4"> - <CoordinatesInput - lat={point ? point.lat : lat} - lng={point ? point.lng : lng} - onUpdate={(lat, lng) => { - point = { lat, lng }; - addClipMapMarker(lng, lat); - }} - /> - </div> - </div> + {/snippet} </ConfirmDialog> diff --git a/web/src/lib/components/shared-components/combobox.svelte b/web/src/lib/components/shared-components/combobox.svelte index c89d0d34f2..b17644f137 100644 --- a/web/src/lib/components/shared-components/combobox.svelte +++ b/web/src/lib/components/shared-components/combobox.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export type ComboBoxOption = { id?: string; label: string; @@ -30,12 +30,23 @@ import { t } from 'svelte-i18n'; import { get } from 'svelte/store'; - export let label: string; - export let hideLabel = false; - export let options: ComboBoxOption[] = []; - export let selectedOption: ComboBoxOption | undefined = undefined; - export let placeholder = ''; - export let onSelect: (option: ComboBoxOption | undefined) => void = () => {}; + interface Props { + label: string; + hideLabel?: boolean; + options?: ComboBoxOption[]; + selectedOption?: ComboBoxOption | undefined; + placeholder?: string; + onSelect?: (option: ComboBoxOption | undefined) => void; + } + + let { + label, + hideLabel = false, + options = [], + selectedOption = $bindable(), + placeholder = '', + onSelect = () => {}, + }: Props = $props(); /** * Unique identifier for the combobox. @@ -44,17 +55,16 @@ /** * Indicates whether or not the dropdown autocomplete list should be visible. */ - let isOpen = false; + let isOpen = $state(false); /** * Keeps track of whether the combobox is actively being used. */ - let isActive = false; - let searchQuery = selectedOption?.label || ''; - let selectedIndex: number | undefined; - let optionRefs: HTMLElement[] = []; - let input: HTMLInputElement; - let bounds: DOMRect | undefined; - let dropdownDirection: 'bottom' | 'top' = 'bottom'; + let isActive = $state(false); + let searchQuery = $state(selectedOption?.label || ''); + let selectedIndex: number | undefined = $state(); + let optionRefs: HTMLElement[] = $state([]); + let input = $state<HTMLInputElement>(); + let bounds: DOMRect | undefined = $state(); const inputId = `combobox-${id}`; const listboxId = `listbox-${id}`; @@ -76,17 +86,12 @@ { threshold: 0.5 }, ); - $: filteredOptions = options.filter((option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())); - - $: { - searchQuery = selectedOption ? selectedOption.label : ''; - } - - $: position = calculatePosition(bounds); - onMount(() => { + if (!input) { + return; + } observer.observe(input); - const scrollableAncestor = input.closest('.overflow-y-auto, .overflow-y-scroll'); + const scrollableAncestor = input?.closest('.overflow-y-auto, .overflow-y-scroll'); scrollableAncestor?.addEventListener('scroll', onPositionChange); window.visualViewport?.addEventListener('resize', onPositionChange); window.visualViewport?.addEventListener('scroll', onPositionChange); @@ -157,7 +162,6 @@ const calculatePosition = (boundary: DOMRect | undefined) => { const visualViewport = window.visualViewport; - dropdownDirection = getComboboxDirection(boundary, visualViewport); if (!boundary) { return; @@ -212,9 +216,19 @@ }; const getInputPosition = () => input?.getBoundingClientRect(); + + $effect(() => { + // searchQuery = selectedOption ? selectedOption.label : ''; + }); + + let filteredOptions = $derived( + options.filter((option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())), + ); + let position = $derived(calculatePosition(bounds)); + let dropdownDirection: 'bottom' | 'top' = $derived(getComboboxDirection(bounds, visualViewport)); </script> -<svelte:window on:resize={onPositionChange} /> +<svelte:window onresize={onPositionChange} /> <label class="immich-form-label" class:sr-only={hideLabel} for={inputId}>{label}</label> <div class="relative w-full dark:text-gray-300 text-gray-700 text-base" @@ -252,9 +266,9 @@ class:cursor-pointer={!isActive} class="immich-form-input text-sm text-left w-full !pr-12 transition-all" id={inputId} - on:click={activate} - on:focus={activate} - on:input={onInput} + onclick={activate} + onfocus={activate} + oninput={onInput} role="combobox" type="text" value={searchQuery} @@ -304,7 +318,7 @@ class:pointer-events-none={!selectedOption} > {#if selectedOption} - <CircleIconButton on:click={onClear} title={$t('clear_value')} icon={mdiClose} size="16" padding="2" /> + <CircleIconButton onclick={onClear} title={$t('clear_value')} icon={mdiClose} size="16" padding="2" /> {:else if !isOpen} <Icon path={mdiUnfoldMoreHorizontal} ariaHidden={true} /> {/if} @@ -329,26 +343,26 @@ > {#if isOpen} {#if filteredOptions.length === 0} - <!-- svelte-ignore a11y-click-events-have-key-events --> + <!-- svelte-ignore a11y_click_events_have_key_events --> <li role="option" aria-selected={selectedIndex === 0} aria-disabled={true} class="text-left w-full px-4 py-2 hover:bg-gray-200 dark:hover:bg-gray-700 cursor-default aria-selected:bg-gray-200 aria-selected:dark:bg-gray-700" id={`${listboxId}-${0}`} - on:click={() => closeDropdown()} + onclick={() => closeDropdown()} > {$t('no_results')} </li> {/if} {#each filteredOptions as option, index (option.id || option.label)} - <!-- svelte-ignore a11y-click-events-have-key-events --> + <!-- svelte-ignore a11y_click_events_have_key_events --> <li aria-selected={index === selectedIndex} bind:this={optionRefs[index]} class="text-left w-full px-4 py-2 hover:bg-gray-200 dark:hover:bg-gray-700 transition-all cursor-pointer aria-selected:bg-gray-200 aria-selected:dark:bg-gray-700 break-words" id={`${listboxId}-${index}`} - on:click={() => handleSelect(option)} + onclick={() => handleSelect(option)} role="option" > {option.label} diff --git a/web/src/lib/components/shared-components/context-menu/button-context-menu.svelte b/web/src/lib/components/shared-components/context-menu/button-context-menu.svelte index f1ee93cc50..46dc17b9ad 100644 --- a/web/src/lib/components/shared-components/context-menu/button-context-menu.svelte +++ b/web/src/lib/components/shared-components/context-menu/button-context-menu.svelte @@ -14,41 +14,52 @@ import { optionClickCallbackStore, selectedIdStore } from '$lib/stores/context-menu.store'; import { clickOutside } from '$lib/actions/click-outside'; import { shortcuts } from '$lib/actions/shortcut'; + import type { Snippet } from 'svelte'; - export let icon: string; - export let title: string; - /** - * The alignment of the context menu relative to the button. - */ - export let align: Align = 'top-left'; - /** - * The direction in which the context menu should open. - */ - export let direction: 'left' | 'right' = 'right'; - export let color: Color = 'transparent'; - export let size: string | undefined = undefined; - export let padding: Padding | undefined = undefined; - /** - * Additional classes to apply to the button. - */ - export let buttonClass: string | undefined = undefined; - export let hideContent = false; + interface Props { + icon: string; + title: string; + /** + * The alignment of the context menu relative to the button. + */ + align?: Align; + /** + * The direction in which the context menu should open. + */ + direction?: 'left' | 'right'; + color?: Color; + size?: string | undefined; + padding?: Padding | undefined; + /** + * Additional classes to apply to the button. + */ + buttonClass?: string | undefined; + hideContent?: boolean; + children?: Snippet; + } - let isOpen = false; - let contextMenuPosition = { x: 0, y: 0 }; - let menuContainer: HTMLUListElement; - let buttonContainer: HTMLDivElement; + let { + icon, + title, + align = 'top-left', + direction = 'right', + color = 'transparent', + size = undefined, + padding = undefined, + buttonClass = undefined, + hideContent = false, + children, + }: Props = $props(); + + let isOpen = $state(false); + let contextMenuPosition = $state({ x: 0, y: 0 }); + let menuContainer: HTMLUListElement | undefined = $state(); + let buttonContainer: HTMLDivElement | undefined = $state(); const id = generateId(); const buttonId = `context-menu-button-${id}`; const menuId = `context-menu-${id}`; - $: { - if (isOpen) { - $optionClickCallbackStore = handleOptionClick; - } - } - const openDropdown = (event: KeyboardEvent | MouseEvent) => { contextMenuPosition = getContextMenuPositionFromEvent(event, align); isOpen = true; @@ -72,9 +83,10 @@ }; const onResize = () => { - if (!isOpen) { + if (!isOpen || !buttonContainer) { return; } + contextMenuPosition = getContextMenuPositionFromBoundingRect(buttonContainer.getBoundingClientRect(), align); }; @@ -92,12 +104,19 @@ }; const focusButton = () => { - const button: HTMLButtonElement | null = buttonContainer.querySelector(`#${buttonId}`); + const button = buttonContainer?.querySelector(`#${buttonId}`) as HTMLButtonElement | null; button?.focus(); }; + + $effect(() => { + if (isOpen) { + $optionClickCallbackStore = handleOptionClick; + } + }); </script> -<svelte:window on:resize={onResize} /> +<svelte:window onresize={onResize} /> + <div use:contextMenuNavigation={{ closeDropdown, @@ -109,7 +128,7 @@ selectionChanged: (id) => ($selectedIdStore = id), }} use:clickOutside={{ onOutclick: closeDropdown }} - on:resize={onResize} + onresize={onResize} > <div bind:this={buttonContainer}> <CircleIconButton @@ -123,7 +142,7 @@ aria-haspopup={true} class={buttonClass} id={buttonId} - on:click={handleClick} + onclick={handleClick} /> </div> {#if isOpen || !hideContent} @@ -150,7 +169,7 @@ id={menuId} isVisible={isOpen} > - <slot /> + {@render children?.()} </ContextMenu> </div> {/if} diff --git a/web/src/lib/components/shared-components/context-menu/context-menu.svelte b/web/src/lib/components/shared-components/context-menu/context-menu.svelte index 8f5ebfa2cf..aff583d1fc 100644 --- a/web/src/lib/components/shared-components/context-menu/context-menu.svelte +++ b/web/src/lib/components/shared-components/context-menu/context-menu.svelte @@ -2,27 +2,44 @@ import { quintOut } from 'svelte/easing'; import { slide } from 'svelte/transition'; import { clickOutside } from '$lib/actions/click-outside'; + import type { Snippet } from 'svelte'; - export let isVisible: boolean = false; - export let direction: 'left' | 'right' = 'right'; - export let x = 0; - export let y = 0; - export let id: string | undefined = undefined; - export let ariaLabel: string | undefined = undefined; - export let ariaLabelledBy: string | undefined = undefined; - export let ariaActiveDescendant: string | undefined = undefined; + interface Props { + isVisible?: boolean; + direction?: 'left' | 'right'; + x?: number; + y?: number; + id?: string | undefined; + ariaLabel?: string | undefined; + ariaLabelledBy?: string | undefined; + ariaActiveDescendant?: string | undefined; + menuElement?: HTMLUListElement | undefined; + onClose?: (() => void) | undefined; + children?: Snippet; + } - export let menuElement: HTMLUListElement | undefined = undefined; - export let onClose: (() => void) | undefined = undefined; + let { + isVisible = false, + direction = 'right', + x = 0, + y = 0, + id = undefined, + ariaLabel = undefined, + ariaLabelledBy = undefined, + ariaActiveDescendant = undefined, + menuElement = $bindable(), + onClose = undefined, + children, + }: Props = $props(); - let left: number; - let top: number; + let left: number = $state(0); + let top: number = $state(0); // We need to bind clientHeight since the bounding box may return a height // of zero when starting the 'slide' animation. - let height: number; + let height: number = $state(0); - $: { + $effect(() => { if (menuElement) { const rect = menuElement.getBoundingClientRect(); const directionWidth = direction === 'left' ? rect.width : 0; @@ -31,7 +48,7 @@ left = Math.min(window.innerWidth - rect.width, x - directionWidth); top = Math.min(window.innerHeight - menuHeight, y); } - } + }); </script> <div @@ -54,6 +71,6 @@ role="menu" tabindex="-1" > - <slot /> + {@render children?.()} </ul> </div> diff --git a/web/src/lib/components/shared-components/context-menu/menu-option.svelte b/web/src/lib/components/shared-components/context-menu/menu-option.svelte index e7ff4c626e..5d3c29dc3c 100644 --- a/web/src/lib/components/shared-components/context-menu/menu-option.svelte +++ b/web/src/lib/components/shared-components/context-menu/menu-option.svelte @@ -3,16 +3,27 @@ import { generateId } from '$lib/utils/generate-id'; import { optionClickCallbackStore, selectedIdStore } from '$lib/stores/context-menu.store'; - export let text: string; - export let subtitle = ''; - export let icon = ''; - export let activeColor = 'bg-slate-300'; - export let textColor = 'text-immich-fg dark:text-immich-dark-bg'; - export let onClick: () => void; + interface Props { + text: string; + subtitle?: string; + icon?: string; + activeColor?: string; + textColor?: string; + onClick: () => void; + } + + let { + text, + subtitle = '', + icon = '', + activeColor = 'bg-slate-300', + textColor = 'text-immich-fg dark:text-immich-dark-bg', + onClick, + }: Props = $props(); let id: string = generateId(); - $: isActive = $selectedIdStore === id; + let isActive = $derived($selectedIdStore === id); const handleClick = () => { $optionClickCallbackStore?.(); @@ -20,13 +31,13 @@ }; </script> -<!-- svelte-ignore a11y-click-events-have-key-events --> -<!-- svelte-ignore a11y-mouse-events-have-key-events --> +<!-- svelte-ignore a11y_click_events_have_key_events --> +<!-- svelte-ignore a11y_mouse_events_have_key_events --> <li {id} - on:click={handleClick} - on:mouseover={() => ($selectedIdStore = id)} - on:mouseleave={() => ($selectedIdStore = undefined)} + onclick={handleClick} + onmouseover={() => ($selectedIdStore = id)} + onmouseleave={() => ($selectedIdStore = undefined)} class="w-full p-4 text-left text-sm font-medium {textColor} focus:outline-none focus:ring-2 focus:ring-inset cursor-pointer border-gray-200 flex gap-2 items-center {isActive ? activeColor : 'bg-slate-100'}" diff --git a/web/src/lib/components/shared-components/context-menu/right-click-context-menu.svelte b/web/src/lib/components/shared-components/context-menu/right-click-context-menu.svelte index f0b0408ff9..f0d8f0213a 100644 --- a/web/src/lib/components/shared-components/context-menu/right-click-context-menu.svelte +++ b/web/src/lib/components/shared-components/context-menu/right-click-context-menu.svelte @@ -1,33 +1,30 @@ <script lang="ts"> - import { tick } from 'svelte'; + import { tick, type Snippet } from 'svelte'; import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte'; import { shortcuts } from '$lib/actions/shortcut'; import { generateId } from '$lib/utils/generate-id'; import { contextMenuNavigation } from '$lib/actions/context-menu-navigation'; import { optionClickCallbackStore, selectedIdStore } from '$lib/stores/context-menu.store'; - export let title: string; - export let direction: 'left' | 'right' = 'right'; - export let x = 0; - export let y = 0; - export let isOpen = false; - export let onClose: (() => unknown) | undefined; + interface Props { + title: string; + direction?: 'left' | 'right'; + x?: number; + y?: number; + isOpen?: boolean; + onClose: (() => unknown) | undefined; + children?: Snippet; + } - let uniqueKey = {}; - let menuContainer: HTMLUListElement; - let triggerElement: HTMLElement | undefined = undefined; + let { title, direction = 'right', x = 0, y = 0, isOpen = false, onClose, children }: Props = $props(); + + let uniqueKey = $state({}); + let menuContainer: HTMLUListElement | undefined = $state(); + let triggerElement: HTMLElement | undefined = $state(undefined); const id = generateId(); const menuId = `context-menu-${id}`; - $: { - if (isOpen && menuContainer) { - triggerElement = document.activeElement as HTMLElement; - menuContainer.focus(); - $optionClickCallbackStore = closeContextMenu; - } - } - const reopenContextMenu = async (event: MouseEvent) => { const contextMenuEvent = new MouseEvent('contextmenu', { bubbles: true, @@ -39,7 +36,7 @@ const elements = document.elementsFromPoint(event.x, event.y); - if (elements.includes(menuContainer)) { + if (menuContainer && elements.includes(menuContainer)) { // User right-clicked on the context menu itself, we keep the context // menu as is return; @@ -58,6 +55,18 @@ triggerElement?.focus(); onClose?.(); }; + $effect(() => { + if (isOpen && menuContainer) { + triggerElement = document.activeElement as HTMLElement; + menuContainer.focus(); + $optionClickCallbackStore = closeContextMenu; + } + }); + + const oncontextmenu = async (event: MouseEvent) => { + event.preventDefault(); + await reopenContextMenu(event); + }; </script> {#key uniqueKey} @@ -81,11 +90,7 @@ }, ]} > - <section - class="fixed left-0 top-0 z-10 flex h-screen w-screen" - on:contextmenu|preventDefault={reopenContextMenu} - role="presentation" - > + <section class="fixed left-0 top-0 z-10 flex h-screen w-screen" {oncontextmenu} role="presentation"> <ContextMenu {direction} {x} @@ -97,7 +102,7 @@ isVisible onClose={closeContextMenu} > - <slot /> + {@render children?.()} </ContextMenu> </section> </div> 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 228cd88a86..c78edaa601 100644 --- a/web/src/lib/components/shared-components/control-app-bar.svelte +++ b/web/src/lib/components/shared-components/control-app-bar.svelte @@ -1,23 +1,39 @@ <script lang="ts"> import { browser } from '$app/environment'; - import { onDestroy, onMount } from 'svelte'; + import { onDestroy, onMount, type Snippet } from 'svelte'; import CircleIconButton from '../elements/buttons/circle-icon-button.svelte'; import { fly } from 'svelte/transition'; import { mdiClose } from '@mdi/js'; import { isSelectingAllAssets } from '$lib/stores/assets.store'; import { t } from 'svelte-i18n'; - export let showBackButton = true; - export let backIcon = mdiClose; - export let tailwindClasses = ''; - export let forceDark = false; - export let onClose: () => void = () => {}; + interface Props { + showBackButton?: boolean; + backIcon?: string; + tailwindClasses?: string; + forceDark?: boolean; + onClose?: () => void; + leading?: Snippet; + children?: Snippet; + trailing?: Snippet; + } - let appBarBorder = 'bg-immich-bg border border-transparent'; + let { + showBackButton = true, + backIcon = mdiClose, + tailwindClasses = '', + forceDark = false, + onClose = () => {}, + leading, + children, + trailing, + }: Props = $props(); + + let appBarBorder = $state('bg-immich-bg border border-transparent'); const onScroll = () => { - if (window.pageYOffset > 80) { + if (window.scrollY > 80) { appBarBorder = 'border border-gray-200 bg-gray-50 dark:border-gray-600'; if (forceDark) { @@ -45,7 +61,7 @@ } }); - $: buttonClass = forceDark ? 'hover:text-immich-dark-gray' : undefined; + let buttonClass = $derived(forceDark ? 'hover:text-immich-dark-gray' : undefined); </script> <div in:fly={{ y: 10, duration: 200 }} class="absolute top-0 w-full z-[100] bg-transparent"> @@ -57,17 +73,17 @@ > <div class="flex place-items-center sm:gap-6 justify-self-start dark:text-immich-dark-fg"> {#if showBackButton} - <CircleIconButton title={$t('close')} on:click={handleClose} icon={backIcon} size={'24'} class={buttonClass} /> + <CircleIconButton title={$t('close')} onclick={handleClose} icon={backIcon} size={'24'} class={buttonClass} /> {/if} - <slot name="leading" /> + {@render leading?.()} </div> <div class="w-full"> - <slot /> + {@render children?.()} </div> <div class="mr-4 flex place-items-center gap-1 justify-self-end"> - <slot name="trailing" /> + {@render trailing?.()} </div> </div> </div> diff --git a/web/src/lib/components/shared-components/coordinates-input.svelte b/web/src/lib/components/shared-components/coordinates-input.svelte index f5ad120a7b..d39cea2fd1 100644 --- a/web/src/lib/components/shared-components/coordinates-input.svelte +++ b/web/src/lib/components/shared-components/coordinates-input.svelte @@ -3,9 +3,13 @@ import { generateId } from '$lib/utils/generate-id'; import { t } from 'svelte-i18n'; - export let lat: number | null | undefined = undefined; - export let lng: number | null | undefined = undefined; - export let onUpdate: (lat: number, lng: number) => void; + interface Props { + lat?: number; + lng?: number; + onUpdate: (lat: number, lng: number) => void; + } + + let { lat = $bindable(), lng = $bindable(), onUpdate }: Props = $props(); const id = generateId(); diff --git a/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte b/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte index ea5f801e29..443e8f06b1 100644 --- a/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte +++ b/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte @@ -8,29 +8,40 @@ import { SharedLinkType, createSharedLink, updateSharedLink, type SharedLinkResponseDto } from '@immich/sdk'; import { mdiContentCopy, mdiLink } from '@mdi/js'; import { NotificationType, notificationController } from '../notification/notification'; - import SettingInputField, { SettingInputFieldType } from '../settings/setting-input-field.svelte'; + import SettingInputField from '../settings/setting-input-field.svelte'; import SettingSwitch from '../settings/setting-switch.svelte'; import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte'; import { t } from 'svelte-i18n'; import { locale } from '$lib/stores/preferences.store'; import { DateTime, Duration } from 'luxon'; import SettingSelect from '$lib/components/shared-components/settings/setting-select.svelte'; + import { SettingInputFieldType } from '$lib/constants'; - export let onClose: () => void; - export let albumId: string | undefined = undefined; - export let assetIds: string[] = []; - export let editingLink: SharedLinkResponseDto | undefined = undefined; - export let onCreated: () => void = () => {}; + interface Props { + onClose: () => void; + albumId?: string | undefined; + assetIds?: string[]; + editingLink?: SharedLinkResponseDto | undefined; + onCreated?: () => void; + } - let sharedLink: string | null = null; - let description = ''; - let allowDownload = true; - let allowUpload = false; - let showMetadata = true; - let expirationOption: number = 0; - let password = ''; - let shouldChangeExpirationTime = false; - let enablePassword = false; + let { + onClose, + albumId = $bindable(undefined), + assetIds = $bindable([]), + editingLink = undefined, + onCreated = () => {}, + }: Props = $props(); + + let sharedLink: string | null = $state(null); + let description = $state(''); + let allowDownload = $state(true); + let allowUpload = $state(false); + let showMetadata = $state(true); + let expirationOption: number = $state(0); + let password = $state(''); + let shouldChangeExpirationTime = $state(false); + let enablePassword = $state(false); const expirationOptions: [number, Intl.RelativeTimeFormatUnit][] = [ [30, 'minutes'], @@ -43,22 +54,23 @@ [1, 'year'], ]; - $: relativeTime = new Intl.RelativeTimeFormat($locale); - $: expiredDateOptions = [ + let relativeTime = $derived(new Intl.RelativeTimeFormat($locale)); + let expiredDateOptions = $derived([ { text: $t('never'), value: 0 }, ...expirationOptions.map(([value, unit]) => ({ text: relativeTime.format(value, unit), value: Duration.fromObject({ [unit]: value }).toMillis(), })), - ]; + ]); - // svelte-ignore reactive_declaration_non_reactive_property - $: shareType = albumId ? SharedLinkType.Album : SharedLinkType.Individual; - $: { + let shareType = $derived(albumId ? SharedLinkType.Album : SharedLinkType.Individual); + + $effect(() => { if (!showMetadata) { allowDownload = false; } - } + }); + if (editingLink) { if (editingLink.description) { description = editingLink.description; @@ -223,22 +235,22 @@ </div> </section> - <svelte:fragment slot="sticky-bottom"> + {#snippet stickyBottom()} {#if !sharedLink} {#if editingLink} - <Button size="sm" fullwidth on:click={handleEditLink}>{$t('confirm')}</Button> + <Button size="sm" fullwidth onclick={handleEditLink}>{$t('confirm')}</Button> {:else} - <Button size="sm" fullwidth on:click={handleCreateSharedLink}>{$t('create_link')}</Button> + <Button size="sm" fullwidth onclick={handleCreateSharedLink}>{$t('create_link')}</Button> {/if} {:else} <div class="flex w-full gap-2"> <input class="immich-form-input w-full" bind:value={sharedLink} disabled /> - <LinkButton on:click={() => (sharedLink ? copyToClipboard(sharedLink) : '')}> + <LinkButton onclick={() => (sharedLink ? copyToClipboard(sharedLink) : '')}> <div class="flex place-items-center gap-2 text-sm"> <Icon path={mdiContentCopy} ariaLabel={$t('copy_link_to_clipboard')} size="18" /> </div> </LinkButton> </div> {/if} - </svelte:fragment> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/shared-components/dialog/confirm-dialog.svelte b/web/src/lib/components/shared-components/dialog/confirm-dialog.svelte index 50d5fe56ce..3efc56dc41 100644 --- a/web/src/lib/components/shared-components/dialog/confirm-dialog.svelte +++ b/web/src/lib/components/shared-components/dialog/confirm-dialog.svelte @@ -3,18 +3,37 @@ import Button from '../../elements/buttons/button.svelte'; import type { Color } from '$lib/components/elements/buttons/button.svelte'; import { t } from 'svelte-i18n'; + import type { Snippet } from 'svelte'; - export let title = $t('confirm'); - export let prompt = $t('are_you_sure_to_do_this'); - export let confirmText = $t('confirm'); - export let confirmColor: Color = 'red'; - export let cancelText = $t('cancel'); - export let cancelColor: Color = 'secondary'; - export let hideCancelButton = false; - export let disabled = false; - export let width: 'wide' | 'narrow' = 'narrow'; - export let onCancel: () => void; - export let onConfirm: () => void; + interface Props { + title?: string; + prompt?: string; + confirmText?: string; + confirmColor?: Color; + cancelText?: string; + cancelColor?: Color; + hideCancelButton?: boolean; + disabled?: boolean; + width?: 'wide' | 'narrow'; + onCancel: () => void; + onConfirm: () => void; + promptSnippet?: Snippet; + } + + let { + title = $t('confirm'), + prompt = $t('are_you_sure_to_do_this'), + confirmText = $t('confirm'), + confirmColor = 'red', + cancelText = $t('cancel'), + cancelColor = 'secondary', + hideCancelButton = false, + disabled = false, + width = 'narrow', + onCancel, + onConfirm, + promptSnippet, + }: Props = $props(); const handleConfirm = () => { onConfirm(); @@ -23,19 +42,19 @@ <FullScreenModal {title} onClose={onCancel} {width}> <div class="text-md py-5 text-center"> - <slot name="prompt"> + {#if promptSnippet}{@render promptSnippet()}{:else} <p>{prompt}</p> - </slot> + {/if} </div> - <svelte:fragment slot="sticky-bottom"> + {#snippet stickyBottom()} {#if !hideCancelButton} - <Button color={cancelColor} fullwidth on:click={onCancel}> + <Button color={cancelColor} fullwidth onclick={onCancel}> {cancelText} </Button> {/if} - <Button color={confirmColor} fullwidth on:click={handleConfirm} {disabled}> + <Button color={confirmColor} fullwidth onclick={handleConfirm} {disabled}> {confirmText} </Button> - </svelte:fragment> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte b/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte index 6f92d81886..620064ca1e 100644 --- a/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte +++ b/web/src/lib/components/shared-components/drag-and-drop-upload-overlay.svelte @@ -8,10 +8,10 @@ import { fade } from 'svelte/transition'; import ImmichLogo from './immich-logo.svelte'; - $: albumId = isAlbumsRoute($page.route?.id) ? $page.params.albumId : undefined; - $: isShare = isSharedLinkRoute($page.route?.id); + let albumId = $derived(isAlbumsRoute($page.route?.id) ? $page.params.albumId : undefined); + let isShare = $derived(isSharedLinkRoute($page.route?.id)); - let dragStartTarget: EventTarget | null = null; + let dragStartTarget: EventTarget | null = $state(null); const onDragEnter = (e: DragEvent) => { if (e.dataTransfer && e.dataTransfer.types.includes('Files')) { @@ -117,26 +117,41 @@ await fileUploadHandler(filesArray, albumId); } }; + + const ondragenter = (e: DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + onDragEnter(e); + }; + + const ondragleave = (e: DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + onDragLeave(e); + }; + + const ondrop = async (e: DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + await onDrop(e); + }; + + const onDragOver = (e: DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + }; </script> -<svelte:window on:paste={onPaste} /> +<svelte:window onpaste={onPaste} /> -<svelte:body - on:dragenter|stopPropagation|preventDefault={onDragEnter} - on:dragleave|stopPropagation|preventDefault={onDragLeave} - on:drop|stopPropagation|preventDefault={onDrop} -/> +<svelte:body {ondragenter} {ondragleave} {ondrop} /> {#if dragStartTarget} - <!-- svelte-ignore a11y-no-static-element-interactions --> + <!-- svelte-ignore a11y_no_static_element_interactions --> <div class="fixed inset-0 z-[1000] flex h-full w-full flex-col items-center justify-center bg-gray-100/90 text-immich-dark-gray dark:bg-immich-dark-bg/90 dark:text-immich-gray" transition:fade={{ duration: 250 }} - on:dragover={(e) => { - // Prevent browser from opening the dropped file. - e.stopPropagation(); - e.preventDefault(); - }} + ondragover={onDragOver} > <ImmichLogo noText class="m-16 w-48 animate-bounce" /> <div class="text-2xl">{$t('drop_files_to_upload')}</div> diff --git a/web/src/lib/components/shared-components/empty-placeholder.svelte b/web/src/lib/components/shared-components/empty-placeholder.svelte index 781f7821f1..922d7ad92f 100644 --- a/web/src/lib/components/shared-components/empty-placeholder.svelte +++ b/web/src/lib/components/shared-components/empty-placeholder.svelte @@ -1,22 +1,26 @@ <script lang="ts"> import empty1Url from '$lib/assets/empty-1.svg'; - export let onClick: undefined | (() => unknown) = undefined; - export let text: string; - export let fullWidth = false; - export let src = empty1Url; + interface Props { + onClick?: undefined | (() => unknown); + text: string; + fullWidth?: boolean; + src?: string; + } - $: width = fullWidth ? 'w-full' : 'w-1/2'; + let { onClick = undefined, text, fullWidth = false, src = empty1Url }: Props = $props(); + + let width = $derived(fullWidth ? 'w-full' : 'w-1/2'); const hoverClasses = onClick ? `border dark:border-immich-dark-gray hover:bg-immich-primary/5 dark:hover:bg-immich-dark-primary/25` : ''; </script> -<!-- svelte-ignore a11y-no-static-element-interactions --> +<!-- svelte-ignore a11y_no_static_element_interactions --> <svelte:element this={onClick ? 'button' : 'div'} - on:click={onClick} + onclick={onClick} class="{width} m-auto mt-10 flex flex-col place-content-center place-items-center rounded-3xl bg-gray-50 p-5 dark:bg-immich-dark-gray {hoverClasses}" > <img {src} alt="" width="500" draggable="false" /> diff --git a/web/src/lib/components/shared-components/full-screen-modal.svelte b/web/src/lib/components/shared-components/full-screen-modal.svelte index ab85155276..1263aed03b 100644 --- a/web/src/lib/components/shared-components/full-screen-modal.svelte +++ b/web/src/lib/components/shared-components/full-screen-modal.svelte @@ -4,36 +4,52 @@ import { fade } from 'svelte/transition'; import ModalHeader from '$lib/components/shared-components/modal-header.svelte'; import { generateId } from '$lib/utils/generate-id'; + import type { Snippet } from 'svelte'; - export let onClose: () => void; - export let title: string; - /** - * If true, the logo will be displayed next to the modal title. - */ - export let showLogo = false; - /** - * Optional icon to display next to the modal title, if `showLogo` is false. - */ - export let icon: string | undefined = undefined; - /** - * Sets the width of the modal. - * - * - `wide`: 48rem - * - `narrow`: 28rem - * - `auto`: fits the width of the modal content, up to a maximum of 32rem - */ - export let width: 'extra-wide' | 'wide' | 'narrow' | 'auto' = 'narrow'; + interface Props { + onClose: () => void; + title: string; + /** + * If true, the logo will be displayed next to the modal title. + */ + showLogo?: boolean; + /** + * Optional icon to display next to the modal title, if `showLogo` is false. + */ + icon?: string | undefined; + /** + * Sets the width of the modal. + * + * - `wide`: 48rem + * - `narrow`: 28rem + * - `auto`: fits the width of the modal content, up to a maximum of 32rem + */ + width?: 'extra-wide' | 'wide' | 'narrow' | 'auto'; + stickyBottom?: Snippet; + children?: Snippet; + } + + let { + onClose, + title, + showLogo = false, + icon = undefined, + width = 'narrow', + stickyBottom, + children, + }: Props = $props(); /** * Unique identifier for the modal. */ let id: string = generateId(); - $: titleId = `${id}-title`; - $: isStickyBottom = !!$$slots['sticky-bottom']; + let titleId = $derived(`${id}-title`); + let isStickyBottom = $derived(!!stickyBottom); - let modalWidth: string; - $: { + let modalWidth = $state<string>(); + + $effect(() => { switch (width) { case 'extra-wide': { modalWidth = 'w-[56rem]'; @@ -54,7 +70,7 @@ modalWidth = 'sm:max-w-4xl'; } } - } + }); </script> <section @@ -62,7 +78,7 @@ in:fade={{ duration: 100 }} out:fade={{ duration: 100 }} class="fixed left-0 top-0 z-[9999] flex h-dvh w-screen place-content-center place-items-center bg-black/40" - on:keydown={(event) => { + onkeydown={(event) => { event.stopPropagation(); }} use:focusTrap @@ -77,14 +93,14 @@ <div class="immich-scrollbar overflow-y-auto pt-1" class:pb-4={isStickyBottom}> <ModalHeader id={titleId} {title} {showLogo} {icon} {onClose} /> <div class="px-5 pt-0 mb-5"> - <slot /> + {@render children?.()} </div> </div> {#if isStickyBottom} <div class="flex flex-col sm:flex-row justify-end w-full gap-2 sm:gap-4 sticky pt-4 px-5 bg-immich-bg dark:bg-immich-dark-gray border-t border-gray-200 dark:border-gray-500" > - <slot name="sticky-bottom" /> + {@render stickyBottom?.()} </div> {/if} </div> diff --git a/web/src/lib/components/shared-components/fullscreen-container.svelte b/web/src/lib/components/shared-components/fullscreen-container.svelte index 6d577f60bd..64ee41a225 100644 --- a/web/src/lib/components/shared-components/fullscreen-container.svelte +++ b/web/src/lib/components/shared-components/fullscreen-container.svelte @@ -1,8 +1,15 @@ <script lang="ts"> + import type { Snippet } from 'svelte'; import ImmichLogo from './immich-logo.svelte'; - export let title: string; - export let showMessage = $$slots.message; + interface Props { + title: string; + message?: Snippet; + showMessage?: boolean; + children?: Snippet; + } + + let { title, message, showMessage = message != undefined, children }: Props = $props(); </script> <section class="min-w-screen flex min-h-screen place-content-center place-items-center p-4"> @@ -20,10 +27,10 @@ <div class="w-full rounded-xl border-2 border-immich-primary bg-immich-primary/5 p-4 text-sm font-medium text-immich-primary dark:border-immich-dark-bg dark:text-immich-dark-primary" > - <slot name="message" /> + {@render message?.()} </div> {/if} - <slot /> + {@render children?.()} </div> </section> diff --git a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte index b595a6bb62..aa84bd69f0 100644 --- a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte +++ b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte @@ -17,20 +17,34 @@ import Portal from '../portal/portal.svelte'; import { handlePromiseError } from '$lib/utils'; - export let assets: AssetResponseDto[]; - export let selectedAssets: Set<AssetResponseDto> = new Set(); - export let disableAssetSelect = false; - export let showArchiveIcon = false; - export let viewport: Viewport; - export let onIntersected: (() => void) | undefined = undefined; - export let showAssetName = false; - export let onPrevious: (() => Promise<AssetResponseDto | undefined>) | undefined = undefined; - export let onNext: (() => Promise<AssetResponseDto | undefined>) | undefined = undefined; + interface Props { + assets: AssetResponseDto[]; + selectedAssets?: Set<AssetResponseDto>; + disableAssetSelect?: boolean; + showArchiveIcon?: boolean; + viewport: Viewport; + onIntersected?: (() => void) | undefined; + showAssetName?: boolean; + onPrevious?: (() => Promise<AssetResponseDto | undefined>) | undefined; + onNext?: (() => Promise<AssetResponseDto | undefined>) | undefined; + } + + let { + assets = $bindable(), + selectedAssets = $bindable(new Set()), + disableAssetSelect = false, + showArchiveIcon = false, + viewport, + onIntersected = undefined, + showAssetName = false, + onPrevious = undefined, + onNext = undefined, + }: Props = $props(); let { isViewing: isViewerOpen, asset: viewingAsset, setAsset } = assetViewingStore; let currentViewAssetIndex = 0; - $: isMultiSelectionMode = selectedAssets.size > 0; + let isMultiSelectionMode = $derived(selectedAssets.size > 0); const viewAssetHandler = async (asset: AssetResponseDto) => { currentViewAssetIndex = assets.findIndex((a) => a.id == asset.id); @@ -100,23 +114,25 @@ $isViewerOpen = false; }); - $: geometry = (() => { - const justifiedLayoutResult = justifiedLayout( - assets.map((asset) => getAssetRatio(asset)), - { - boxSpacing: 2, - containerWidth: Math.floor(viewport.width), - containerPadding: 0, - targetRowHeightTolerance: 0.15, - targetRowHeight: 235, - }, - ); + let geometry = $derived( + (() => { + const justifiedLayoutResult = justifiedLayout( + assets.map((asset) => getAssetRatio(asset)), + { + boxSpacing: 2, + containerWidth: Math.floor(viewport.width), + containerPadding: 0, + targetRowHeightTolerance: 0.15, + targetRowHeight: 235, + }, + ); - return { - ...justifiedLayoutResult, - containerWidth: calculateWidth(justifiedLayoutResult.boxes), - }; - })(); + return { + ...justifiedLayoutResult, + containerWidth: calculateWidth(justifiedLayoutResult.boxes), + }; + })(), + ); </script> {#if assets.length > 0} diff --git a/web/src/lib/components/shared-components/help-and-feedback-modal.svelte b/web/src/lib/components/shared-components/help-and-feedback-modal.svelte index 19e12a51f9..c122e0f23e 100644 --- a/web/src/lib/components/shared-components/help-and-feedback-modal.svelte +++ b/web/src/lib/components/shared-components/help-and-feedback-modal.svelte @@ -7,9 +7,12 @@ import { mdiBugOutline, mdiFaceAgent, mdiGit, mdiGithub, mdiInformationOutline } from '@mdi/js'; import { discordPath } from '$lib/assets/svg-paths'; - export let onClose: () => void; + interface Props { + onClose: () => void; + info: ServerAboutResponseDto; + } - export let info: ServerAboutResponseDto; + let { onClose, info }: Props = $props(); </script> <Portal> diff --git a/web/src/lib/components/shared-components/immich-logo-small-link.svelte b/web/src/lib/components/shared-components/immich-logo-small-link.svelte index 9f1dd9714e..cd3149e6de 100644 --- a/web/src/lib/components/shared-components/immich-logo-small-link.svelte +++ b/web/src/lib/components/shared-components/immich-logo-small-link.svelte @@ -1,7 +1,11 @@ <script lang="ts"> import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte'; - export let width: number; + interface Props { + width: number; + } + + let { width }: Props = $props(); </script> <a data-sveltekit-preload-data="hover" class="ml-4" href="/"> diff --git a/web/src/lib/components/shared-components/immich-logo.svelte b/web/src/lib/components/shared-components/immich-logo.svelte index 952960ef3f..7046ea689e 100644 --- a/web/src/lib/components/shared-components/immich-logo.svelte +++ b/web/src/lib/components/shared-components/immich-logo.svelte @@ -9,14 +9,12 @@ import type { HTMLImgAttributes } from 'svelte/elements'; import { t } from 'svelte-i18n'; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface $$Props extends HTMLImgAttributes { + interface Props extends HTMLImgAttributes { noText?: boolean; draggable?: boolean; } - export let noText = false; - export let draggable = false; + let { noText = false, draggable = false, ...rest }: Props = $props(); const today = DateTime.now().toLocal(); </script> @@ -28,6 +26,6 @@ src={noText ? logoNoText : $colorTheme.value == Theme.LIGHT ? logoLightUrl : logoDarkUrl} alt={$t('immich_logo')} {draggable} - {...$$restProps} + {...rest} /> {/if} diff --git a/web/src/lib/components/shared-components/loading-spinner.svelte b/web/src/lib/components/shared-components/loading-spinner.svelte index 48626a50f4..e81d2225b7 100644 --- a/web/src/lib/components/shared-components/loading-spinner.svelte +++ b/web/src/lib/components/shared-components/loading-spinner.svelte @@ -1,5 +1,9 @@ <script lang="ts"> - export let size: string = '24'; + interface Props { + size?: string; + } + + let { size = '24' }: Props = $props(); </script> <div> diff --git a/web/src/lib/components/shared-components/map/map.svelte b/web/src/lib/components/shared-components/map/map.svelte index 85d927d166..7644064d9d 100644 --- a/web/src/lib/components/shared-components/map/map.svelte +++ b/web/src/lib/components/shared-components/map/map.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> void maplibregl.setRTLTextPlugin(mapboxRtlUrl, true); </script> @@ -6,12 +6,13 @@ import Icon from '$lib/components/elements/icon.svelte'; import { Theme } from '$lib/constants'; import { colorTheme, mapSettings } from '$lib/stores/preferences.store'; + import { serverConfig } from '$lib/stores/server-config.store'; import { getAssetThumbnailUrl, handlePromiseError } from '$lib/utils'; - import { getServerConfig, type MapMarkerResponseDto } from '@immich/sdk'; + import { type MapMarkerResponseDto } from '@immich/sdk'; import mapboxRtlUrl from '@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js?url'; import { mdiCog, mdiMap, mdiMapMarker } from '@mdi/js'; import type { Feature, GeoJsonProperties, Geometry, Point } from 'geojson'; - import type { GeoJSONSource, LngLatLike, StyleSpecification } from 'maplibre-gl'; + import type { GeoJSONSource, LngLatLike } from 'maplibre-gl'; import maplibregl from 'maplibre-gl'; import { t } from 'svelte-i18n'; import { @@ -30,14 +31,43 @@ type Map, } from 'svelte-maplibre'; - export let mapMarkers: MapMarkerResponseDto[]; - export let showSettingsModal: boolean | undefined = undefined; - export let zoom: number | undefined = undefined; - export let center: LngLatLike | undefined = undefined; - export let hash = false; - export let simplified = false; - export let clickable = false; - export let useLocationPin = false; + interface Props { + mapMarkers: MapMarkerResponseDto[]; + showSettingsModal?: boolean | undefined; + zoom?: number | undefined; + center?: LngLatLike | undefined; + hash?: boolean; + simplified?: boolean; + clickable?: boolean; + useLocationPin?: boolean; + onOpenInMapView?: (() => Promise<void> | void) | undefined; + onSelect?: (assetIds: string[]) => void; + onClickPoint?: ({ lat, lng }: { lat: number; lng: number }) => void; + popup?: import('svelte').Snippet<[{ marker: MapMarkerResponseDto }]>; + } + + let { + mapMarkers = $bindable(), + showSettingsModal = $bindable(undefined), + zoom = undefined, + center = $bindable(undefined), + hash = false, + simplified = false, + clickable = false, + useLocationPin = false, + onOpenInMapView = undefined, + onSelect = () => {}, + onClickPoint = () => {}, + popup, + }: Props = $props(); + + let map: maplibregl.Map | undefined = $state(); + let marker: maplibregl.Marker | null = null; + + const theme = $derived($mapSettings.allowDarkMode ? $colorTheme.value : Theme.LIGHT); + const styleUrl = $derived(theme === Theme.DARK ? $serverConfig.mapDarkStyleUrl : $serverConfig.mapLightStyleUrl); + const style = $derived(fetch(styleUrl).then((response) => response.json())); + export function addClipMapMarker(lng: number, lat: number) { if (map) { if (marker) { @@ -46,26 +76,9 @@ center = { lng, lat }; marker = new maplibregl.Marker().setLngLat([lng, lat]).addTo(map); - map.setZoom(15); } } - export let onOpenInMapView: (() => Promise<void> | void) | undefined = undefined; - export let onSelect: (assetIds: string[]) => void = () => {}; - export let onClickPoint: ({ lat, lng }: { lat: number; lng: number }) => void = () => {}; - - let map: maplibregl.Map; - let marker: maplibregl.Marker | null = null; - - // svelte-ignore reactive_declaration_non_reactive_property - $: style = (async () => { - const config = await getServerConfig(); - const theme = $mapSettings.allowDarkMode ? $colorTheme.value : Theme.LIGHT; - const styleUrl = theme === Theme.DARK ? config.mapDarkStyleUrl : config.mapLightStyleUrl; - const style = await fetch(styleUrl).then((response) => response.json()); - return style as StyleSpecification; - })(); - function handleAssetClick(assetId: string, map: Map | null) { if (!map) { return; @@ -93,7 +106,9 @@ marker.remove(); } - marker = new maplibregl.Marker().setLngLat([lng, lat]).addTo(map); + if (map) { + marker = new maplibregl.Marker().setLngLat([lng, lat]).addTo(map); + } } } @@ -135,92 +150,96 @@ {zoom} attributionControl={false} diffStyleUpdates={true} - let:map on:load={(event) => event.detail.setMaxZoom(18)} on:load={(event) => event.detail.on('click', handleMapClick)} bind:map > - <NavigationControl position="top-left" showCompass={!simplified} /> + {#snippet children({ map }: { map: maplibregl.Map })} + <NavigationControl position="top-left" showCompass={!simplified} /> - {#if !simplified} - <GeolocateControl position="top-left" /> - <FullscreenControl position="top-left" /> - <ScaleControl /> - <AttributionControl compact={false} /> - {/if} + {#if !simplified} + <GeolocateControl position="top-left" /> + <FullscreenControl position="top-left" /> + <ScaleControl /> + <AttributionControl compact={false} /> + {/if} - {#if showSettingsModal !== undefined} - <Control> - <ControlGroup> - <ControlButton on:click={() => (showSettingsModal = true)}><Icon path={mdiCog} size="100%" /></ControlButton> - </ControlGroup> - </Control> - {/if} + {#if showSettingsModal !== undefined} + <Control> + <ControlGroup> + <ControlButton on:click={() => (showSettingsModal = true)}><Icon path={mdiCog} size="100%" /></ControlButton + > + </ControlGroup> + </Control> + {/if} - {#if onOpenInMapView} - <Control position="top-right"> - <ControlGroup> - <ControlButton on:click={() => onOpenInMapView()}> - <Icon title={$t('open_in_map_view')} path={mdiMap} size="100%" /> - </ControlButton> - </ControlGroup> - </Control> - {/if} + {#if onOpenInMapView} + <Control position="top-right"> + <ControlGroup> + <ControlButton on:click={() => onOpenInMapView()}> + <Icon title={$t('open_in_map_view')} path={mdiMap} size="100%" /> + </ControlButton> + </ControlGroup> + </Control> + {/if} - <GeoJSON - data={{ - type: 'FeatureCollection', - features: mapMarkers.map((marker) => asFeature(marker)), - }} - id="geojson" - cluster={{ radius: 500, maxZoom: 24 }} - > - <MarkerLayer - applyToClusters - asButton - let:feature - on:click={(event) => handlePromiseError(handleClusterClick(event.detail.feature.properties?.cluster_id, map))} - > - <div - class="rounded-full w-[40px] h-[40px] bg-immich-primary text-immich-gray flex justify-center items-center font-mono font-bold shadow-lg hover:bg-immich-dark-primary transition-all duration-200 hover:text-immich-dark-bg opacity-90" - > - {feature.properties?.point_count} - </div> - </MarkerLayer> - <MarkerLayer - applyToClusters={false} - asButton - let:feature - on:click={(event) => { - if (!$$slots.popup) { - handleAssetClick(event.detail.feature.properties?.id, map); - } + <GeoJSON + data={{ + type: 'FeatureCollection', + features: mapMarkers.map((marker) => asFeature(marker)), }} + id="geojson" + cluster={{ radius: 500, maxZoom: 24 }} > - {#if useLocationPin} - <Icon - path={mdiMapMarker} - size="50px" - class="location-pin dark:text-immich-dark-primary text-immich-primary" - /> - {:else} - <img - src={getAssetThumbnailUrl(feature.properties?.id)} - class="rounded-full w-[60px] h-[60px] border-2 border-immich-primary shadow-lg hover:border-immich-dark-primary transition-all duration-200 hover:scale-150 object-cover bg-immich-primary" - alt={feature.properties?.city && feature.properties.country - ? $t('map_marker_for_images', { - values: { city: feature.properties.city, country: feature.properties.country }, - }) - : $t('map_marker_with_image')} - /> - {/if} - {#if $$slots.popup} - <Popup offset={[0, -30]} openOn="click" closeOnClickOutside> - <slot name="popup" marker={asMarker(feature)} /> - </Popup> - {/if} - </MarkerLayer> - </GeoJSON> + <MarkerLayer + applyToClusters + asButton + on:click={(event) => handlePromiseError(handleClusterClick(event.detail.feature.properties?.cluster_id, map))} + > + {#snippet children({ feature }: { feature: maplibregl.Feature })} + <div + class="rounded-full w-[40px] h-[40px] bg-immich-primary text-immich-gray flex justify-center items-center font-mono font-bold shadow-lg hover:bg-immich-dark-primary transition-all duration-200 hover:text-immich-dark-bg opacity-90" + > + {feature.properties?.point_count} + </div> + {/snippet} + </MarkerLayer> + <MarkerLayer + applyToClusters={false} + asButton + on:click={(event) => { + if (!popup) { + handleAssetClick(event.detail.feature.properties?.id, map); + } + }} + > + {#snippet children({ feature }: { feature: Feature<Geometry, GeoJsonProperties> })} + {#if useLocationPin} + <Icon + path={mdiMapMarker} + size="50px" + class="location-pin dark:text-immich-dark-primary text-immich-primary" + /> + {:else} + <img + src={getAssetThumbnailUrl(feature.properties?.id)} + class="rounded-full w-[60px] h-[60px] border-2 border-immich-primary shadow-lg hover:border-immich-dark-primary transition-all duration-200 hover:scale-150 object-cover bg-immich-primary" + alt={feature.properties?.city && feature.properties.country + ? $t('map_marker_for_images', { + values: { city: feature.properties.city, country: feature.properties.country }, + }) + : $t('map_marker_with_image')} + /> + {/if} + {#if popup} + <Popup offset={[0, -30]} openOn="click" closeOnClickOutside> + {@render popup?.({ marker: asMarker(feature) })} + </Popup> + {/if} + {/snippet} + </MarkerLayer> + </GeoJSON> + {/snippet} </MapLibre> <style> .location-pin { diff --git a/web/src/lib/components/shared-components/modal-header.svelte b/web/src/lib/components/shared-components/modal-header.svelte index efd87b476c..53f3fbdabb 100644 --- a/web/src/lib/components/shared-components/modal-header.svelte +++ b/web/src/lib/components/shared-components/modal-header.svelte @@ -5,20 +5,24 @@ import { mdiClose } from '@mdi/js'; import { t } from 'svelte-i18n'; - /** - * Unique identifier for the header text. - */ - export let id: string; - export let title: string; - export let onClose: () => void; - /** - * If true, the logo will be displayed next to the modal title. - */ - export let showLogo = false; - /** - * Optional icon to display next to the modal title, if `showLogo` is false. - */ - export let icon: string | undefined = undefined; + interface Props { + /** + * Unique identifier for the header text. + */ + id: string; + title: string; + onClose: () => void; + /** + * If true, the logo will be displayed next to the modal title. + */ + showLogo?: boolean; + /** + * Optional icon to display next to the modal title, if `showLogo` is false. + */ + icon?: string; + } + + let { id, title, onClose, showLogo = false, icon = undefined }: Props = $props(); </script> <div class="flex place-items-center justify-between px-5 pb-3"> @@ -33,5 +37,5 @@ </h1> </div> - <CircleIconButton on:click={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/account-info-panel.svelte b/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte index bf0ca26d61..478b43b190 100644 --- a/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte +++ b/web/src/lib/components/shared-components/navigation-bar/account-info-panel.svelte @@ -15,10 +15,14 @@ import UserAvatar from '../user-avatar.svelte'; import AvatarSelector from './avatar-selector.svelte'; - export let onLogout: () => void; - export let onClose: () => void = () => {}; + interface Props { + onLogout: () => void; + onClose?: () => void; + } - let isShowSelectAvatar = false; + let { onLogout, onClose = () => {} }: Props = $props(); + + let isShowSelectAvatar = $state(false); const handleSaveProfile = async (color: UserAvatarColor) => { try { @@ -60,7 +64,7 @@ class="border" size="12" padding="2" - on:click={() => (isShowSelectAvatar = true)} + onclick={() => (isShowSelectAvatar = true)} /> </div> </div> @@ -72,7 +76,7 @@ </div> <div class="flex flex-col gap-1"> - <Button href={AppRoute.USER_SETTINGS} on:click={onClose} color="dark-gray" size="sm" shadow={false} border> + <Button href={AppRoute.USER_SETTINGS} onclick={onClose} color="dark-gray" size="sm" shadow={false} border> <div class="flex place-content-center place-items-center text-center gap-2 px-2"> <Icon path={mdiCog} size="18" ariaHidden /> {$t('account_settings')} @@ -81,7 +85,7 @@ {#if $user.isAdmin} <Button href={AppRoute.ADMIN_USER_MANAGEMENT} - on:click={onClose} + onclick={onClose} color="dark-gray" size="sm" shadow={false} @@ -101,7 +105,7 @@ <button type="button" class="flex w-full place-content-center place-items-center gap-2 py-3 font-medium text-gray-500 hover:bg-immich-primary/10 dark:text-gray-300" - on:click={onLogout} + onclick={onLogout} > <Icon path={mdiLogout} size={24} /> {$t('sign_out')}</button 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 77a6e3a2d0..d762c7ba88 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 @@ -4,9 +4,13 @@ import FullScreenModal from '../full-screen-modal.svelte'; import UserAvatar from '../user-avatar.svelte'; - export let user: UserResponseDto; - export let onClose: () => void; - export let onChoose: (color: UserAvatarColor) => void; + interface Props { + user: UserResponseDto; + onClose: () => void; + onChoose: (color: UserAvatarColor) => void; + } + + let { user, onClose, onChoose }: Props = $props(); const colors: UserAvatarColor[] = Object.values(UserAvatarColor); </script> @@ -15,7 +19,7 @@ <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} - <button type="button" on:click={() => onChoose(color)}> + <button type="button" onclick={() => onChoose(color)}> <UserAvatar label={color} {user} {color} size="xl" showProfileImage={false} /> </button> {/each} diff --git a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte index 2f8d0e2574..1bbf34316c 100644 --- a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte +++ b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte @@ -21,20 +21,24 @@ import HelpAndFeedbackModal from '$lib/components/shared-components/help-and-feedback-modal.svelte'; import { onMount } from 'svelte'; - export let showUploadButton = true; - export let onUploadClick: () => void; + interface Props { + showUploadButton?: boolean; + onUploadClick: () => void; + } - let shouldShowAccountInfo = false; - let shouldShowAccountInfoPanel = false; - let shouldShowHelpPanel = false; - let innerWidth: number; + let { showUploadButton = true, onUploadClick }: Props = $props(); + + let shouldShowAccountInfo = $state(false); + let shouldShowAccountInfoPanel = $state(false); + let shouldShowHelpPanel = $state(false); + let innerWidth: number = $state(0); const onLogout = async () => { const { redirectUri } = await logout(); await handleLogout(redirectUri); }; - let aboutInfo: ServerAboutResponseDto; + let aboutInfo: ServerAboutResponseDto | undefined = $state(); onMount(async () => { aboutInfo = await getAboutInfo(); @@ -43,7 +47,7 @@ <svelte:window bind:innerWidth /> -{#if shouldShowHelpPanel} +{#if shouldShowHelpPanel && aboutInfo} <HelpAndFeedbackModal onClose={() => (shouldShowHelpPanel = false)} info={aboutInfo} /> {/if} @@ -71,6 +75,7 @@ title={$t('go_to_search')} icon={mdiMagnify} padding="2" + onclick={() => {}} /> {/if} @@ -85,20 +90,20 @@ id="support-feedback-button" title={$t('support_and_feedback')} icon={mdiHelpCircleOutline} - on:click={() => (shouldShowHelpPanel = !shouldShowHelpPanel)} + onclick={() => (shouldShowHelpPanel = !shouldShowHelpPanel)} padding="1" /> </div> {#if !$page.url.pathname.includes('/admin') && showUploadButton} - <LinkButton on:click={onUploadClick} class="hidden lg:block"> + <LinkButton onclick={onUploadClick} class="hidden lg:block"> <div class="flex gap-2"> <Icon path={mdiTrayArrowUp} size="1.5em" /> <span>{$t('upload')}</span> </div> </LinkButton> <CircleIconButton - on:click={onUploadClick} + onclick={onUploadClick} title={$t('upload')} icon={mdiTrayArrowUp} class="lg:hidden" @@ -115,11 +120,11 @@ <button type="button" class="flex pl-2" - on:mouseover={() => (shouldShowAccountInfo = true)} - on:focus={() => (shouldShowAccountInfo = true)} - on:blur={() => (shouldShowAccountInfo = false)} - on:mouseleave={() => (shouldShowAccountInfo = false)} - on:click={() => (shouldShowAccountInfoPanel = !shouldShowAccountInfoPanel)} + onmouseover={() => (shouldShowAccountInfo = true)} + onfocus={() => (shouldShowAccountInfo = true)} + onblur={() => (shouldShowAccountInfo = false)} + onmouseleave={() => (shouldShowAccountInfo = false)} + onclick={() => (shouldShowAccountInfoPanel = !shouldShowAccountInfoPanel)} > {#key $user} <UserAvatar user={$user} size="md" showTitle={false} interactive /> diff --git a/web/src/lib/components/shared-components/navigation-loading-bar.svelte b/web/src/lib/components/shared-components/navigation-loading-bar.svelte index b6913ae025..f5879cf0a1 100644 --- a/web/src/lib/components/shared-components/navigation-loading-bar.svelte +++ b/web/src/lib/components/shared-components/navigation-loading-bar.svelte @@ -3,7 +3,7 @@ import { cubicOut } from 'svelte/easing'; import { tweened } from 'svelte/motion'; - let showing = false; + let showing = $state(false); // delay showing any progress for a little bit so very fast loads // do not cause flicker diff --git a/web/src/lib/components/shared-components/notification/__tests__/notification-component-test.svelte b/web/src/lib/components/shared-components/notification/__tests__/notification-component-test.svelte index dfa305a19d..4dea370952 100644 --- a/web/src/lib/components/shared-components/notification/__tests__/notification-component-test.svelte +++ b/web/src/lib/components/shared-components/notification/__tests__/notification-component-test.svelte @@ -1,5 +1,9 @@ <script lang="ts"> - export let href: string; + interface Props { + href: string; + } + + let { href }: Props = $props(); </script> Notification <b>message</b> with <a {href}>link</a> diff --git a/web/src/lib/components/shared-components/notification/notification-card.svelte b/web/src/lib/components/shared-components/notification/notification-card.svelte index f5e70d856a..5054c18695 100644 --- a/web/src/lib/components/shared-components/notification/notification-card.svelte +++ b/web/src/lib/components/shared-components/notification/notification-card.svelte @@ -13,11 +13,14 @@ import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; import { t } from 'svelte-i18n'; - export let notification: Notification | ComponentNotification; + interface Props { + notification: Notification | ComponentNotification; + } - // svelte-ignore reactive_declaration_non_reactive_property - $: icon = notification.type === NotificationType.Error ? mdiCloseCircleOutline : mdiInformationOutline; - $: hoverStyle = notification.action.type === 'discard' ? 'hover:cursor-pointer' : ''; + let { notification }: Props = $props(); + + let icon = $derived(notification.type === NotificationType.Error ? mdiCloseCircleOutline : mdiInformationOutline); + let hoverStyle = $derived(notification.action.type === 'discard' ? 'hover:cursor-pointer' : ''); const backgroundColor: Record<NotificationType, string> = { [NotificationType.Info]: '#E0E2F0', @@ -67,14 +70,14 @@ }; </script> -<!-- svelte-ignore a11y-no-static-element-interactions --> +<!-- svelte-ignore a11y_no_static_element_interactions --> <div transition:fade={{ duration: 250 }} style:background-color={backgroundColor[notification.type]} style:border-color={borderColor[notification.type]} class="border z-[999999] mb-4 min-h-[80px] w-[300px] rounded-2xl p-4 shadow-md {hoverStyle}" - on:click={handleClick} - on:keydown={handleClick} + onclick={handleClick} + onkeydown={handleClick} > <div class="flex justify-between"> <div class="flex place-items-center gap-2"> @@ -91,15 +94,15 @@ class="dark:text-immich-dark-gray" size="20" padding="2" - on:click={discard} - aria-hidden="true" + onclick={discard} + aria-hidden={true} tabindex={-1} /> </div> <p class="whitespace-pre-wrap pl-[28px] pr-[16px] text-sm" data-testid="message"> {#if isComponentNotification(notification)} - <svelte:component this={notification.component.type} {...notification.component.props} /> + <notification.component.type {...notification.component.props} /> {:else} {notification.message} {/if} @@ -110,7 +113,7 @@ <button type="button" class="{buttonStyle[notification.type]} rounded px-3 pt-1.5 pb-1 transition-all duration-200" - on:click={handleButtonClick} + onclick={handleButtonClick} aria-hidden="true" tabindex={-1} > diff --git a/web/src/lib/components/shared-components/number-range-input.svelte b/web/src/lib/components/shared-components/number-range-input.svelte index 2e7dca8781..6ee993cf88 100644 --- a/web/src/lib/components/shared-components/number-range-input.svelte +++ b/web/src/lib/components/shared-components/number-range-input.svelte @@ -2,14 +2,38 @@ import { clamp } from 'lodash-es'; import type { ClipboardEventHandler } from 'svelte/elements'; - export let id: string; - export let min: number; - export let max: number; - export let step: number | string = 'any'; - export let required = true; - export let value: number | null = null; - export let onInput: (value: number | null) => void; - export let onPaste: ClipboardEventHandler<HTMLInputElement> | undefined = undefined; + interface Props { + id: string; + min: number; + max: number; + step?: number | string; + required?: boolean; + value?: number; + onInput: (value: number | null) => void; + onPaste?: ClipboardEventHandler<HTMLInputElement>; + } + + let { + id, + min, + max, + step = 'any', + required = true, + value = $bindable(), + onInput, + onPaste = undefined, + }: Props = $props(); + + const oninput = () => { + if (!value) { + return; + } + + if (value !== null && (value < min || value > max)) { + value = clamp(value, min, max); + } + onInput(value); + }; </script> <input @@ -21,11 +45,6 @@ {step} {required} bind:value - on:input={() => { - if (value !== null && (value < min || value > max)) { - value = clamp(value, min, max); - } - onInput(value); - }} - on:paste={onPaste} + {oninput} + onpaste={onPaste} /> diff --git a/web/src/lib/components/shared-components/password-field.svelte b/web/src/lib/components/shared-components/password-field.svelte index e623d08423..8519f84134 100644 --- a/web/src/lib/components/shared-components/password-field.svelte +++ b/web/src/lib/components/shared-components/password-field.svelte @@ -4,28 +4,26 @@ import Icon from '../elements/icon.svelte'; import { t } from 'svelte-i18n'; - interface $$Props extends HTMLInputAttributes { + interface Props extends HTMLInputAttributes { password: string; autocomplete: AutoFill; required?: boolean; onInput?: (value: string) => void; } - export let password: $$Props['password']; - export let required = true; - export let onInput: $$Props['onInput'] = undefined; + let { password = $bindable(), required = true, onInput = undefined, ...rest }: Props = $props(); - let showPassword = false; + let showPassword = $state(false); </script> <div class="relative w-full"> <input - {...$$restProps} + {...rest} class="immich-form-input w-full !pr-12" type={showPassword ? 'text' : 'password'} {required} value={password} - on:input={(e) => { + oninput={(e) => { password = e.currentTarget.value; onInput?.(password); }} @@ -36,7 +34,7 @@ type="button" tabindex="-1" class="absolute inset-y-0 end-0 px-4 text-gray-700 dark:text-gray-200" - on:click={() => (showPassword = !showPassword)} + onclick={() => (showPassword = !showPassword)} title={showPassword ? $t('hide_password') : $t('show_password')} > <Icon path={showPassword ? mdiEyeOffOutline : mdiEyeOutline} size="1.25em" /> diff --git a/web/src/lib/components/shared-components/portal/portal.svelte b/web/src/lib/components/shared-components/portal/portal.svelte index 7a9e577083..60ccc993af 100644 --- a/web/src/lib/components/shared-components/portal/portal.svelte +++ b/web/src/lib/components/shared-components/portal/portal.svelte @@ -1,6 +1,6 @@ -<script context="module" lang="ts"> +<script module lang="ts"> import { handlePromiseError } from '$lib/utils'; - import { tick } from 'svelte'; + import { tick, type Snippet } from 'svelte'; /** * Usage: <div use:portal={'css selector'}> or <div use:portal={document.body}> @@ -64,12 +64,17 @@ Used for every occurrence of an HTML tag in a message ``` --> <script lang="ts"> - /** - * DOM Element or CSS Selector - */ - export let target: HTMLElement | string = 'body'; + interface Props { + /** + * DOM Element or CSS Selector + */ + target?: HTMLElement | string; + children?: Snippet; + } + + let { target = 'body', children }: Props = $props(); </script> <div use:portal={target} hidden> - <slot /> + {@render children?.()} </div> diff --git a/web/src/lib/components/shared-components/profile-image-cropper.svelte b/web/src/lib/components/shared-components/profile-image-cropper.svelte index 3dabd86d4f..b8ac866761 100644 --- a/web/src/lib/components/shared-components/profile-image-cropper.svelte +++ b/web/src/lib/components/shared-components/profile-image-cropper.svelte @@ -10,12 +10,20 @@ import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte'; import { t } from 'svelte-i18n'; - export let asset: AssetResponseDto; - export let onClose: () => void; + interface Props { + asset: AssetResponseDto; + onClose: () => void; + } - let imgElement: HTMLDivElement; + let { asset, onClose }: Props = $props(); + + let imgElement: HTMLDivElement | undefined = $state(); onMount(() => { + if (!imgElement) { + return; + } + imgElement.style.width = '100%'; }); @@ -45,6 +53,10 @@ }; const handleSetProfilePicture = async () => { + if (!imgElement) { + return; + } + try { const blob = await domtoimage.toBlob(imgElement); if (await hasTransparentPixels(blob)) { @@ -79,7 +91,8 @@ <PhotoViewer bind:element={imgElement} {asset} /> </div> </div> - <svelte:fragment slot="sticky-bottom"> - <Button fullwidth on:click={handleSetProfilePicture}>{$t('set_as_profile_picture')}</Button> - </svelte:fragment> + + {#snippet stickyBottom()} + <Button fullwidth onclick={handleSetProfilePicture}>{$t('set_as_profile_picture')}</Button> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/shared-components/progress-bar/progress-bar.svelte b/web/src/lib/components/shared-components/progress-bar/progress-bar.svelte index 81de8a24a1..0ccb8f9556 100644 --- a/web/src/lib/components/shared-components/progress-bar/progress-bar.svelte +++ b/web/src/lib/components/shared-components/progress-bar/progress-bar.svelte @@ -1,4 +1,4 @@ -<script context="module" lang="ts"> +<script module lang="ts"> export enum ProgressBarStatus { Playing = 'playing', Paused = 'paused', @@ -11,41 +11,49 @@ import { onMount } from 'svelte'; import { tweened } from 'svelte/motion'; - /** - * Autoplay on mount - * @default false - */ - export let autoplay = false; + interface Props { + /** + * Autoplay on mount + * @default false + */ + autoplay?: boolean; + /** + * Progress bar status + */ + status?: ProgressBarStatus; + hidden?: boolean; + duration?: number; + onDone: () => void; + onPlaying?: () => void; + onPaused?: () => void; + } - /** - * Progress bar status - */ - export let status: ProgressBarStatus = ProgressBarStatus.Paused; + let { + autoplay = false, + status = $bindable(), + hidden = false, + duration = 5, + onDone, + onPlaying = () => {}, + onPaused = () => {}, + }: Props = $props(); - export let hidden = false; - - export let duration = 5; - - export let onDone: () => void; - export let onPlaying: () => void = () => {}; - export let onPaused: () => void = () => {}; - - const onChange = async () => { - progress = setDuration(duration); + const onChange = async (progressDuration: number) => { + progress = setDuration(progressDuration); await play(); }; let progress = setDuration(duration); - // svelte 5, again.... - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - $: duration, handlePromiseError(onChange()); + $effect(() => { + handlePromiseError(onChange(duration)); + }); - $: { + $effect(() => { if ($progress === 1) { onDone(); } - } + }); onMount(async () => { if (autoplay) { diff --git a/web/src/lib/components/shared-components/purchasing/purchase-activation-success.svelte b/web/src/lib/components/shared-components/purchasing/purchase-activation-success.svelte index 3bd462f997..00800ab489 100644 --- a/web/src/lib/components/shared-components/purchasing/purchase-activation-success.svelte +++ b/web/src/lib/components/shared-components/purchasing/purchase-activation-success.svelte @@ -7,7 +7,11 @@ import { preferences } from '$lib/stores/user.store'; import { setSupportBadgeVisibility } from '$lib/utils/purchase-utils'; - export let onDone: () => void; + interface Props { + onDone: () => void; + } + + let { onDone }: Props = $props(); </script> <div class="m-auto w-3/4 text-center flex flex-col place-content-center place-items-center dark:text-white my-6"> @@ -25,6 +29,6 @@ </div> <div class="mt-6 w-full"> - <Button fullwidth on:click={onDone}>{$t('ok')}</Button> + <Button fullwidth onclick={onDone}>{$t('ok')}</Button> </div> </div> diff --git a/web/src/lib/components/shared-components/purchasing/purchase-content.svelte b/web/src/lib/components/shared-components/purchasing/purchase-content.svelte index 0d782f85b3..6a4e7f1a4b 100644 --- a/web/src/lib/components/shared-components/purchasing/purchase-content.svelte +++ b/web/src/lib/components/shared-components/purchasing/purchase-content.svelte @@ -8,12 +8,15 @@ import { purchaseStore } from '$lib/stores/purchase.store'; import { t } from 'svelte-i18n'; - export let onActivate: () => void; + interface Props { + onActivate: () => void; + showTitle?: boolean; + showMessage?: boolean; + } - export let showTitle = true; - export let showMessage = true; - let productKey = ''; - let isLoading = false; + let { onActivate, showTitle = true, showMessage = true }: Props = $props(); + let productKey = $state(''); + let isLoading = $state(false); const activate = async () => { try { @@ -61,7 +64,7 @@ <div class="mt-6"> <p class="dark:text-immich-gray">{$t('purchase_input_suggestion')}</p> - <form class="mt-2 flex gap-2" on:submit={activate}> + <form class="mt-2 flex gap-2" onsubmit={activate}> <input class="immich-form-input w-full" id="purchaseKey" 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 52757bc32a..0334fb9e99 100644 --- a/web/src/lib/components/shared-components/purchasing/purchase-modal.svelte +++ b/web/src/lib/components/shared-components/purchasing/purchase-modal.svelte @@ -5,9 +5,13 @@ import Portal from '$lib/components/shared-components/portal/portal.svelte'; - export let onClose: () => void; + interface Props { + onClose: () => void; + } - let showProductActivated = false; + let { onClose }: Props = $props(); + + let showProductActivated = $state(false); </script> <Portal> diff --git a/web/src/lib/components/shared-components/scrubber/scrubber.svelte b/web/src/lib/components/shared-components/scrubber/scrubber.svelte index a55ad1a69c..bdcca509bb 100644 --- a/web/src/lib/components/shared-components/scrubber/scrubber.svelte +++ b/web/src/lib/components/shared-components/scrubber/scrubber.svelte @@ -7,28 +7,45 @@ import { isTimelineScrolling } from '$lib/stores/timeline.store'; import { fade, fly } from 'svelte/transition'; - export let timelineTopOffset = 0; - export let timelineBottomOffset = 0; - export let height = 0; - export let assetStore: AssetStore; - export let invisible = false; - export let scrubOverallPercent: number = 0; - export let scrubBucketPercent: number = 0; - export let scrubBucket: { bucketDate: string | undefined } | undefined = undefined; - export let leadout: boolean = false; - export let onScrub: ScrubberListener | undefined = undefined; - export let startScrub: ScrubberListener | undefined = undefined; - export let stopScrub: ScrubberListener | undefined = undefined; + interface Props { + timelineTopOffset?: number; + timelineBottomOffset?: number; + height?: number; + assetStore: AssetStore; + invisible?: boolean; + scrubOverallPercent?: number; + scrubBucketPercent?: number; + scrubBucket?: { bucketDate: string | undefined } | undefined; + leadout?: boolean; + onScrub?: ScrubberListener | undefined; + startScrub?: ScrubberListener | undefined; + stopScrub?: ScrubberListener | undefined; + } - let isHover = false; - let isDragging = false; - let hoverLabel: string | undefined; + let { + timelineTopOffset = 0, + timelineBottomOffset = 0, + height = 0, + assetStore, + invisible = false, + scrubOverallPercent = 0, + scrubBucketPercent = 0, + scrubBucket = undefined, + leadout = false, + onScrub = undefined, + startScrub = undefined, + stopScrub = undefined, + }: Props = $props(); + + let isHover = $state(false); + let isDragging = $state(false); + let hoverLabel: string | undefined = $state(); let bucketDate: string | undefined; - let hoverY = 0; + let hoverY = $state(0); let clientY = 0; - let windowHeight = 0; - let scrollBar: HTMLElement | undefined; - let segments: Segment[] = []; + let windowHeight = $state(0); + let scrollBar: HTMLElement | undefined = $state(); + let segments: Segment[] = $state([]); const toScrollY = (percent: number) => percent * (height - HOVER_DATE_HEIGHT * 2); const toTimelineY = (scrollY: number) => scrollY / (height - HOVER_DATE_HEIGHT * 2); @@ -70,10 +87,14 @@ return scrubOverallPercent * (height - HOVER_DATE_HEIGHT * 2) - 2; } }; - $: scrollY = toScrollFromBucketPercentage(scrubBucket, scrubBucketPercent, scrubOverallPercent); - $: timelineFullHeight = $assetStore.timelineHeight + timelineTopOffset + timelineBottomOffset; - $: relativeTopOffset = toScrollY(timelineTopOffset / timelineFullHeight); - $: relativeBottomOffset = toScrollY(timelineBottomOffset / timelineFullHeight); + let scrollY = $state(0); + $effect(() => { + scrollY = toScrollFromBucketPercentage(scrubBucket, scrubBucketPercent, scrubOverallPercent); + }); + + let timelineFullHeight = $derived($assetStore.timelineHeight + timelineTopOffset + timelineBottomOffset); + let relativeTopOffset = $derived(toScrollY(timelineTopOffset / timelineFullHeight)); + let relativeBottomOffset = $derived(toScrollY(timelineBottomOffset / timelineFullHeight)); const listener: BucketListener = (event) => { const { type } = event; @@ -204,12 +225,12 @@ <svelte:window bind:innerHeight={windowHeight} - on:mousemove={({ clientY }) => (isDragging || isHover) && handleMouseEvent({ clientY })} - on:mousedown={({ clientY }) => isHover && handleMouseEvent({ clientY, isDragging: true })} - on:mouseup={({ clientY }) => handleMouseEvent({ clientY, isDragging: false })} + onmousemove={({ clientY }) => (isDragging || isHover) && handleMouseEvent({ clientY })} + onmousedown={({ clientY }) => isHover && handleMouseEvent({ clientY, isDragging: true })} + onmouseup={({ clientY }) => handleMouseEvent({ clientY, isDragging: false })} /> -<!-- svelte-ignore a11y-no-static-element-interactions --> +<!-- svelte-ignore a11y_no_static_element_interactions --> <div transition:fly={{ x: 50, duration: 250 }} @@ -223,8 +244,8 @@ style:background-color={isDragging ? 'transparent' : 'transparent'} draggable="false" bind:this={scrollBar} - on:mouseenter={() => (isHover = true)} - on:mouseleave={() => (isHover = false)} + onmouseenter={() => (isHover = true)} + onmouseleave={() => (isHover = false)} > {#if hoverLabel && (isHover || isDragging)} <div diff --git a/web/src/lib/components/shared-components/search-bar/search-bar.svelte b/web/src/lib/components/shared-components/search-bar/search-bar.svelte index 67c3cfe757..d92bd1806c 100644 --- a/web/src/lib/components/shared-components/search-bar/search-bar.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-bar.svelte @@ -15,35 +15,38 @@ import { generateId } from '$lib/utils/generate-id'; import { tick } from 'svelte'; - export let value = ''; - export let grayTheme: boolean; - export let searchQuery: MetadataSearchDto | SmartSearchDto = {}; + interface Props { + value?: string; + grayTheme: boolean; + searchQuery?: MetadataSearchDto | SmartSearchDto; + onSearch?: () => void; + } - $: showClearIcon = value.length > 0; + let { value = $bindable(''), grayTheme, searchQuery = {}, onSearch }: Props = $props(); - let input: HTMLInputElement; + let showClearIcon = $derived(value.length > 0); - let showSuggestions = false; - let showFilter = false; - let isSearchSuggestions = false; - let selectedId: string | undefined; - let moveSelection: (direction: 1 | -1) => void; - let clearSelection: () => void; - let selectActiveOption: () => void; + let input = $state<HTMLInputElement>(); + let searchHistoryBox = $state<ReturnType<typeof SearchHistoryBox>>(); + let showSuggestions = $state(false); + let showFilter = $state(false); + let isSearchSuggestions = $state(false); + let selectedId: string | undefined = $state(); const listboxId = generateId(); - const onSearch = async (payload: SmartSearchDto | MetadataSearchDto) => { + const handleSearch = async (payload: SmartSearchDto | MetadataSearchDto) => { const params = getMetadataSearchQuery(payload); closeDropdown(); showFilter = false; $isSearchEnabled = false; await goto(`${AppRoute.SEARCH}?${params}`); + onSearch?.(); }; const clearSearchTerm = (searchTerm: string) => { - input.focus(); + input?.focus(); $savedSearchTerms = $savedSearchTerms.filter((item) => item !== searchTerm); }; @@ -57,7 +60,7 @@ }; const clearAllSearchTerms = () => { - input.focus(); + input?.focus(); $savedSearchTerms = []; }; @@ -82,7 +85,7 @@ const onHistoryTermClick = async (searchTerm: string) => { value = searchTerm; const searchPayload = { query: searchTerm }; - await onSearch(searchPayload); + await handleSearch(searchPayload); }; const onFilterClick = () => { @@ -95,13 +98,13 @@ }; const onSubmit = () => { - handlePromiseError(onSearch({ query: value })); + handlePromiseError(handleSearch({ query: value })); saveSearchTerm(value); }; const onClear = () => { value = ''; - input.focus(); + input?.focus(); }; const onEscape = () => { @@ -112,19 +115,19 @@ const onArrow = async (direction: 1 | -1) => { openDropdown(); await tick(); - moveSelection(direction); + searchHistoryBox?.moveSelection(direction); }; const onEnter = (event: KeyboardEvent) => { if (selectedId) { event.preventDefault(); - selectActiveOption(); + searchHistoryBox?.selectActiveOption(); } }; const onInput = () => { openDropdown(); - clearSelection(); + searchHistoryBox?.clearSelection(); }; const openDropdown = () => { @@ -133,14 +136,19 @@ const closeDropdown = () => { showSuggestions = false; - clearSelection(); + searchHistoryBox?.clearSelection(); + }; + + const onsubmit = (event: Event) => { + event.preventDefault(); + onSubmit(); }; </script> <svelte:window use:shortcuts={[ { shortcut: { key: 'Escape' }, onShortcut: onEscape }, - { shortcut: { ctrl: true, key: 'k' }, onShortcut: () => input.select() }, + { shortcut: { ctrl: true, key: 'k' }, onShortcut: () => input?.select() }, { shortcut: { ctrl: true, shift: true, key: 'k' }, onShortcut: onFilterClick }, ]} /> @@ -151,9 +159,9 @@ autocomplete="off" class="select-text text-sm" action={AppRoute.SEARCH} - on:reset={() => (value = '')} - on:submit|preventDefault={onSubmit} - on:focusin={onFocusIn} + onreset={() => (value = '')} + {onsubmit} + onfocusin={onFocusIn} role="search" > <div use:focusOutside={{ onFocusOut: closeDropdown }} tabindex="-1"> @@ -171,8 +179,8 @@ pattern="^(?!m:$).*$" bind:value bind:this={input} - on:focus={openDropdown} - on:input={onInput} + onfocus={openDropdown} + oninput={onInput} disabled={showFilter} role="combobox" aria-controls={listboxId} @@ -191,13 +199,11 @@ <!-- SEARCH HISTORY BOX --> <SearchHistoryBox + bind:this={searchHistoryBox} + bind:isSearchSuggestions id={listboxId} searchQuery={value} isOpen={showSuggestions} - bind:isSearchSuggestions - bind:moveSelection - bind:clearSelection - bind:selectActiveOption onClearAllSearchTerms={clearAllSearchTerms} onClearSearchTerm={(searchTerm) => clearSearchTerm(searchTerm)} onSelectSearchTerm={(searchTerm) => handlePromiseError(onHistoryTermClick(searchTerm))} @@ -206,19 +212,30 @@ </div> <div class="absolute inset-y-0 {showClearIcon ? 'right-14' : 'right-2'} flex items-center pl-6 transition-all"> - <CircleIconButton title={$t('show_search_options')} icon={mdiTune} on:click={onFilterClick} size="20" /> + <CircleIconButton title={$t('show_search_options')} icon={mdiTune} onclick={onFilterClick} size="20" /> </div> {#if showClearIcon} <div class="absolute inset-y-0 right-0 flex items-center pr-2"> - <CircleIconButton on:click={onClear} icon={mdiClose} title={$t('clear')} size="20" /> + <CircleIconButton onclick={onClear} icon={mdiClose} title={$t('clear')} size="20" /> </div> {/if} <div class="absolute inset-y-0 left-0 flex items-center pl-2"> - <CircleIconButton type="submit" disabled={showFilter} title={$t('search')} icon={mdiMagnify} size="20" /> + <CircleIconButton + type="submit" + disabled={showFilter} + title={$t('search')} + icon={mdiMagnify} + size="20" + onclick={() => {}} + /> </div> </form> {#if showFilter} - <SearchFilterModal {searchQuery} onSearch={(payload) => onSearch(payload)} onClose={() => (showFilter = false)} /> + <SearchFilterModal + {searchQuery} + onSearch={(payload) => handleSearch(payload)} + onClose={() => (showFilter = false)} + /> {/if} </div> diff --git a/web/src/lib/components/shared-components/search-bar/search-camera-section.svelte b/web/src/lib/components/shared-components/search-bar/search-camera-section.svelte index 3ac8cb8d5a..08ed57d70e 100644 --- a/web/src/lib/components/shared-components/search-bar/search-camera-section.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-camera-section.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export interface SearchCameraFilter { make?: string; model?: string; @@ -6,20 +6,21 @@ </script> <script lang="ts"> + import { run } from 'svelte/legacy'; + import Combobox, { asComboboxOptions, asSelectedOption } from '$lib/components/shared-components/combobox.svelte'; import { handlePromiseError } from '$lib/utils'; import { SearchSuggestionType, getSearchSuggestions } from '@immich/sdk'; import { t } from 'svelte-i18n'; - export let filters: SearchCameraFilter; + interface Props { + filters: SearchCameraFilter; + } - let makes: string[] = []; - let models: string[] = []; + let { filters = $bindable() }: Props = $props(); - $: makeFilter = filters.make; - $: modelFilter = filters.model; - $: handlePromiseError(updateMakes()); - $: handlePromiseError(updateModels(makeFilter)); + let makes: string[] = $state([]); + let models: string[] = $state([]); async function updateMakes() { const results: Array<string | null> = await getSearchSuggestions({ @@ -47,6 +48,14 @@ filters.model = undefined; } } + let makeFilter = $derived(filters.make); + let modelFilter = $derived(filters.model); + run(() => { + handlePromiseError(updateMakes()); + }); + run(() => { + handlePromiseError(updateModels(makeFilter)); + }); </script> <div id="camera-selection"> diff --git a/web/src/lib/components/shared-components/search-bar/search-date-section.svelte b/web/src/lib/components/shared-components/search-bar/search-date-section.svelte index 6b661b6c03..ea27142074 100644 --- a/web/src/lib/components/shared-components/search-bar/search-date-section.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-date-section.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export interface SearchDateFilter { takenBefore?: string; takenAfter?: string; @@ -9,7 +9,11 @@ import DateInput from '$lib/components/elements/date-input.svelte'; import { t } from 'svelte-i18n'; - export let filters: SearchDateFilter; + interface Props { + filters: SearchDateFilter; + } + + let { filters = $bindable() }: Props = $props(); </script> <div id="date-range-selection" class="grid grid-auto-fit-40 gap-5"> diff --git a/web/src/lib/components/shared-components/search-bar/search-display-section.svelte b/web/src/lib/components/shared-components/search-bar/search-display-section.svelte index 00a5403068..06fa3c5bdf 100644 --- a/web/src/lib/components/shared-components/search-bar/search-display-section.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-display-section.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export interface SearchDisplayFilters { isNotInAlbum?: boolean; isArchive?: boolean; @@ -10,7 +10,11 @@ import Checkbox from '$lib/components/elements/checkbox.svelte'; import { t } from 'svelte-i18n'; - export let filters: SearchDisplayFilters; + interface Props { + filters: SearchDisplayFilters; + } + + let { filters = $bindable() }: Props = $props(); </script> <div id="display-options-selection"> diff --git a/web/src/lib/components/shared-components/search-bar/search-filter-modal.svelte b/web/src/lib/components/shared-components/search-bar/search-filter-modal.svelte index 3ec539ad97..4b53f60b5f 100644 --- a/web/src/lib/components/shared-components/search-bar/search-filter-modal.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-filter-modal.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> import type { SearchLocationFilter } from './search-location-section.svelte'; import type { SearchDisplayFilters } from './search-display-section.svelte'; import type { SearchDateFilter } from './search-date-section.svelte'; @@ -36,10 +36,15 @@ import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte'; import { mdiTune } from '@mdi/js'; import { generateId } from '$lib/utils/generate-id'; + import { SvelteSet } from 'svelte/reactivity'; - export let searchQuery: MetadataSearchDto | SmartSearchDto; - export let onClose: () => void; - export let onSearch: (search: SmartSearchDto | MetadataSearchDto) => void; + interface Props { + searchQuery: MetadataSearchDto | SmartSearchDto; + onClose: () => void; + onSearch: (search: SmartSearchDto | MetadataSearchDto) => void; + } + + let { searchQuery, onClose, onSearch }: Props = $props(); const parseOptionalDate = (dateString?: string) => (dateString ? parseUtcDate(dateString) : undefined); const toStartOfDayDate = (dateString: string) => parseUtcDate(dateString)?.startOf('day').toISODate() || undefined; @@ -50,10 +55,10 @@ return value === null ? undefined : value; } - let filter: SearchFilter = { + let filter: SearchFilter = $state({ query: 'query' in searchQuery ? searchQuery.query : searchQuery.originalFileName || '', queryType: 'query' in searchQuery ? 'smart' : 'metadata', - personIds: new Set('personIds' in searchQuery ? searchQuery.personIds : []), + personIds: new SvelteSet('personIds' in searchQuery ? searchQuery.personIds : []), location: { country: withNullAsUndefined(searchQuery.country), state: withNullAsUndefined(searchQuery.state), @@ -78,7 +83,7 @@ : searchQuery.type === AssetTypeEnum.Video ? MediaType.Video : MediaType.All, - }; + }); const resetForm = () => { filter = { @@ -122,10 +127,20 @@ onSearch(payload); }; + + const onreset = (event: Event) => { + event.preventDefault(); + resetForm(); + }; + + const onsubmit = (event: Event) => { + event.preventDefault(); + search(); + }; </script> <FullScreenModal icon={mdiTune} width="extra-wide" title={$t('search_options')} {onClose}> - <form id={formId} autocomplete="off" on:submit|preventDefault={search} on:reset|preventDefault={resetForm}> + <form id={formId} autocomplete="off" {onsubmit} {onreset}> <div class="space-y-10 pb-10" tabindex="-1"> <!-- PEOPLE --> <SearchPeopleSection bind:selectedPeople={filter.personIds} /> @@ -152,8 +167,8 @@ </div> </form> - <svelte:fragment slot="sticky-bottom"> + {#snippet stickyBottom()} <Button type="reset" color="gray" fullwidth form={formId}>{$t('clear_all')}</Button> <Button type="submit" fullwidth form={formId}>{$t('search')}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/shared-components/search-bar/search-history-box.svelte b/web/src/lib/components/shared-components/search-bar/search-history-box.svelte index ca25ef5691..92a2f8847e 100644 --- a/web/src/lib/components/shared-components/search-bar/search-history-box.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-history-box.svelte @@ -6,22 +6,41 @@ import { t } from 'svelte-i18n'; import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; - export let id: string; - export let searchQuery: string = ''; - export let isSearchSuggestions: boolean = false; - export let isOpen: boolean = false; - export let onSelectSearchTerm: (searchTerm: string) => void; - export let onClearSearchTerm: (searchTerm: string) => void; - export let onClearAllSearchTerms: () => void; - export let onActiveSelectionChange: (selectedId: string | undefined) => void; + interface Props { + id: string; + searchQuery?: string; + isSearchSuggestions?: boolean; + isOpen?: boolean; + onSelectSearchTerm: (searchTerm: string) => void; + onClearSearchTerm: (searchTerm: string) => void; + onClearAllSearchTerms: () => void; + onActiveSelectionChange: (selectedId: string | undefined) => void; + } - $: filteredSearchTerms = $savedSearchTerms.filter((term) => term.toLowerCase().includes(searchQuery.toLowerCase())); - $: isSearchSuggestions = filteredSearchTerms.length > 0; - $: showClearAll = searchQuery === ''; - $: suggestionCount = showClearAll ? filteredSearchTerms.length + 1 : filteredSearchTerms.length; + let { + id, + searchQuery = '', + isSearchSuggestions = $bindable(false), + isOpen = false, + onSelectSearchTerm, + onClearSearchTerm, + onClearAllSearchTerms, + onActiveSelectionChange, + }: Props = $props(); - let selectedIndex: number | undefined = undefined; - let element: HTMLDivElement; + let filteredSearchTerms = $derived( + $savedSearchTerms.filter((term) => term.toLowerCase().includes(searchQuery.toLowerCase())), + ); + + $effect(() => { + isSearchSuggestions = filteredSearchTerms.length > 0; + }); + + let showClearAll = $derived(searchQuery === ''); + let suggestionCount = $derived(showClearAll ? filteredSearchTerms.length + 1 : filteredSearchTerms.length); + + let selectedIndex: number | undefined = $state(undefined); + let element = $state<HTMLDivElement>(); export function moveSelection(increment: 1 | -1) { if (!isSearchSuggestions) { @@ -45,7 +64,7 @@ if (selectedIndex === undefined) { return; } - const selectedElement = element.querySelector(`#${getId(selectedIndex)}`) as HTMLElement; + const selectedElement = element?.querySelector(`#${getId(selectedIndex)}`) as HTMLElement; selectedElement?.click(); } @@ -86,7 +105,7 @@ type="button" class="rounded-lg p-2 font-semibold text-immich-primary aria-selected:bg-immich-primary/25 hover:bg-immich-primary/25 dark:text-immich-dark-primary" role="option" - on:click={() => handleClearAll()} + onclick={() => handleClearAll()} tabindex="-1" aria-selected={selectedIndex === 0} aria-label={$t('clear_all_recent_searches')} @@ -100,11 +119,11 @@ {@const index = showClearAll ? i + 1 : i} <div class="flex w-full items-center justify-between text-sm text-black dark:text-gray-300"> <div class="relative w-full items-center"> - <!-- svelte-ignore a11y-click-events-have-key-events --> + <!-- svelte-ignore a11y_click_events_have_key_events --> <div id={getId(index)} class="relative flex w-full cursor-pointer gap-3 py-3 pl-5 hover:bg-gray-100 aria-selected:bg-gray-100 dark:aria-selected:bg-gray-500/30 dark:hover:bg-gray-500/30" - on:click={() => handleSelect(savedSearchTerm)} + onclick={() => handleSelect(savedSearchTerm)} role="option" tabindex="-1" aria-selected={selectedIndex === index} @@ -120,7 +139,7 @@ size="18" padding="1" tabindex={-1} - on:click={() => handleClearSingle(savedSearchTerm)} + onclick={() => handleClearSingle(savedSearchTerm)} /> </div> </div> diff --git a/web/src/lib/components/shared-components/search-bar/search-location-section.svelte b/web/src/lib/components/shared-components/search-bar/search-location-section.svelte index 71912264ed..d68578276c 100644 --- a/web/src/lib/components/shared-components/search-bar/search-location-section.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-location-section.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export interface SearchLocationFilter { country?: string; state?: string; @@ -7,22 +7,22 @@ </script> <script lang="ts"> + import { run } from 'svelte/legacy'; + import Combobox, { asComboboxOptions, asSelectedOption } from '$lib/components/shared-components/combobox.svelte'; import { handlePromiseError } from '$lib/utils'; import { getSearchSuggestions, SearchSuggestionType } from '@immich/sdk'; import { t } from 'svelte-i18n'; - export let filters: SearchLocationFilter; + interface Props { + filters: SearchLocationFilter; + } - let countries: string[] = []; - let states: string[] = []; - let cities: string[] = []; + let { filters = $bindable() }: Props = $props(); - $: countryFilter = filters.country; - $: stateFilter = filters.state; - $: handlePromiseError(updateCountries()); - $: handlePromiseError(updateStates(countryFilter)); - $: handlePromiseError(updateCities(countryFilter, stateFilter)); + let countries: string[] = $state([]); + let states: string[] = $state([]); + let cities: string[] = $state([]); async function updateCountries() { const results: Array<string | null> = await getSearchSuggestions({ @@ -64,6 +64,17 @@ filters.city = undefined; } } + let countryFilter = $derived(filters.country); + let stateFilter = $derived(filters.state); + run(() => { + handlePromiseError(updateCountries()); + }); + run(() => { + handlePromiseError(updateStates(countryFilter)); + }); + run(() => { + handlePromiseError(updateCities(countryFilter, stateFilter)); + }); </script> <div id="location-selection"> diff --git a/web/src/lib/components/shared-components/search-bar/search-media-section.svelte b/web/src/lib/components/shared-components/search-bar/search-media-section.svelte index b78868d614..37fa4292ae 100644 --- a/web/src/lib/components/shared-components/search-bar/search-media-section.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-media-section.svelte @@ -3,7 +3,11 @@ import { MediaType } from './search-filter-modal.svelte'; import { t } from 'svelte-i18n'; - export let filteredMedia: MediaType; + interface Props { + filteredMedia: MediaType; + } + + let { filteredMedia = $bindable() }: Props = $props(); </script> <div id="media-type-selection"> diff --git a/web/src/lib/components/shared-components/search-bar/search-people-section.svelte b/web/src/lib/components/shared-components/search-bar/search-people-section.svelte index 0c8d32a1ae..8e5059cbbf 100644 --- a/web/src/lib/components/shared-components/search-bar/search-people-section.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-people-section.svelte @@ -10,12 +10,16 @@ import { t } from 'svelte-i18n'; import SingleGridRow from '$lib/components/shared-components/single-grid-row.svelte'; - export let selectedPeople: Set<string>; + interface Props { + selectedPeople: Set<string>; + } + + let { selectedPeople = $bindable() }: Props = $props(); let peoplePromise = getPeople(); - let showAllPeople = false; - let name = ''; - let numberOfPeople = 1; + let showAllPeople = $state(false); + let name = $state(''); + let numberOfPeople = $state(1); function orderBySelectedPeopleFirst(people: PersonResponseDto[]) { return [ @@ -72,7 +76,7 @@ ) ? 'dark:border-slate-500 border-slate-400 bg-slate-200 dark:bg-slate-800 dark:text-white' : 'border-transparent'}" - on:click={() => togglePersonSelection(person.id)} + onclick={() => togglePersonSelection(person.id)} > <ImageThumbnail circle shadow url={getPeopleThumbnailUrl(person)} altText={person.name} widthStyle="100%" /> <p class="mt-2 line-clamp-2 text-sm font-medium dark:text-white">{person.name}</p> @@ -86,7 +90,7 @@ shadow={false} color="text-primary" class="flex gap-2 place-items-center" - on:click={() => (showAllPeople = !showAllPeople)} + onclick={() => (showAllPeople = !showAllPeople)} > {#if showAllPeople} <span><Icon path={mdiClose} ariaHidden /></span> diff --git a/web/src/lib/components/shared-components/search-bar/search-text-section.svelte b/web/src/lib/components/shared-components/search-bar/search-text-section.svelte index c3145b2f0c..2f118e6567 100644 --- a/web/src/lib/components/shared-components/search-bar/search-text-section.svelte +++ b/web/src/lib/components/shared-components/search-bar/search-text-section.svelte @@ -2,8 +2,12 @@ import RadioButton from '$lib/components/elements/radio-button.svelte'; import { t } from 'svelte-i18n'; - export let query: string | undefined; - export let queryType: 'smart' | 'metadata' = 'smart'; + interface Props { + query: string | undefined; + queryType?: 'smart' | 'metadata'; + } + + let { query = $bindable(), queryType = $bindable('smart') }: Props = $props(); </script> <fieldset> diff --git a/web/src/lib/components/shared-components/server-about-modal.svelte b/web/src/lib/components/shared-components/server-about-modal.svelte index 1373a98d3f..cf935cd314 100644 --- a/web/src/lib/components/shared-components/server-about-modal.svelte +++ b/web/src/lib/components/shared-components/server-about-modal.svelte @@ -7,10 +7,13 @@ import { mdiAlert } from '@mdi/js'; import Icon from '$lib/components/elements/icon.svelte'; - export let onClose: () => void; + interface Props { + onClose: () => void; + info: ServerAboutResponseDto; + versions: ServerVersionHistoryResponseDto[]; + } - export let info: ServerAboutResponseDto; - export let versions: ServerVersionHistoryResponseDto[]; + let { onClose, info, versions }: Props = $props(); </script> <Portal> diff --git a/web/src/lib/components/shared-components/settings/setting-accordion-state.svelte b/web/src/lib/components/shared-components/settings/setting-accordion-state.svelte index a6257fce29..7fbab302d2 100644 --- a/web/src/lib/components/shared-components/settings/setting-accordion-state.svelte +++ b/web/src/lib/components/shared-components/settings/setting-accordion-state.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export type AccordionState = Set<string>; const { get: getAccordionState, set: setAccordionState } = createContext<Writable<AccordionState>>(); @@ -11,25 +11,33 @@ import { page } from '$app/stores'; import { handlePromiseError } from '$lib/utils'; import { goto } from '$app/navigation'; + import type { Snippet } from 'svelte'; const getParamValues = (param: string) => { return new Set(($page.url.searchParams.get(param) || '').split(' ').filter((x) => x !== '')); }; - export let queryParam: string; - export let state: Writable<AccordionState> = writable(getParamValues(queryParam)); + interface Props { + queryParam: string; + state?: Writable<AccordionState>; + children?: Snippet; + } + + let { queryParam, state = writable(getParamValues(queryParam)), children }: Props = $props(); setAccordionState(state); - $: if (queryParam && $state) { - const searchParams = new URLSearchParams($page.url.searchParams); - if ($state.size > 0) { - searchParams.set(queryParam, [...$state].join(' ')); - } else { - searchParams.delete(queryParam); - } + $effect(() => { + if (queryParam && $state) { + const searchParams = new URLSearchParams($page.url.searchParams); + if ($state.size > 0) { + searchParams.set(queryParam, [...$state].join(' ')); + } else { + searchParams.delete(queryParam); + } - handlePromiseError(goto(`?${searchParams.toString()}`, { replaceState: true, noScroll: true, keepFocus: true })); - } + handlePromiseError(goto(`?${searchParams.toString()}`, { replaceState: true, noScroll: true, keepFocus: true })); + } + }); </script> -<slot /> +{@render children?.()} 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 d8b50b2132..0fe1c9dc14 100755 --- a/web/src/lib/components/shared-components/settings/setting-accordion.svelte +++ b/web/src/lib/components/shared-components/settings/setting-accordion.svelte @@ -1,21 +1,34 @@ <script lang="ts"> import { slide } from 'svelte/transition'; import { getAccordionState } from './setting-accordion-state.svelte'; - import { onDestroy } from 'svelte'; + import { onDestroy, onMount, type Snippet } from 'svelte'; import Icon from '$lib/components/elements/icon.svelte'; const accordionState = getAccordionState(); - export let title: string; - export let subtitle = ''; - export let key: string; - export let isOpen = $accordionState.has(key); - export let autoScrollTo = false; - export let icon = ''; + interface Props { + title: string; + subtitle?: string; + key: string; + isOpen?: boolean; + autoScrollTo?: boolean; + icon?: string; + subtitleSnippet?: Snippet; + children?: Snippet; + } - let accordionElement: HTMLDivElement; + let { + title, + subtitle = '', + key, + isOpen = $bindable($accordionState.has(key)), + autoScrollTo = false, + icon = '', + subtitleSnippet, + children, + }: Props = $props(); - $: setIsOpen(isOpen); + let accordionElement: HTMLDivElement | undefined = $state(); const setIsOpen = (isOpen: boolean) => { if (isOpen) { @@ -23,7 +36,7 @@ if (autoScrollTo) { setTimeout(() => { - accordionElement.scrollIntoView({ + accordionElement?.scrollIntoView({ behavior: 'smooth', block: 'start', }); @@ -38,6 +51,15 @@ onDestroy(() => { setIsOpen(false); }); + + const onclick = () => { + isOpen = !isOpen; + setIsOpen(isOpen); + }; + + onMount(() => { + setIsOpen(isOpen); + }); </script> <div @@ -49,7 +71,7 @@ <button type="button" aria-expanded={isOpen} - on:click={() => (isOpen = !isOpen)} + {onclick} class="flex w-full place-items-center justify-between text-left" > <div> @@ -62,9 +84,9 @@ </h2> </div> - <slot name="subtitle"> + {#if subtitleSnippet}{@render subtitleSnippet()}{:else} <p class="text-sm dark:text-immich-dark-fg mt-1">{subtitle}</p> - </slot> + {/if} </div> <div @@ -88,7 +110,7 @@ {#if isOpen} <ul transition:slide={{ duration: 150 }} class="mb-2 ml-4"> - <slot /> + {@render children?.()} </ul> {/if} </div> diff --git a/web/src/lib/components/shared-components/settings/setting-buttons-row.svelte b/web/src/lib/components/shared-components/settings/setting-buttons-row.svelte index 97bcb1d499..95edac6dfb 100644 --- a/web/src/lib/components/shared-components/settings/setting-buttons-row.svelte +++ b/web/src/lib/components/shared-components/settings/setting-buttons-row.svelte @@ -3,10 +3,14 @@ import type { ResetOptions } from '$lib/utils/dipatch'; import { t } from 'svelte-i18n'; - export let showResetToDefault = true; - export let disabled = false; - export let onReset: (options: ResetOptions) => void; - export let onSave: () => void; + interface Props { + showResetToDefault?: boolean; + disabled?: boolean; + onReset: (options: ResetOptions) => void; + onSave: () => void; + } + + let { showResetToDefault = true, disabled = false, onReset, onSave }: Props = $props(); </script> <div class="mt-8 flex justify-between gap-2"> @@ -14,7 +18,7 @@ {#if showResetToDefault} <button type="button" - on:click={() => onReset({ default: true })} + onclick={() => onReset({ default: true })} class="bg-none text-sm font-medium text-immich-primary hover:text-immich-primary/75 dark:text-immich-dark-primary hover:dark:text-immich-dark-primary/75" > {$t('reset_to_default')} @@ -23,7 +27,7 @@ </div> <div class="right"> - <Button {disabled} size="sm" color="gray" on:click={() => onReset({ default: false })}>{$t('reset')}</Button> - <Button type="submit" {disabled} size="sm" on:click={() => onSave()}>{$t('save')}</Button> + <Button {disabled} size="sm" color="gray" onclick={() => onReset({ default: false })}>{$t('reset')}</Button> + <Button type="submit" {disabled} size="sm" onclick={() => onSave()}>{$t('save')}</Button> </div> </div> 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 3def0ce08d..09f0ea438b 100644 --- a/web/src/lib/components/shared-components/settings/setting-checkboxes.svelte +++ b/web/src/lib/components/shared-components/settings/setting-checkboxes.svelte @@ -4,13 +4,25 @@ import { fly } from 'svelte/transition'; import { t } from 'svelte-i18n'; - export let value: string[]; - export let options: { value: string; text: string }[]; - export let label = ''; - export let desc = ''; - export let name = ''; - export let isEdited = false; - export let disabled = false; + interface Props { + value: string[]; + options: { value: string; text: string }[]; + label?: string; + desc?: string; + name?: string; + isEdited?: boolean; + disabled?: boolean; + } + + let { + value = $bindable(), + options, + label = '', + desc = '', + name = '', + isEdited = false, + disabled = false, + }: Props = $props(); function handleCheckboxChange(option: string) { value = value.includes(option) ? value.filter((item) => item !== option) : [...value, option]; @@ -46,7 +58,7 @@ checked={value.includes(option.value)} {disabled} labelClass="text-gray-500 dark:text-gray-300" - on:change={() => handleCheckboxChange(option.value)} + onchange={() => handleCheckboxChange(option.value)} /> {/each} </div> diff --git a/web/src/lib/components/shared-components/settings/setting-combobox.svelte b/web/src/lib/components/shared-components/settings/setting-combobox.svelte index 722af048a5..5314ad7193 100644 --- a/web/src/lib/components/shared-components/settings/setting-combobox.svelte +++ b/web/src/lib/components/shared-components/settings/setting-combobox.svelte @@ -3,14 +3,29 @@ import { fly } from 'svelte/transition'; import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte'; import { t } from 'svelte-i18n'; + import type { Snippet } from 'svelte'; - export let title: string; - export let comboboxPlaceholder: string; - export let subtitle = ''; - export let isEdited = false; - export let options: ComboBoxOption[]; - export let selectedOption: ComboBoxOption; - export let onSelect: (combobox: ComboBoxOption | undefined) => void; + interface Props { + title: string; + comboboxPlaceholder: string; + subtitle?: string; + isEdited?: boolean; + options: ComboBoxOption[]; + selectedOption: ComboBoxOption; + onSelect: (combobox: ComboBoxOption | undefined) => void; + children?: Snippet; + } + + let { + title, + comboboxPlaceholder, + subtitle = '', + isEdited = false, + options, + selectedOption, + onSelect, + children, + }: Props = $props(); </script> <div class="grid grid-cols-2"> @@ -33,6 +48,6 @@ </div> <div class="flex items-center"> <Combobox label={title} hideLabel={true} {selectedOption} {options} placeholder={comboboxPlaceholder} {onSelect} /> - <slot /> + {@render children?.()} </div> </div> diff --git a/web/src/lib/components/shared-components/settings/setting-dropdown.svelte b/web/src/lib/components/shared-components/settings/setting-dropdown.svelte index 20324fe4f8..57e78e6c6f 100644 --- a/web/src/lib/components/shared-components/settings/setting-dropdown.svelte +++ b/web/src/lib/components/shared-components/settings/setting-dropdown.svelte @@ -3,14 +3,27 @@ import { fly } from 'svelte/transition'; import Dropdown, { type RenderedOption } from '$lib/components/elements/dropdown.svelte'; import { t } from 'svelte-i18n'; + import type { Snippet } from 'svelte'; - export let title: string; - export let subtitle = ''; - export let options: RenderedOption[]; - export let selectedOption: RenderedOption; - export let isEdited = false; + interface Props { + title: string; + subtitle?: string; + options: RenderedOption[]; + selectedOption: RenderedOption; + isEdited?: boolean; + onToggle: (option: RenderedOption) => void; + children?: Snippet; + } - export let onToggle: (option: RenderedOption) => void; + let { + title, + subtitle = '', + options, + selectedOption = $bindable(), + isEdited = false, + onToggle, + children, + }: Props = $props(); </script> <div class="flex place-items-center justify-between"> @@ -30,7 +43,7 @@ </div> <p class="text-sm dark:text-immich-dark-fg">{subtitle}</p> - <slot /> + {@render children?.()} </div> <div class="w-fit"> <Dropdown diff --git a/web/src/lib/components/shared-components/settings/setting-input-field.spec.ts b/web/src/lib/components/shared-components/settings/setting-input-field.spec.ts index 642492dda5..80cb920074 100644 --- a/web/src/lib/components/shared-components/settings/setting-input-field.spec.ts +++ b/web/src/lib/components/shared-components/settings/setting-input-field.spec.ts @@ -1,7 +1,7 @@ +import { SettingInputFieldType } from '$lib/constants'; import { render } from '@testing-library/svelte'; import userEvent from '@testing-library/user-event'; -// @ts-expect-error the import works but tsc check errors -import SettingInputField, { SettingInputFieldType } from './setting-input-field.svelte'; +import SettingInputField from './setting-input-field.svelte'; describe('SettingInputField component', () => { it('validates number input on blur', async () => { 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 410adc6458..1463cc4840 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 @@ -1,36 +1,47 @@ -<script lang="ts" context="module"> - export enum SettingInputFieldType { - EMAIL = 'email', - TEXT = 'text', - NUMBER = 'number', - PASSWORD = 'password', - COLOR = 'color', - } -</script> - <script lang="ts"> import { quintOut } from 'svelte/easing'; import type { FormEventHandler } from 'svelte/elements'; import { fly } from 'svelte/transition'; import PasswordField from '../password-field.svelte'; import { t } from 'svelte-i18n'; - import { onMount, tick } from 'svelte'; + import { onMount, tick, type Snippet } from 'svelte'; + import { SettingInputFieldType } from '$lib/constants'; - export let inputType: SettingInputFieldType; - export let value: string | number; - export let min = Number.MIN_SAFE_INTEGER; - export let max = Number.MAX_SAFE_INTEGER; - export let step = '1'; - export let label = ''; - export let desc = ''; - export let title = ''; - export let required = false; - export let disabled = false; - export let isEdited = false; - export let autofocus = false; - export let passwordAutocomplete: AutoFill = 'current-password'; + interface Props { + inputType: SettingInputFieldType; + value: string | number; + min?: number; + max?: number; + step?: string; + label?: string; + description?: string; + title?: string; + required?: boolean; + disabled?: boolean; + isEdited?: boolean; + autofocus?: boolean; + passwordAutocomplete?: AutoFill; + descriptionSnippet?: Snippet; + } - let input: HTMLInputElement; + let { + inputType, + value = $bindable(), + min = Number.MIN_SAFE_INTEGER, + max = Number.MAX_SAFE_INTEGER, + step = '1', + label = '', + description = '', + title = '', + required = false, + disabled = false, + isEdited = false, + autofocus = false, + passwordAutocomplete = 'current-password', + descriptionSnippet, + }: Props = $props(); + + let input: HTMLInputElement | undefined = $state(); const handleChange: FormEventHandler<HTMLInputElement> = (e) => { value = e.currentTarget.value; @@ -73,12 +84,12 @@ {/if} </div> - {#if desc} + {#if description} <p class="immich-form-label pb-2 text-sm" id="{label}-desc"> - {desc} + {description} </p> {:else} - <slot name="desc" /> + {@render descriptionSnippet?.()} {/if} {#if inputType !== SettingInputFieldType.PASSWORD} @@ -87,7 +98,7 @@ <input bind:this={input} class="immich-form-input w-full pb-2 rounded-none mr-1" - aria-describedby={desc ? `${label}-desc` : undefined} + aria-describedby={description ? `${label}-desc` : undefined} aria-labelledby="{label}-label" id={label} name={label} @@ -97,7 +108,7 @@ {step} {required} {value} - on:change={handleChange} + onchange={handleChange} {disabled} {title} /> @@ -107,7 +118,7 @@ bind:this={input} class="immich-form-input w-full pb-2" class:color-picker={inputType === SettingInputFieldType.COLOR} - aria-describedby={desc ? `${label}-desc` : undefined} + aria-describedby={description ? `${label}-desc` : undefined} aria-labelledby="{label}-label" id={label} name={label} @@ -117,14 +128,14 @@ {step} {required} {value} - on:change={handleChange} + onchange={handleChange} {disabled} {title} /> </div> {:else} <PasswordField - aria-describedby={desc ? `${label}-desc` : undefined} + aria-describedby={description ? `${label}-desc` : undefined} aria-labelledby="{label}-label" id={label} name={label} 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 92cabbff25..44f03075da 100644 --- a/web/src/lib/components/shared-components/settings/setting-select.svelte +++ b/web/src/lib/components/shared-components/settings/setting-select.svelte @@ -5,15 +5,29 @@ import Icon from '$lib/components/elements/icon.svelte'; import { mdiChevronDown } from '@mdi/js'; - export let value: string | number; - export let options: { value: string | number; text: string }[]; - export let label = ''; - export let desc = ''; - export let name = ''; - export let isEdited = false; - export let number = false; - export let disabled = false; - export let onSelect: (setting: string | number) => void = () => {}; + interface Props { + value: string | number; + options: { value: string | number; text: string }[]; + label?: string; + desc?: string; + name?: string; + isEdited?: boolean; + number?: boolean; + disabled?: boolean; + onSelect?: (setting: string | number) => void; + } + + let { + value = $bindable(), + options, + label = '', + desc = '', + name = '', + isEdited = false, + number = false, + disabled = false, + onSelect = () => {}, + }: Props = $props(); const handleChange = (e: Event) => { value = (e.target as HTMLInputElement).value; @@ -62,7 +76,7 @@ {name} id="{name}-select" bind:value - on:change={handleChange} + onchange={handleChange} > {#each options as option} <option value={option.value}>{option.text}</option> diff --git a/web/src/lib/components/shared-components/settings/setting-switch.svelte b/web/src/lib/components/shared-components/settings/setting-switch.svelte index 11716526f8..29c1f213d3 100644 --- a/web/src/lib/components/shared-components/settings/setting-switch.svelte +++ b/web/src/lib/components/shared-components/settings/setting-switch.svelte @@ -4,18 +4,32 @@ import Slider from '$lib/components/elements/slider.svelte'; import { generateId } from '$lib/utils/generate-id'; import { t } from 'svelte-i18n'; + import type { Snippet } from 'svelte'; - export let title: string; - export let subtitle = ''; - export let checked = false; - export let disabled = false; - export let isEdited = false; - export let onToggle: (isChecked: boolean) => void = () => {}; + interface Props { + title: string; + subtitle?: string; + checked?: boolean; + disabled?: boolean; + isEdited?: boolean; + onToggle?: (isChecked: boolean) => void; + children?: Snippet; + } + + let { + title, + subtitle = '', + checked = $bindable(false), + disabled = false, + isEdited = false, + onToggle = () => {}, + children, + }: Props = $props(); let id: string = generateId(); - $: sliderId = `${id}-slider`; - $: subtitleId = subtitle ? `${id}-subtitle` : undefined; + let sliderId = $derived(`${id}-slider`); + let subtitleId = $derived(subtitle ? `${id}-subtitle` : undefined); </script> <div class="flex place-items-center justify-between"> @@ -37,7 +51,7 @@ {#if subtitle} <p id={subtitleId} class="text-sm dark:text-immich-dark-fg">{subtitle}</p> {/if} - <slot /> + {@render children?.()} </div> <Slider id={sliderId} bind:checked {disabled} {onToggle} ariaDescribedBy={subtitleId} /> 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 5c7b138388..9f9f885263 100644 --- a/web/src/lib/components/shared-components/settings/setting-textarea.svelte +++ b/web/src/lib/components/shared-components/settings/setting-textarea.svelte @@ -2,13 +2,27 @@ import { quintOut } from 'svelte/easing'; import { fly } from 'svelte/transition'; import { t } from 'svelte-i18n'; + import type { Snippet } from 'svelte'; - export let value: string; - export let label = ''; - export let desc = ''; - export let required = false; - export let disabled = false; - export let isEdited = false; + interface Props { + value: string; + label?: string; + description?: string; + required?: boolean; + disabled?: boolean; + isEdited?: boolean; + descriptionSnippet?: Snippet; + } + + let { + value = $bindable(), + label = '', + description = '', + required = false, + disabled = false, + isEdited = false, + descriptionSnippet, + }: Props = $props(); const handleInput = (e: Event) => { value = (e.target as HTMLInputElement).value; @@ -32,23 +46,23 @@ {/if} </div> - {#if desc} + {#if description} <p class="immich-form-label pb-2 text-sm" id="{label}-desc"> - {desc} + {description} </p> {:else} - <slot name="desc" /> + {@render descriptionSnippet?.()} {/if} <textarea class="immich-form-input w-full pb-2" - aria-describedby={desc ? `${label}-desc` : undefined} + aria-describedby={description ? `${label}-desc` : undefined} aria-labelledby="{label}-label" id={label} name={label} {required} {value} - on:input={handleInput} + oninput={handleInput} {disabled} ></textarea> </div> diff --git a/web/src/lib/components/shared-components/show-shortcuts.svelte b/web/src/lib/components/shared-components/show-shortcuts.svelte index 2bd1b8976b..a3cfd83ad5 100644 --- a/web/src/lib/components/shared-components/show-shortcuts.svelte +++ b/web/src/lib/components/shared-components/show-shortcuts.svelte @@ -15,25 +15,31 @@ info?: string; } - export let onClose: () => void; + interface Props { + onClose: () => void; + shortcuts?: Shortcuts; + } - export let shortcuts: Shortcuts = { - general: [ - { key: ['←', '→'], action: $t('previous_or_next_photo') }, - { key: ['Esc'], action: $t('back_close_deselect') }, - { key: ['Ctrl', 'k'], action: $t('search_your_photos') }, - { key: ['Ctrl', '⇧', 'k'], action: $t('open_the_search_filters') }, - ], - actions: [ - { key: ['f'], action: $t('favorite_or_unfavorite_photo') }, - { key: ['i'], action: $t('show_or_hide_info') }, - { key: ['s'], action: $t('stack_selected_photos') }, - { key: ['⇧', 'a'], action: $t('archive_or_unarchive_photo') }, - { key: ['⇧', 'd'], action: $t('download') }, - { key: ['Space'], action: $t('play_or_pause_video') }, - { key: ['Del'], action: $t('trash_delete_asset'), info: $t('shift_to_permanent_delete') }, - ], - }; + let { + onClose, + shortcuts = { + general: [ + { key: ['←', '→'], action: $t('previous_or_next_photo') }, + { key: ['Esc'], action: $t('back_close_deselect') }, + { key: ['Ctrl', 'k'], action: $t('search_your_photos') }, + { key: ['Ctrl', '⇧', 'k'], action: $t('open_the_search_filters') }, + ], + actions: [ + { key: ['f'], action: $t('favorite_or_unfavorite_photo') }, + { key: ['i'], action: $t('show_or_hide_info') }, + { key: ['s'], action: $t('stack_selected_photos') }, + { key: ['⇧', 'a'], action: $t('archive_or_unarchive_photo') }, + { key: ['⇧', 'd'], action: $t('download') }, + { key: ['Space'], action: $t('play_or_pause_video') }, + { key: ['Del'], action: $t('trash_delete_asset'), info: $t('shift_to_permanent_delete') }, + ], + }, + }: Props = $props(); </script> <FullScreenModal title={$t('keyboard_shortcuts')} width="auto" {onClose}> diff --git a/web/src/lib/components/shared-components/side-bar/more-information-albums.svelte b/web/src/lib/components/shared-components/side-bar/more-information-albums.svelte index 68c58ab155..58ce0c8574 100644 --- a/web/src/lib/components/shared-components/side-bar/more-information-albums.svelte +++ b/web/src/lib/components/shared-components/side-bar/more-information-albums.svelte @@ -3,7 +3,11 @@ import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; import { t } from 'svelte-i18n'; - export let albumType: keyof AlbumStatisticsResponseDto; + interface Props { + albumType: keyof AlbumStatisticsResponseDto; + } + + let { albumType }: Props = $props(); const handleAlbumCount = async () => { try { diff --git a/web/src/lib/components/shared-components/side-bar/more-information-assets.svelte b/web/src/lib/components/shared-components/side-bar/more-information-assets.svelte index 1da245390b..5e4589be18 100644 --- a/web/src/lib/components/shared-components/side-bar/more-information-assets.svelte +++ b/web/src/lib/components/shared-components/side-bar/more-information-assets.svelte @@ -3,7 +3,11 @@ import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; import { t } from 'svelte-i18n'; - export let assetStats: NonNullable<Parameters<typeof getAssetStatistics>[0]>; + interface Props { + assetStats: NonNullable<Parameters<typeof getAssetStatistics>[0]>; + } + + let { assetStats }: Props = $props(); </script> {#await getAssetStatistics(assetStats)} diff --git a/web/src/lib/components/shared-components/side-bar/purchase-info.svelte b/web/src/lib/components/shared-components/side-bar/purchase-info.svelte index a284c7efc1..2c4ab8818c 100644 --- a/web/src/lib/components/shared-components/side-bar/purchase-info.svelte +++ b/web/src/lib/components/shared-components/side-bar/purchase-info.svelte @@ -18,12 +18,12 @@ import { getButtonVisibility } from '$lib/utils/purchase-utils'; import SupporterBadge from '$lib/components/shared-components/side-bar/supporter-badge.svelte'; - let showMessage = false; - let isOpen = false; - let hoverMessage = false; - let hoverButton = false; + let showMessage = $state(false); + let isOpen = $state(false); + let hoverMessage = $state(false); + let hoverButton = $state(false); - let showBuyButton = getButtonVisibility(); + let showBuyButton = $state(getButtonVisibility()); const { isPurchased } = purchaseStore; @@ -63,13 +63,15 @@ } }; - $: if (showMessage && !hoverMessage && !hoverButton) { - setTimeout(() => { - if (!hoverMessage && !hoverButton) { - showMessage = false; - } - }, 300); - } + $effect(() => { + if (showMessage && !hoverMessage && !hoverButton) { + setTimeout(() => { + if (!hoverMessage && !hoverButton) { + showMessage = false; + } + }, 300); + } + }); </script> {#if isOpen} @@ -79,7 +81,7 @@ <div class="hidden md:block license-status pl-4 text-sm"> {#if $isPurchased && $preferences.purchase.showSupportBadge} <button - on:click={() => goto(`${AppRoute.USER_SETTINGS}?isOpen=user-purchase-settings`)} + onclick={() => goto(`${AppRoute.USER_SETTINGS}?isOpen=user-purchase-settings`)} class="w-full" type="button" > @@ -88,11 +90,11 @@ {:else if !$isPurchased && showBuyButton && getAccountAge() > 14} <button type="button" - on:click={openPurchaseModal} - on:mouseover={onButtonHover} - on:mouseleave={() => (hoverButton = false)} - on:focus={onButtonHover} - on:blur={() => (hoverButton = false)} + onclick={openPurchaseModal} + onmouseover={onButtonHover} + onmouseleave={() => (hoverButton = false)} + onfocus={onButtonHover} + onblur={() => (hoverButton = false)} class="p-2 flex justify-between place-items-center place-content-center border border-immich-primary/20 dark:border-immich-dark-primary/10 mt-2 rounded-lg shadow-md dark:bg-immich-dark-primary/10 w-full" > <div class="flex justify-between w-full place-items-center place-content-center"> @@ -122,10 +124,10 @@ <div class="w-[500px] absolute bottom-[75px] left-[255px] bg-gray-50 dark:border-gray-800 border border-gray-200 dark:bg-immich-dark-gray dark:text-white text-black rounded-3xl z-10 shadow-2xl px-8 py-6" transition:fade={{ duration: 150 }} - on:mouseover={() => (hoverMessage = true)} - on:mouseleave={() => (hoverMessage = false)} - on:focus={() => (hoverMessage = true)} - on:blur={() => (hoverMessage = false)} + onmouseover={() => (hoverMessage = true)} + onmouseleave={() => (hoverMessage = false)} + onfocus={() => (hoverMessage = true)} + onblur={() => (hoverMessage = false)} role="dialog" > <div class="flex justify-between place-items-center"> @@ -134,7 +136,7 @@ </div> <CircleIconButton icon={mdiClose} - on:click={() => { + onclick={() => { showMessage = false; }} title={$t('close')} @@ -157,12 +159,12 @@ </p> </div> - <Button class="mt-2" fullwidth on:click={openPurchaseModal}>{$t('purchase_button_buy_immich')}</Button> + <Button class="mt-2" fullwidth onclick={openPurchaseModal}>{$t('purchase_button_buy_immich')}</Button> <div class="mt-3 flex gap-4"> - <Button size="sm" fullwidth shadow={false} color="transparent-gray" on:click={() => hideButton(true)}> + <Button size="sm" fullwidth shadow={false} color="transparent-gray" onclick={() => hideButton(true)}> {$t('purchase_button_never_show_again')} </Button> - <Button size="sm" fullwidth shadow={false} color="transparent-gray" on:click={() => hideButton(false)}> + <Button size="sm" fullwidth shadow={false} color="transparent-gray" onclick={() => hideButton(false)}> {$t('purchase_button_reminder')} </Button> </div> diff --git a/web/src/lib/components/shared-components/side-bar/server-status.svelte b/web/src/lib/components/shared-components/side-bar/server-status.svelte index 9774c07c63..2a0e6a0821 100644 --- a/web/src/lib/components/shared-components/side-bar/server-status.svelte +++ b/web/src/lib/components/shared-components/side-bar/server-status.svelte @@ -15,21 +15,22 @@ const { serverVersion, connected } = websocketStore; - let isOpen = false; + let isOpen = $state(false); - $: isMain = info?.sourceRef === 'main' && info.repository === 'immich-app/immich'; - $: version = $serverVersion ? `v${$serverVersion.major}.${$serverVersion.minor}.${$serverVersion.patch}` : null; - - let info: ServerAboutResponseDto; - let versions: ServerVersionHistoryResponseDto[] = []; + let info: ServerAboutResponseDto | undefined = $state(); + let versions: ServerVersionHistoryResponseDto[] = $state([]); onMount(async () => { await requestServerInfo(); [info, versions] = await Promise.all([getAboutInfo(), getVersionHistory()]); }); + let isMain = $derived(info?.sourceRef === 'main' && info.repository === 'immich-app/immich'); + let version = $derived( + $serverVersion ? `v${$serverVersion.major}.${$serverVersion.minor}.${$serverVersion.patch}` : null, + ); </script> -{#if isOpen} +{#if isOpen && info} <ServerAboutModal onClose={() => (isOpen = false)} {info} {versions} /> {/if} @@ -50,9 +51,9 @@ <div class="flex justify-between justify-items-center"> {#if $connected && version} - <button type="button" on:click={() => (isOpen = true)} class="dark:text-immich-gray flex gap-1"> + <button type="button" onclick={() => (isOpen = true)} class="dark:text-immich-gray flex gap-1"> {#if isMain} - <Icon path={mdiAlert} size="1.5em" color="#ffcc4d" /> {info.sourceRef} + <Icon path={mdiAlert} size="1.5em" color="#ffcc4d" /> {info?.sourceRef} {:else} {version} {/if} diff --git a/web/src/lib/components/shared-components/side-bar/side-bar-link.svelte b/web/src/lib/components/shared-components/side-bar/side-bar-link.svelte index 4590b12255..d3fd94ae08 100644 --- a/web/src/lib/components/shared-components/side-bar/side-bar-link.svelte +++ b/web/src/lib/components/shared-components/side-bar/side-bar-link.svelte @@ -4,17 +4,34 @@ import { mdiInformationOutline } from '@mdi/js'; import { resolveRoute } from '$app/paths'; import { page } from '$app/stores'; + import type { Snippet } from 'svelte'; - export let title: string; - export let routeId: string; - export let icon: string; - export let flippedLogo = false; - export let isSelected = false; - export let preloadData = true; + interface Props { + title: string; + routeId: string; + icon: string; + flippedLogo?: boolean; + isSelected?: boolean; + preloadData?: boolean; + moreInformation?: Snippet; + } - let showMoreInformation = false; - $: routePath = resolveRoute(routeId, {}); - $: isSelected = ($page.route.id?.match(/^\/(admin|\(user\))\/[^/]*/) || [])[0] === routeId; + let { + title, + routeId, + icon, + flippedLogo = false, + isSelected = $bindable(false), + preloadData = true, + moreInformation, + }: Props = $props(); + + let showMoreInformation = $state(false); + let routePath = $derived(resolveRoute(routeId, {})); + + $effect(() => { + isSelected = ($page.route.id?.match(/^\/(admin|\(user\))\/[^/]*/) || [])[0] === routeId; + }); </script> <a @@ -37,12 +54,12 @@ <div class="h-0 overflow-hidden transition-[height] delay-1000 duration-100 sm:group-hover:h-auto group-hover:sm:overflow-visible md:h-auto md:overflow-visible" > - {#if $$slots.moreInformation} - <!-- svelte-ignore a11y-no-static-element-interactions --> + {#if moreInformation} + <!-- svelte-ignore a11y_no_static_element_interactions --> <div class="relative flex cursor-default select-none justify-center" - on:mouseenter={() => (showMoreInformation = true)} - on:mouseleave={() => (showMoreInformation = false)} + onmouseenter={() => (showMoreInformation = true)} + onmouseleave={() => (showMoreInformation = false)} > <div class="p-1 text-gray-600 hover:cursor-help dark:text-gray-400"> <Icon path={mdiInformationOutline} /> @@ -55,7 +72,7 @@ class:hidden={!showMoreInformation} transition:fade={{ duration: 200 }} > - <slot name="moreInformation" /> + {@render moreInformation?.()} </div> </div> {/if} diff --git a/web/src/lib/components/shared-components/side-bar/side-bar-section.svelte b/web/src/lib/components/shared-components/side-bar/side-bar-section.svelte index 233010153f..37867da7af 100644 --- a/web/src/lib/components/shared-components/side-bar/side-bar-section.svelte +++ b/web/src/lib/components/shared-components/side-bar/side-bar-section.svelte @@ -1,4 +1,11 @@ <script lang="ts"> + import type { Snippet } from 'svelte'; + + interface Props { + children?: Snippet; + } + + let { children }: Props = $props(); </script> <section @@ -6,5 +13,5 @@ tabindex="-1" class="immich-scrollbar group relative z-10 flex w-18 flex-col gap-1 overflow-y-auto bg-immich-bg pt-8 transition-all duration-200 dark:bg-immich-dark-bg hover:sm:w-64 hover:sm:border-r hover:sm:pr-6 hover:sm:shadow-2xl hover:sm:dark:border-r-immich-dark-gray md:w-64 md:pr-6 hover:md:border-none hover:md:shadow-none" > - <slot /> + {@render children?.()} </section> diff --git a/web/src/lib/components/shared-components/side-bar/side-bar.svelte b/web/src/lib/components/shared-components/side-bar/side-bar.svelte index fab7c6ed6d..54607e1779 100644 --- a/web/src/lib/components/shared-components/side-bar/side-bar.svelte +++ b/web/src/lib/components/shared-components/side-bar/side-bar.svelte @@ -30,14 +30,14 @@ import BottomInfo from '$lib/components/shared-components/side-bar/bottom-info.svelte'; import { preferences } from '$lib/stores/user.store'; - let isArchiveSelected: boolean; - let isFavoritesSelected: boolean; - let isMapSelected: boolean; - let isPeopleSelected: boolean; - let isPhotosSelected: boolean; - let isSharingSelected: boolean; - let isTrashSelected: boolean; - let isUtilitiesSelected: boolean; + let isArchiveSelected: boolean = $state(false); + let isFavoritesSelected: boolean = $state(false); + let isMapSelected: boolean = $state(false); + let isPeopleSelected: boolean = $state(false); + let isPhotosSelected: boolean = $state(false); + let isSharingSelected: boolean = $state(false); + let isTrashSelected: boolean = $state(false); + let isUtilitiesSelected: boolean = $state(false); </script> <SideBarSection> @@ -48,9 +48,9 @@ bind:isSelected={isPhotosSelected} icon={isPhotosSelected ? mdiImageMultiple : mdiImageMultipleOutline} > - <svelte:fragment slot="moreInformation"> + {#snippet moreInformation()} <MoreInformationAssets assetStats={{ isArchived: false }} /> - </svelte:fragment> + {/snippet} </SideBarLink> {#if $featureFlags.search} @@ -81,9 +81,9 @@ icon={isSharingSelected ? mdiAccountMultiple : mdiAccountMultipleOutline} bind:isSelected={isSharingSelected} > - <svelte:fragment slot="moreInformation"> + {#snippet moreInformation()} <MoreInformationAlbums albumType="shared" /> - </svelte:fragment> + {/snippet} </SideBarLink> <div class="text-xs transition-all duration-200 dark:text-immich-dark-fg"> @@ -97,15 +97,15 @@ icon={isFavoritesSelected ? mdiHeart : mdiHeartOutline} bind:isSelected={isFavoritesSelected} > - <svelte:fragment slot="moreInformation"> + {#snippet moreInformation()} <MoreInformationAssets assetStats={{ isFavorite: true }} /> - </svelte:fragment> + {/snippet} </SideBarLink> <SideBarLink title={$t('albums')} routeId="/(user)/albums" icon={mdiImageAlbum} flippedLogo> - <svelte:fragment slot="moreInformation"> + {#snippet moreInformation()} <MoreInformationAlbums albumType="owned" /> - </svelte:fragment> + {/snippet} </SideBarLink> {#if $preferences.tags.enabled && $preferences.tags.sidebarWeb} @@ -129,9 +129,9 @@ bind:isSelected={isArchiveSelected} icon={isArchiveSelected ? mdiArchiveArrowDown : mdiArchiveArrowDownOutline} > - <svelte:fragment slot="moreInformation"> + {#snippet moreInformation()} <MoreInformationAssets assetStats={{ isArchived: true }} /> - </svelte:fragment> + {/snippet} </SideBarLink> {#if $featureFlags.trash} @@ -141,9 +141,9 @@ bind:isSelected={isTrashSelected} icon={isTrashSelected ? mdiTrashCan : mdiTrashCanOutline} > - <svelte:fragment slot="moreInformation"> + {#snippet moreInformation()} <MoreInformationAssets assetStats={{ isTrashed: true }} /> - </svelte:fragment> + {/snippet} </SideBarLink> {/if} </nav> diff --git a/web/src/lib/components/shared-components/side-bar/storage-space.svelte b/web/src/lib/components/shared-components/side-bar/storage-space.svelte index c62b73e1b2..c0de9378ac 100644 --- a/web/src/lib/components/shared-components/side-bar/storage-space.svelte +++ b/web/src/lib/components/shared-components/side-bar/storage-space.svelte @@ -8,12 +8,12 @@ import { getByteUnitString } from '../../../utils/byte-units'; import LoadingSpinner from '../loading-spinner.svelte'; - let usageClasses = ''; + let usageClasses = $state(''); - $: hasQuota = $user?.quotaSizeInBytes !== null; - $: availableBytes = (hasQuota ? $user?.quotaSizeInBytes : $serverInfo?.diskSizeRaw) || 0; - $: usedBytes = (hasQuota ? $user?.quotaUsageInBytes : $serverInfo?.diskUseRaw) || 0; - $: usedPercentage = Math.min(Math.round((usedBytes / availableBytes) * 100), 100); + let hasQuota = $derived($user?.quotaSizeInBytes !== null); + let availableBytes = $derived((hasQuota ? $user?.quotaSizeInBytes : $serverInfo?.diskSizeRaw) || 0); + let usedBytes = $derived((hasQuota ? $user?.quotaUsageInBytes : $serverInfo?.diskUseRaw) || 0); + let usedPercentage = $derived(Math.min(Math.round((usedBytes / availableBytes) * 100), 100)); const onUpdate = () => { usageClasses = getUsageClass(); @@ -31,9 +31,11 @@ return 'bg-immich-primary dark:bg-immich-dark-primary'; }; - $: if ($user) { - onUpdate(); - } + $effect(() => { + if ($user) { + onUpdate(); + } + }); onMount(async () => { await requestServerInfo(); diff --git a/web/src/lib/components/shared-components/side-bar/supporter-badge.svelte b/web/src/lib/components/shared-components/side-bar/supporter-badge.svelte index f2cb326c39..3d5e815996 100644 --- a/web/src/lib/components/shared-components/side-bar/supporter-badge.svelte +++ b/web/src/lib/components/shared-components/side-bar/supporter-badge.svelte @@ -2,8 +2,12 @@ import { t } from 'svelte-i18n'; import ImmichLogo from '../immich-logo.svelte'; - export let centered = false; - export let logoSize: 'sm' | 'lg' = 'sm'; + interface Props { + centered?: boolean; + logoSize?: 'sm' | 'lg'; + } + + let { centered = false, logoSize = 'sm' }: Props = $props(); </script> <div diff --git a/web/src/lib/components/shared-components/single-grid-row.svelte b/web/src/lib/components/shared-components/single-grid-row.svelte index 90020f2922..7764b9eb17 100644 --- a/web/src/lib/components/shared-components/single-grid-row.svelte +++ b/web/src/lib/components/shared-components/single-grid-row.svelte @@ -1,10 +1,14 @@ <script lang="ts"> - let className = ''; - export { className as class }; - export let itemCount = 1; + interface Props { + class?: string; + itemCount?: number; + children?: import('svelte').Snippet<[{ itemCount: number }]>; + } - let container: HTMLElement | undefined; - let contentRect: DOMRectReadOnly | undefined; + let { class: className = '', itemCount = $bindable(1), children }: Props = $props(); + + let container: HTMLElement | undefined = $state(); + let contentRect: DOMRectReadOnly | undefined = $state(); const getGridGap = (element: Element) => { const style = getComputedStyle(element); @@ -28,11 +32,13 @@ return Math.floor((containerWidth + columnGap) / (childWidth + columnGap)) || 1; }; - $: if (container && contentRect) { - itemCount = getItemCount(container, contentRect.width); - } + $effect(() => { + if (container && contentRect) { + itemCount = getItemCount(container, contentRect.width); + } + }); </script> <div class={className} bind:this={container} bind:contentRect> - <slot {itemCount} /> + {@render children?.({ itemCount })} </div> diff --git a/web/src/lib/components/shared-components/star-rating.svelte b/web/src/lib/components/shared-components/star-rating.svelte index ee1b2b7433..333248c227 100644 --- a/web/src/lib/components/shared-components/star-rating.svelte +++ b/web/src/lib/components/shared-components/star-rating.svelte @@ -5,17 +5,23 @@ import { generateId } from '$lib/utils/generate-id'; import { t } from 'svelte-i18n'; - export let count = 5; - export let rating: number; - export let readOnly = false; - export let onRating: (rating: number) => void | undefined; + interface Props { + count?: number; + rating: number; + readOnly?: boolean; + onRating: (rating: number) => void | undefined; + } - let ratingSelection = 0; - let hoverRating = 0; - let focusRating = 0; + let { count = 5, rating, readOnly = false, onRating }: Props = $props(); + + let ratingSelection = $state(rating); + let hoverRating = $state(0); + let focusRating = $state(0); let timeoutId: ReturnType<typeof setTimeout> | undefined; - $: ratingSelection = rating; + $effect(() => { + ratingSelection = rating; + }); const starIcon = 'M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.007 5.404.433c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.433 2.082-5.006z'; @@ -53,10 +59,10 @@ }; </script> -<!-- svelte-ignore a11y-mouse-events-have-key-events --> +<!-- svelte-ignore a11y_mouse_events_have_key_events --> <fieldset class="text-immich-primary dark:text-immich-dark-primary w-fit cursor-default" - on:mouseleave={() => setHoverRating(0)} + onmouseleave={() => setHoverRating(0)} use:focusOutside={{ onFocusOut: reset }} use:shortcuts={[ { shortcut: { key: 'ArrowLeft' }, preventDefault: false, onShortcut: (event) => event.stopPropagation() }, @@ -69,13 +75,13 @@ {@const value = index + 1} {@const filled = hoverRating >= value || (hoverRating === 0 && ratingSelection >= value)} {@const starId = `${id}-${value}`} - <!-- svelte-ignore a11y-mouse-events-have-key-events --> - <!-- svelte-ignore a11y-no-noninteractive-tabindex --> + <!-- svelte-ignore a11y_mouse_events_have_key_events --> + <!-- svelte-ignore a11y_no_noninteractive_tabindex --> <label for={starId} class:cursor-pointer={!readOnly} class:ring-2={focusRating === value} - on:mouseover={() => setHoverRating(value)} + onmouseover={() => setHoverRating(value)} tabindex={-1} data-testid="star" > @@ -96,10 +102,10 @@ id={starId} bind:group={ratingSelection} disabled={readOnly} - on:focus={() => { + onfocus={() => { focusRating = value; }} - on:change={() => handleSelectDebounced(value)} + onchange={() => handleSelectDebounced(value)} class="sr-only" /> {/each} @@ -108,7 +114,7 @@ {#if ratingSelection > 0 && !readOnly} <button type="button" - on:click={() => { + onclick={() => { ratingSelection = 0; handleSelect(ratingSelection); }} diff --git a/web/src/lib/components/shared-components/theme-button.svelte b/web/src/lib/components/shared-components/theme-button.svelte index f5ba87799b..446668256f 100644 --- a/web/src/lib/components/shared-components/theme-button.svelte +++ b/web/src/lib/components/shared-components/theme-button.svelte @@ -5,14 +5,15 @@ import { colorTheme, handleToggleTheme } from '$lib/stores/preferences.store'; import { t } from 'svelte-i18n'; - // svelte-ignore reactive_declaration_non_reactive_property - $: icon = $colorTheme.value === Theme.LIGHT ? moonPath : sunPath; - // svelte-ignore reactive_declaration_non_reactive_property - $: viewBox = $colorTheme.value === Theme.LIGHT ? moonViewBox : sunViewBox; - // svelte-ignore reactive_declaration_non_reactive_property - $: isDark = $colorTheme.value === Theme.DARK; + let icon = $derived($colorTheme.value === Theme.LIGHT ? moonPath : sunPath); + let viewBox = $derived($colorTheme.value === Theme.LIGHT ? moonViewBox : sunViewBox); + let isDark = $derived($colorTheme.value === Theme.DARK); - export let padding: Padding = '3'; + interface Props { + padding?: Padding; + } + + let { padding = '3' }: Props = $props(); </script> {#if !$colorTheme.system} @@ -22,7 +23,7 @@ {viewBox} role="switch" aria-checked={isDark ? 'true' : 'false'} - on:click={handleToggleTheme} + onclick={handleToggleTheme} {padding} /> {/if} diff --git a/web/src/lib/components/shared-components/tree/breadcrumbs.svelte b/web/src/lib/components/shared-components/tree/breadcrumbs.svelte index a3c49a1430..1d841339bc 100644 --- a/web/src/lib/components/shared-components/tree/breadcrumbs.svelte +++ b/web/src/lib/components/shared-components/tree/breadcrumbs.svelte @@ -4,12 +4,16 @@ import { mdiArrowUpLeft, mdiChevronRight } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let pathSegments: string[] = []; - export let getLink: (path: string) => string; - export let title: string; - export let icon: string; + interface Props { + pathSegments?: string[]; + getLink: (path: string) => string; + title: string; + icon: string; + } - $: isRoot = pathSegments.length === 0; + let { pathSegments = [], getLink, title, icon }: Props = $props(); + + let isRoot = $derived(pathSegments.length === 0); </script> <nav class="flex items-center py-2"> @@ -21,6 +25,7 @@ href={getLink(pathSegments.slice(0, -1).join('/'))} class="mr-2" padding="2" + onclick={() => {}} /> </div> {/if} @@ -37,6 +42,7 @@ size="1.25em" padding="2" aria-current={isRoot ? 'page' : undefined} + onclick={() => {}} /> </li> {#each pathSegments as segment, index} 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 759a3e5e65..1b4d30d050 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 @@ -1,9 +1,13 @@ <script lang="ts"> import Icon from '$lib/components/elements/icon.svelte'; - export let items: string[] = []; - export let icon: string; - export let onClick: (path: string) => void; + interface Props { + items?: string[]; + icon: string; + onClick: (path: string) => void; + } + + let { items = [], icon, onClick }: Props = $props(); </script> {#if items.length > 0} @@ -13,7 +17,7 @@ {#each items as 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" - on:click={() => onClick(item)} + onclick={() => onClick(item)} title={item} type="button" > 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 4bdc95db9f..c6db9fec8d 100644 --- a/web/src/lib/components/shared-components/tree/tree-items.svelte +++ b/web/src/lib/components/shared-components/tree/tree-items.svelte @@ -2,12 +2,16 @@ import Tree from '$lib/components/shared-components/tree/tree.svelte'; import { normalizeTreePath, type RecursiveObject } from '$lib/utils/tree-utils'; - export let items: RecursiveObject; - export let parent = ''; - export let active = ''; - export let icons: { default: string; active: string }; - export let getLink: (path: string) => string; - export let getColor: (path: string) => string | undefined = () => undefined; + interface Props { + items: RecursiveObject; + parent?: string; + active?: string; + icons: { default: string; active: string }; + getLink: (path: string) => string; + getColor?: (path: string) => string | undefined; + } + + let { items, parent = '', active = '', icons, getLink, getColor = () => undefined }: Props = $props(); </script> <ul class="list-none ml-2"> diff --git a/web/src/lib/components/shared-components/tree/tree.svelte b/web/src/lib/components/shared-components/tree/tree.svelte index 5c4b367a54..c6a13ec197 100644 --- a/web/src/lib/components/shared-components/tree/tree.svelte +++ b/web/src/lib/components/shared-components/tree/tree.svelte @@ -4,19 +4,31 @@ import { normalizeTreePath, type RecursiveObject } from '$lib/utils/tree-utils'; import { mdiChevronDown, mdiChevronRight } from '@mdi/js'; - export let tree: RecursiveObject; - export let parent: string; - export let value: string; - export let active = ''; - export let icons: { default: string; active: string }; - export let getLink: (path: string) => string; - export let getColor: (path: string) => string | undefined; + interface Props { + tree: RecursiveObject; + parent: string; + value: string; + active?: string; + icons: { default: string; active: string }; + getLink: (path: string) => string; + getColor: (path: string) => string | undefined; + } - $: path = normalizeTreePath(`${parent}/${value}`); - $: isActive = active === path || active.startsWith(`${path}/`); - $: isOpen = isActive; - $: isTarget = active === path; - $: color = getColor(path); + let { tree, parent, value, active = '', icons, getLink, getColor }: Props = $props(); + + let path = $derived(normalizeTreePath(`${parent}/${value}`)); + let isActive = $derived(active === path || active.startsWith(`${path}/`)); + let isOpen = $state(false); + $effect(() => { + isOpen = isActive; + }); + let isTarget = $derived(active === path); + let color = $derived(getColor(path)); + + const onclick = (event: MouseEvent) => { + event.preventDefault(); + isOpen = !isOpen; + }; </script> <a @@ -24,11 +36,7 @@ title={value} class={`flex flex-grow place-items-center pl-2 py-1 text-sm rounded-lg hover:bg-slate-200 dark:hover:bg-slate-800 hover:font-semibold ${isTarget ? 'bg-slate-100 dark:bg-slate-700 font-semibold text-immich-primary dark:text-immich-dark-primary' : 'dark:text-gray-200'}`} > - <button - type="button" - on:click|preventDefault={() => (isOpen = !isOpen)} - class={Object.values(tree).length === 0 ? 'invisible' : ''} - > + <button type="button" {onclick} class={Object.values(tree).length === 0 ? 'invisible' : ''}> <Icon path={isOpen ? mdiChevronDown : mdiChevronRight} class="text-gray-400" size={20} /> </button> <div> diff --git a/web/src/lib/components/shared-components/upload-asset-preview.svelte b/web/src/lib/components/shared-components/upload-asset-preview.svelte index 7765e2ce5c..bd3b7856d1 100644 --- a/web/src/lib/components/shared-components/upload-asset-preview.svelte +++ b/web/src/lib/components/shared-components/upload-asset-preview.svelte @@ -20,7 +20,11 @@ import { t } from 'svelte-i18n'; import { fade } from 'svelte/transition'; - export let uploadAsset: UploadAsset; + interface Props { + uploadAsset: UploadAsset; + } + + let { uploadAsset }: Props = $props(); const handleDismiss = (uploadAsset: UploadAsset) => { uploadAssetsStore.removeItem(uploadAsset.id); @@ -74,16 +78,16 @@ > <Icon path={mdiOpenInNew} size="20" /> </a> - <button type="button" on:click={() => handleDismiss(uploadAsset)} class="" aria-hidden="true" tabindex={-1}> + <button type="button" onclick={() => handleDismiss(uploadAsset)} class="" aria-hidden="true" tabindex={-1}> <Icon path={mdiClose} size="20" /> </button> </div> {:else if uploadAsset.state === UploadState.ERROR} <div class="flex items-center justify-between gap-1"> - <button type="button" on:click={() => handleRetry(uploadAsset)} class="" aria-hidden="true" tabindex={-1}> + <button type="button" onclick={() => handleRetry(uploadAsset)} class="" aria-hidden="true" tabindex={-1}> <Icon path={mdiRestart} size="20" /> </button> - <button type="button" on:click={() => handleDismiss(uploadAsset)} class="" aria-hidden="true" tabindex={-1}> + <button type="button" onclick={() => handleDismiss(uploadAsset)} class="" aria-hidden="true" tabindex={-1}> <Icon path={mdiClose} size="20" /> </button> </div> diff --git a/web/src/lib/components/shared-components/upload-panel.svelte b/web/src/lib/components/shared-components/upload-panel.svelte index d536053286..7dd6d25596 100644 --- a/web/src/lib/components/shared-components/upload-panel.svelte +++ b/web/src/lib/components/shared-components/upload-panel.svelte @@ -11,9 +11,9 @@ import { t } from 'svelte-i18n'; import { locale } from '$lib/stores/preferences.store'; - let showDetail = false; - let showOptions = false; - let concurrency = uploadExecutionQueue.concurrency; + let showDetail = $state(false); + let showOptions = $state(false); + let concurrency = $state(uploadExecutionQueue.concurrency); let { stats, isDismissible, isUploading, remainingUploads } = uploadAssetsStore; @@ -27,16 +27,18 @@ } }; - $: if ($isUploading) { - autoHide(); - } + $effect(() => { + if ($isUploading) { + autoHide(); + } + }); </script> {#if $isUploading} <div in:fade={{ duration: 250 }} out:fade={{ duration: 250 }} - on:outroend={() => { + onoutroend={() => { if ($stats.errors > 0) { notificationController.show({ message: $t('upload_errors', { values: { count: $stats.errors } }), @@ -92,14 +94,14 @@ icon={mdiCog} size="14" padding="1" - on:click={() => (showOptions = !showOptions)} + onclick={() => (showOptions = !showOptions)} /> <CircleIconButton title={$t('minimize')} icon={mdiWindowMinimize} size="14" padding="1" - on:click={() => (showDetail = false)} + onclick={() => (showDetail = false)} /> </div> {#if $isDismissible} @@ -108,7 +110,7 @@ icon={mdiCancel} size="14" padding="1" - on:click={() => uploadAssetsStore.dismissErrors()} + onclick={() => uploadAssetsStore.dismissErrors()} /> {/if} </div> @@ -128,7 +130,7 @@ max="50" step="1" bind:value={concurrency} - on:change={() => (uploadExecutionQueue.concurrency = concurrency)} + onchange={() => (uploadExecutionQueue.concurrency = concurrency)} /> </div> {/if} @@ -143,7 +145,7 @@ <button type="button" in:scale={{ duration: 250, easing: quartInOut }} - on:click={() => (showDetail = true)} + onclick={() => (showDetail = true)} class="absolute -left-4 -top-4 flex h-10 w-10 place-content-center place-items-center rounded-full bg-immich-primary p-5 text-xs text-gray-200" > {$remainingUploads.toLocaleString($locale)} @@ -152,7 +154,7 @@ <button type="button" in:scale={{ duration: 250, easing: quartInOut }} - on:click={() => (showDetail = true)} + onclick={() => (showDetail = true)} class="absolute -right-4 -top-4 flex h-10 w-10 place-content-center place-items-center rounded-full bg-immich-error p-5 text-xs text-gray-200" > {$stats.errors.toLocaleString($locale)} @@ -161,7 +163,7 @@ <button type="button" in:scale={{ duration: 250, easing: quartInOut }} - on:click={() => (showDetail = true)} + onclick={() => (showDetail = true)} class="flex h-16 w-16 place-content-center place-items-center rounded-full bg-gray-200 p-5 text-sm text-immich-primary shadow-lg dark:bg-gray-600 dark:text-immich-gray" > <div class="animate-pulse"> diff --git a/web/src/lib/components/shared-components/user-avatar.svelte b/web/src/lib/components/shared-components/user-avatar.svelte index 74750953b5..938f569508 100644 --- a/web/src/lib/components/shared-components/user-avatar.svelte +++ b/web/src/lib/components/shared-components/user-avatar.svelte @@ -1,4 +1,4 @@ -<script lang="ts" context="module"> +<script lang="ts" module> export type Size = 'full' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | 'xxxl'; </script> @@ -16,25 +16,34 @@ profileChangedAt: string; } - export let user: User; - export let color: UserAvatarColor | undefined = undefined; - export let size: Size = 'full'; - export let rounded = true; - export let interactive = false; - export let showTitle = true; - export let showProfileImage = true; - export let label: string | undefined = undefined; + interface Props { + user: User; + color?: UserAvatarColor | undefined; + size?: Size; + rounded?: boolean; + interactive?: boolean; + showTitle?: boolean; + showProfileImage?: boolean; + label?: string | undefined; + } - let img: HTMLImageElement; - let showFallback = true; + let { + user, + color = undefined, + size = 'full', + rounded = true, + interactive = false, + showTitle = true, + showProfileImage = true, + label = undefined, + }: Props = $props(); - // sveeeeeeelteeeeee fiveeeeee - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - $: img, user, void tryLoadImage(); + let img: HTMLImageElement | undefined = $state(); + let showFallback = $state(true); const tryLoadImage = async () => { try { - await img.decode(); + await img?.decode(); showFallback = false; } catch { showFallback = true; @@ -64,12 +73,20 @@ xxxl: 'w-28 h-28', }; - $: colorClass = colorClasses[color || user.avatarColor]; - $: sizeClass = sizeClasses[size]; - $: title = label ?? `${user.name} (${user.email})`; - $: interactiveClass = interactive - ? 'border-2 border-immich-primary hover:border-immich-dark-primary dark:hover:border-immich-primary dark:border-immich-dark-primary transition-colors' - : ''; + $effect(() => { + if (img && user) { + tryLoadImage().catch(console.error); + } + }); + + let colorClass = $derived(colorClasses[color || user.avatarColor]); + let sizeClass = $derived(sizeClasses[size]); + let title = $derived(label ?? `${user.name} (${user.email})`); + let interactiveClass = $derived( + interactive + ? 'border-2 border-immich-primary hover:border-immich-dark-primary dark:hover:border-immich-primary dark:border-immich-dark-primary transition-colors' + : '', + ); </script> <figure diff --git a/web/src/lib/components/shared-components/version-announcement-box.svelte b/web/src/lib/components/shared-components/version-announcement-box.svelte index fb5466e7ae..62e9baf779 100644 --- a/web/src/lib/components/shared-components/version-announcement-box.svelte +++ b/web/src/lib/components/shared-components/version-announcement-box.svelte @@ -6,18 +6,12 @@ import { t } from 'svelte-i18n'; import FormatMessage from '$lib/components/i18n/format-message.svelte'; - let showModal = false; + let showModal = $state(false); const { release } = websocketStore; const semverToName = ({ major, minor, patch }: ServerVersionResponseDto) => `v${major}.${minor}.${patch}`; - $: releaseVersion = $release && semverToName($release.releaseVersion); - $: serverVersion = $release && semverToName($release.serverVersion); - $: if ($release?.isAvailable) { - handleRelease(); - } - const onAcknowledge = () => { localStorage.setItem('appVersion', releaseVersion); showModal = false; @@ -34,21 +28,30 @@ console.error('Error [VersionAnnouncementBox]:', error); } }; + let releaseVersion = $derived($release && semverToName($release.releaseVersion)); + let serverVersion = $derived($release && semverToName($release.serverVersion)); + $effect(() => { + if ($release?.isAvailable) { + handleRelease(); + } + }); </script> {#if showModal} <FullScreenModal title="🎉 {$t('new_version_available')}" onClose={() => (showModal = false)}> <div> - <FormatMessage key="version_announcement_message" let:tag let:message> - {#if tag === 'link'} - <span class="font-medium underline"> - <a href="https://github.com/immich-app/immich/releases/latest" target="_blank" rel="noopener noreferrer"> - {message} - </a> - </span> - {:else if tag === 'code'} - <code>{message}</code> - {/if} + <FormatMessage key="version_announcement_message"> + {#snippet children({ tag, message })} + {#if tag === 'link'} + <span class="font-medium underline"> + <a href="https://github.com/immich-app/immich/releases/latest" target="_blank" rel="noopener noreferrer"> + {message} + </a> + </span> + {:else if tag === 'code'} + <code>{message}</code> + {/if} + {/snippet} </FormatMessage> </div> @@ -60,8 +63,8 @@ <code>{$t('latest_version')}: {releaseVersion}</code> </div> - <svelte:fragment slot="sticky-bottom"> - <Button fullwidth on:click={onAcknowledge}>{$t('acknowledge')}</Button> - </svelte:fragment> + {#snippet stickyBottom()} + <Button fullwidth onclick={onAcknowledge}>{$t('acknowledge')}</Button> + {/snippet} </FullScreenModal> {/if} diff --git a/web/src/lib/components/sharedlinks-page/actions/shared-link-copy.svelte b/web/src/lib/components/sharedlinks-page/actions/shared-link-copy.svelte index f955d8479a..9ec9fc76ce 100644 --- a/web/src/lib/components/sharedlinks-page/actions/shared-link-copy.svelte +++ b/web/src/lib/components/sharedlinks-page/actions/shared-link-copy.svelte @@ -7,8 +7,12 @@ import { mdiContentCopy } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let link: SharedLinkResponseDto; - export let menuItem = false; + interface Props { + link: SharedLinkResponseDto; + menuItem?: boolean; + } + + let { link, menuItem = false }: Props = $props(); const handleCopy = async () => { await copyToClipboard(makeSharedLinkUrl($serverConfig.externalDomain, link.key)); @@ -18,5 +22,5 @@ {#if menuItem} <MenuOption text={$t('copy_link')} icon={mdiContentCopy} onClick={handleCopy} /> {:else} - <CircleIconButton title={$t('copy_link')} icon={mdiContentCopy} on:click={handleCopy} /> + <CircleIconButton title={$t('copy_link')} icon={mdiContentCopy} onclick={handleCopy} /> {/if} diff --git a/web/src/lib/components/sharedlinks-page/actions/shared-link-delete.svelte b/web/src/lib/components/sharedlinks-page/actions/shared-link-delete.svelte index d458d5d77a..8c81e736bb 100644 --- a/web/src/lib/components/sharedlinks-page/actions/shared-link-delete.svelte +++ b/web/src/lib/components/sharedlinks-page/actions/shared-link-delete.svelte @@ -4,12 +4,16 @@ import { mdiDelete } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let menuItem = false; - export let onDelete: () => void; + interface Props { + menuItem?: boolean; + onDelete: () => void; + } + + let { menuItem = false, onDelete }: Props = $props(); </script> {#if menuItem} <MenuOption text={$t('delete_link')} icon={mdiDelete} onClick={onDelete} /> {:else} - <CircleIconButton title={$t('delete_link')} icon={mdiDelete} on:click={onDelete} /> + <CircleIconButton title={$t('delete_link')} icon={mdiDelete} onclick={onDelete} /> {/if} diff --git a/web/src/lib/components/sharedlinks-page/actions/shared-link-edit.svelte b/web/src/lib/components/sharedlinks-page/actions/shared-link-edit.svelte index 49c6105632..0a0c5a4736 100644 --- a/web/src/lib/components/sharedlinks-page/actions/shared-link-edit.svelte +++ b/web/src/lib/components/sharedlinks-page/actions/shared-link-edit.svelte @@ -4,12 +4,16 @@ import { mdiCircleEditOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let menuItem = false; - export let onEdit: () => void; + interface Props { + menuItem?: boolean; + onEdit: () => void; + } + + let { menuItem = false, onEdit }: Props = $props(); </script> {#if menuItem} <MenuOption text={$t('edit_link')} icon={mdiCircleEditOutline} onClick={onEdit} /> {:else} - <CircleIconButton title={$t('edit_link')} icon={mdiCircleEditOutline} on:click={onEdit} /> + <CircleIconButton title={$t('edit_link')} icon={mdiCircleEditOutline} onclick={onEdit} /> {/if} diff --git a/web/src/lib/components/sharedlinks-page/covers/asset-cover.svelte b/web/src/lib/components/sharedlinks-page/covers/asset-cover.svelte index bf5031e39d..76822cc786 100644 --- a/web/src/lib/components/sharedlinks-page/covers/asset-cover.svelte +++ b/web/src/lib/components/sharedlinks-page/covers/asset-cover.svelte @@ -1,13 +1,16 @@ <script lang="ts"> import BrokenAsset from '$lib/components/assets/broken-asset.svelte'; - export let alt; - export let preload = false; - export let src: string; - let className = ''; - export { className as class }; + interface Props { + alt?: string; + preload?: boolean; + src: string; + class?: string; + } - let isBroken = false; + let { alt, preload = false, src, class: className = '' }: Props = $props(); + + let isBroken = $state(false); </script> {#if isBroken} @@ -15,7 +18,7 @@ {:else} <img {alt} - on:error={() => (isBroken = true)} + onerror={() => (isBroken = true)} class="size-full rounded-xl object-cover aspect-square {className}" data-testid="album-image" draggable="false" diff --git a/web/src/lib/components/sharedlinks-page/covers/no-cover.svelte b/web/src/lib/components/sharedlinks-page/covers/no-cover.svelte index 087204d6a5..1e09c6bcfa 100644 --- a/web/src/lib/components/sharedlinks-page/covers/no-cover.svelte +++ b/web/src/lib/components/sharedlinks-page/covers/no-cover.svelte @@ -1,8 +1,11 @@ <script lang="ts"> - export let alt = ''; - export let preload = false; - let className = ''; - export { className as class }; + interface Props { + alt?: string; + preload?: boolean; + class?: string; + } + + let { alt = '', preload = false, class: className = '' }: Props = $props(); </script> <enhanced:img diff --git a/web/src/lib/components/sharedlinks-page/covers/share-cover.svelte b/web/src/lib/components/sharedlinks-page/covers/share-cover.svelte index 09f32d7dac..6f15cca45f 100644 --- a/web/src/lib/components/sharedlinks-page/covers/share-cover.svelte +++ b/web/src/lib/components/sharedlinks-page/covers/share-cover.svelte @@ -6,10 +6,13 @@ import { getAssetThumbnailUrl } from '$lib/utils'; import { t } from 'svelte-i18n'; - export let link: SharedLinkResponseDto; - export let preload = false; - let className = ''; - export { className as class }; + interface Props { + link: SharedLinkResponseDto; + preload?: boolean; + class?: string; + } + + let { link, preload = false, class: className = '' }: Props = $props(); </script> <div class="relative shrink-0 size-24"> diff --git a/web/src/lib/components/sharedlinks-page/shared-link-card.svelte b/web/src/lib/components/sharedlinks-page/shared-link-card.svelte index 13beec0ec0..70f6247533 100644 --- a/web/src/lib/components/sharedlinks-page/shared-link-card.svelte +++ b/web/src/lib/components/sharedlinks-page/shared-link-card.svelte @@ -12,13 +12,17 @@ import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte'; import { mdiDotsVertical } from '@mdi/js'; - export let link: SharedLinkResponseDto; - export let onDelete: () => void; - export let onEdit: () => void; + interface Props { + link: SharedLinkResponseDto; + onDelete: () => void; + onEdit: () => void; + } + + let { link, onDelete, onEdit }: Props = $props(); let now = DateTime.now(); - $: expiresAt = link.expiresAt ? DateTime.fromISO(link.expiresAt) : undefined; - $: isExpired = expiresAt ? now > expiresAt : false; + let expiresAt = $derived(link.expiresAt ? DateTime.fromISO(link.expiresAt) : undefined); + let isExpired = $derived(expiresAt ? now > expiresAt : false); const getCountDownExpirationDate = (expiresAtDate: DateTime, now: DateTime) => { const relativeUnits: ToRelativeUnit[] = ['days', 'hours', 'minutes', 'seconds']; diff --git a/web/src/lib/components/slideshow-settings.svelte b/web/src/lib/components/slideshow-settings.svelte index 6f0397be98..723960d914 100644 --- a/web/src/lib/components/slideshow-settings.svelte +++ b/web/src/lib/components/slideshow-settings.svelte @@ -1,8 +1,6 @@ <script lang="ts"> import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; import { mdiArrowDownThin, @@ -17,10 +15,15 @@ import type { RenderedOption } from './elements/dropdown.svelte'; import SettingDropdown from './shared-components/settings/setting-dropdown.svelte'; import { t } from 'svelte-i18n'; + import { SettingInputFieldType } from '$lib/constants'; const { slideshowDelay, showProgressBar, slideshowNavigation, slideshowLook, slideshowTransition } = slideshowStore; - export let onClose = () => {}; + interface Props { + onClose?: () => void; + } + + let { onClose = () => {} }: Props = $props(); const navigationOptions: Record<SlideshowNavigation, RenderedOption> = { [SlideshowNavigation.Shuffle]: { icon: mdiShuffle, title: $t('shuffle') }, @@ -46,7 +49,7 @@ }; </script> -<FullScreenModal title={$t('slideshow_settings')} {onClose}> +<FullScreenModal title={$t('slideshow_settings')} onClose={() => onClose()}> <div class="flex flex-col gap-4 text-immich-primary dark:text-immich-dark-primary"> <SettingDropdown title={$t('direction')} @@ -69,12 +72,13 @@ <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('duration')} - desc={$t('admin.slideshow_duration_description')} + description={$t('admin.slideshow_duration_description')} min={1} bind:value={$slideshowDelay} /> </div> - <svelte:fragment slot="sticky-bottom"> - <Button fullwidth color="primary" on:click={onClose}>{$t('done')}</Button> - </svelte:fragment> + + {#snippet stickyBottom()} + <Button fullwidth color="primary" onclick={(_) => onClose()}>{$t('done')}</Button> + {/snippet} </FullScreenModal> diff --git a/web/src/lib/components/user-settings-page/app-settings.svelte b/web/src/lib/components/user-settings-page/app-settings.svelte index 4bfd9a4e0e..63209ca289 100644 --- a/web/src/lib/components/user-settings-page/app-settings.svelte +++ b/web/src/lib/components/user-settings-page/app-settings.svelte @@ -19,26 +19,7 @@ import { fade } from 'svelte/transition'; import { invalidateAll } from '$app/navigation'; - let time = new Date(); - - $: formattedDate = time.toLocaleString(editedLocale, { - year: 'numeric', - month: '2-digit', - day: '2-digit', - }); - $: timePortion = time.toLocaleString(editedLocale, { - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - }); - $: selectedDate = `${formattedDate} ${timePortion}`; - $: editedLocale = findLocale($locale).code; - // svelte-ignore reactive_declaration_non_reactive_property - $: selectedOption = { - value: findLocale(editedLocale).code || fallbackLocale.code, - label: findLocale(editedLocale).name || fallbackLocale.name, - }; - $: closestLanguage = getClosestAvailableLocale([$lang], langCodes); + let time = $state(new Date()); onMount(() => { const interval = setInterval(() => { @@ -90,6 +71,27 @@ $locale = newLocale; } }; + let editedLocale = $derived(findLocale($locale).code); + let formattedDate = $derived( + time.toLocaleString(editedLocale, { + year: 'numeric', + month: '2-digit', + day: '2-digit', + }), + ); + let timePortion = $derived( + time.toLocaleString(editedLocale, { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + }), + ); + let selectedDate = $derived(`${formattedDate} ${timePortion}`); + let selectedOption = $derived({ + value: findLocale(editedLocale).code || fallbackLocale.code, + label: findLocale(editedLocale).name || fallbackLocale.name, + }); + let closestLanguage = $derived(getClosestAvailableLocale([$lang], langCodes)); </script> <section class="my-4"> diff --git a/web/src/lib/components/user-settings-page/change-password-settings.svelte b/web/src/lib/components/user-settings-page/change-password-settings.svelte index 39fd78e037..b31cbac34f 100644 --- a/web/src/lib/components/user-settings-page/change-password-settings.svelte +++ b/web/src/lib/components/user-settings-page/change-password-settings.svelte @@ -8,14 +8,13 @@ import Button from '$lib/components/elements/buttons/button.svelte'; import type { HttpError } from '@sveltejs/kit'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import { t } from 'svelte-i18n'; + import { SettingInputFieldType } from '$lib/constants'; - let password = ''; - let newPassword = ''; - let confirmPassword = ''; + let password = $state(''); + let newPassword = $state(''); + let confirmPassword = $state(''); const handleChangePassword = async () => { try { @@ -37,11 +36,15 @@ }); } }; + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <section class="my-4"> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingInputField inputType={SettingInputFieldType.PASSWORD} @@ -72,7 +75,7 @@ type="submit" size="sm" disabled={!(password && newPassword && newPassword === confirmPassword)} - on:click={() => handleChangePassword()}>{$t('save')}</Button + onclick={() => handleChangePassword()}>{$t('save')}</Button > </div> </div> diff --git a/web/src/lib/components/user-settings-page/device-card.svelte b/web/src/lib/components/user-settings-page/device-card.svelte index d43977ea08..5248a6d119 100644 --- a/web/src/lib/components/user-settings-page/device-card.svelte +++ b/web/src/lib/components/user-settings-page/device-card.svelte @@ -17,8 +17,12 @@ import { DateTime, type ToRelativeCalendarOptions } from 'luxon'; import { t } from 'svelte-i18n'; - export let device: SessionResponseDto; - export let onDelete: (() => void) | undefined = undefined; + interface Props { + device: SessionResponseDto; + onDelete?: (() => void) | undefined; + } + + let { device, onDelete = undefined }: Props = $props(); const options: ToRelativeCalendarOptions = { unit: 'days', @@ -71,7 +75,7 @@ icon={mdiTrashCanOutline} title={$t('log_out')} size="16" - on:click={onDelete} + onclick={onDelete} /> </div> {/if} 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 26e03c35d8..bb202b3606 100644 --- a/web/src/lib/components/user-settings-page/device-list.svelte +++ b/web/src/lib/components/user-settings-page/device-list.svelte @@ -7,12 +7,16 @@ import { dialogController } from '$lib/components/shared-components/dialog/dialog'; import { t } from 'svelte-i18n'; - export let devices: SessionResponseDto[]; + interface Props { + devices: SessionResponseDto[]; + } + + let { devices = $bindable() }: Props = $props(); const refresh = () => getSessions().then((_devices) => (devices = _devices)); - $: currentDevice = devices.find((device) => device.current); - $: otherDevices = devices.filter((device) => !device.current); + let currentDevice = $derived(devices.find((device) => device.current)); + let otherDevices = $derived(devices.filter((device) => !device.current)); const handleDelete = async (device: SessionResponseDto) => { const isConfirmed = await dialogController.show({ @@ -78,7 +82,7 @@ {$t('log_out_all_devices').toUpperCase()} </h3> <div class="flex justify-end"> - <Button color="red" size="sm" on:click={handleDeleteAll}>{$t('log_out_all_devices')}</Button> + <Button color="red" size="sm" onclick={handleDeleteAll}>{$t('log_out_all_devices')}</Button> </div> {/if} </section> diff --git a/web/src/lib/components/user-settings-page/download-settings.svelte b/web/src/lib/components/user-settings-page/download-settings.svelte index f5b94ebee8..97da347fb7 100644 --- a/web/src/lib/components/user-settings-page/download-settings.svelte +++ b/web/src/lib/components/user-settings-page/download-settings.svelte @@ -10,14 +10,13 @@ import { preferences } from '$lib/stores/user.store'; import Button from '../elements/buttons/button.svelte'; import { t } from 'svelte-i18n'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import { ByteUnit, convertFromBytes, convertToBytes } from '$lib/utils/byte-units'; import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; + import { SettingInputFieldType } from '$lib/constants'; - let archiveSize = convertFromBytes($preferences?.download?.archiveSize || 4, ByteUnit.GiB); - let includeEmbeddedVideos = $preferences?.download?.includeEmbeddedVideos || false; + let archiveSize = $state(convertFromBytes($preferences?.download?.archiveSize || 4, ByteUnit.GiB)); + let includeEmbeddedVideos = $state($preferences?.download?.includeEmbeddedVideos || false); const handleSave = async () => { try { @@ -36,16 +35,20 @@ handleError(error, $t('errors.unable_to_update_settings')); } }; + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <section class="my-4"> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingInputField inputType={SettingInputFieldType.NUMBER} label={$t('archive_size')} - desc={$t('archive_size_description')} + description={$t('archive_size_description')} bind:value={archiveSize} /> <SettingSwitch @@ -54,7 +57,7 @@ bind:checked={includeEmbeddedVideos} ></SettingSwitch> <div class="flex justify-end"> - <Button type="submit" size="sm" on:click={() => handleSave()}>{$t('save')}</Button> + <Button type="submit" size="sm" onclick={() => handleSave()}>{$t('save')}</Button> </div> </div> </form> diff --git a/web/src/lib/components/user-settings-page/feature-settings.svelte b/web/src/lib/components/user-settings-page/feature-settings.svelte index d04bbc3e7d..9a60f83647 100644 --- a/web/src/lib/components/user-settings-page/feature-settings.svelte +++ b/web/src/lib/components/user-settings-page/feature-settings.svelte @@ -14,22 +14,22 @@ import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte'; // Folders - let foldersEnabled = $preferences?.folders?.enabled ?? false; - let foldersSidebar = $preferences?.folders?.sidebarWeb ?? false; + let foldersEnabled = $state($preferences?.folders?.enabled ?? false); + let foldersSidebar = $state($preferences?.folders?.sidebarWeb ?? false); // Memories - let memoriesEnabled = $preferences?.memories?.enabled ?? true; + let memoriesEnabled = $state($preferences?.memories?.enabled ?? true); // People - let peopleEnabled = $preferences?.people?.enabled ?? false; - let peopleSidebar = $preferences?.people?.sidebarWeb ?? false; + let peopleEnabled = $state($preferences?.people?.enabled ?? false); + let peopleSidebar = $state($preferences?.people?.sidebarWeb ?? false); // Ratings - let ratingsEnabled = $preferences?.ratings?.enabled ?? false; + let ratingsEnabled = $state($preferences?.ratings?.enabled ?? false); // Tags - let tagsEnabled = $preferences?.tags?.enabled ?? false; - let tagsSidebar = $preferences?.tags?.sidebarWeb ?? false; + let tagsEnabled = $state($preferences?.tags?.enabled ?? false); + let tagsSidebar = $state($preferences?.tags?.sidebarWeb ?? false); const handleSave = async () => { try { @@ -50,11 +50,15 @@ handleError(error, $t('errors.unable_to_update_settings')); } }; + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <section class="my-4"> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4 flex flex-col"> <SettingAccordion key="folders" title={$t('folders')} subtitle={$t('folders_feature_description')}> <div class="ml-4 mt-6"> @@ -116,7 +120,7 @@ </SettingAccordion> <div class="flex justify-end"> - <Button type="submit" size="sm" on:click={() => handleSave()}>{$t('save')}</Button> + <Button type="submit" size="sm" onclick={() => handleSave()}>{$t('save')}</Button> </div> </div> </form> diff --git a/web/src/lib/components/user-settings-page/notifications-settings.svelte b/web/src/lib/components/user-settings-page/notifications-settings.svelte index 275f628f0a..bec0633964 100644 --- a/web/src/lib/components/user-settings-page/notifications-settings.svelte +++ b/web/src/lib/components/user-settings-page/notifications-settings.svelte @@ -12,9 +12,9 @@ import Button from '../elements/buttons/button.svelte'; import { t } from 'svelte-i18n'; - let emailNotificationsEnabled = $preferences?.emailNotifications?.enabled ?? true; - let albumInviteNotificationEnabled = $preferences?.emailNotifications?.albumInvite ?? true; - let albumUpdateNotificationEnabled = $preferences?.emailNotifications?.albumUpdate ?? true; + let emailNotificationsEnabled = $state($preferences?.emailNotifications?.enabled ?? true); + let albumInviteNotificationEnabled = $state($preferences?.emailNotifications?.albumInvite ?? true); + let albumUpdateNotificationEnabled = $state($preferences?.emailNotifications?.albumUpdate ?? true); const handleSave = async () => { try { @@ -37,11 +37,15 @@ handleError(error, $t('errors.unable_to_update_settings')); } }; + + const onsubmit = (event: Event) => { + event.preventDefault(); + }; </script> <section class="my-4"> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" {onsubmit}> <div class="ml-4 mt-4 flex flex-col gap-4"> <div class="ml-4"> <SettingSwitch @@ -67,7 +71,7 @@ </div> <div class="flex justify-end"> - <Button type="submit" size="sm" on:click={() => handleSave()}>{$t('save')}</Button> + <Button type="submit" size="sm" onclick={() => handleSave()}>{$t('save')}</Button> </div> </div> </form> diff --git a/web/src/lib/components/user-settings-page/oauth-settings.svelte b/web/src/lib/components/user-settings-page/oauth-settings.svelte index 10e71e64eb..8dbe3539b8 100644 --- a/web/src/lib/components/user-settings-page/oauth-settings.svelte +++ b/web/src/lib/components/user-settings-page/oauth-settings.svelte @@ -11,9 +11,13 @@ import { notificationController, NotificationType } from '../shared-components/notification/notification'; import { t } from 'svelte-i18n'; - export let user: UserAdminResponseDto; + interface Props { + user: UserAdminResponseDto; + } - let loading = true; + let { user = $bindable() }: Props = $props(); + + let loading = $state(true); onMount(async () => { if (oauth.isCallback(window.location)) { @@ -58,9 +62,9 @@ </div> {:else if $featureFlags.oauth} {#if user.oauthId} - <Button size="sm" on:click={() => handleUnlink()}>{$t('unlink_oauth')}</Button> + <Button size="sm" onclick={() => handleUnlink()}>{$t('unlink_oauth')}</Button> {:else} - <Button size="sm" on:click={() => oauth.authorize(window.location)}>{$t('link_to_oauth')}</Button> + <Button size="sm" onclick={() => oauth.authorize(window.location)}>{$t('link_to_oauth')}</Button> {/if} {/if} </div> 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 8ab747aa27..070246b612 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 @@ -6,12 +6,16 @@ import Button from '../elements/buttons/button.svelte'; import UserAvatar from '../shared-components/user-avatar.svelte'; - export let user: UserResponseDto; - export let onClose: () => void; - export let onAddUsers: (users: UserResponseDto[]) => void; + interface Props { + user: UserResponseDto; + onClose: () => void; + onAddUsers: (users: UserResponseDto[]) => void; + } - let availableUsers: UserResponseDto[] = []; - let selectedUsers: UserResponseDto[] = []; + let { user, onClose, onAddUsers }: Props = $props(); + + let availableUsers: UserResponseDto[] = $state([]); + let selectedUsers: UserResponseDto[] = $state([]); onMount(async () => { let users = await searchUsers(); @@ -38,7 +42,7 @@ {#each availableUsers as user} <button type="button" - on:click={() => selectUser(user)} + onclick={() => selectUser(user)} class="flex w-full place-items-center gap-4 px-5 py-4 transition-all hover:bg-gray-200 dark:hover:bg-gray-700 rounded-xl" > {#if selectedUsers.includes(user)} @@ -68,7 +72,7 @@ {#if selectedUsers.length > 0} <div class="pt-5"> - <Button size="sm" fullwidth on:click={() => onAddUsers(selectedUsers)}>{$t('add')}</Button> + <Button size="sm" fullwidth onclick={() => onAddUsers(selectedUsers)}>{$t('add')}</Button> </div> {/if} </div> 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 050e2c42f3..7d57510547 100644 --- a/web/src/lib/components/user-settings-page/partner-settings.svelte +++ b/web/src/lib/components/user-settings-page/partner-settings.svelte @@ -27,11 +27,15 @@ inTimeline: boolean; } - export let user: UserResponseDto; + interface Props { + user: UserResponseDto; + } - let createPartnerFlag = false; + let { user }: Props = $props(); + + let createPartnerFlag = $state(false); // let removePartnerDto: PartnerResponseDto | null = null; - let partners: Array<PartnerSharing> = []; + let partners: Array<PartnerSharing> = $state([]); onMount(async () => { await refreshPartners(); @@ -139,7 +143,7 @@ {#if partner.sharedByMe} <CircleIconButton - on:click={() => handleRemovePartner(partner.user)} + onclick={() => handleRemovePartner(partner.user)} icon={mdiClose} size={'16'} title={$t('stop_sharing_photos_with_user')} @@ -186,7 +190,7 @@ {/if} <div class="flex justify-end mt-5"> - <Button size="sm" on:click={() => (createPartnerFlag = true)}>{$t('add_partner')}</Button> + <Button size="sm" onclick={() => (createPartnerFlag = true)}>{$t('add_partner')}</Button> </div> </section> 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 a63bdb3ca9..c5c6bae9e5 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 @@ -19,11 +19,15 @@ import { dialogController } from '$lib/components/shared-components/dialog/dialog'; import { t } from 'svelte-i18n'; - export let keys: ApiKeyResponseDto[]; + interface Props { + keys: ApiKeyResponseDto[]; + } - let newKey: { name: string } | null = null; - let editKey: ApiKeyResponseDto | null = null; - let secret = ''; + let { keys = $bindable() }: Props = $props(); + + let newKey: { name: string } | null = $state(null); + let editKey: ApiKeyResponseDto | null = $state(null); + let secret = $state(''); const format: Intl.DateTimeFormatOptions = { month: 'short', @@ -118,7 +122,7 @@ <section class="my-4"> <div class="flex flex-col gap-2" in:fade={{ duration: 500 }}> <div class="mb-2 flex justify-end"> - <Button size="sm" on:click={() => (newKey = { name: $t('api_key') })}>{$t('new_api_key')}</Button> + <Button size="sm" onclick={() => (newKey = { name: $t('api_key') })}>{$t('new_api_key')}</Button> </div> {#if keys.length > 0} @@ -152,14 +156,14 @@ icon={mdiPencilOutline} title={$t('edit_key')} size="16" - on:click={() => (editKey = key)} + onclick={() => (editKey = key)} /> <CircleIconButton color="primary" icon={mdiTrashCanOutline} title={$t('delete_key')} size="16" - on:click={() => handleDelete(key)} + onclick={() => handleDelete(key)} /> </td> </tr> diff --git a/web/src/lib/components/user-settings-page/user-profile-settings.svelte b/web/src/lib/components/user-settings-page/user-profile-settings.svelte index 1f3b59bfdd..a49eabcf13 100644 --- a/web/src/lib/components/user-settings-page/user-profile-settings.svelte +++ b/web/src/lib/components/user-settings-page/user-profile-settings.svelte @@ -1,11 +1,12 @@ <script lang="ts"> + import { createBubbler, preventDefault } from 'svelte/legacy'; + + const bubble = createBubbler(); import { notificationController, NotificationType, } from '$lib/components/shared-components/notification/notification'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import { user } from '$lib/stores/user.store'; import { updateMyUser } from '@immich/sdk'; import { cloneDeep } from 'lodash-es'; @@ -13,8 +14,9 @@ import { handleError } from '../../utils/handle-error'; import Button from '../elements/buttons/button.svelte'; import { t } from 'svelte-i18n'; + import { SettingInputFieldType } from '$lib/constants'; - let editedUser = cloneDeep($user); + let editedUser = $state(cloneDeep($user)); const handleSaveProfile = async () => { try { @@ -40,7 +42,7 @@ <section class="my-4"> <div in:fade={{ duration: 500 }}> - <form autocomplete="off" on:submit|preventDefault> + <form autocomplete="off" onsubmit={preventDefault(bubble('submit'))}> <div class="ml-4 mt-4 flex flex-col gap-4"> <SettingInputField inputType={SettingInputFieldType.TEXT} @@ -67,7 +69,7 @@ /> <div class="flex justify-end"> - <Button type="submit" size="sm" on:click={() => handleSaveProfile()}>{$t('save')}</Button> + <Button type="submit" size="sm" onclick={() => handleSaveProfile()}>{$t('save')}</Button> </div> </div> </form> diff --git a/web/src/lib/components/user-settings-page/user-purchase-settings.svelte b/web/src/lib/components/user-settings-page/user-purchase-settings.svelte index 71f76d07c0..2408651234 100644 --- a/web/src/lib/components/user-settings-page/user-purchase-settings.svelte +++ b/web/src/lib/components/user-settings-page/user-purchase-settings.svelte @@ -24,8 +24,8 @@ import { setSupportBadgeVisibility } from '$lib/utils/purchase-utils'; const { isPurchased } = purchaseStore; - let isServerProduct = false; - let serverPurchaseInfo: LicenseResponseDto | null = null; + let isServerProduct = $state(false); + let serverPurchaseInfo: LicenseResponseDto | null = $state(null); const checkPurchaseInfo = async () => { const serverInfo = await getAboutInfo(); @@ -145,7 +145,7 @@ {#if $user.isAdmin} <div class="text-right mt-4"> - <Button size="sm" color="red" on:click={removeServerProductKey}>{$t('purchase_button_remove_key')}</Button> + <Button size="sm" color="red" onclick={removeServerProductKey}>{$t('purchase_button_remove_key')}</Button> </div> {/if} {:else} @@ -169,8 +169,7 @@ </div> <div class="text-right mt-4"> - <Button size="sm" color="red" on:click={removeIndividualProductKey}>{$t('purchase_button_remove_key')}</Button - > + <Button size="sm" color="red" onclick={removeIndividualProductKey}>{$t('purchase_button_remove_key')}</Button> </div> {/if} {:else} diff --git a/web/src/lib/components/user-settings-page/user-settings-list.svelte b/web/src/lib/components/user-settings-page/user-settings-list.svelte index f355c3105c..6f8a0ce4dc 100644 --- a/web/src/lib/components/user-settings-page/user-settings-list.svelte +++ b/web/src/lib/components/user-settings-page/user-settings-list.svelte @@ -33,8 +33,12 @@ mdiTwoFactorAuthentication, } from '@mdi/js'; - export let keys: ApiKeyResponseDto[] = []; - export let sessions: SessionResponseDto[] = []; + interface Props { + keys?: ApiKeyResponseDto[]; + sessions?: SessionResponseDto[]; + } + + let { keys = $bindable([]), sessions = $bindable([]) }: Props = $props(); let oauthOpen = oauth.isCallback(window.location) || diff --git a/web/src/lib/components/utilities-page/duplicates/duplicate-asset.svelte b/web/src/lib/components/utilities-page/duplicates/duplicate-asset.svelte index 2103250b54..19190745d1 100644 --- a/web/src/lib/components/utilities-page/duplicates/duplicate-asset.svelte +++ b/web/src/lib/components/utilities-page/duplicates/duplicate-asset.svelte @@ -7,13 +7,17 @@ import { mdiHeart, mdiMagnifyPlus, mdiImageMultipleOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let asset: AssetResponseDto; - export let isSelected: boolean; - export let onSelectAsset: (asset: AssetResponseDto) => void; - export let onViewAsset: (asset: AssetResponseDto) => void; + interface Props { + asset: AssetResponseDto; + isSelected: boolean; + onSelectAsset: (asset: AssetResponseDto) => void; + onViewAsset: (asset: AssetResponseDto) => void; + } - $: isFromExternalLibrary = !!asset.libraryId; - $: assetData = JSON.stringify(asset, null, 2); + let { asset, isSelected, onSelectAsset, onViewAsset }: Props = $props(); + + let isFromExternalLibrary = $derived(!!asset.libraryId); + let assetData = $derived(JSON.stringify(asset, null, 2)); </script> <div @@ -24,7 +28,7 @@ <div class="relative w-full"> <button type="button" - on:click={() => onSelectAsset(asset)} + onclick={() => onSelectAsset(asset)} class="block relative w-full" aria-pressed={isSelected} aria-label={$t('keep')} @@ -74,7 +78,7 @@ <button type="button" - on:click={() => onViewAsset(asset)} + onclick={() => onViewAsset(asset)} class="absolute rounded-full top-1 left-1 text-gray-200 p-2 hover:text-white bg-black/35 hover:bg-black/50" title={$t('view')} > diff --git a/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte b/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte index fd5b68d8c3..6b9bc93c1e 100644 --- a/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte +++ b/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte @@ -11,21 +11,26 @@ import { mdiCheck, mdiTrashCanOutline, mdiImageMultipleOutline } from '@mdi/js'; import { onDestroy, onMount } from 'svelte'; import { t } from 'svelte-i18n'; + import { SvelteSet } from 'svelte/reactivity'; - export let assets: AssetResponseDto[]; - export let onResolve: (duplicateAssetIds: string[], trashIds: string[]) => void; - export let onStack: (assets: AssetResponseDto[]) => void; + interface Props { + assets: AssetResponseDto[]; + onResolve: (duplicateAssetIds: string[], trashIds: string[]) => void; + onStack: (assets: AssetResponseDto[]) => void; + } + + let { assets, onResolve, onStack }: Props = $props(); const { isViewing: showAssetViewer, asset: viewingAsset, setAsset } = assetViewingStore; const getAssetIndex = (id: string) => assets.findIndex((asset) => asset.id === id); - let selectedAssetIds = new Set<string>(); - $: trashCount = assets.length - selectedAssetIds.size; + let selectedAssetIds = $state(new SvelteSet<string>()); + let trashCount = $derived(assets.length - selectedAssetIds.size); onMount(() => { const suggestedAsset = suggestDuplicateByFileSize(assets); if (!suggestedAsset) { - selectedAssetIds = new Set(assets[0].id); + selectedAssetIds = new SvelteSet(assets[0].id); return; } @@ -53,7 +58,7 @@ }; const onSelectAll = () => { - selectedAssetIds = new Set(assets.map((asset) => asset.id)); + selectedAssetIds = new SvelteSet(assets.map((asset) => asset.id)); }; const handleResolve = () => { @@ -100,12 +105,12 @@ <button type="button" class="px-4 py-3 flex place-items-center gap-2 rounded-tl-full rounded-bl-full dark:bg-immich-dark-primary hover:dark:bg-immich-dark-primary/90 bg-immich-primary/25 hover:bg-immich-primary/50" - on:click={onSelectAll}><Icon path={mdiCheck} size="20" />{$t('select_keep_all')}</button + onclick={onSelectAll}><Icon path={mdiCheck} size="20" />{$t('select_keep_all')}</button > <button type="button" class="px-4 py-3 flex place-items-center gap-2 rounded-tr-full rounded-br-full dark:bg-immich-dark-primary/50 hover:dark:bg-immich-dark-primary/70 bg-immich-primary hover:bg-immich-primary/80 text-white" - on:click={onSelectNone}><Icon path={mdiTrashCanOutline} size="20" />{$t('select_trash_all')}</button + onclick={onSelectNone}><Icon path={mdiTrashCanOutline} size="20" />{$t('select_trash_all')}</button > </div> @@ -116,7 +121,7 @@ size="sm" color="primary" class="flex place-items-center rounded-tl-full rounded-bl-full gap-2" - on:click={handleResolve} + onclick={handleResolve} > <Icon path={mdiCheck} size="20" />{$t('keep_all')} </Button> @@ -125,7 +130,7 @@ size="sm" color="red" class="flex place-items-center rounded-tl-full rounded-bl-full gap-2 py-3" - on:click={handleResolve} + onclick={handleResolve} > <Icon path={mdiTrashCanOutline} size="20" />{trashCount === assets.length ? $t('trash_all') @@ -136,7 +141,7 @@ size="sm" color="primary" class="flex place-items-center rounded-tr-full rounded-br-full gap-2" - on:click={handleStack} + onclick={handleStack} disabled={selectedAssetIds.size !== 1} > <Icon path={mdiImageMultipleOutline} size="20" />{$t('stack')} diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts index 390f4be378..c0031ac436 100644 --- a/web/src/lib/constants.ts +++ b/web/src/lib/constants.ts @@ -333,3 +333,30 @@ export enum ImmichProduct { Client = 'immich-client', Server = 'immich-server', } + +export enum SettingInputFieldType { + EMAIL = 'email', + TEXT = 'text', + NUMBER = 'number', + PASSWORD = 'password', + COLOR = 'color', +} + +export enum AlbumPageViewMode { + LINK_SHARING = 'link-sharing', + SELECT_USERS = 'select-users', + SELECT_THUMBNAIL = 'select-thumbnail', + SELECT_ASSETS = 'select-assets', + VIEW_USERS = 'view-users', + VIEW = 'view', + OPTIONS = 'options', +} + +export enum PersonPageViewMode { + VIEW_ASSETS = 'view-assets', + SELECT_PERSON = 'select-person', + MERGE_PEOPLE = 'merge-people', + SUGGEST_MERGE = 'suggest-merge', + BIRTH_DATE = 'birth-date', + UNASSIGN_ASSETS = 'unassign-faces', +} diff --git a/web/src/routes/(user)/+layout.svelte b/web/src/routes/(user)/+layout.svelte index bf24d0e7e4..feda36fa01 100644 --- a/web/src/routes/(user)/+layout.svelte +++ b/web/src/routes/(user)/+layout.svelte @@ -1,13 +1,21 @@ <script lang="ts"> + import { run } from 'svelte/legacy'; + import UploadCover from '$lib/components/shared-components/drag-and-drop-upload-overlay.svelte'; import { page } from '$app/stores'; import { assetViewingStore } from '$lib/stores/asset-viewing.store'; + import type { Snippet } from 'svelte'; + interface Props { + children?: Snippet; + } + + let { children }: Props = $props(); let { isViewing: showAssetViewer, setAsset, gridScrollTarget } = assetViewingStore; // $page.data.asset is loaded by route specific +page.ts loaders if that // route contains the assetId path. - $: { + run(() => { if ($page.data.asset) { setAsset($page.data.asset); } else { @@ -15,11 +23,11 @@ } const asset = $page.url.searchParams.get('at'); $gridScrollTarget = { at: asset }; - } + }); </script> <div class:display-none={$showAssetViewer}> - <slot /> + {@render children?.()} </div> <UploadCover /> diff --git a/web/src/routes/(user)/albums/+page.svelte b/web/src/routes/(user)/albums/+page.svelte index 35402ce331..29079a48b8 100644 --- a/web/src/routes/(user)/albums/+page.svelte +++ b/web/src/routes/(user)/albums/+page.svelte @@ -10,16 +10,22 @@ import SearchBar from '$lib/components/elements/search-bar.svelte'; import { t } from 'svelte-i18n'; - export let data: PageData; + interface Props { + data: PageData; + } - let searchQuery = ''; - let albumGroups: string[] = []; + let { data }: Props = $props(); + + let searchQuery = $state(''); + let albumGroups: string[] = $state([]); </script> <UserPageLayout title={data.meta.title}> - <div class="flex place-items-center gap-2" slot="buttons"> - <AlbumsControls {albumGroups} bind:searchQuery /> - </div> + {#snippet buttons()} + <div class="flex place-items-center gap-2"> + <AlbumsControls {albumGroups} bind:searchQuery /> + </div> + {/snippet} <div class="xl:hidden"> <div class="w-fit h-14 dark:text-immich-dark-fg py-2"> @@ -43,6 +49,8 @@ {searchQuery} bind:albumGroupIds={albumGroups} > - <EmptyPlaceholder slot="empty" text={$t('no_albums_message')} onClick={() => createAlbumAndRedirect()} /> + {#snippet empty()} + <EmptyPlaceholder text={$t('no_albums_message')} onClick={() => createAlbumAndRedirect()} /> + {/snippet} </Albums> </UserPageLayout> diff --git a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte index 9ccb2b7182..2a78b02aa6 100644 --- a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -32,7 +32,7 @@ notificationController, } from '$lib/components/shared-components/notification/notification'; import UserAvatar from '$lib/components/shared-components/user-avatar.svelte'; - import { AppRoute } from '$lib/constants'; + import { AppRoute, AlbumPageViewMode } from '$lib/constants'; import { numberOfComments, setNumberOfComments, updateNumberOfComments } from '$lib/stores/activity.store'; import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store'; import { assetViewingStore } from '$lib/stores/asset-viewing.store'; @@ -87,69 +87,33 @@ import { confirmAlbumDelete } from '$lib/utils/album-utils'; import TagAction from '$lib/components/photos-page/actions/tag-action.svelte'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data = $bindable() }: Props = $props(); let { isViewing: showAssetViewer, setAsset, gridScrollTarget } = assetViewingStore; let { slideshowState, slideshowNavigation } = slideshowStore; - let oldAt: AssetGridRouteSearchParams | null | undefined; + let oldAt: AssetGridRouteSearchParams | null | undefined = $state(); - $: album = data.album; - $: albumId = album.id; - $: albumKey = `${albumId}_${albumOrder}`; + let backUrl: string = $state(AppRoute.ALBUMS); + let viewMode = $state(AlbumPageViewMode.VIEW); + let isCreatingSharedAlbum = $state(false); + let isShowActivity = $state(false); + let isLiked: ActivityResponseDto | null = $state(null); + let reactions: ActivityResponseDto[] = $state([]); + let globalWidth: number = $state(0); + let assetGridWidth: number = $derived(isShowActivity ? globalWidth - (globalWidth < 768 ? 360 : 460) : globalWidth); + let albumOrder: AssetOrder | undefined = $state(data.album.order); - $: { - if (!album.isActivityEnabled && $numberOfComments === 0) { - isShowActivity = false; - } - } - - enum ViewMode { - LINK_SHARING = 'link-sharing', - SELECT_USERS = 'select-users', - SELECT_THUMBNAIL = 'select-thumbnail', - SELECT_ASSETS = 'select-assets', - VIEW_USERS = 'view-users', - VIEW = 'view', - OPTIONS = 'options', - } - - let backUrl: string = AppRoute.ALBUMS; - let viewMode = ViewMode.VIEW; - let isCreatingSharedAlbum = false; - let isShowActivity = false; - let isLiked: ActivityResponseDto | null = null; - let reactions: ActivityResponseDto[] = []; - let globalWidth: number; - let assetGridWidth: number; - let albumOrder: AssetOrder | undefined = data.album.order; - - $: assetStore = new AssetStore({ albumId, order: albumOrder }); const assetInteractionStore = createAssetInteractionStore(); const { isMultiSelectState, selectedAssets } = assetInteractionStore; - $: timelineStore = new AssetStore({ isArchived: false, withPartners: true }, albumId); const timelineInteractionStore = createAssetInteractionStore(); const { selectedAssets: timelineSelected } = timelineInteractionStore; - $: isOwned = $user.id == album.ownerId; - $: isAllUserOwned = [...$selectedAssets].every((asset) => asset.ownerId === $user.id); - $: isAllFavorite = [...$selectedAssets].every((asset) => asset.isFavorite); - $: isAllArchived = [...$selectedAssets].every((asset) => asset.isArchived); - $: { - assetGridWidth = isShowActivity ? globalWidth - (globalWidth < 768 ? 360 : 460) : globalWidth; - } - $: showActivityStatus = - album.albumUsers.length > 0 && !$showAssetViewer && (album.isActivityEnabled || $numberOfComments > 0); - - // svelte-ignore reactive_declaration_non_reactive_property - $: isEditor = - album.albumUsers.find(({ user: { id } }) => id === $user.id)?.role === AlbumUserRole.Editor || - album.ownerId === $user.id; - - // svelte-ignore reactive_declaration_non_reactive_property - $: albumHasViewers = album.albumUsers.some(({ role }) => role === AlbumUserRole.Viewer); - afterNavigate(({ from }) => { let url: string | undefined = from?.url?.pathname; @@ -171,12 +135,15 @@ const handleToggleEnableActivity = async () => { try { - await updateAlbumInfo({ + const updateAlbum = await updateAlbumInfo({ id: album.id, updateAlbumDto: { isActivityEnabled: !album.isActivityEnabled, }, }); + + album = { ...album, isActivityEnabled: updateAlbum.isActivityEnabled }; + await refreshAlbum(); notificationController.show({ type: NotificationType.Info, @@ -236,11 +203,6 @@ isShowActivity = !isShowActivity; }; - $: if (album.albumUsers.length > 0) { - handlePromiseError(getFavorite()); - handlePromiseError(getNumberOfComments()); - } - const handleStartSlideshow = async () => { const asset = $slideshowNavigation === SlideshowNavigation.Shuffle ? await assetStore.getRandomAsset() : assetStore.assets[0]; @@ -251,21 +213,21 @@ }; const handleEscape = async () => { - if (viewMode === ViewMode.SELECT_USERS) { - viewMode = ViewMode.VIEW; + if (viewMode === AlbumPageViewMode.SELECT_USERS) { + viewMode = AlbumPageViewMode.VIEW; return; } - if (viewMode === ViewMode.SELECT_ASSETS) { + if (viewMode === AlbumPageViewMode.SELECT_ASSETS) { await handleCloseSelectAssets(); return; } - if (viewMode === ViewMode.LINK_SHARING) { - viewMode = ViewMode.VIEW; + if (viewMode === AlbumPageViewMode.LINK_SHARING) { + viewMode = AlbumPageViewMode.VIEW; return; } - if (viewMode === ViewMode.OPTIONS) { - viewMode = ViewMode.VIEW; + if (viewMode === AlbumPageViewMode.OPTIONS) { + viewMode = AlbumPageViewMode.VIEW; return; } if ($showAssetViewer) { @@ -280,7 +242,7 @@ }; const refreshAlbum = async () => { - data.album = await getAlbumInfo({ id: album.id, withoutAssets: true }); + album = await getAlbumInfo({ id: album.id, withoutAssets: true }); }; const handleAddAssets = async () => { @@ -308,7 +270,7 @@ }; const setModeToView = async () => { - viewMode = ViewMode.VIEW; + viewMode = AlbumPageViewMode.VIEW; assetStore.destroy(); assetStore = new AssetStore({ albumId, order: albumOrder }); timelineStore.destroy(); @@ -341,13 +303,13 @@ }); await refreshAlbum(); - viewMode = ViewMode.VIEW; + viewMode = AlbumPageViewMode.VIEW; } catch (error) { handleError(error, $t('errors.error_adding_users_to_album')); } }; - const handleRemoveUser = async (userId: string, nextViewMode: ViewMode) => { + const handleRemoveUser = async (userId: string, nextViewMode: AlbumPageViewMode) => { if (userId == 'me' || userId === $user.id) { await goto(backUrl); return; @@ -357,7 +319,7 @@ await refreshAlbum(); // Dynamically set the view mode based on the passed argument - viewMode = album.albumUsers.length > 0 ? nextViewMode : ViewMode.VIEW; + viewMode = album.albumUsers.length > 0 ? nextViewMode : AlbumPageViewMode.VIEW; } catch (error) { handleError(error, $t('errors.error_deleting_shared_user')); } @@ -371,7 +333,7 @@ const isConfirmed = await confirmAlbumDelete(album); if (!isConfirmed) { - viewMode = ViewMode.VIEW; + viewMode = AlbumPageViewMode.VIEW; return; } @@ -381,7 +343,7 @@ } catch (error) { handleError(error, $t('errors.unable_to_delete_album')); } finally { - viewMode = ViewMode.VIEW; + viewMode = AlbumPageViewMode.VIEW; } }; @@ -391,11 +353,11 @@ }; const handleUpdateThumbnail = async (assetId: string) => { - if (viewMode !== ViewMode.SELECT_THUMBNAIL) { + if (viewMode !== AlbumPageViewMode.SELECT_THUMBNAIL) { return; } - viewMode = ViewMode.VIEW; + viewMode = AlbumPageViewMode.VIEW; assetInteractionStore.clearMultiselect(); await updateThumbnail(assetId); @@ -432,6 +394,40 @@ assetStore.destroy(); timelineStore.destroy(); }); + + let album = $state(data.album); + let albumId = $derived(album.id); + let albumKey = $derived(`${albumId}_${albumOrder}`); + + $effect(() => { + if (!album.isActivityEnabled && $numberOfComments === 0) { + isShowActivity = false; + } + }); + + let assetStore = $derived(new AssetStore({ albumId, order: albumOrder })); + let timelineStore = $derived(new AssetStore({ isArchived: false, withPartners: true }, albumId)); + + let isOwned = $derived($user.id == album.ownerId); + let isAllUserOwned = $derived([...$selectedAssets].every((asset) => asset.ownerId === $user.id)); + let isAllFavorite = $derived([...$selectedAssets].every((asset) => asset.isFavorite)); + let isAllArchived = $derived([...$selectedAssets].every((asset) => asset.isArchived)); + + let showActivityStatus = $derived( + album.albumUsers.length > 0 && !$showAssetViewer && (album.isActivityEnabled || $numberOfComments > 0), + ); + let isEditor = $derived( + album.albumUsers.find(({ user: { id } }) => id === $user.id)?.role === AlbumUserRole.Editor || + album.ownerId === $user.id, + ); + + let albumHasViewers = $derived(album.albumUsers.some(({ role }) => role === AlbumUserRole.Viewer)); + $effect(() => { + if (album.albumUsers.length > 0) { + handlePromiseError(getFavorite()); + handlePromiseError(getNumberOfComments()); + } + }); </script> <div class="flex overflow-hidden" bind:clientWidth={globalWidth}> @@ -475,14 +471,14 @@ </ButtonContextMenu> </AssetSelectControlBar> {:else} - {#if viewMode === ViewMode.VIEW} + {#if viewMode === AlbumPageViewMode.VIEW} <ControlAppBar showBackButton backIcon={mdiArrowLeft} onClose={() => goto(backUrl)}> - <svelte:fragment slot="trailing"> + {#snippet trailing()} {#if isEditor} <CircleIconButton title={$t('add_photos')} - on:click={async () => { - viewMode = ViewMode.SELECT_ASSETS; + onclick={async () => { + viewMode = AlbumPageViewMode.SELECT_ASSETS; oldAt = { at: $gridScrollTarget?.at }; await navigate( { targetRoute: 'current', assetId: null, assetGridRouteSearchParams: { at: null } }, @@ -496,23 +492,27 @@ {#if isOwned} <CircleIconButton title={$t('share')} - on:click={() => (viewMode = ViewMode.SELECT_USERS)} + onclick={() => (viewMode = AlbumPageViewMode.SELECT_USERS)} icon={mdiShareVariantOutline} /> {/if} {#if album.assetCount > 0} - <CircleIconButton title={$t('slideshow')} on:click={handleStartSlideshow} icon={mdiPresentationPlay} /> - <CircleIconButton title={$t('download')} on:click={handleDownloadAlbum} icon={mdiFolderDownloadOutline} /> + <CircleIconButton title={$t('slideshow')} onclick={handleStartSlideshow} icon={mdiPresentationPlay} /> + <CircleIconButton title={$t('download')} onclick={handleDownloadAlbum} icon={mdiFolderDownloadOutline} /> {#if isOwned} <ButtonContextMenu icon={mdiDotsVertical} title={$t('album_options')}> <MenuOption icon={mdiImageOutline} text={$t('select_album_cover')} - onClick={() => (viewMode = ViewMode.SELECT_THUMBNAIL)} + onClick={() => (viewMode = AlbumPageViewMode.SELECT_THUMBNAIL)} + /> + <MenuOption + icon={mdiCogOutline} + text={$t('options')} + onClick={() => (viewMode = AlbumPageViewMode.OPTIONS)} /> - <MenuOption icon={mdiCogOutline} text={$t('options')} onClick={() => (viewMode = ViewMode.OPTIONS)} /> <MenuOption icon={mdiDeleteOutline} text={$t('delete_album')} onClick={() => handleRemoveAlbum()} /> </ButtonContextMenu> {/if} @@ -523,18 +523,18 @@ size="sm" rounded="lg" disabled={album.assetCount === 0} - on:click={() => (viewMode = ViewMode.SELECT_USERS)} + onclick={() => (viewMode = AlbumPageViewMode.SELECT_USERS)} > {$t('share')} </Button> {/if} - </svelte:fragment> + {/snippet} </ControlAppBar> {/if} - {#if viewMode === ViewMode.SELECT_ASSETS} + {#if viewMode === AlbumPageViewMode.SELECT_ASSETS} <ControlAppBar onClose={handleCloseSelectAssets}> - <svelte:fragment slot="leading"> + {#snippet leading()} <p class="text-lg dark:text-immich-dark-fg"> {#if $timelineSelected.size === 0} {$t('add_to_album')} @@ -542,26 +542,28 @@ {$t('selected_count', { values: { count: $timelineSelected.size } })} {/if} </p> - </svelte:fragment> + {/snippet} - <svelte:fragment slot="trailing"> + {#snippet trailing()} <button type="button" - on:click={handleSelectFromComputer} + onclick={handleSelectFromComputer} class="rounded-lg px-6 py-2 text-sm font-medium text-immich-primary transition-all hover:bg-immich-primary/10 dark:text-immich-dark-primary dark:hover:bg-immich-dark-primary/25" > {$t('select_from_computer')} </button> - <Button size="sm" rounded="lg" disabled={$timelineSelected.size === 0} on:click={handleAddAssets} + <Button size="sm" rounded="lg" disabled={$timelineSelected.size === 0} onclick={handleAddAssets} >{$t('done')}</Button > - </svelte:fragment> + {/snippet} </ControlAppBar> {/if} - {#if viewMode === ViewMode.SELECT_THUMBNAIL} - <ControlAppBar onClose={() => (viewMode = ViewMode.VIEW)}> - <svelte:fragment slot="leading">{$t('select_album_cover')}</svelte:fragment> + {#if viewMode === AlbumPageViewMode.SELECT_THUMBNAIL} + <ControlAppBar onClose={() => (viewMode = AlbumPageViewMode.VIEW)}> + {#snippet leading()} + {$t('select_album_cover')} + {/snippet} </ControlAppBar> {/if} {/if} @@ -572,7 +574,7 @@ > <!-- Use key because AssetGrid can't deal with changing stores --> {#key albumKey} - {#if viewMode === ViewMode.SELECT_ASSETS} + {#if viewMode === AlbumPageViewMode.SELECT_ASSETS} <AssetGrid enableRouting={false} assetStore={timelineStore} @@ -586,13 +588,13 @@ {assetStore} {assetInteractionStore} isShared={album.albumUsers.length > 0} - isSelectionMode={viewMode === ViewMode.SELECT_THUMBNAIL} - singleSelect={viewMode === ViewMode.SELECT_THUMBNAIL} + isSelectionMode={viewMode === AlbumPageViewMode.SELECT_THUMBNAIL} + singleSelect={viewMode === AlbumPageViewMode.SELECT_THUMBNAIL} showArchiveIcon onSelect={({ id }) => handleUpdateThumbnail(id)} onEscape={handleEscape} > - {#if viewMode !== ViewMode.SELECT_THUMBNAIL} + {#if viewMode !== AlbumPageViewMode.SELECT_THUMBNAIL} <!-- ALBUM TITLE --> <section class="pt-8 md:pt-24"> <AlbumTitle @@ -616,18 +618,18 @@ color="gray" size="20" icon={mdiLink} - on:click={() => (viewMode = ViewMode.LINK_SHARING)} + onclick={() => (viewMode = AlbumPageViewMode.LINK_SHARING)} /> {/if} <!-- owner --> - <button type="button" on:click={() => (viewMode = ViewMode.VIEW_USERS)}> + <button type="button" onclick={() => (viewMode = AlbumPageViewMode.VIEW_USERS)}> <UserAvatar user={album.owner} size="md" /> </button> <!-- users with write access (collaborators) --> {#each album.albumUsers.filter(({ role }) => role === AlbumUserRole.Editor) as { user } (user.id)} - <button type="button" on:click={() => (viewMode = ViewMode.VIEW_USERS)}> + <button type="button" onclick={() => (viewMode = AlbumPageViewMode.VIEW_USERS)}> <UserAvatar {user} size="md" /> </button> {/each} @@ -639,7 +641,7 @@ color="gray" size="20" icon={mdiDotsVertical} - on:click={() => (viewMode = ViewMode.VIEW_USERS)} + onclick={() => (viewMode = AlbumPageViewMode.VIEW_USERS)} /> {/if} @@ -648,7 +650,7 @@ color="gray" size="20" icon={mdiPlus} - on:click={() => (viewMode = ViewMode.SELECT_USERS)} + onclick={() => (viewMode = AlbumPageViewMode.SELECT_USERS)} title={$t('add_more_users')} /> {/if} @@ -665,7 +667,7 @@ <p class="text-xs dark:text-immich-dark-fg">{$t('add_photos').toUpperCase()}</p> <button type="button" - on:click={() => (viewMode = ViewMode.SELECT_ASSETS)} + onclick={() => (viewMode = AlbumPageViewMode.SELECT_ASSETS)} class="mt-5 flex w-full place-items-center gap-6 rounded-md border bg-immich-bg px-8 py-8 text-immich-fg transition-all hover:bg-gray-100 hover:text-immich-primary dark:border-none dark:bg-immich-dark-gray dark:text-immich-dark-fg dark:hover:text-immich-dark-primary" > <span class="text-text-immich-primary dark:text-immich-dark-primary" @@ -717,29 +719,29 @@ </div> {/if} </div> -{#if viewMode === ViewMode.SELECT_USERS} +{#if viewMode === AlbumPageViewMode.SELECT_USERS} <UserSelectionModal {album} onSelect={handleAddUsers} - onShare={() => (viewMode = ViewMode.LINK_SHARING)} - onClose={() => (viewMode = ViewMode.VIEW)} + onShare={() => (viewMode = AlbumPageViewMode.LINK_SHARING)} + onClose={() => (viewMode = AlbumPageViewMode.VIEW)} /> {/if} -{#if viewMode === ViewMode.LINK_SHARING} - <CreateSharedLinkModal albumId={album.id} onClose={() => (viewMode = ViewMode.VIEW)} /> +{#if viewMode === AlbumPageViewMode.LINK_SHARING} + <CreateSharedLinkModal albumId={album.id} onClose={() => (viewMode = AlbumPageViewMode.VIEW)} /> {/if} -{#if viewMode === ViewMode.VIEW_USERS} +{#if viewMode === AlbumPageViewMode.VIEW_USERS} <ShareInfoModal - onClose={() => (viewMode = ViewMode.VIEW)} + onClose={() => (viewMode = AlbumPageViewMode.VIEW)} {album} - onRemove={(userId) => handleRemoveUser(userId, ViewMode.VIEW_USERS)} + onRemove={(userId) => handleRemoveUser(userId, AlbumPageViewMode.VIEW_USERS)} onRefreshAlbum={refreshAlbum} /> {/if} -{#if viewMode === ViewMode.OPTIONS && $user} +{#if viewMode === AlbumPageViewMode.OPTIONS && $user} <AlbumOptions {album} order={albumOrder} @@ -748,11 +750,11 @@ albumOrder = order; await setModeToView(); }} - onRemove={(userId) => handleRemoveUser(userId, ViewMode.OPTIONS)} + onRemove={(userId) => handleRemoveUser(userId, AlbumPageViewMode.OPTIONS)} onRefreshAlbum={refreshAlbum} - onClose={() => (viewMode = ViewMode.VIEW)} + onClose={() => (viewMode = AlbumPageViewMode.VIEW)} onToggleEnabledActivity={handleToggleEnableActivity} - onShowSelectSharedUser={() => (viewMode = ViewMode.SELECT_USERS)} + onShowSelectSharedUser={() => (viewMode = AlbumPageViewMode.SELECT_USERS)} /> {/if} diff --git a/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte index 2ce1309351..3402dff960 100644 --- a/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/archive/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -19,13 +19,17 @@ import { t } from 'svelte-i18n'; import { onDestroy } from 'svelte'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); const assetStore = new AssetStore({ isArchived: true }); const assetInteractionStore = createAssetInteractionStore(); const { isMultiSelectState, selectedAssets } = assetInteractionStore; - $: isAllFavorite = [...$selectedAssets].every((asset) => asset.isFavorite); + let isAllFavorite = $derived([...$selectedAssets].every((asset) => asset.isFavorite)); onDestroy(() => { assetStore.destroy(); @@ -51,6 +55,8 @@ <UserPageLayout hideNavbar={$isMultiSelectState} title={data.meta.title} scrollbar={false}> <AssetGrid enableRouting={true} {assetStore} {assetInteractionStore} removeAction={AssetAction.UNARCHIVE}> - <EmptyPlaceholder text={$t('no_archived_assets_message')} slot="empty" /> + {#snippet empty()} + <EmptyPlaceholder text={$t('no_archived_assets_message')} /> + {/snippet} </AssetGrid> </UserPageLayout> diff --git a/web/src/routes/(user)/buy/+page.svelte b/web/src/routes/(user)/buy/+page.svelte index 1f71269c11..eb0194c447 100644 --- a/web/src/routes/(user)/buy/+page.svelte +++ b/web/src/routes/(user)/buy/+page.svelte @@ -11,8 +11,12 @@ import { purchaseStore } from '$lib/stores/purchase.store'; import SupporterBadge from '$lib/components/shared-components/side-bar/supporter-badge.svelte'; - export let data: PageData; - let showLicenseActivated = false; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); + let showLicenseActivated = $state(false); const { isPurchased } = purchaseStore; </script> diff --git a/web/src/routes/(user)/explore/+page.svelte b/web/src/routes/(user)/explore/+page.svelte index ebd2e96b5a..c31c0538e4 100644 --- a/web/src/routes/(user)/explore/+page.svelte +++ b/web/src/routes/(user)/explore/+page.svelte @@ -12,7 +12,11 @@ import { websocketEvents } from '$lib/stores/websocket'; import SingleGridRow from '$lib/components/shared-components/single-grid-row.svelte'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); enum Field { CITY = 'exifInfo.city', @@ -23,9 +27,10 @@ return targetField?.items || []; }; - $: places = getFieldItems(data.items, Field.CITY); - $: people = data.response.people; - $: hasPeople = data.response.total > 0; + let places = $derived(getFieldItems(data.items, Field.CITY)); + let people = $state(data.response.people); + + let hasPeople = $derived(data.response.total > 0); onMount(() => { return websocketEvents.on('on_person_thumbnail', (personId: string) => { @@ -51,13 +56,21 @@ draggable="false">{$t('view_all')}</a > </div> - <SingleGridRow class="grid md:grid-auto-fill-28 grid-auto-fill-20 gap-x-4" let:itemCount> - {#each people.slice(0, itemCount) as person (person.id)} - <a href="{AppRoute.PEOPLE}/{person.id}" class="text-center"> - <ImageThumbnail circle shadow url={getPeopleThumbnailUrl(person)} altText={person.name} widthStyle="100%" /> - <p class="mt-2 text-ellipsis text-sm font-medium dark:text-white">{person.name}</p> - </a> - {/each} + <SingleGridRow class="grid md:grid-auto-fill-28 grid-auto-fill-20 gap-x-4"> + {#snippet children({ itemCount })} + {#each people.slice(0, itemCount) as person (person.id)} + <a href="{AppRoute.PEOPLE}/{person.id}" class="text-center"> + <ImageThumbnail + circle + shadow + url={getPeopleThumbnailUrl(person)} + altText={person.name} + widthStyle="100%" + /> + <p class="mt-2 text-ellipsis text-sm font-medium dark:text-white">{person.name}</p> + </a> + {/each} + {/snippet} </SingleGridRow> </div> {/if} @@ -72,23 +85,29 @@ draggable="false">{$t('view_all')}</a > </div> - <SingleGridRow class="grid md:grid-auto-fill-36 grid-auto-fill-28 gap-x-4" let:itemCount> - {#each places.slice(0, itemCount) as item (item.data.id)} - <a class="relative" href="{AppRoute.SEARCH}?{getMetadataSearchQuery({ city: item.value })}" draggable="false"> - <div class="flex justify-center overflow-hidden rounded-xl brightness-75 filter"> - <img - src={getAssetThumbnailUrl({ id: item.data.id, size: AssetMediaSize.Thumbnail })} - alt={item.value} - class="object-cover aspect-square w-full" - /> - </div> - <span - class="w-100 absolute bottom-2 w-full text-ellipsis px-1 text-center text-sm font-medium capitalize text-white backdrop-blur-[1px] hover:cursor-pointer" + <SingleGridRow class="grid md:grid-auto-fill-36 grid-auto-fill-28 gap-x-4"> + {#snippet children({ itemCount })} + {#each places.slice(0, itemCount) as item (item.data.id)} + <a + class="relative" + href="{AppRoute.SEARCH}?{getMetadataSearchQuery({ city: item.value })}" + draggable="false" > - {item.value} - </span> - </a> - {/each} + <div class="flex justify-center overflow-hidden rounded-xl brightness-75 filter"> + <img + src={getAssetThumbnailUrl({ id: item.data.id, size: AssetMediaSize.Thumbnail })} + alt={item.value} + class="object-cover aspect-square w-full" + /> + </div> + <span + class="w-100 absolute bottom-2 w-full text-ellipsis px-1 text-center text-sm font-medium capitalize text-white backdrop-blur-[1px] hover:cursor-pointer" + > + {item.value} + </span> + </a> + {/each} + {/snippet} </SingleGridRow> </div> {/if} diff --git a/web/src/routes/(user)/favorites/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/favorites/[[photos=photos]]/[[assetId=id]]/+page.svelte index 13e70c9161..8699582f9a 100644 --- a/web/src/routes/(user)/favorites/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/favorites/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -21,13 +21,17 @@ import { t } from 'svelte-i18n'; import { onDestroy } from 'svelte'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); const assetStore = new AssetStore({ isFavorite: true }); const assetInteractionStore = createAssetInteractionStore(); const { isMultiSelectState, selectedAssets } = assetInteractionStore; - $: isAllArchive = [...$selectedAssets].every((asset) => asset.isArchived); + let isAllArchive = $derived([...$selectedAssets].every((asset) => asset.isArchived)); onDestroy(() => { assetStore.destroy(); @@ -56,6 +60,8 @@ <UserPageLayout hideNavbar={$isMultiSelectState} title={data.meta.title} scrollbar={false}> <AssetGrid enableRouting={true} {assetStore} {assetInteractionStore} removeAction={AssetAction.UNFAVORITE}> - <EmptyPlaceholder text={$t('no_favorites_message')} slot="empty" /> + {#snippet empty()} + <EmptyPlaceholder text={$t('no_favorites_message')} /> + {/snippet} </AssetGrid> </UserPageLayout> diff --git a/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte index 2cd3d8c9f3..255a4373ca 100644 --- a/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -18,15 +18,19 @@ import Breadcrumbs from '$lib/components/shared-components/tree/breadcrumbs.svelte'; import SkipLink from '$lib/components/elements/buttons/skip-link.svelte'; - export let data: PageData; + interface Props { + data: PageData; + } - let selectedAssets: Set<AssetResponseDto> = new Set(); - const viewport: Viewport = { width: 0, height: 0 }; + let { data }: Props = $props(); - $: pathSegments = data.path ? data.path.split('/') : []; - $: tree = buildTree($foldersStore?.uniquePaths || []); - $: currentPath = $page.url.searchParams.get(QueryParameter.PATH) || ''; - $: currentTreeItems = currentPath ? data.currentFolders : Object.keys(tree); + let selectedAssets: Set<AssetResponseDto> = $state(new Set()); + const viewport: Viewport = $state({ width: 0, height: 0 }); + + let pathSegments = $derived(data.path ? data.path.split('/') : []); + let tree = $derived(buildTree($foldersStore?.uniquePaths || [])); + let currentPath = $derived($page.url.searchParams.get(QueryParameter.PATH) || ''); + let currentTreeItems = $derived(currentPath ? data.currentFolders : Object.keys(tree)); onMount(async () => { await foldersStore.fetchUniquePaths(); @@ -48,20 +52,22 @@ </script> <UserPageLayout title={data.meta.title}> - <SideBarSection slot="sidebar"> - <SkipLink target={`#${headerId}`} text={$t('skip_to_folders')} /> - <section> - <div class="text-xs pl-4 mb-2 dark:text-white">{$t('explorer').toUpperCase()}</div> - <div class="h-full"> - <TreeItems - icons={{ default: mdiFolderOutline, active: mdiFolder }} - items={tree} - active={currentPath} - {getLink} - /> - </div> - </section> - </SideBarSection> + {#snippet sidebar()} + <SideBarSection> + <SkipLink target={`#${headerId}`} text={$t('skip_to_folders')} /> + <section> + <div class="text-xs pl-4 mb-2 dark:text-white">{$t('explorer').toUpperCase()}</div> + <div class="h-full"> + <TreeItems + icons={{ default: mdiFolderOutline, active: mdiFolder }} + items={tree} + active={currentPath} + {getLink} + /> + </div> + </section> + </SideBarSection> + {/snippet} <Breadcrumbs {pathSegments} icon={mdiFolderHome} title={$t('folders')} {getLink} /> diff --git a/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte index adbc3cfe69..613ae4d66b 100644 --- a/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -1,4 +1,6 @@ <script lang="ts"> + import { run } from 'svelte/legacy'; + import { goto } from '$app/navigation'; import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte'; import MapSettingsModal from '$lib/components/map-page/map-settings-modal.svelte'; @@ -17,15 +19,19 @@ import { handlePromiseError } from '$lib/utils'; import { navigate } from '$lib/utils/navigation'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); let { isViewing: showAssetViewer, asset: viewingAsset, setAssetId } = assetViewingStore; let abortController: AbortController; - let mapMarkers: MapMarkerResponseDto[] = []; - let viewingAssets: string[] = []; + let mapMarkers: MapMarkerResponseDto[] = $state([]); + let viewingAssets: string[] = $state([]); let viewingAssetCursor = 0; - let showSettingsModal = false; + let showSettingsModal = $state(false); onMount(async () => { mapMarkers = await loadMapMarkers(); @@ -36,9 +42,11 @@ assetViewingStore.showAssetViewer(false); }); - $: if (!$featureFlags.map) { - handlePromiseError(goto(AppRoute.PHOTOS)); - } + run(() => { + if (!$featureFlags.map) { + handlePromiseError(goto(AppRoute.PHOTOS)); + } + }); const omit = (obj: MapSettings, key: string) => { return Object.fromEntries(Object.entries(obj).filter(([k]) => k !== key)); }; diff --git a/web/src/routes/(user)/partners/[userId]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/partners/[userId]/[[photos=photos]]/[[assetId=id]]/+page.svelte index 2caab9de82..4332e5339e 100644 --- a/web/src/routes/(user)/partners/[userId]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/partners/[userId]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -15,7 +15,11 @@ import { mdiPlus, mdiArrowLeft } from '@mdi/js'; import { t } from 'svelte-i18n'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); const assetStore = new AssetStore({ userId: data.partner.id, isArchived: false, withStacked: true }); const assetInteractionStore = createAssetInteractionStore(); @@ -39,11 +43,11 @@ </AssetSelectControlBar> {:else} <ControlAppBar showBackButton backIcon={mdiArrowLeft} onClose={() => goto(AppRoute.SHARING)}> - <svelte:fragment slot="leading"> + {#snippet leading()} <p class="whitespace-nowrap text-immich-fg dark:text-immich-dark-fg"> {data.partner.name}'s photos </p> - </svelte:fragment> + {/snippet} </ControlAppBar> {/if} <AssetGrid enableRouting={true} {assetStore} {assetInteractionStore} /> diff --git a/web/src/routes/(user)/people/+page.svelte b/web/src/routes/(user)/people/+page.svelte index b6d25c48bf..5b3fbeea03 100644 --- a/web/src/routes/(user)/people/+page.svelte +++ b/web/src/routes/(user)/people/+page.svelte @@ -38,34 +38,35 @@ import { fly } from 'svelte/transition'; import type { PageData } from './$types'; - export let data: PageData; + interface Props { + data: PageData; + } - $: people = data.people.people; - $: visiblePeople = people.filter((people) => !people.isHidden); - $: countVisiblePeople = searchName ? searchedPeopleLocal.length : data.people.total - data.people.hidden; - $: showPeople = searchName ? searchedPeopleLocal : visiblePeople; - - let selectHidden = false; - let searchName = ''; - let showChangeNameModal = false; - let showSetBirthDateModal = false; - let showMergeModal = false; - let personName = ''; - let nextPage = data.people.hasNextPage ? 2 : null; - let personMerge1: PersonResponseDto; - let personMerge2: PersonResponseDto; - let potentialMergePeople: PersonResponseDto[] = []; - let edittingPerson: PersonResponseDto | null = null; - let searchedPeopleLocal: PersonResponseDto[] = []; - let handleSearchPeople: (force?: boolean, name?: string) => Promise<void>; - let changeNameInputEl: HTMLInputElement | null; - let innerHeight: number; + let { data }: Props = $props(); + let selectHidden = $state(false); + let searchName = $state(''); + let showChangeNameModal = $state(false); + let showSetBirthDateModal = $state(false); + let showMergeModal = $state(false); + let personName = $state(''); + let nextPage = $state(data.people.hasNextPage ? 2 : null); + let personMerge1 = $state<PersonResponseDto>(); + let personMerge2 = $state<PersonResponseDto>(); + let potentialMergePeople: PersonResponseDto[] = $state([]); + let edittingPerson: PersonResponseDto | null = $state(null); + let searchedPeopleLocal: PersonResponseDto[] = $state([]); + // let handleSearchPeople: (force?: boolean, name?: string) => Promise<void> = $state(); + let changeNameInputEl = $state<HTMLInputElement>(); + let innerHeight = $state(0); + let searchPeopleElement = $state<ReturnType<typeof SearchPeople>>(); onMount(() => { const getSearchedPeople = $page.url.searchParams.get(QueryParameter.SEARCHED_PEOPLE); if (getSearchedPeople) { searchName = getSearchedPeople; - handlePromiseError(handleSearchPeople(true, searchName)); + if (searchPeopleElement) { + handlePromiseError(searchPeopleElement.searchPeople(true, searchName)); + } } return websocketEvents.on('on_person_thumbnail', (personId: string) => { for (const person of people) { @@ -198,7 +199,9 @@ ); }; - const submitNameChange = async () => { + const submitNameChange = async (event: Event) => { + event.preventDefault(); + potentialMergePeople = []; showChangeNameModal = false; if (!edittingPerson || personName === edittingPerson.name) { @@ -225,9 +228,9 @@ potentialMergePeople = people .filter( (person: PersonResponseDto) => - personMerge2.name.toLowerCase() === person.name.toLowerCase() && + personMerge2?.name.toLowerCase() === person.name.toLowerCase() && person.id !== personMerge2.id && - person.id !== personMerge1.id && + person.id !== personMerge1?.id && !person.isHidden, ) .slice(0, 3); @@ -293,11 +296,26 @@ const onResetSearchBar = async () => { await clearQueryParam(QueryParameter.SEARCHED_PEOPLE, $page.url); }; + + let people = $state(data.people.people); + $effect(() => { + people = data.people.people; + }); + let visiblePeople = $derived(people.filter((people) => !people.isHidden)); + let countVisiblePeople = $derived(searchName ? searchedPeopleLocal.length : data.people.total - data.people.hidden); + let showPeople = $derived(searchName ? searchedPeopleLocal : visiblePeople); + + // const submitNameChange = (event: Event) => { + // event.preventDefault(); + // if (searchPeopleElement) { + // handlePromiseError(searchPeopleElement.searchPeople(true, searchName)); + // } + // }; </script> <svelte:window bind:innerHeight /> -{#if showMergeModal} +{#if showMergeModal && personMerge1 && personMerge2} <MergeSuggestionModal {personMerge1} {personMerge2} @@ -312,23 +330,23 @@ title={$t('people')} description={countVisiblePeople === 0 && !searchName ? undefined : `(${countVisiblePeople.toLocaleString($locale)})`} > - <svelte:fragment slot="buttons"> + {#snippet buttons()} {#if people.length > 0} <div class="flex gap-2 items-center justify-center"> <div class="hidden sm:block"> <div class="w-40 lg:w-80 h-10"> <SearchPeople + bind:this={searchPeopleElement} type="searchBar" placeholder={$t('search_people')} onReset={onResetSearchBar} onSearch={handleSearch} bind:searchName bind:searchedPeopleLocal - bind:handleSearch={handleSearchPeople} /> </div> </div> - <LinkButton on:click={() => (selectHidden = !selectHidden)}> + <LinkButton onclick={() => (selectHidden = !selectHidden)}> <div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm"> <Icon path={mdiEyeOutline} size="18" /> <p class="ml-2">{$t('show_and_hide_people')}</p> @@ -336,24 +354,20 @@ </LinkButton> </div> {/if} - </svelte:fragment> + {/snippet} {#if countVisiblePeople > 0 && (!searchName || searchedPeopleLocal.length > 0)} - <PeopleInfiniteScroll - people={showPeople} - hasNextPage={!!nextPage && !searchName} - {loadNextPage} - let:person - let:index - > - <PeopleCard - {person} - preload={index < 20} - onChangeName={() => handleChangeName(person)} - onSetBirthDate={() => handleSetBirthDate(person)} - onMergePeople={() => handleMergePeople(person)} - onHidePerson={() => handleHidePerson(person)} - /> + <PeopleInfiniteScroll people={showPeople} hasNextPage={!!nextPage && !searchName} {loadNextPage}> + {#snippet children({ person, index })} + <PeopleCard + {person} + preload={index < 20} + onChangeName={() => handleChangeName(person)} + onSetBirthDate={() => handleSetBirthDate(person)} + onMergePeople={() => handleMergePeople(person)} + onHidePerson={() => handleHidePerson(person)} + /> + {/snippet} </PeopleInfiniteScroll> {:else} <div class="flex min-h-[calc(66vh_-_11rem)] w-full place-content-center items-center dark:text-white"> @@ -368,7 +382,7 @@ {#if showChangeNameModal} <FullScreenModal title={$t('change_name')} onClose={() => (showChangeNameModal = false)}> - <form on:submit|preventDefault={submitNameChange} autocomplete="off" id="change-name-form"> + <form onsubmit={submitNameChange} autocomplete="off" id="change-name-form"> <div class="flex flex-col gap-2"> <label class="immich-form-label" for="name">{$t('name')}</label> <input @@ -381,16 +395,17 @@ /> </div> </form> - <svelte:fragment slot="sticky-bottom"> + + {#snippet stickyBottom()} <Button color="gray" fullwidth - on:click={() => { + onclick={() => { showChangeNameModal = false; }}>{$t('cancel')}</Button > <Button type="submit" fullwidth form="change-name-form">{$t('ok')}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> {/if} diff --git a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte index d68367d106..d9b7c6a08f 100644 --- a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -25,7 +25,7 @@ NotificationType, notificationController, } from '$lib/components/shared-components/notification/notification'; - import { AppRoute, QueryParameter } from '$lib/constants'; + import { AppRoute, PersonPageViewMode, QueryParameter } from '$lib/constants'; import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store'; import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { AssetStore } from '$lib/stores/assets.store'; @@ -58,47 +58,33 @@ import { t } from 'svelte-i18n'; import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte'; - export let data: PageData; - - let numberOfAssets = data.statistics.assets; - let { isViewing: showAssetViewer } = assetViewingStore; - - enum ViewMode { - VIEW_ASSETS = 'view-assets', - SELECT_PERSON = 'select-person', - MERGE_PEOPLE = 'merge-people', - SUGGEST_MERGE = 'suggest-merge', - BIRTH_DATE = 'birth-date', - UNASSIGN_ASSETS = 'unassign-faces', + interface Props { + data: PageData; } + let { data = $bindable() }: Props = $props(); + + let numberOfAssets = $state(data.statistics.assets); + let { isViewing: showAssetViewer } = assetViewingStore; + let assetStore = new AssetStore({ isArchived: false, personId: data.person.id, }); - $: person = data.person; - $: thumbnailData = getPeopleThumbnailUrl(person); - $: if (person) { - handlePromiseError(updateAssetCount()); - handlePromiseError(assetStore.updateOptions({ personId: person.id })); - } - const assetInteractionStore = createAssetInteractionStore(); const { selectedAssets, isMultiSelectState } = assetInteractionStore; - let viewMode: ViewMode = ViewMode.VIEW_ASSETS; - let isEditingName = false; - let previousRoute: string = AppRoute.EXPLORE; + let viewMode: PersonPageViewMode = $state(PersonPageViewMode.VIEW_ASSETS); + let isEditingName = $state(false); + let previousRoute: string = $state(AppRoute.EXPLORE); let people: PersonResponseDto[] = []; - let personMerge1: PersonResponseDto; - let personMerge2: PersonResponseDto; - let potentialMergePeople: PersonResponseDto[] = []; - - let refreshAssetGrid = false; + let personMerge1: PersonResponseDto | undefined = $state(); + let personMerge2: PersonResponseDto | undefined = $state(); + let potentialMergePeople: PersonResponseDto[] = $state([]); let personName = ''; - let suggestedPeople: PersonResponseDto[] = []; + let suggestedPeople: PersonResponseDto[] = $state([]); /** * Save the word used to search people name: for example, @@ -107,11 +93,8 @@ * However, it needs to make a new api request if searching 'r' returns 20 names (arbitrary value, the limit sent back by the server). * or if the new search word starts with another word / letter **/ - let isSearchingPeople = false; - let suggestionContainer: HTMLDivElement; - - $: isAllArchive = [...$selectedAssets].every((asset) => asset.isArchived); - $: isAllFavorite = [...$selectedAssets].every((asset) => asset.isFavorite); + let isSearchingPeople = $state(false); + let suggestionContainer: HTMLElement | undefined = $state(); onMount(() => { const action = $page.url.searchParams.get(QueryParameter.ACTION); @@ -120,7 +103,7 @@ previousRoute = getPreviousRoute; } if (action == 'merge') { - viewMode = ViewMode.MERGE_PEOPLE; + viewMode = PersonPageViewMode.MERGE_PEOPLE; } return websocketEvents.on('on_person_thumbnail', (personId: string) => { @@ -131,7 +114,7 @@ }); const handleEscape = async () => { - if ($showAssetViewer || viewMode === ViewMode.SUGGEST_MERGE) { + if ($showAssetViewer || viewMode === PersonPageViewMode.SUGGEST_MERGE) { return; } if ($isMultiSelectState) { @@ -162,11 +145,11 @@ const handleUnmerge = () => { $assetStore.removeAssets([...$selectedAssets].map((a) => a.id)); assetInteractionStore.clearMultiselect(); - viewMode = ViewMode.VIEW_ASSETS; + viewMode = PersonPageViewMode.VIEW_ASSETS; }; const handleReassignAssets = () => { - viewMode = ViewMode.UNASSIGN_ASSETS; + viewMode = PersonPageViewMode.UNASSIGN_ASSETS; }; const toggleHidePerson = async () => { @@ -191,13 +174,11 @@ await updateAssetCount(); await handleGoBack(); - data.person = person; - - refreshAssetGrid = !refreshAssetGrid; + data = { ...data, person }; }; const handleSelectFeaturePhoto = async (asset: AssetResponseDto) => { - if (viewMode !== ViewMode.SELECT_PERSON) { + if (viewMode !== PersonPageViewMode.SELECT_PERSON) { return; } try { @@ -209,12 +190,12 @@ assetInteractionStore.clearMultiselect(); - viewMode = ViewMode.VIEW_ASSETS; + viewMode = PersonPageViewMode.VIEW_ASSETS; }; const handleMergeSamePerson = async (response: [PersonResponseDto, PersonResponseDto]) => { const [personToMerge, personToBeMergedIn] = response; - viewMode = ViewMode.VIEW_ASSETS; + viewMode = PersonPageViewMode.VIEW_ASSETS; isEditingName = false; try { await mergePerson({ @@ -228,7 +209,6 @@ people = people.filter((person: PersonResponseDto) => person.id !== personToMerge.id); if (personToBeMergedIn.name != personName && person.id === personToBeMergedIn.id) { await updateAssetCount(); - refreshAssetGrid = !refreshAssetGrid; return; } await goto(`${AppRoute.PEOPLE}/${personToBeMergedIn.id}`, { replaceState: true }); @@ -243,11 +223,11 @@ personName = person.name; personMerge1 = person; personMerge2 = person2; - viewMode = ViewMode.SUGGEST_MERGE; + viewMode = PersonPageViewMode.SUGGEST_MERGE; }; const changeName = async () => { - viewMode = ViewMode.VIEW_ASSETS; + viewMode = PersonPageViewMode.VIEW_ASSETS; person.name = personName; try { isEditingName = false; @@ -264,7 +244,7 @@ }; const handleCancelEditName = () => { - if (viewMode === ViewMode.SUGGEST_MERGE) { + if (viewMode === PersonPageViewMode.SUGGEST_MERGE) { return; } isSearchingPeople = false; @@ -295,13 +275,13 @@ potentialMergePeople = result .filter( (person: PersonResponseDto) => - personMerge2.name.toLowerCase() === person.name.toLowerCase() && + personMerge2?.name.toLowerCase() === person.name.toLowerCase() && person.id !== personMerge2.id && - person.id !== personMerge1.id && + person.id !== personMerge1?.id && !person.isHidden, ) .slice(0, 3); - viewMode = ViewMode.SUGGEST_MERGE; + viewMode = PersonPageViewMode.SUGGEST_MERGE; return; } await changeName(); @@ -309,7 +289,7 @@ const handleSetBirthDate = async (birthDate: string) => { try { - viewMode = ViewMode.VIEW_ASSETS; + viewMode = PersonPageViewMode.VIEW_ASSETS; person.birthDate = birthDate; const updatedPerson = await updatePerson({ @@ -331,7 +311,7 @@ }; const handleGoBack = async () => { - viewMode = ViewMode.VIEW_ASSETS; + viewMode = PersonPageViewMode.VIEW_ASSETS; if ($page.url.searchParams.has(QueryParameter.ACTION)) { $page.url.searchParams.delete(QueryParameter.ACTION); await goto($page.url); @@ -341,37 +321,50 @@ onDestroy(() => { assetStore.destroy(); }); + let person = $derived(data.person); + + let thumbnailData = $derived(getPeopleThumbnailUrl(person)); + + $effect(() => { + if (person) { + handlePromiseError(updateAssetCount()); + handlePromiseError(assetStore.updateOptions({ personId: person.id })); + } + }); + + let isAllArchive = $derived([...$selectedAssets].every((asset) => asset.isArchived)); + let isAllFavorite = $derived([...$selectedAssets].every((asset) => asset.isFavorite)); </script> -{#if viewMode === ViewMode.UNASSIGN_ASSETS} +{#if viewMode === PersonPageViewMode.UNASSIGN_ASSETS} <UnMergeFaceSelector assetIds={[...$selectedAssets].map((a) => a.id)} personAssets={person} - onClose={() => (viewMode = ViewMode.VIEW_ASSETS)} + onClose={() => (viewMode = PersonPageViewMode.VIEW_ASSETS)} onConfirm={handleUnmerge} /> {/if} -{#if viewMode === ViewMode.SUGGEST_MERGE} +{#if viewMode === PersonPageViewMode.SUGGEST_MERGE && personMerge1 && personMerge2} <MergeSuggestionModal {personMerge1} {personMerge2} {potentialMergePeople} - onClose={() => (viewMode = ViewMode.VIEW_ASSETS)} + onClose={() => (viewMode = PersonPageViewMode.VIEW_ASSETS)} onReject={changeName} onConfirm={handleMergeSamePerson} /> {/if} -{#if viewMode === ViewMode.BIRTH_DATE} +{#if viewMode === PersonPageViewMode.BIRTH_DATE} <SetBirthDateModal birthDate={person.birthDate ?? ''} - onClose={() => (viewMode = ViewMode.VIEW_ASSETS)} + onClose={() => (viewMode = PersonPageViewMode.VIEW_ASSETS)} onUpdate={handleSetBirthDate} /> {/if} -{#if viewMode === ViewMode.MERGE_PEOPLE} +{#if viewMode === PersonPageViewMode.MERGE_PEOPLE} <MergeFaceSelector {person} onBack={handleGoBack} onMerge={handleMerge} /> {/if} @@ -399,14 +392,14 @@ </ButtonContextMenu> </AssetSelectControlBar> {:else} - {#if viewMode === ViewMode.VIEW_ASSETS || viewMode === ViewMode.SUGGEST_MERGE || viewMode === ViewMode.BIRTH_DATE} + {#if viewMode === PersonPageViewMode.VIEW_ASSETS || viewMode === PersonPageViewMode.SUGGEST_MERGE || viewMode === PersonPageViewMode.BIRTH_DATE} <ControlAppBar showBackButton backIcon={mdiArrowLeft} onClose={() => goto(previousRoute)}> - <svelte:fragment slot="trailing"> + {#snippet trailing()} <ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}> <MenuOption text={$t('select_featured_photo')} icon={mdiAccountBoxOutline} - onClick={() => (viewMode = ViewMode.SELECT_PERSON)} + onClick={() => (viewMode = PersonPageViewMode.SELECT_PERSON)} /> <MenuOption text={person.isHidden ? $t('unhide_person') : $t('hide_person')} @@ -416,21 +409,23 @@ <MenuOption text={$t('set_date_of_birth')} icon={mdiCalendarEditOutline} - onClick={() => (viewMode = ViewMode.BIRTH_DATE)} + onClick={() => (viewMode = PersonPageViewMode.BIRTH_DATE)} /> <MenuOption text={$t('merge_people')} icon={mdiAccountMultipleCheckOutline} - onClick={() => (viewMode = ViewMode.MERGE_PEOPLE)} + onClick={() => (viewMode = PersonPageViewMode.MERGE_PEOPLE)} /> </ButtonContextMenu> - </svelte:fragment> + {/snippet} </ControlAppBar> {/if} - {#if viewMode === ViewMode.SELECT_PERSON} - <ControlAppBar onClose={() => (viewMode = ViewMode.VIEW_ASSETS)}> - <svelte:fragment slot="leading">{$t('select_featured_photo')}</svelte:fragment> + {#if viewMode === PersonPageViewMode.SELECT_PERSON} + <ControlAppBar onClose={() => (viewMode = PersonPageViewMode.VIEW_ASSETS)}> + {#snippet leading()} + {$t('select_featured_photo')} + {/snippet} </ControlAppBar> {/if} {/if} @@ -442,12 +437,12 @@ enableRouting={true} {assetStore} {assetInteractionStore} - isSelectionMode={viewMode === ViewMode.SELECT_PERSON} - singleSelect={viewMode === ViewMode.SELECT_PERSON} + isSelectionMode={viewMode === PersonPageViewMode.SELECT_PERSON} + singleSelect={viewMode === PersonPageViewMode.SELECT_PERSON} onSelect={handleSelectFeaturePhoto} onEscape={handleEscape} > - {#if viewMode === ViewMode.VIEW_ASSETS || viewMode === ViewMode.SUGGEST_MERGE || viewMode === ViewMode.BIRTH_DATE} + {#if viewMode === PersonPageViewMode.VIEW_ASSETS || viewMode === PersonPageViewMode.SUGGEST_MERGE || viewMode === PersonPageViewMode.BIRTH_DATE} <!-- Person information block --> <div class="relative w-fit p-4 sm:px-6" @@ -473,7 +468,7 @@ type="button" class="flex items-center justify-center" title={$t('edit_name')} - on:click={() => (isEditingName = true)} + onclick={() => (isEditingName = true)} > <ImageThumbnail circle @@ -510,11 +505,11 @@ {#each suggestedPeople as person, index (person.id)} <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 === + class="flex w-full border border-gray-200 dark:border-immich-dark-gray h-14 place-items-center bg-gray-100 p-2 dark:bg-gray-700 hover:bg-gray-300 hover:dark:bg-[#232932] focus:bg-gray-300 focus:dark:bg-[#232932] {index === suggestedPeople.length - 1 ? 'rounded-b-lg border-b' : ''}" - on:click={() => handleSuggestPeople(person)} + onclick={() => handleSuggestPeople(person)} > <ImageThumbnail circle diff --git a/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte index b44c58bc76..7e233fcd17 100644 --- a/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte @@ -35,13 +35,12 @@ const assetInteractionStore = createAssetInteractionStore(); const { isMultiSelectState, selectedAssets } = assetInteractionStore; - let isAllFavorite: boolean; - let isAllOwned: boolean; - let isAssetStackSelected: boolean; - let isLinkActionAvailable: boolean; + let isAllFavorite = $state(false); + let isAllOwned = $state(false); + let isAssetStackSelected = $state(false); + let isLinkActionAvailable = $state(false); - // svelte-ignore reactive_declaration_non_reactive_property - $: { + $effect(() => { const selection = [...$selectedAssets]; isAllOwned = selection.every((asset) => asset.ownerId === $user.id); isAllFavorite = selection.every((asset) => asset.isFavorite); @@ -52,7 +51,7 @@ selection.some((asset) => asset.type === AssetTypeEnum.Image) && selection.some((asset) => asset.type === AssetTypeEnum.Image); isLinkActionAvailable = isAllOwned && (isLivePhoto || isLivePhotoCandidate); - } + }); const handleEscape = () => { if ($showAssetViewer) { @@ -134,6 +133,8 @@ {#if $preferences.memories.enabled} <MemoryLane /> {/if} - <EmptyPlaceholder text={$t('no_assets_message')} onClick={() => openFileUploadDialog()} slot="empty" /> + {#snippet empty()} + <EmptyPlaceholder text={$t('no_assets_message')} onClick={() => openFileUploadDialog()} /> + {/snippet} </AssetGrid> </UserPageLayout> diff --git a/web/src/routes/(user)/places/+page.svelte b/web/src/routes/(user)/places/+page.svelte index 28c8e95cb1..1808755482 100644 --- a/web/src/routes/(user)/places/+page.svelte +++ b/web/src/routes/(user)/places/+page.svelte @@ -9,7 +9,11 @@ import { t } from 'svelte-i18n'; import { getAssetThumbnailUrl } from '$lib/utils'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); type AssetWithCity = AssetResponseDto & { exifInfo: { @@ -17,10 +21,10 @@ }; }; - $: places = data.items.filter((item): item is AssetWithCity => !!item.exifInfo?.city); - $: hasPlaces = places.length > 0; + let places = $derived(data.items.filter((item): item is AssetWithCity => !!item.exifInfo?.city)); + let hasPlaces = $derived(places.length > 0); - let innerHeight: number; + let innerHeight: number = $state(0); </script> <svelte:window bind:innerHeight /> 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 4605a2207e..0b6fba1613 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 @@ -40,24 +40,40 @@ import AlbumCardGroup from '$lib/components/album-page/album-card-group.svelte'; import { isAlbumsRoute, isPeopleRoute } from '$lib/utils/navigation'; import { t } from 'svelte-i18n'; - import { afterUpdate, tick } from 'svelte'; + import { onMount, tick } from 'svelte'; import AssetJobActions from '$lib/components/photos-page/actions/asset-job-actions.svelte'; const MAX_ASSET_COUNT = 5000; let { isViewing: showAssetViewer } = assetViewingStore; - const viewport: Viewport = { width: 0, height: 0 }; + const viewport: Viewport = $state({ width: 0, height: 0 }); // The GalleryViewer pushes it's own history state, which causes weird // behavior for history.back(). To prevent that we store the previous page // manually and navigate back to that. - let previousRoute = AppRoute.EXPLORE as string; + let previousRoute = $state(AppRoute.EXPLORE as string); let nextPage: number | null = 1; - let searchResultAlbums: AlbumResponseDto[] = []; - let searchResultAssets: AssetResponseDto[] = []; - let isLoading = true; - let scrollY = 0; + let searchResultAlbums: AlbumResponseDto[] = $state([]); + let searchResultAssets: AssetResponseDto[] = $state([]); + let isLoading = $state(true); + let scrollY = $state(0); let scrollYHistory = 0; + let selectedAssets: Set<AssetResponseDto> = $state(new Set()); + + type SearchTerms = MetadataSearchDto & Pick<SmartSearchDto, 'query'>; + + let isMultiSelectionMode = $derived(selectedAssets.size > 0); + let isAllArchived = $derived([...selectedAssets].every((asset) => asset.isArchived)); + let isAllFavorite = $derived([...selectedAssets].every((asset) => asset.isFavorite)); + let searchQuery = $derived($page.url.searchParams.get(QueryParameter.QUERY)); + + onMount(() => { + if (terms && $featureFlags.loaded) { + handlePromiseError(onSearchQueryUpdate()); + } + }); + + let terms = $derived(searchQuery ? JSON.parse(searchQuery) : {}); const onEscape = () => { if ($showAssetViewer) { @@ -74,8 +90,7 @@ $preventRaceConditionSearchBar = false; }; - // save and restore scroll position - afterUpdate(() => { + $effect(() => { if (scrollY) { scrollYHistory = scrollY; } @@ -105,11 +120,6 @@ }); }); - let selectedAssets: Set<AssetResponseDto> = new Set(); - $: isMultiSelectionMode = selectedAssets.size > 0; - $: isAllArchived = [...selectedAssets].every((asset) => asset.isArchived); - $: isAllFavorite = [...selectedAssets].every((asset) => asset.isFavorite); - const onAssetDelete = (assetIds: string[]) => { const assetIdSet = new Set(assetIds); searchResultAssets = searchResultAssets.filter((a: AssetResponseDto) => !assetIdSet.has(a.id)); @@ -118,16 +128,6 @@ selectedAssets = new Set(searchResultAssets); }; - type SearchTerms = MetadataSearchDto & Pick<SmartSearchDto, 'query'>; - - $: searchQuery = $page.url.searchParams.get(QueryParameter.QUERY); - let terms: SearchTerms; - $: terms = searchQuery ? JSON.parse(searchQuery) : {}; - - $: if (terms && $featureFlags.loaded) { - handlePromiseError(onSearchQueryUpdate()); - } - async function onSearchQueryUpdate() { nextPage = 1; searchResultAssets = []; @@ -234,7 +234,7 @@ <div class="fixed z-[100] top-0 left-0 w-full"> <AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}> <CreateSharedLink /> - <CircleIconButton title={$t('select_all')} icon={mdiSelectAll} on:click={handleSelectAll} /> + <CircleIconButton title={$t('select_all')} icon={mdiSelectAll} onclick={handleSelectAll} /> <ButtonContextMenu icon={mdiPlus} title={$t('add_to')}> <AddToAlbum {onAddToAlbum} /> <AddToAlbum shared {onAddToAlbum} /> @@ -256,45 +256,52 @@ <div class="fixed z-[100] top-0 left-0 w-full"> <ControlAppBar onClose={() => goto(previousRoute)} backIcon={mdiArrowLeft}> <div class="w-full flex-1 pl-4"> - <SearchBar grayTheme={false} value={terms.query ?? ''} searchQuery={terms} /> + <SearchBar + grayTheme={false} + value={terms?.query ?? ''} + searchQuery={terms} + onSearch={() => handlePromiseError(onSearchQueryUpdate())} + /> </div> </ControlAppBar> </div> {/if} </section> -<section - id="search-chips" - class="mt-24 text-center w-full flex gap-5 place-content-center place-items-center flex-wrap px-24" -> - {#each getObjectKeys(terms) as key (key)} - {@const value = terms[key]} - <div class="flex place-content-center place-items-center text-xs"> - <div - class="bg-immich-primary py-2 px-4 text-white dark:text-black dark:bg-immich-dark-primary +{#if terms} + <section + id="search-chips" + class="mt-24 text-center w-full flex gap-5 place-content-center place-items-center flex-wrap px-24" + > + {#each getObjectKeys(terms) as key (key)} + {@const value = terms[key]} + <div class="flex place-content-center place-items-center text-xs"> + <div + class="bg-immich-primary py-2 px-4 text-white dark:text-black dark:bg-immich-dark-primary {value === true ? 'rounded-full' : 'rounded-tl-full rounded-bl-full'}" - > - {getHumanReadableSearchKey(key)} - </div> - - {#if value !== true} - <div class="bg-gray-300 py-2 px-4 dark:bg-gray-800 dark:text-white rounded-tr-full rounded-br-full"> - {#if (key === 'takenAfter' || key === 'takenBefore') && typeof value === 'string'} - {getHumanReadableDate(value)} - {:else if key === 'personIds' && Array.isArray(value)} - {#await getPersonName(value) then personName} - {personName} - {/await} - {:else if value === null || value === ''} - {$t('unknown')} - {:else} - {value} - {/if} + > + {getHumanReadableSearchKey(key as keyof SearchTerms)} </div> - {/if} - </div> - {/each} -</section> + + {#if value !== true} + <div class="bg-gray-300 py-2 px-4 dark:bg-gray-800 dark:text-white rounded-tr-full rounded-br-full"> + {#if (key === 'takenAfter' || key === 'takenBefore') && typeof value === 'string'} + {getHumanReadableDate(value)} + {:else if key === 'personIds' && Array.isArray(value)} + {#await getPersonName(value) then personName} + {personName} + {/await} + {:else if value === null || value === ''} + {$t('unknown')} + {:else} + {value} + {/if} + </div> + {/if} + </div> + {/each} + </section> +{/if} <section class="relative mb-12 bg-immich-bg dark:bg-immich-dark-bg m-4" diff --git a/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte index f4fac282ba..dfe465f94d 100644 --- a/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/share/[key]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -15,21 +15,24 @@ import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { tick } from 'svelte'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); let { gridScrollTarget } = assetViewingStore; - let { sharedLink, passwordRequired, sharedLinkKey: key, meta } = data; - let { title, description } = meta; - let isOwned = $user ? $user.id === sharedLink?.userId : false; - let password = ''; - let innerWidth: number; + let { sharedLink, passwordRequired, sharedLinkKey: key, meta } = $state(data); + let { title, description } = $state(meta); + let isOwned = $derived($user ? $user.id === sharedLink?.userId : false); + let password = $state(''); + let innerWidth: number = $state(0); const handlePasswordSubmit = async () => { try { sharedLink = await getMySharedLink({ password, key }); setSharedLink(sharedLink); passwordRequired = false; - isOwned = $user ? $user.id === sharedLink.userId : false; title = (sharedLink.album ? sharedLink.album.albumName : $t('public_share')) + ' - Immich'; description = sharedLink.description || @@ -43,6 +46,11 @@ handleError(error, $t('errors.unable_to_get_shared_link')); } }; + + const onsubmit = async (event: Event) => { + event.preventDefault(); + await handlePasswordSubmit(); + }; </script> <svelte:window bind:innerWidth /> @@ -54,13 +62,13 @@ {#if passwordRequired} <header> <ControlAppBar showBackButton={false}> - <svelte:fragment slot="leading"> + {#snippet leading()} <ImmichLogoSmallLink width={innerWidth} /> - </svelte:fragment> + {/snippet} - <svelte:fragment slot="trailing"> + {#snippet trailing()} <ThemeButton /> - </svelte:fragment> + {/snippet} </ControlAppBar> </header> <main @@ -72,7 +80,7 @@ {$t('sharing_enter_password')} </div> <div class="mt-4"> - <form novalidate autocomplete="off" on:submit|preventDefault={handlePasswordSubmit}> + <form novalidate autocomplete="off" {onsubmit}> <input type="password" class="immich-form-input mr-2" placeholder={$t('password')} bind:value={password} /> <Button type="submit">{$t('submit')}</Button> </form> diff --git a/web/src/routes/(user)/sharing/+page.svelte b/web/src/routes/(user)/sharing/+page.svelte index 35279a02db..1e59a2720d 100644 --- a/web/src/routes/(user)/sharing/+page.svelte +++ b/web/src/routes/(user)/sharing/+page.svelte @@ -20,7 +20,11 @@ import Albums from '$lib/components/album-page/albums-list.svelte'; import { t } from 'svelte-i18n'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); const settings: AlbumViewSettings = { view: AlbumViewMode.Cover, @@ -34,21 +38,23 @@ </script> <UserPageLayout title={data.meta.title}> - <div class="flex" slot="buttons"> - <LinkButton on:click={() => createAlbumAndRedirect()}> - <div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm"> - <Icon path={mdiPlusBoxOutline} size="18" class="shrink-0" /> - <span class="leading-none max-sm:text-xs">{$t('create_album')}</span> - </div> - </LinkButton> + {#snippet buttons()} + <div class="flex"> + <LinkButton onclick={() => createAlbumAndRedirect()}> + <div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm"> + <Icon path={mdiPlusBoxOutline} size="18" class="shrink-0" /> + <span class="leading-none max-sm:text-xs">{$t('create_album')}</span> + </div> + </LinkButton> - <LinkButton href={AppRoute.SHARED_LINKS}> - <div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm"> - <Icon path={mdiLink} size="18" class="shrink-0" /> - <span class="leading-none max-sm:text-xs">{$t('shared_links')}</span> - </div> - </LinkButton> - </div> + <LinkButton href={AppRoute.SHARED_LINKS}> + <div class="flex flex-wrap place-items-center justify-center gap-x-1 text-sm"> + <Icon path={mdiLink} size="18" class="shrink-0" /> + <span class="leading-none max-sm:text-xs">{$t('shared_links')}</span> + </div> + </LinkButton> + </div> + {/snippet} <div class="flex flex-col"> {#if data.partners.length > 0} @@ -89,7 +95,9 @@ <!-- Shared Album List --> <Albums sharedAlbums={data.sharedAlbums} userSettings={settings} showOwner> <!-- Empty List --> - <EmptyPlaceholder slot="empty" text={$t('no_shared_albums_message')} src={empty2Url} /> + {#snippet empty()} + <EmptyPlaceholder text={$t('no_shared_albums_message')} src={empty2Url} /> + {/snippet} </Albums> </div> </div> diff --git a/web/src/routes/(user)/sharing/sharedlinks/+page.svelte b/web/src/routes/(user)/sharing/sharedlinks/+page.svelte index 67e80f4703..8ed4ae9fb6 100644 --- a/web/src/routes/(user)/sharing/sharedlinks/+page.svelte +++ b/web/src/routes/(user)/sharing/sharedlinks/+page.svelte @@ -15,8 +15,8 @@ import { dialogController } from '$lib/components/shared-components/dialog/dialog'; import { t } from 'svelte-i18n'; - let sharedLinks: SharedLinkResponseDto[] = []; - let editSharedLink: SharedLinkResponseDto | null = null; + let sharedLinks: SharedLinkResponseDto[] = $state([]); + let editSharedLink: SharedLinkResponseDto | null = $state(null); const refresh = async () => { sharedLinks = await getAllSharedLinks(); @@ -53,7 +53,9 @@ </script> <ControlAppBar backIcon={mdiArrowLeft} onClose={() => goto(AppRoute.SHARING)}> - <svelte:fragment slot="leading">{$t('shared_links')}</svelte:fragment> + {#snippet leading()} + {$t('shared_links')} + {/snippet} </ControlAppBar> <section class="mt-[120px] flex flex-col pb-[120px] container max-w-screen-lg mx-auto px-3"> diff --git a/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte index ce91abb451..c52f0acb9e 100644 --- a/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/tags/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -11,13 +11,11 @@ notificationController, NotificationType, } from '$lib/components/shared-components/notification/notification'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; + import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte'; import SideBarSection from '$lib/components/shared-components/side-bar/side-bar-section.svelte'; import TreeItemThumbnails from '$lib/components/shared-components/tree/tree-item-thumbnails.svelte'; import TreeItems from '$lib/components/shared-components/tree/tree-items.svelte'; - import { AppRoute, AssetAction, QueryParameter } from '$lib/constants'; + import { AppRoute, AssetAction, QueryParameter, SettingInputFieldType } from '$lib/constants'; import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store'; import { AssetStore } from '$lib/stores/assets.store'; import { buildTree, normalizeTreePath } from '$lib/utils/tree-utils'; @@ -29,10 +27,14 @@ import Breadcrumbs from '$lib/components/shared-components/tree/breadcrumbs.svelte'; import SkipLink from '$lib/components/elements/buttons/skip-link.svelte'; - export let data: PageData; + interface Props { + data: PageData; + } - $: pathSegments = data.path ? data.path.split('/') : []; - $: currentPath = $page.url.searchParams.get(QueryParameter.PATH) || ''; + let { data }: Props = $props(); + + let pathSegments = $derived(data.path ? data.path.split('/') : []); + let currentPath = $derived($page.url.searchParams.get(QueryParameter.PATH) || ''); const assetInteractionStore = createAssetInteractionStore(); @@ -42,14 +44,19 @@ const assetStore = new AssetStore({}); - $: tags = data.tags; - $: tagsMap = buildMap(tags); - $: tag = currentPath ? tagsMap[currentPath] : null; - $: tagId = tag?.id; - $: tree = buildTree(tags.map((tag) => tag.value)); - $: { + let tags = $state<TagResponseDto[]>([]); + $effect(() => { + tags = data.tags; + }); + + let tagsMap = $derived(buildMap(tags)); + let tag = $derived(currentPath ? tagsMap[currentPath] : null); + let tagId = $derived(tag?.id); + let tree = $derived(buildTree(tags.map((tag) => tag.value))); + + $effect.pre(() => { void assetStore.updateOptions({ tagId }); - } + }); const handleNavigation = async (tag: string) => { await navigateToView(normalizeTreePath(`${data.path || ''}/${tag}`)); @@ -67,15 +74,15 @@ const navigateToView = (path: string) => goto(getLink(path)); - let isNewOpen = false; - let newTagValue = ''; + let isNewOpen = $state(false); + let newTagValue = $state(''); const handleCreate = () => { newTagValue = tag ? tag.value + '/' : ''; isNewOpen = true; }; - let isEditOpen = false; - let newTagColor = ''; + let isEditOpen = $state(false); + let newTagColor = $state(''); const handleEdit = () => { newTagColor = tag?.color ?? ''; isEditOpen = true; @@ -135,49 +142,66 @@ const parentPath = pathSegments.slice(0, -1).join('/'); await navigateToView(parentPath); }; + + const onsubmit = async (event: Event) => { + event.preventDefault(); + await handleSubmit(); + }; </script> <UserPageLayout title={data.meta.title} scrollbar={false}> - <SideBarSection slot="sidebar"> - <SkipLink target={`#${headerId}`} text={$t('skip_to_tags')} /> + {#snippet sidebar()} + <SideBarSection> + <SkipLink target={`#${headerId}`} text={$t('skip_to_tags')} /> + <section> + <div class="text-xs pl-4 mb-2 dark:text-white">{$t('explorer').toUpperCase()}</div> + <div class="h-full"> + <TreeItems + icons={{ default: mdiTag, active: mdiTag }} + items={tree} + active={currentPath} + {getLink} + {getColor} + /> + </div> + </section> + </SideBarSection> + {/snippet} + + {#snippet buttons()} <section> - <div class="text-xs pl-4 mb-2 dark:text-white">{$t('explorer').toUpperCase()}</div> - <div class="h-full"> - <TreeItems icons={{ default: mdiTag, active: mdiTag }} items={tree} active={currentPath} {getLink} {getColor} /> - </div> + <LinkButton onclick={handleCreate}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiPlus} size="18" /> + <p class="hidden md:block">{$t('create_tag')}</p> + </div> + </LinkButton> + + {#if pathSegments.length > 0 && tag} + <LinkButton onclick={handleEdit}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiPencil} size="18" /> + <p class="hidden md:block">{$t('edit_tag')}</p> + </div> + </LinkButton> + <LinkButton onclick={handleDelete}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiTrashCanOutline} size="18" /> + <p class="hidden md:block">{$t('delete_tag')}</p> + </div> + </LinkButton> + {/if} </section> - </SideBarSection> - - <section slot="buttons"> - <LinkButton on:click={handleCreate}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiPlus} size="18" /> - <p class="hidden md:block">{$t('create_tag')}</p> - </div> - </LinkButton> - - {#if pathSegments.length > 0 && tag} - <LinkButton on:click={handleEdit}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiPencil} size="18" /> - <p class="hidden md:block">{$t('edit_tag')}</p> - </div> - </LinkButton> - <LinkButton on:click={handleDelete}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiTrashCanOutline} size="18" /> - <p class="hidden md:block">{$t('delete_tag')}</p> - </div> - </LinkButton> - {/if} - </section> + {/snippet} <Breadcrumbs {pathSegments} icon={mdiTagMultiple} title={$t('tags')} {getLink} /> <section class="mt-2 h-full"> {#if tag} <AssetGrid enableRouting={true} {assetStore} {assetInteractionStore} removeAction={AssetAction.UNARCHIVE}> - <TreeItemThumbnails items={data.children} icon={mdiTag} onClick={handleNavigation} slot="empty" /> + {#snippet empty()} + <TreeItemThumbnails items={data.children} icon={mdiTag} onClick={handleNavigation} /> + {/snippet} </AssetGrid> {:else} <TreeItemThumbnails items={Object.keys(tree)} icon={mdiTag} onClick={handleNavigation} /> @@ -193,7 +217,7 @@ </p> </div> - <form on:submit|preventDefault={handleSubmit} autocomplete="off" id="create-tag-form"> + <form {onsubmit} autocomplete="off" id="create-tag-form"> <div class="my-4 flex flex-col gap-2"> <SettingInputField inputType={SettingInputFieldType.TEXT} @@ -204,16 +228,17 @@ /> </div> </form> - <svelte:fragment slot="sticky-bottom"> - <Button color="gray" fullwidth on:click={() => handleCancel()}>{$t('cancel')}</Button> + + {#snippet stickyBottom()} + <Button color="gray" fullwidth onclick={() => handleCancel()}>{$t('cancel')}</Button> <Button type="submit" fullwidth form="create-tag-form">{$t('create')}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> {/if} {#if isEditOpen} <FullScreenModal title={$t('edit_tag')} icon={mdiTag} onClose={handleCancel}> - <form on:submit|preventDefault={handleSubmit} autocomplete="off" id="edit-tag-form"> + <form {onsubmit} autocomplete="off" id="edit-tag-form"> <div class="my-4 flex flex-col gap-2"> <SettingInputField inputType={SettingInputFieldType.COLOR} @@ -222,9 +247,10 @@ /> </div> </form> - <svelte:fragment slot="sticky-bottom"> - <Button color="gray" fullwidth on:click={() => handleCancel()}>{$t('cancel')}</Button> + + {#snippet stickyBottom()} + <Button color="gray" fullwidth onclick={() => handleCancel()}>{$t('cancel')}</Button> <Button type="submit" fullwidth form="edit-tag-form">{$t('save')}</Button> - </svelte:fragment> + {/snippet} </FullScreenModal> {/if} diff --git a/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte index 862d9382a4..8803ea38c8 100644 --- a/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -27,7 +27,11 @@ import { t } from 'svelte-i18n'; import { onDestroy } from 'svelte'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); if (!$featureFlags.trash) { handlePromiseError(goto(AppRoute.PHOTOS)); @@ -99,26 +103,30 @@ {#if $featureFlags.loaded && $featureFlags.trash} <UserPageLayout hideNavbar={$isMultiSelectState} title={data.meta.title} scrollbar={false}> - <div class="flex place-items-center gap-2" slot="buttons"> - <LinkButton on:click={handleRestoreTrash} disabled={$isMultiSelectState}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiHistory} size="18" /> - {$t('restore_all')} - </div> - </LinkButton> - <LinkButton on:click={() => handleEmptyTrash()} disabled={$isMultiSelectState}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiDeleteForeverOutline} size="18" /> - {$t('empty_trash')} - </div> - </LinkButton> - </div> + {#snippet buttons()} + <div class="flex place-items-center gap-2"> + <LinkButton onclick={handleRestoreTrash} disabled={$isMultiSelectState}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiHistory} size="18" /> + {$t('restore_all')} + </div> + </LinkButton> + <LinkButton onclick={() => handleEmptyTrash()} disabled={$isMultiSelectState}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiDeleteForeverOutline} size="18" /> + {$t('empty_trash')} + </div> + </LinkButton> + </div> + {/snippet} <AssetGrid enableRouting={true} {assetStore} {assetInteractionStore}> <p class="font-medium text-gray-500/60 dark:text-gray-300/60 p-4"> {$t('trashed_items_will_be_permanently_deleted_after', { values: { days: $serverConfig.trashDays } })} </p> - <EmptyPlaceholder text={$t('trash_no_results_message')} src={empty3Url} slot="empty" /> + {#snippet empty()} + <EmptyPlaceholder text={$t('trash_no_results_message')} src={empty3Url} /> + {/snippet} </AssetGrid> </UserPageLayout> {/if} diff --git a/web/src/routes/(user)/user-settings/+page.svelte b/web/src/routes/(user)/user-settings/+page.svelte index 4ed46b580f..53cc661a30 100644 --- a/web/src/routes/(user)/user-settings/+page.svelte +++ b/web/src/routes/(user)/user-settings/+page.svelte @@ -7,18 +7,22 @@ import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; import { t } from 'svelte-i18n'; - export let data: PageData; - export let isShowKeyboardShortcut = false; + interface Props { + data: PageData; + isShowKeyboardShortcut?: boolean; + } + + let { data, isShowKeyboardShortcut = $bindable(false) }: Props = $props(); </script> <UserPageLayout title={data.meta.title}> - <svelte:fragment slot="buttons"> + {#snippet buttons()} <CircleIconButton icon={mdiKeyboard} title={$t('show_keyboard_shortcuts')} - on:click={() => (isShowKeyboardShortcut = !isShowKeyboardShortcut)} + onclick={() => (isShowKeyboardShortcut = !isShowKeyboardShortcut)} /> - </svelte:fragment> + {/snippet} <section class="mx-4 flex place-content-center"> <div class="w-full max-w-3xl"> <UserSettingsList keys={data.keys} sessions={data.sessions} /> diff --git a/web/src/routes/(user)/utilities/+page.svelte b/web/src/routes/(user)/utilities/+page.svelte index bf18b99436..6713fe4a4b 100644 --- a/web/src/routes/(user)/utilities/+page.svelte +++ b/web/src/routes/(user)/utilities/+page.svelte @@ -3,7 +3,11 @@ import type { PageData } from './$types'; import UtilitiesMenu from '$lib/components/utilities-page/utilities-menu.svelte'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); </script> <UserPageLayout title={data.meta.title}> diff --git a/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte index e1029b7ccb..fd2bcb438c 100644 --- a/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -22,8 +22,12 @@ import Icon from '$lib/components/elements/icon.svelte'; import { locale } from '$lib/stores/preferences.store'; - export let data: PageData; - export let isShowKeyboardShortcut = false; + interface Props { + data: PageData; + isShowKeyboardShortcut?: boolean; + } + + let { data = $bindable(), isShowKeyboardShortcut = $bindable(false) }: Props = $props(); interface Shortcuts { general: ExplainedShortcut[]; @@ -46,8 +50,8 @@ ], }; - $: hasDuplicates = data.duplicates.length > 0; - + let duplicates = $state(data.duplicates); + let hasDuplicates = $derived(duplicates.length > 0); const withConfirmation = async (callback: () => Promise<void>, prompt?: string, confirmText?: string) => { if (prompt && confirmText) { const isConfirmed = await dialogController.show({ prompt, confirmText }); @@ -82,7 +86,7 @@ await deleteAssets({ assetBulkDeleteDto: { ids: trashIds, force: !$featureFlags.trash } }); await updateAssets({ assetBulkUpdateDto: { ids: duplicateAssetIds, duplicateId: null } }); - data.duplicates = data.duplicates.filter((duplicate) => duplicate.duplicateId !== duplicateId); + duplicates = duplicates.filter((duplicate) => duplicate.duplicateId !== duplicateId); deletedNotification(trashIds.length); }, @@ -95,14 +99,12 @@ await stackAssets(assets, false); const duplicateAssetIds = assets.map((asset) => asset.id); await updateAssets({ assetBulkUpdateDto: { ids: duplicateAssetIds, duplicateId: null } }); - data.duplicates = data.duplicates.filter((duplicate) => duplicate.duplicateId !== duplicateId); + duplicates = duplicates.filter((duplicate) => duplicate.duplicateId !== duplicateId); }; const handleDeduplicateAll = async () => { - const idsToKeep = data.duplicates - .map((group) => suggestDuplicateByFileSize(group.assets)) - .map((asset) => asset?.id); - const idsToDelete = data.duplicates.flatMap((group, i) => + const idsToKeep = duplicates.map((group) => suggestDuplicateByFileSize(group.assets)).map((asset) => asset?.id); + const idsToDelete = duplicates.flatMap((group, i) => group.assets.map((asset) => asset.id).filter((asset) => asset !== idsToKeep[i]), ); @@ -125,7 +127,7 @@ }, }); - data.duplicates = []; + duplicates = []; deletedNotification(idsToDelete.length); }, @@ -135,12 +137,12 @@ }; const handleKeepAll = async () => { - const ids = data.duplicates.flatMap((group) => group.assets.map((asset) => asset.id)); + const ids = duplicates.flatMap((group) => group.assets.map((asset) => asset.id)); return withConfirmation( async () => { await updateAssets({ assetBulkUpdateDto: { ids, duplicateId: null } }); - data.duplicates = []; + duplicates = []; notificationController.show({ message: $t('resolved_all_duplicates'), @@ -153,38 +155,40 @@ }; </script> -<UserPageLayout title={data.meta.title + ` (${data.duplicates.length.toLocaleString($locale)})`} scrollbar={true}> - <div class="flex place-items-center gap-2" slot="buttons"> - <LinkButton on:click={() => handleDeduplicateAll()} disabled={!hasDuplicates}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiTrashCanOutline} size="18" /> - {$t('deduplicate_all')} - </div> - </LinkButton> - <LinkButton on:click={() => handleKeepAll()} disabled={!hasDuplicates}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiCheckOutline} size="18" /> - {$t('keep_all')} - </div> - </LinkButton> - <CircleIconButton - icon={mdiKeyboard} - title={$t('show_keyboard_shortcuts')} - on:click={() => (isShowKeyboardShortcut = !isShowKeyboardShortcut)} - /> - </div> +<UserPageLayout title={data.meta.title + ` (${duplicates.length.toLocaleString($locale)})`} scrollbar={true}> + {#snippet buttons()} + <div class="flex place-items-center gap-2"> + <LinkButton onclick={() => handleDeduplicateAll()} disabled={!hasDuplicates}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiTrashCanOutline} size="18" /> + {$t('deduplicate_all')} + </div> + </LinkButton> + <LinkButton onclick={() => handleKeepAll()} disabled={!hasDuplicates}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiCheckOutline} size="18" /> + {$t('keep_all')} + </div> + </LinkButton> + <CircleIconButton + icon={mdiKeyboard} + title={$t('show_keyboard_shortcuts')} + onclick={() => (isShowKeyboardShortcut = !isShowKeyboardShortcut)} + /> + </div> + {/snippet} <div class="mt-4"> - {#if data.duplicates && data.duplicates.length > 0} + {#if duplicates && duplicates.length > 0} <div class="mb-4 text-sm dark:text-white"> <p>{$t('duplicates_description')}</p> </div> - {#key data.duplicates[0].duplicateId} + {#key duplicates[0].duplicateId} <DuplicatesCompareControl - assets={data.duplicates[0].assets} + assets={duplicates[0].assets} onResolve={(duplicateAssetIds, trashIds) => - handleResolve(data.duplicates[0].duplicateId, duplicateAssetIds, trashIds)} - onStack={(assets) => handleStack(data.duplicates[0].duplicateId, assets)} + handleResolve(duplicates[0].duplicateId, duplicateAssetIds, trashIds)} + onStack={(assets) => handleStack(duplicates[0].duplicateId, assets)} /> {/key} {:else} diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 8f8bd033eb..a6e6727d39 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -1,4 +1,6 @@ <script lang="ts"> + import { run } from 'svelte/legacy'; + import { afterNavigate, beforeNavigate } from '$app/navigation'; import { page } from '$app/stores'; import DownloadPanel from '$lib/components/asset-viewer/download-panel.svelte'; @@ -16,23 +18,21 @@ import { user } from '$lib/stores/user.store'; import { closeWebsocketConnection, openWebsocketConnection } from '$lib/stores/websocket'; import { copyToClipboard, setKey } from '$lib/utils'; - import { onDestroy, onMount } from 'svelte'; + import { onDestroy, onMount, type Snippet } from 'svelte'; import '../app.css'; import { isAssetViewerRoute, isSharedLinkRoute } from '$lib/utils/navigation'; import DialogWrapper from '$lib/components/shared-components/dialog/dialog-wrapper.svelte'; import { t } from 'svelte-i18n'; import Error from '$lib/components/error.svelte'; import { shortcut } from '$lib/actions/shortcut'; - - let showNavigationLoadingBar = false; - $: changeTheme($colorTheme); - - $: if ($user) { - openWebsocketConnection(); - } else { - closeWebsocketConnection(); + interface Props { + children?: Snippet; } + let { children }: Props = $props(); + + let showNavigationLoadingBar = $state(false); + const changeTheme = (theme: ThemeSetting) => { if (theme.system) { theme.value = window.matchMedia('(prefers-color-scheme: dark)').matches ? Theme.DARK : Theme.LIGHT; @@ -82,6 +82,16 @@ afterNavigate(() => { showNavigationLoadingBar = false; }); + run(() => { + changeTheme($colorTheme); + }); + run(() => { + if ($user) { + openWebsocketConnection(); + } else { + closeWebsocketConnection(); + } + }); </script> <svelte:head> @@ -135,7 +145,7 @@ {#if $page.data.error} <Error error={$page.data.error}></Error> {:else} - <slot /> + {@render children?.()} {/if} {#if showNavigationLoadingBar} diff --git a/web/src/routes/admin/jobs-status/+page.svelte b/web/src/routes/admin/jobs-status/+page.svelte index 16c2541e61..b323a136aa 100644 --- a/web/src/routes/admin/jobs-status/+page.svelte +++ b/web/src/routes/admin/jobs-status/+page.svelte @@ -18,13 +18,17 @@ import { t } from 'svelte-i18n'; import type { PageData } from './$types'; - export let data: PageData; + interface Props { + data: PageData; + } - let jobs: AllJobStatusResponseDto; + let { data }: Props = $props(); + + let jobs: AllJobStatusResponseDto | undefined = $state(); let running = true; - let isOpen = false; - let selectedJob: ComboBoxOption | undefined = undefined; + let isOpen = $state(false); + let selectedJob: ComboBoxOption | undefined = $state(undefined); onMount(async () => { while (running) { @@ -58,23 +62,30 @@ handleError(error, $t('errors.unable_to_submit_job')); } }; + + const onsubmit = async (event: Event) => { + event.preventDefault(); + await handleCreate(); + }; </script> <UserPageLayout title={data.meta.title} admin> - <div class="flex justify-end" slot="buttons"> - <LinkButton on:click={() => (isOpen = true)}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiPlus} size="18" /> - {$t('admin.create_job')} - </div> - </LinkButton> - <LinkButton href="{AppRoute.ADMIN_SETTINGS}?isOpen=job"> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiCog} size="18" /> - {$t('admin.manage_concurrency')} - </div> - </LinkButton> - </div> + {#snippet buttons()} + <div class="flex justify-end"> + <LinkButton onclick={() => (isOpen = true)}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiPlus} size="18" /> + {$t('admin.create_job')} + </div> + </LinkButton> + <LinkButton href="{AppRoute.ADMIN_SETTINGS}?isOpen=job"> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiCog} size="18" /> + {$t('admin.manage_concurrency')} + </div> + </LinkButton> + </div> + {/snippet} <section id="setting-content" class="flex place-content-center sm:mx-4"> <section class="w-full pb-28 sm:w-5/6 md:w-[850px]"> {#if jobs} @@ -92,15 +103,17 @@ onConfirm={handleCreate} onCancel={handleCancel} > - <form on:submit|preventDefault={handleCreate} autocomplete="off" id="create-tag-form" slot="prompt" class="w-full"> - <div class="flex flex-col gap-1 text-left"> - <Combobox - bind:selectedOption={selectedJob} - label={$t('jobs')} - {options} - placeholder={$t('admin.search_jobs')} - /> - </div> - </form> + {#snippet promptSnippet()} + <form {onsubmit} autocomplete="off" id="create-tag-form" class="w-full"> + <div class="flex flex-col gap-1 text-left"> + <Combobox + bind:selectedOption={selectedJob} + label={$t('jobs')} + {options} + placeholder={$t('admin.search_jobs')} + /> + </div> + </form> + {/snippet} </ConfirmDialog> {/if} diff --git a/web/src/routes/admin/library-management/+page.svelte b/web/src/routes/admin/library-management/+page.svelte index 6f61572b0e..b89e81ebf6 100644 --- a/web/src/routes/admin/library-management/+page.svelte +++ b/web/src/routes/admin/library-management/+page.svelte @@ -36,32 +36,36 @@ import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte'; import { locale } from '$lib/stores/preferences.store'; - export let data: PageData; + interface Props { + data: PageData; + } - let libraries: LibraryResponseDto[] = []; + let { data }: Props = $props(); + + let libraries: LibraryResponseDto[] = $state([]); let stats: LibraryStatsResponseDto[] = []; - let owner: UserResponseDto[] = []; + let owner: UserResponseDto[] = $state([]); let photos: number[] = []; let videos: number[] = []; - let totalCount: number[] = []; - let diskUsage: number[] = []; - let diskUsageUnit: ByteUnit[] = []; - let editImportPaths: number | null; - let editScanSettings: number | null; - let renameLibrary: number | null; + let totalCount: number[] = $state([]); + let diskUsage: number[] = $state([]); + let diskUsageUnit: ByteUnit[] = $state([]); + let editImportPaths: number | undefined = $state(); + let editScanSettings: number | undefined = $state(); + let renameLibrary: number | undefined = $state(); let updateLibraryIndex: number | null; let dropdownOpen: boolean[] = []; - let toCreateLibrary = false; + let toCreateLibrary = $state(false); onMount(async () => { await readLibraryList(); }); const closeAll = () => { - editImportPaths = null; - editScanSettings = null; - renameLibrary = null; + editImportPaths = undefined; + editScanSettings = undefined; + renameLibrary = undefined; updateLibraryIndex = null; for (let index = 0; index < dropdownOpen.length; index++) { @@ -213,22 +217,24 @@ {/if} <UserPageLayout title={data.meta.title} admin> - <div class="flex justify-end gap-2" slot="buttons"> - {#if libraries.length > 0} - <LinkButton on:click={() => handleScanAll()}> + {#snippet buttons()} + <div class="flex justify-end gap-2"> + {#if libraries.length > 0} + <LinkButton onclick={() => handleScanAll()}> + <div class="flex gap-1 text-sm"> + <Icon path={mdiSync} size="18" /> + <span>{$t('scan_all_libraries')}</span> + </div> + </LinkButton> + {/if} + <LinkButton onclick={() => (toCreateLibrary = true)}> <div class="flex gap-1 text-sm"> - <Icon path={mdiSync} size="18" /> - <span>{$t('scan_all_libraries')}</span> + <Icon path={mdiPlusBoxOutline} size="18" /> + <span>{$t('create_library')}</span> </div> </LinkButton> - {/if} - <LinkButton on:click={() => (toCreateLibrary = true)}> - <div class="flex gap-1 text-sm"> - <Icon path={mdiPlusBoxOutline} size="18" /> - <span>{$t('create_library')}</span> - </div> - </LinkButton> - </div> + </div> + {/snippet} <section class="my-4"> <div class="flex flex-col gap-2" in:fade={{ duration: 500 }}> {#if libraries.length > 0} @@ -311,13 +317,17 @@ {#if renameLibrary === index} <!-- svelte-ignore node_invalid_placement_ssr --> <div transition:slide={{ duration: 250 }}> - <LibraryRenameForm {library} onSubmit={handleUpdate} onCancel={() => (renameLibrary = null)} /> + <LibraryRenameForm {library} onSubmit={handleUpdate} onCancel={() => (renameLibrary = undefined)} /> </div> {/if} {#if editImportPaths === index} <!-- svelte-ignore node_invalid_placement_ssr --> <div transition:slide={{ duration: 250 }}> - <LibraryImportPathsForm {library} onSubmit={handleUpdate} onCancel={() => (editImportPaths = null)} /> + <LibraryImportPathsForm + {library} + onSubmit={handleUpdate} + onCancel={() => (editImportPaths = undefined)} + /> </div> {/if} {#if editScanSettings === index} @@ -326,7 +336,7 @@ <LibraryScanSettingsForm {library} onSubmit={handleUpdate} - onCancel={() => (editScanSettings = null)} + onCancel={() => (editScanSettings = undefined)} /> </div> {/if} diff --git a/web/src/routes/admin/repair/+page.svelte b/web/src/routes/admin/repair/+page.svelte index e8cb0649c2..9f19fddd03 100644 --- a/web/src/routes/admin/repair/+page.svelte +++ b/web/src/routes/admin/repair/+page.svelte @@ -19,7 +19,11 @@ import { t } from 'svelte-i18n'; import { locale } from '$lib/stores/preferences.store'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); interface UntrackedFile { filename: string; @@ -33,12 +37,12 @@ const normalize = (filenames: string[]) => filenames.map((filename) => ({ filename, checksum: null })); - let checking = false; - let repairing = false; + let checking = $state(false); + let repairing = $state(false); - let orphans: FileReportItemDto[] = data.orphans; - let extras: UntrackedFile[] = normalize(data.extras); - let matches: Match[] = []; + let orphans: FileReportItemDto[] = $state(data.orphans); + let extras: UntrackedFile[] = $state(normalize(data.extras)); + let matches: Match[] = $state([]); const handleDownload = () => { if (extras.length > 0) { @@ -180,33 +184,34 @@ </script> <UserPageLayout title={data.meta.title} admin> - <svelte:fragment slot="sidebar" /> - <div class="flex justify-end gap-2" slot="buttons"> - <LinkButton on:click={() => handleRepair()} disabled={matches.length === 0 || repairing}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiWrench} size="18" /> - {$t('admin.repair_all')} - </div> - </LinkButton> - <LinkButton on:click={() => handleCheckAll()} disabled={extras.length === 0 || checking}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiCheckAll} size="18" /> - {$t('admin.check_all')} - </div> - </LinkButton> - <LinkButton on:click={() => handleDownload()} disabled={extras.length + orphans.length === 0}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiDownload} size="18" /> - {$t('export')} - </div> - </LinkButton> - <LinkButton on:click={() => handleRefresh()}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiRefresh} size="18" /> - {$t('refresh')} - </div> - </LinkButton> - </div> + {#snippet buttons()} + <div class="flex justify-end gap-2"> + <LinkButton onclick={() => handleRepair()} disabled={matches.length === 0 || repairing}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiWrench} size="18" /> + {$t('admin.repair_all')} + </div> + </LinkButton> + <LinkButton onclick={() => handleCheckAll()} disabled={extras.length === 0 || checking}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiCheckAll} size="18" /> + {$t('admin.check_all')} + </div> + </LinkButton> + <LinkButton onclick={() => handleDownload()} disabled={extras.length + orphans.length === 0}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiDownload} size="18" /> + {$t('export')} + </div> + </LinkButton> + <LinkButton onclick={() => handleRefresh()}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiRefresh} size="18" /> + {$t('refresh')} + </div> + </LinkButton> + </div> + {/snippet} <section id="setting-content" class="flex place-content-center sm:mx-4"> <section class="w-full pb-28 sm:w-5/6 md:w-[850px]"> {#if matches.length + extras.length + orphans.length === 0} @@ -238,7 +243,7 @@ <tr class="w-full h-[75px] place-items-center border-[3px] border-transparent p-2 odd:bg-immich-gray even:bg-immich-bg hover:cursor-pointer hover:border-immich-primary/75 odd:dark:bg-immich-dark-gray/75 even:dark:bg-immich-dark-gray/50 dark:hover:border-immich-dark-primary/75 md:p-5 flex justify-between" tabindex="0" - on:click={() => handleSplit(match)} + onclick={() => handleSplit(match)} > <td class="text-sm text-ellipsis flex flex-col gap-1 font-mono"> <span>{match.orphan.pathValue} =></span> @@ -279,8 +284,8 @@ tabindex="0" title={orphan.pathValue} > - <td on:click={() => copyToClipboard(orphan.pathValue)}> - <CircleIconButton title={$t('copy_file_path')} icon={mdiContentCopy} size="18" /> + <td onclick={() => copyToClipboard(orphan.pathValue)}> + <CircleIconButton title={$t('copy_file_path')} icon={mdiContentCopy} size="18" onclick={() => {}} /> </td> <td class="truncate text-sm font-mono text-left" title={orphan.pathValue}> {orphan.pathValue} @@ -318,11 +323,11 @@ <tr class="flex h-[50px] w-full place-items-center border-[3px] border-transparent p-1 odd:bg-immich-gray even:bg-immich-bg hover:cursor-pointer hover:border-immich-primary/75 odd:dark:bg-immich-dark-gray/75 even:dark:bg-immich-dark-gray/50 dark:hover:border-immich-dark-primary/75 md:p-5 justify-between" tabindex="0" - on:click={() => handleCheckOne(extra.filename)} + onclick={() => handleCheckOne(extra.filename)} title={extra.filename} > - <td on:click={() => copyToClipboard(extra.filename)}> - <CircleIconButton title={$t('copy_file_path')} icon={mdiContentCopy} size="18" /> + <td onclick={() => copyToClipboard(extra.filename)}> + <CircleIconButton title={$t('copy_file_path')} icon={mdiContentCopy} size="18" onclick={() => {}} /> </td> <td class="w-full text-md text-ellipsis flex justify-between pr-5"> <span class="text-ellipsis grow truncate font-mono text-sm pr-5" title={extra.filename} diff --git a/web/src/routes/admin/server-status/+page.svelte b/web/src/routes/admin/server-status/+page.svelte index 54f62b3adb..0aa4c3dd69 100644 --- a/web/src/routes/admin/server-status/+page.svelte +++ b/web/src/routes/admin/server-status/+page.svelte @@ -6,7 +6,11 @@ import type { PageData } from './$types'; import { asyncTimeout } from '$lib/utils'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data = $bindable() }: Props = $props(); let running = true; diff --git a/web/src/routes/admin/system-settings/+page.svelte b/web/src/routes/admin/system-settings/+page.svelte index 9eb7351060..6a71245051 100644 --- a/web/src/routes/admin/system-settings/+page.svelte +++ b/web/src/routes/admin/system-settings/+page.svelte @@ -27,7 +27,6 @@ import { featureFlags } from '$lib/stores/server-config.store'; import { copyToClipboard } from '$lib/utils'; import { downloadBlob } from '$lib/utils/asset-utils'; - import type { SystemConfigDto } from '@immich/sdk'; import { mdiAccountOutline, mdiAlert, @@ -53,16 +52,20 @@ } from '@mdi/js'; import type { PageData } from './$types'; import { t } from 'svelte-i18n'; - import type { ComponentType, SvelteComponent } from 'svelte'; + import type { Component } from 'svelte'; import type { SettingsComponentProps } from '$lib/components/admin-page/settings/admin-settings'; import SearchBar from '$lib/components/elements/search-bar.svelte'; - export let data: PageData; + interface Props { + data: PageData; + } - let config = data.configs; - let handleSave: (update: Partial<SystemConfigDto>) => Promise<void>; + let { data }: Props = $props(); - type SettingsComponent = ComponentType<SvelteComponent<SettingsComponentProps>>; + let config = $state(data.configs); + let adminSettingElement = $state<ReturnType<typeof AdminSettings>>(); + + type SettingsComponent = Component<SettingsComponentProps>; // https://stackoverflow.com/questions/16167581/sort-object-properties-and-json-stringify/43636793#43636793 const jsonReplacer = (key: string, value: unknown) => @@ -85,7 +88,8 @@ setTimeout(() => downloadManager.clear(downloadKey), 5000); }; - let inputElement: HTMLInputElement; + let inputElement: HTMLInputElement | undefined = $state(); + const uploadConfig = (e: Event) => { const file = (e.target as HTMLInputElement).files?.[0]; if (!file) { @@ -94,7 +98,7 @@ const reader = async () => { const text = await file.text(); const newConfig = JSON.parse(text); - await handleSave(newConfig); + await adminSettingElement?.handleSave(newConfig); }; reader().catch((error) => console.error('Error handling JSON config upload', error)); }; @@ -227,15 +231,17 @@ }, ]; - let searchQuery = ''; + let searchQuery = $state(''); - $: filteredSettings = settings.filter(({ title, subtitle }) => { - const query = searchQuery.toLowerCase(); - return title.toLowerCase().includes(query) || subtitle.toLowerCase().includes(query); - }); + let filteredSettings = $derived( + settings.filter(({ title, subtitle }) => { + const query = searchQuery.toLowerCase(); + return title.toLowerCase().includes(query) || subtitle.toLowerCase().includes(query); + }), + ); </script> -<input bind:this={inputElement} type="file" accept=".json" style="display: none" on:change={uploadConfig} /> +<input bind:this={inputElement} type="file" accept=".json" style="display: none" onchange={uploadConfig} /> <div class="h-svh flex flex-col overflow-hidden"> {#if $featureFlags.configFile} @@ -248,54 +254,58 @@ {/if} <UserPageLayout title={data.meta.title} admin> - <div class="flex justify-end gap-2" slot="buttons"> - <div class="hidden lg:block"> - <SearchBar placeholder={$t('search_settings')} bind:name={searchQuery} showLoadingSpinner={false} /> - </div> - <LinkButton on:click={() => copyToClipboard(JSON.stringify(config, jsonReplacer, 2))}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiContentCopy} size="18" /> - {$t('copy_to_clipboard')} + {#snippet buttons()} + <div class="flex justify-end gap-2"> + <div class="hidden lg:block"> + <SearchBar placeholder={$t('search_settings')} bind:name={searchQuery} showLoadingSpinner={false} /> </div> - </LinkButton> - <LinkButton on:click={() => downloadConfig()}> - <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiDownload} size="18" /> - {$t('export_as_json')} - </div> - </LinkButton> - {#if !$featureFlags.configFile} - <LinkButton on:click={() => inputElement?.click()}> + <LinkButton onclick={() => copyToClipboard(JSON.stringify(config, jsonReplacer, 2))}> <div class="flex place-items-center gap-2 text-sm"> - <Icon path={mdiUpload} size="18" /> - {$t('import_from_json')} + <Icon path={mdiContentCopy} size="18" /> + {$t('copy_to_clipboard')} </div> </LinkButton> - {/if} - </div> - - <AdminSettings bind:config let:handleReset bind:handleSave let:savedConfig let:defaultConfig> - <section id="setting-content" class="flex place-content-center sm:mx-4"> - <section class="w-full pb-28 sm:w-5/6 md:w-[896px]"> - <div class="block lg:hidden"> - <SearchBar placeholder={$t('search_settings')} bind:name={searchQuery} showLoadingSpinner={false} /> + <LinkButton onclick={() => downloadConfig()}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiDownload} size="18" /> + {$t('export_as_json')} </div> - <SettingAccordionState queryParam={QueryParameter.IS_OPEN}> - {#each filteredSettings as { component: Component, title, subtitle, key, icon } (key)} - <SettingAccordion {title} {subtitle} {key} {icon}> - <Component - onSave={(config) => handleSave(config)} - onReset={(options) => handleReset(options)} - disabled={$featureFlags.configFile} - {defaultConfig} - {config} - {savedConfig} - /> - </SettingAccordion> - {/each} - </SettingAccordionState> + </LinkButton> + {#if !$featureFlags.configFile} + <LinkButton onclick={() => inputElement?.click()}> + <div class="flex place-items-center gap-2 text-sm"> + <Icon path={mdiUpload} size="18" /> + {$t('import_from_json')} + </div> + </LinkButton> + {/if} + </div> + {/snippet} + + <AdminSettings bind:config bind:this={adminSettingElement}> + {#snippet children({ savedConfig, defaultConfig })} + <section id="setting-content" class="flex place-content-center sm:mx-4"> + <section class="w-full pb-28 sm:w-5/6 md:w-[896px]"> + <div class="block lg:hidden"> + <SearchBar placeholder={$t('search_settings')} bind:name={searchQuery} showLoadingSpinner={false} /> + </div> + <SettingAccordionState queryParam={QueryParameter.IS_OPEN}> + {#each filteredSettings as { component: Component, title, subtitle, key, icon } (key)} + <SettingAccordion {title} {subtitle} {key} {icon}> + <Component + onSave={(config) => adminSettingElement?.handleSave(config)} + onReset={(options) => adminSettingElement?.handleReset(options)} + disabled={$featureFlags.configFile} + bind:config + {defaultConfig} + {savedConfig} + /> + </SettingAccordion> + {/each} + </SettingAccordionState> + </section> </section> - </section> + {/snippet} </AdminSettings> </UserPageLayout> </div> diff --git a/web/src/routes/admin/user-management/+page.svelte b/web/src/routes/admin/user-management/+page.svelte index 80c0169176..d93a8a5731 100644 --- a/web/src/routes/admin/user-management/+page.svelte +++ b/web/src/routes/admin/user-management/+page.svelte @@ -27,16 +27,20 @@ import { t } from 'svelte-i18n'; import type { PageData } from './$types'; - export let data: PageData; + interface Props { + data: PageData; + } - let allUsers: UserAdminResponseDto[] = []; - let shouldShowEditUserForm = false; - let shouldShowCreateUserForm = false; - let shouldShowPasswordResetSuccess = false; - let shouldShowDeleteConfirmDialog = false; - let shouldShowRestoreDialog = false; - let selectedUser: UserAdminResponseDto; - let newPassword: string; + let { data }: Props = $props(); + + let allUsers: UserAdminResponseDto[] = $state([]); + let shouldShowEditUserForm = $state(false); + let shouldShowCreateUserForm = $state(false); + let shouldShowPasswordResetSuccess = $state(false); + let shouldShowDeleteConfirmDialog = $state(false); + let shouldShowRestoreDialog = $state(false); + let selectedUser = $state<UserAdminResponseDto>(); + let newPassword = $state(''); const refresh = async () => { allUsers = await searchUsersAdmin({ withDeleted: true }); @@ -117,7 +121,7 @@ /> {/if} - {#if shouldShowEditUserForm} + {#if shouldShowEditUserForm && selectedUser} <EditUserForm user={selectedUser} bind:newPassword @@ -128,7 +132,7 @@ /> {/if} - {#if shouldShowDeleteConfirmDialog} + {#if shouldShowDeleteConfirmDialog && selectedUser} <DeleteConfirmDialog user={selectedUser} onSuccess={onUserDelete} @@ -137,7 +141,7 @@ /> {/if} - {#if shouldShowRestoreDialog} + {#if shouldShowRestoreDialog && selectedUser} <RestoreDialogue user={selectedUser} onSuccess={onUserRestore} @@ -155,7 +159,7 @@ hideCancelButton={true} confirmColor="green" > - <svelte:fragment slot="prompt"> + {#snippet promptSnippet()} <div class="flex flex-col gap-4"> <p>{$t('admin.user_password_has_been_reset')}</p> @@ -165,7 +169,7 @@ > {newPassword} </code> - <LinkButton on:click={() => copyToClipboard(newPassword)} title={$t('copy_password')}> + <LinkButton onclick={() => copyToClipboard(newPassword)} title={$t('copy_password')}> <div class="flex place-items-center gap-2 text-sm"> <Icon path={mdiContentCopy} size="18" /> </div> @@ -174,7 +178,7 @@ <p>{$t('admin.user_password_reset_description')}</p> </div> - </svelte:fragment> + {/snippet} </ConfirmDialog> {/if} @@ -223,7 +227,7 @@ title={$t('edit_user')} color="primary" size="16" - on:click={() => editUserHandler(immichUser)} + onclick={() => editUserHandler(immichUser)} /> {#if immichUser.id !== $user.id} <CircleIconButton @@ -231,7 +235,7 @@ title={$t('delete_user')} color="primary" size="16" - on:click={() => deleteUserHandler(immichUser)} + onclick={() => deleteUserHandler(immichUser)} /> {/if} {/if} @@ -243,7 +247,7 @@ })} color="primary" size="16" - on:click={() => restoreUserHandler(immichUser)} + onclick={() => restoreUserHandler(immichUser)} /> {/if} </td> @@ -253,7 +257,7 @@ </tbody> </table> - <Button size="sm" on:click={() => (shouldShowCreateUserForm = true)}>{$t('create_user')}</Button> + <Button size="sm" onclick={() => (shouldShowCreateUserForm = true)}>{$t('create_user')}</Button> </section> </section> </UserPageLayout> diff --git a/web/src/routes/auth/change-password/+page.svelte b/web/src/routes/auth/change-password/+page.svelte index eaf5a88fe2..21226b9387 100644 --- a/web/src/routes/auth/change-password/+page.svelte +++ b/web/src/routes/auth/change-password/+page.svelte @@ -8,7 +8,11 @@ import type { PageData } from './$types'; import { t } from 'svelte-i18n'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); const onSuccess = async () => { await goto(AppRoute.AUTH_LOGIN); @@ -18,12 +22,14 @@ </script> <FullscreenContainer title={data.meta.title}> - <p slot="message"> - {$t('hi_user', { values: { name: $user.name, email: $user.email } })} - <br /> - <br /> - {$t('change_password_description')} - </p> + {#snippet message()} + <p> + {$t('hi_user', { values: { name: $user.name, email: $user.email } })} + <br /> + <br /> + {$t('change_password_description')} + </p> + {/snippet} <ChangePasswordForm {onSuccess} /> </FullscreenContainer> diff --git a/web/src/routes/auth/login/+page.svelte b/web/src/routes/auth/login/+page.svelte index dd0f64c5a8..0ab506f5e3 100644 --- a/web/src/routes/auth/login/+page.svelte +++ b/web/src/routes/auth/login/+page.svelte @@ -6,15 +6,21 @@ import { featureFlags, serverConfig } from '$lib/stores/server-config.store'; import type { PageData } from './$types'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); </script> {#if $featureFlags.loaded} <FullscreenContainer title={data.meta.title} showMessage={!!$serverConfig.loginPageMessage}> - <p slot="message"> - <!-- eslint-disable-next-line svelte/no-at-html-tags --> - {@html $serverConfig.loginPageMessage} - </p> + {#snippet message()} + <p> + <!-- eslint-disable-next-line svelte/no-at-html-tags --> + {@html $serverConfig.loginPageMessage} + </p> + {/snippet} <LoginForm onSuccess={async () => await goto(AppRoute.PHOTOS, { invalidateAll: true })} diff --git a/web/src/routes/auth/onboarding/+page.svelte b/web/src/routes/auth/onboarding/+page.svelte index ddb30d1b45..0c8e33e37b 100644 --- a/web/src/routes/auth/onboarding/+page.svelte +++ b/web/src/routes/auth/onboarding/+page.svelte @@ -1,4 +1,6 @@ <script lang="ts"> + import { run } from 'svelte/legacy'; + import { goto } from '$app/navigation'; import { page } from '$app/stores'; import OnboardingHello from '$lib/components/onboarding-page/onboarding-hello.svelte'; @@ -9,7 +11,7 @@ import { retrieveServerConfig } from '$lib/stores/server-config.store'; import { updateAdminOnboarding } from '@immich/sdk'; - let index = 0; + let index = $state(0); interface OnboardingStep { name: string; @@ -27,11 +29,11 @@ { name: 'storage', component: OnboadingStorageTemplate }, ]; - $: { + run(() => { const stepState = $page.url.searchParams.get('step'); const temporaryIndex = onboardingSteps.findIndex((step) => step.name === stepState); index = temporaryIndex >= 0 ? temporaryIndex : 0; - } + }); const handleDoneClicked = async () => { if (index >= onboardingSteps.length - 1) { @@ -50,6 +52,8 @@ await goto(`${AppRoute.AUTH_ONBOARDING}?${QueryParameter.ONBOARDING_STEP}=${onboardingSteps[index].name}`); } }; + + const SvelteComponent = $derived(onboardingSteps[index].component); </script> <section id="onboarding-page" class="min-w-screen flex min-h-screen p-4"> @@ -61,11 +65,7 @@ ></div> </div> <div class="w-full min-w-screen py-8 flex h-full place-content-center place-items-center"> - <svelte:component - this={onboardingSteps[index].component} - onDone={handleDoneClicked} - onPrevious={handlePrevious} - /> + <SvelteComponent onDone={handleDoneClicked} onPrevious={handlePrevious} /> </div> </div> </section> diff --git a/web/src/routes/auth/register/+page.svelte b/web/src/routes/auth/register/+page.svelte index 9c1f0ca6c4..2e55ba7435 100644 --- a/web/src/routes/auth/register/+page.svelte +++ b/web/src/routes/auth/register/+page.svelte @@ -4,13 +4,19 @@ import type { PageData } from './$types'; import { t } from 'svelte-i18n'; - export let data: PageData; + interface Props { + data: PageData; + } + + let { data }: Props = $props(); </script> <FullscreenContainer title={data.meta.title}> - <p slot="message"> - {$t('admin.registration_description')} - </p> + {#snippet message()} + <p> + {$t('admin.registration_description')} + </p> + {/snippet} <AdminRegistrationForm /> </FullscreenContainer> From 1f1a4ab1a3b7adc95893e2f806a9ccc10d9d6a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=90=E1=BB=A9c?= <facoder2k2@gmail.com> Date: Thu, 14 Nov 2024 22:00:18 +0700 Subject: [PATCH 34/36] fix(web): textarea autogrow height (#13983) fix(web): remove album assetGridWidth & globalWidth Co-authored-by: Alex Tran <alex.tran1502@gmail.com> --- .../[[photos=photos]]/[[assetId=id]]/+page.svelte | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte index 2a78b02aa6..5b23cd0c21 100644 --- a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -104,8 +104,6 @@ let isShowActivity = $state(false); let isLiked: ActivityResponseDto | null = $state(null); let reactions: ActivityResponseDto[] = $state([]); - let globalWidth: number = $state(0); - let assetGridWidth: number = $derived(isShowActivity ? globalWidth - (globalWidth < 768 ? 360 : 460) : globalWidth); let albumOrder: AssetOrder | undefined = $state(data.album.order); const assetInteractionStore = createAssetInteractionStore(); @@ -430,7 +428,7 @@ }); </script> -<div class="flex overflow-hidden" bind:clientWidth={globalWidth}> +<div class="flex overflow-hidden"> <div class="relative w-full shrink"> {#if $isMultiSelectState} <AssetSelectControlBar assets={$selectedAssets} clearSelect={() => assetInteractionStore.clearMultiselect()}> @@ -568,10 +566,7 @@ {/if} {/if} - <main - class="relative h-screen overflow-hidden bg-immich-bg px-6 pt-[var(--navbar-height)] dark:bg-immich-dark-bg" - style={`width:${assetGridWidth}px`} - > + <main class="relative h-screen overflow-hidden bg-immich-bg px-6 pt-[var(--navbar-height)] dark:bg-immich-dark-bg"> <!-- Use key because AssetGrid can't deal with changing stores --> {#key albumKey} {#if viewMode === AlbumPageViewMode.SELECT_ASSETS} From 35f24270feef04e045c52add572bb43c2ca3ae73 Mon Sep 17 00:00:00 2001 From: Pranay Pandey <79053599+Pranay-Pandey@users.noreply.github.com> Date: Thu, 14 Nov 2024 20:30:33 +0530 Subject: [PATCH 35/36] fix: Routing back button in sharedLinks page (#13703) * fix: go back to last page from shared links page. Handle albums page from shared links page routing * add default route for sharing * chore: remove redundant import * remove unnecessary comment --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com> --- .../[[photos=photos]]/[[assetId=id]]/+page.svelte | 2 ++ .../routes/(user)/sharing/sharedlinks/+page.svelte | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte index 5b23cd0c21..7ee9c60a54 100644 --- a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -128,6 +128,8 @@ if (backUrl === AppRoute.SHARING && album.albumUsers.length === 0 && !album.hasSharedLink) { isCreatingSharedAlbum = true; + } else if (backUrl === AppRoute.SHARED_LINKS) { + backUrl = history.state?.backUrl || AppRoute.ALBUMS; } }); diff --git a/web/src/routes/(user)/sharing/sharedlinks/+page.svelte b/web/src/routes/(user)/sharing/sharedlinks/+page.svelte index 8ed4ae9fb6..b7d4da2941 100644 --- a/web/src/routes/(user)/sharing/sharedlinks/+page.svelte +++ b/web/src/routes/(user)/sharing/sharedlinks/+page.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { goto } from '$app/navigation'; + import { goto, afterNavigate } from '$app/navigation'; import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte'; import CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte'; import { @@ -50,9 +50,16 @@ await refresh(); editSharedLink = null; }; + + let backUrl: string = AppRoute.SHARING; + + afterNavigate(({ from }) => { + let url: string | undefined = from?.url?.pathname; + backUrl = url || AppRoute.SHARING; + }); </script> -<ControlAppBar backIcon={mdiArrowLeft} onClose={() => goto(AppRoute.SHARING)}> +<ControlAppBar backIcon={mdiArrowLeft} onClose={() => goto(backUrl)}> {#snippet leading()} {$t('shared_links')} {/snippet} From d3fe238eef031998417a981d09b5b0125812fa39 Mon Sep 17 00:00:00 2001 From: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> Date: Thu, 14 Nov 2024 16:05:36 +0100 Subject: [PATCH 36/36] fix(web): ensure current asset index stays within bounds (#14013) --- .../gallery-viewer/gallery-viewer.svelte | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte index aa84bd69f0..35eaf45d53 100644 --- a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte +++ b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte @@ -66,11 +66,15 @@ const handleNext = async () => { try { - const asset = onNext ? await onNext() : assets[++currentViewAssetIndex]; - if (asset) { - setAsset(asset); - await navigate({ targetRoute: 'current', assetId: $viewingAsset.id }); + let asset: AssetResponseDto | undefined; + if (onNext) { + asset = await onNext(); + } else { + currentViewAssetIndex = Math.min(currentViewAssetIndex + 1, assets.length - 1); + asset = assets[currentViewAssetIndex]; } + + await navigateToAsset(asset); } catch (error) { handleError(error, $t('errors.cannot_navigate_next_asset')); } @@ -78,16 +82,27 @@ const handlePrevious = async () => { try { - const asset = onPrevious ? await onPrevious() : assets[--currentViewAssetIndex]; - if (asset) { - setAsset(asset); - await navigate({ targetRoute: 'current', assetId: $viewingAsset.id }); + let asset: AssetResponseDto | undefined; + if (onPrevious) { + asset = await onPrevious(); + } else { + currentViewAssetIndex = Math.max(currentViewAssetIndex - 1, 0); + asset = assets[currentViewAssetIndex]; } + + await navigateToAsset(asset); } catch (error) { handleError(error, $t('errors.cannot_navigate_previous_asset')); } }; + const navigateToAsset = async (asset?: AssetResponseDto) => { + if (asset && asset.id !== $viewingAsset.id) { + setAsset(asset); + await navigate({ targetRoute: 'current', assetId: $viewingAsset.id }); + } + }; + const handleAction = async (action: Action) => { switch (action.type) { case AssetAction.ARCHIVE: