diff --git a/i18n/en.json b/i18n/en.json index 4f2922f35d..4f0b3a658c 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1392,6 +1392,7 @@ "light_theme": "Switch to light theme", "like": "Like", "like_deleted": "Like deleted", + "link": "Link", "link_motion_video": "Link motion video", "link_to_docs": "For more information, refer to the documentation.", "link_to_oauth": "Link to OAuth", @@ -1562,6 +1563,8 @@ "multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping", "mute_memories": "Mute Memories", "my_albums": "My albums", + "my_immich_description": "Copy current page as a My Immich link", + "my_immich_title": "My Immich link", "name": "Name", "name_or_nickname": "Name or nickname", "name_required": "Name is required", @@ -1926,6 +1929,8 @@ "scan_settings": "Scan Settings", "scanning": "Scanning", "scanning_for_album": "Scanning for album...", + "screencast_mode_description": "Show keyboard and mouse event indicators on the screen", + "screencast_mode_title": "Toggle screencast mode", "search": "Search", "search_albums": "Search albums", "search_by_context": "Search by context", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b9b8b49159..b1dc871f7d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,8 +741,8 @@ importers: specifier: workspace:* version: link:../open-api/typescript-sdk '@immich/ui': - specifier: ^0.69.0 - version: 0.69.0(@sveltejs/kit@2.57.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)(typescript@6.0.2)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1) + specifier: ^0.71.0 + version: 0.71.0(@sveltejs/kit@2.57.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)(typescript@6.0.2)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1) '@mapbox/mapbox-gl-rtl-text': specifier: 0.3.0 version: 0.3.0 @@ -3042,13 +3042,13 @@ packages: resolution: {integrity: sha512-UWhy/+Lf8C1dJip5wPfFytI3Vq/9UyDKQE1ROjXwVhT6E/CPgBkRLwHPetjYGPJ4o1JVVpRLnEEJCXdvzqVpGw==} hasBin: true - '@immich/svelte-markdown-preprocess@0.2.1': - resolution: {integrity: sha512-mbr/g75lO8Zh+ELCuYrZP0XB4gf2UbK8rJcGYMYxFJJzMMunV+sm9FqtV1dbwW2dpXzCZGz1XPCEZ6oo526TbA==} + '@immich/svelte-markdown-preprocess@0.3.0': + resolution: {integrity: sha512-6xspWnOgaTi+TasteJgI6DjOGjBQQI30mOYiY/FnyEjczNbrV6r5SFWjNbR+JY+Umn7MsPcZf5yzomK+q5AThg==} peerDependencies: svelte: ^5.0.0 - '@immich/ui@0.69.0': - resolution: {integrity: sha512-YQ+27pGQhzdRBOo/7cHcbXnax5BUrrJeYjUc+VdRYp6KMS8SlGWAKQhvZPdcqiPB332fxJMmpHjV+VqXJJjrqg==} + '@immich/ui@0.71.0': + resolution: {integrity: sha512-L5of/qSNlliTLAF4aoHYXsshs+JLeuX9+r685RED6LsZIR0mObb33SJcniGlPqbi5oyELI+7Qp/cEoyS7TPqwg==} peerDependencies: svelte: ^5.0.0 @@ -15225,16 +15225,16 @@ snapshots: pg-connection-string: 2.12.0 postgres: 3.4.8 - '@immich/svelte-markdown-preprocess@0.2.1(svelte@5.55.1)': + '@immich/svelte-markdown-preprocess@0.3.0(svelte@5.55.1)': dependencies: front-matter: 4.0.2 marked: 17.0.5 node-emoji: 2.2.0 svelte: 5.55.1 - '@immich/ui@0.69.0(@sveltejs/kit@2.57.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)(typescript@6.0.2)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)': + '@immich/ui@0.71.0(@sveltejs/kit@2.57.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)(typescript@6.0.2)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)': dependencies: - '@immich/svelte-markdown-preprocess': 0.2.1(svelte@5.55.1) + '@immich/svelte-markdown-preprocess': 0.3.0(svelte@5.55.1) '@internationalized/date': 3.12.0 '@mdi/js': 7.4.47 bits-ui: 2.16.3(@internationalized/date@3.12.0)(@sveltejs/kit@2.57.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)(typescript@6.0.2)(vite@8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1) diff --git a/web/package.json b/web/package.json index 1cfb7e8216..96bde9324b 100644 --- a/web/package.json +++ b/web/package.json @@ -27,7 +27,7 @@ "@formatjs/icu-messageformat-parser": "^3.0.0", "@immich/justified-layout-wasm": "^0.4.3", "@immich/sdk": "workspace:*", - "@immich/ui": "^0.69.0", + "@immich/ui": "^0.71.0", "@mapbox/mapbox-gl-rtl-text": "0.3.0", "@mdi/js": "^7.4.47", "@photo-sphere-viewer/core": "^5.14.0", 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 0b624ff5dc..1b2d15994e 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 @@ -90,7 +90,6 @@ const Close: ActionItem = $derived({ title: $t('go_back'), - type: $t('assets'), icon: languageManager.rtl ? mdiArrowRight : mdiArrowLeft, $if: () => !!onClose && !assetViewerManager.isFaceEditMode, onAction: () => onClose?.(), diff --git a/web/src/lib/services/album.service.ts b/web/src/lib/services/album.service.ts index 101c4647c4..a04620db4b 100644 --- a/web/src/lib/services/album.service.ts +++ b/web/src/lib/services/album.service.ts @@ -46,7 +46,6 @@ export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto) = const Share: ActionItem = { title: $t('share'), - type: $t('command'), icon: mdiShareVariantOutline, $if: () => isOwned, onAction: () => modalManager.show(AlbumOptionsModal, { album }), @@ -54,7 +53,6 @@ export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto) = const AddUsers: ActionItem = { title: $t('invite_people'), - type: $t('command'), icon: mdiPlus, color: 'primary', onAction: () => modalManager.show(AlbumAddUsersModal, { album }), @@ -62,7 +60,6 @@ export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto) = const CreateSharedLink: ActionItem = { title: $t('create_link'), - type: $t('command'), icon: mdiLink, color: 'primary', onAction: () => modalManager.show(SharedLinkCreateModal, { albumId: album.id }), @@ -74,7 +71,6 @@ export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto) = export const getAlbumAssetsActions = ($t: MessageFormatter, album: AlbumResponseDto, assets: TimelineAsset[]) => { const AddAssets: ActionItem = { title: $t('add_assets'), - type: $t('command'), color: 'primary', icon: mdiPlusBoxOutline, $if: () => assets.length > 0, @@ -89,7 +85,6 @@ export const getAlbumAssetsActions = ($t: MessageFormatter, album: AlbumResponse const Upload: ActionItem = { title: $t('select_from_computer'), description: $t('album_upload_assets'), - type: $t('command'), icon: mdiUpload, onAction: () => void openFileUploadDialog({ albumId: album.id }), }; diff --git a/web/src/lib/services/asset.service.ts b/web/src/lib/services/asset.service.ts index c97ce48048..b22d93af7d 100644 --- a/web/src/lib/services/asset.service.ts +++ b/web/src/lib/services/asset.service.ts @@ -129,7 +129,6 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) = const PlayMotionPhoto: ActionItem = { title: $t('play_motion_photo'), icon: mdiMotionPlayOutline, - type: $t('assets'), $if: () => !!asset.livePhotoVideoId && !assetViewerManager.isPlayingMotionPhoto, onAction: () => { assetViewerManager.isPlayingMotionPhoto = true; @@ -139,7 +138,6 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) = const StopMotionPhoto: ActionItem = { title: $t('stop_motion_photo'), icon: mdiMotionPauseOutline, - type: $t('assets'), $if: () => !!asset.livePhotoVideoId && assetViewerManager.isPlayingMotionPhoto, onAction: () => { assetViewerManager.isPlayingMotionPhoto = false; @@ -149,7 +147,6 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) = const Favorite: ActionItem = { title: $t('to_favorite'), icon: mdiHeartOutline, - type: $t('assets'), $if: () => isOwner && !asset.isFavorite, onAction: () => handleFavorite(asset), shortcuts: [{ key: 'f' }], @@ -158,7 +155,6 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) = const Unfavorite: ActionItem = { title: $t('unfavorite'), icon: mdiHeart, - type: $t('assets'), $if: () => isOwner && asset.isFavorite, onAction: () => handleUnfavorite(asset), shortcuts: [{ key: 'f' }], @@ -175,7 +171,6 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) = const Offline: ActionItem = { title: $t('asset_offline'), icon: mdiAlertOutline, - type: $t('assets'), color: 'danger', $if: () => !!asset.isOffline, onAction: () => assetViewerManager.toggleDetailPanel(), @@ -205,7 +200,6 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) = const Info: ActionItem = { title: $t('info'), icon: mdiInformationOutline, - type: $t('assets'), $if: () => asset.hasMetadata, onAction: () => assetViewerManager.toggleDetailPanel(), shortcuts: { key: 'i' }, @@ -223,7 +217,6 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) = const TagPeople: ActionItem = { title: $t('tag_people'), icon: mdiFaceRecognition, - type: $t('assets'), $if: () => isOwner && asset.type === AssetTypeEnum.Image && !asset.isTrashed, onAction: () => assetViewerManager.toggleFaceEditMode(), shortcuts: { key: 'p' }, diff --git a/web/src/lib/services/database-backups.service.ts b/web/src/lib/services/database-backups.service.ts index 900a0ddb80..b8c048fd7b 100644 --- a/web/src/lib/services/database-backups.service.ts +++ b/web/src/lib/services/database-backups.service.ts @@ -16,14 +16,12 @@ import type { MessageFormatter } from 'svelte-i18n'; export const getDatabaseBackupActions = ($t: MessageFormatter, filename: string) => { const Download: ActionItem = { - type: $t('command'), title: $t('download'), icon: mdiDownload, onAction: () => handleDownloadDatabaseBackup(filename), }; const Delete: ActionItem = { - type: $t('command'), title: $t('delete'), icon: mdiTrashCanOutline, color: 'danger', diff --git a/web/src/lib/services/library.service.ts b/web/src/lib/services/library.service.ts index c856ec3f85..55df0f5ef9 100644 --- a/web/src/lib/services/library.service.ts +++ b/web/src/lib/services/library.service.ts @@ -26,7 +26,6 @@ import type { MessageFormatter } from 'svelte-i18n'; export const getLibrariesActions = ($t: MessageFormatter) => { const ScanAll: ActionItem = { title: $t('scan_all_libraries'), - type: $t('command'), icon: mdiSync, onAction: () => handleScanAllLibraries(), shortcuts: { shift: true, key: 'r' }, @@ -34,7 +33,6 @@ export const getLibrariesActions = ($t: MessageFormatter) => { const Create: ActionItem = { title: $t('create_library'), - type: $t('command'), icon: mdiPlusBoxOutline, onAction: () => goto(Route.newLibrary()), shortcuts: { shift: true, key: 'n' }, @@ -46,14 +44,12 @@ export const getLibrariesActions = ($t: MessageFormatter) => { export const getLibraryActions = ($t: MessageFormatter, library: LibraryResponseDto) => { const Detail: ActionItem = { icon: mdiInformationOutline, - type: $t('command'), title: $t('details'), onAction: () => goto(Route.viewLibrary(library)), }; const Edit: ActionItem = { icon: mdiPencilOutline, - type: $t('command'), title: $t('edit'), onAction: () => goto(Route.editLibrary(library)), shortcuts: { key: 'r' }, @@ -61,7 +57,6 @@ export const getLibraryActions = ($t: MessageFormatter, library: LibraryResponse const Delete: ActionItem = { icon: mdiTrashCanOutline, - type: $t('command'), title: $t('delete'), color: 'danger', onAction: () => handleDeleteLibrary(library), @@ -71,21 +66,18 @@ export const getLibraryActions = ($t: MessageFormatter, library: LibraryResponse const AddFolder: ActionItem = { icon: mdiPlusBoxOutline, - type: $t('command'), title: $t('add'), onAction: () => modalManager.show(LibraryFolderAddModal, { library }), }; const AddExclusionPattern: ActionItem = { icon: mdiPlusBoxOutline, - type: $t('command'), title: $t('add'), onAction: () => modalManager.show(LibraryExclusionPatternAddModal, { library }), }; const Scan: ActionItem = { icon: mdiSync, - type: $t('command'), title: $t('scan_library'), onAction: () => handleScanLibrary(library), shortcuts: { shift: true, key: 'r' }, @@ -97,14 +89,12 @@ export const getLibraryActions = ($t: MessageFormatter, library: LibraryResponse export const getLibraryFolderActions = ($t: MessageFormatter, library: LibraryResponseDto, folder: string) => { const Edit: ActionItem = { icon: mdiPencilOutline, - type: $t('command'), title: $t('edit'), onAction: () => modalManager.show(LibraryFolderEditModal, { folder, library }), }; const Delete: ActionItem = { icon: mdiTrashCanOutline, - type: $t('command'), title: $t('delete'), onAction: () => handleDeleteLibraryFolder(library, folder), }; @@ -119,14 +109,12 @@ export const getLibraryExclusionPatternActions = ( ) => { const Edit: ActionItem = { icon: mdiPencilOutline, - type: $t('command'), title: $t('edit'), onAction: () => modalManager.show(LibraryExclusionPatternEditModal, { exclusionPattern, library }), }; const Delete: ActionItem = { icon: mdiTrashCanOutline, - type: $t('command'), title: $t('delete'), onAction: () => handleDeleteExclusionPattern(library, exclusionPattern), }; diff --git a/web/src/lib/services/queue.service.ts b/web/src/lib/services/queue.service.ts index 414cc2fb17..78d73f91b1 100644 --- a/web/src/lib/services/queue.service.ts +++ b/web/src/lib/services/queue.service.ts @@ -64,7 +64,6 @@ export const getQueuesActions = ($t: MessageFormatter, queues: QueueResponseDto[ const CreateJob: ActionItem = { icon: mdiPlus, title: $t('admin.create_job'), - type: $t('command'), shortcuts: { shift: true, key: 'n' }, onAction: () => modalManager.show(JobCreateModal, {}), }; @@ -73,7 +72,6 @@ export const getQueuesActions = ($t: MessageFormatter, queues: QueueResponseDto[ icon: mdiCog, title: $t('admin.manage_concurrency'), description: $t('admin.manage_concurrency_description'), - type: $t('page'), onAction: () => goto(Route.systemSettings({ isOpen: OpenQueryParam.JOB })), }; diff --git a/web/src/lib/services/system-config.service.ts b/web/src/lib/services/system-config.service.ts index 1e8f898d6d..1a4ed2319d 100644 --- a/web/src/lib/services/system-config.service.ts +++ b/web/src/lib/services/system-config.service.ts @@ -18,7 +18,6 @@ export const getSystemConfigActions = ( const CopyToClipboard: ActionItem = { title: $t('copy_to_clipboard'), description: $t('admin.copy_config_to_clipboard_description'), - type: $t('command'), icon: mdiContentCopy, onAction: () => handleCopyToClipboard(config), shortcuts: { shift: true, key: 'c' }, @@ -27,7 +26,6 @@ export const getSystemConfigActions = ( const Download: ActionItem = { title: $t('export_as_json'), description: $t('admin.export_config_as_json_description'), - type: $t('command'), icon: mdiDownload, onAction: () => handleDownloadConfig(config), shortcuts: [ @@ -39,7 +37,6 @@ export const getSystemConfigActions = ( const Upload: ActionItem = { title: $t('import_from_json'), description: $t('admin.import_config_from_json_description'), - type: $t('command'), icon: mdiUpload, $if: () => !featureFlags.configFile, onAction: () => handleUploadConfig(), diff --git a/web/src/lib/services/user-admin.service.ts b/web/src/lib/services/user-admin.service.ts index 94321c7a74..8957d6d02c 100644 --- a/web/src/lib/services/user-admin.service.ts +++ b/web/src/lib/services/user-admin.service.ts @@ -36,7 +36,6 @@ import type { MessageFormatter } from 'svelte-i18n'; export const getUserAdminsActions = ($t: MessageFormatter) => { const Create: ActionItem = { title: $t('create_user'), - type: $t('command'), icon: mdiPlusBoxOutline, onAction: () => goto(Route.newUser()), shortcuts: { shift: true, key: 'n' }, @@ -61,7 +60,6 @@ export const getUserAdminActions = ($t: MessageFormatter, user: UserAdminRespons const Delete: ActionItem = { icon: mdiTrashCanOutline, title: $t('delete'), - type: $t('command'), color: 'danger', $if: () => authManager.user.id !== user.id && !user.deletedAt, onAction: () => modalManager.show(UserDeleteConfirmModal, { user }), @@ -75,7 +73,6 @@ export const getUserAdminActions = ($t: MessageFormatter, user: UserAdminRespons const Restore: HeaderButtonActionItem = { icon: mdiDeleteRestore, title: $t('restore'), - type: $t('command'), color: 'primary', data: { title: $t('admin.user_restore_scheduled_removal', { values: { date: getDeleteDate(user.deletedAt!) } }), @@ -87,14 +84,12 @@ export const getUserAdminActions = ($t: MessageFormatter, user: UserAdminRespons const ResetPassword: ActionItem = { icon: mdiLockReset, title: $t('reset_password'), - type: $t('command'), $if: () => authManager.user.id !== user.id, onAction: () => handleResetPasswordUserAdmin(user), }; const ResetPinCode: ActionItem = { icon: mdiLockSmart, - type: $t('command'), title: $t('reset_pin_code'), onAction: () => handleResetPinCodeUserAdmin(user), }; 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 62c6f2b16e..3532897ad9 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 @@ -315,7 +315,6 @@ const Close = $derived({ title: $t('go_back'), - type: $t('command'), icon: mdiArrowLeft, onAction: handleEscape, $if: () => !assetViewerManager.isViewing, diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 6947eaeb58..602aa58873 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -1,7 +1,6 @@ - @@ -231,13 +249,6 @@ {/if} - copyToClipboard(getMyImmichLink().toString()), - }} -/> - {#if page.data.error} @@ -251,4 +262,13 @@ + + +