Compare commits

...

21 Commits

Author SHA1 Message Date
CJPeckover
af605876ad Merge branch 'immich-main' into feat/multi-select-asset-viewer 2025-09-16 13:49:32 -04:00
Alex
4e9bdd5e6c fix: storage indicator (#22077) 2025-09-16 12:46:48 -05:00
Jason Rasmussen
f05ef81c4f fix(web): issue with modal locking the page (#22079) 2025-09-16 12:46:09 -05:00
CJPeckover
585199553f revert pnpm-lock 2025-09-16 13:38:34 -04:00
Jason Rasmussen
c21860fb97 refactor: rename timeline actions (#22086) 2025-09-16 13:37:01 -04:00
CJPeckover
cb321afada revert pnpm-lock 2025-09-16 13:35:16 -04:00
CJPeckover
22cbf39fcf - revert pnpm-lock 2025-09-16 13:12:21 -04:00
CJPeckover
097dc3d21e Merge branch 'immich-main' into feat/multi-select-asset-viewer 2025-09-16 13:10:37 -04:00
CJPeckover
7fae893558 - make view icon visible on mobile 2025-09-16 13:07:56 -04:00
linux-universe
449368eee7 chore(docs): add an updated Podman/Quadlets community guide (#20744)
* chore(docs): update Podman/Quadlets instructions link to a more up to date repo

* Update community-guides.tsx: additional guide instead of replacing the other podman one

* fix community-guides.tsx: fixed podman handbook entry

* chore: linting

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-09-16 17:05:54 +00:00
Jason Rasmussen
31e098517d chore: rename asset-grid to timeline (#22084) 2025-09-16 13:05:09 -04:00
CJPeckover
669a7a9a10 - ensure gallery viewer has view icon
- ensure view icon is above video thumbnail
2025-09-16 13:00:41 -04:00
Jason Rasmussen
b9e2590752 chore: simplify (#22082) 2025-09-16 12:48:44 -04:00
Jason Rasmussen
41641ec000 chore: build sdk while server is starting (#22083) 2025-09-16 12:48:31 -04:00
Alex
8821c251c3 fix: navigate to time (#22078) 2025-09-16 11:40:31 -05:00
Jason Rasmussen
1d6b98ff86 chore: remove prepare-volumes (#22071) 2025-09-16 10:19:09 -04:00
bo0tzz
4d00261bc1 chore(mobile): translate missing strings (#22057) 2025-09-16 08:51:03 -05:00
CJPeckover
360b1fea2d format/check 2025-09-16 01:46:26 -04:00
CJPeckover
8497364cc7 make assetViewer.assetInteraction optional, it is not needed on utility pages, map, or individual-shared-viewer 2025-09-16 01:27:51 -04:00
CJPeckover
cf539cc033 Add initial select logic to asset viewer 2025-09-16 00:54:46 -04:00
CJPeckover
52903e510e - add initial viewer button UI 2025-09-16 00:19:10 -04:00
73 changed files with 633 additions and 546 deletions

View File

@@ -12,7 +12,6 @@ services:
- server_node_modules:/workspaces/immich/server/node_modules
- web_node_modules:/workspaces/immich/web/node_modules
- ${UPLOAD_LOCATION}/photos:/data
- ${UPLOAD_LOCATION}/photos/upload:/data/upload
- /etc/localtime:/etc/localtime:ro
database:

View File

@@ -8,8 +8,7 @@ services:
- IMMICH_SERVER_URL=http://127.0.0.1:2283/
volumes: !override
- ..:/workspaces/immich
- ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/data
- ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/data/upload
- ${UPLOAD_LOCATION:-upload-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/data
- /etc/localtime:/etc/localtime:ro
- pnpm-store:/usr/src/app/.pnpm-store
- server-node_modules:/usr/src/app/server/node_modules
@@ -24,9 +23,6 @@ services:
- coverage:/usr/src/app/web/coverage
immich-web:
env_file: !reset []
init:
env_file: !reset []
command: sh -c 'find /data -maxdepth 1 ! -path "/data/postgres" -type d -exec chown ${UID:-0}:${GID:-0} {} + 2>/dev/null || true; for path in /usr/src/app/.pnpm-store /usr/src/app/server/node_modules /usr/src/app/server/dist /usr/src/app/.github/node_modules /usr/src/app/cli/node_modules /usr/src/app/docs/node_modules /usr/src/app/e2e/node_modules /usr/src/app/open-api/typescript-sdk/node_modules /usr/src/app/web/.svelte-kit /usr/src/app/web/coverage /usr/src/app/node_modules /usr/src/app/web/node_modules; do [ -e "$$path" ] && chown -R ${UID:-0}:${GID:-0} "$$path" || true; done'
immich-machine-learning:
env_file: !reset []
database:
@@ -42,7 +38,5 @@ services:
redis:
env_file: !reset []
volumes:
# Node modules for each service to avoid conflicts and ensure consistent dependencies
upload1-devcontainer-volume:
upload2-devcontainer-volume:
upload-devcontainer-volume:
postgres-devcontainer-volume:

View File

@@ -1,13 +1,13 @@
dev: prepare-volumes
dev:
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --remove-orphans
dev-down:
docker compose -f ./docker/docker-compose.dev.yml down --remove-orphans
dev-update: prepare-volumes
dev-update:
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --build -V --remove-orphans
dev-scale: prepare-volumes
dev-scale:
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --build -V --scale immich-server=3 --remove-orphans
dev-docs:
@@ -23,7 +23,7 @@ e2e-update:
e2e-down:
docker compose -f ./e2e/docker-compose.yml down --remove-orphans
prod:
prod:
@trap 'make prod-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.prod.yml up --build -V --remove-orphans
prod-down:
@@ -33,16 +33,16 @@ prod-scale:
@trap 'make prod-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.prod.yml up --build -V --scale immich-server=3 --scale immich-microservices=3 --remove-orphans
.PHONY: open-api
open-api: prepare-volumes
open-api:
cd ./open-api && bash ./bin/generate-open-api.sh
open-api-dart: prepare-volumes
open-api-dart:
cd ./open-api && bash ./bin/generate-open-api.sh dart
open-api-typescript: prepare-volumes
open-api-typescript:
cd ./open-api && bash ./bin/generate-open-api.sh typescript
sql: prepare-volumes
sql:
pnpm --filter immich run sync:sql
attach-server:
@@ -68,32 +68,6 @@ VOLUME_DIRS = \
# Include .env file if it exists
-include docker/.env
# Helper function to chown, on error suggest remediation and exit
define safe_chown
CURRENT_OWNER=$$(stat -c '%u:%g' "$(1)" 2>/dev/null || echo "none"); \
DESIRED_OWNER="$(or $(UID),0):$(or $(GID),0)"; \
if [ "$$CURRENT_OWNER" != "$$DESIRED_OWNER" ] && ! chown -v $(2) $$DESIRED_OWNER "$(1)" 2>/dev/null; then \
echo "Permission denied when changing owner of volumes and upload location. Try running 'sudo make prepare-volumes' first."; \
exit 1; \
fi;
endef
# create empty directories and chown
prepare-volumes:
@$(foreach dir,$(VOLUME_DIRS),mkdir -p $(dir);)
@$(foreach dir,$(VOLUME_DIRS),$(call safe_chown,$(dir),-R))
ifneq ($(UPLOAD_LOCATION),)
ifeq ($(filter /%,$(UPLOAD_LOCATION)),)
@mkdir -p "docker/$(UPLOAD_LOCATION)/photos/upload"
@$(call safe_chown,docker/$(UPLOAD_LOCATION),)
@$(call safe_chown,docker/$(UPLOAD_LOCATION)/photos,-R)
else
@mkdir -p "$(UPLOAD_LOCATION)/photos/upload"
@$(call safe_chown,$(UPLOAD_LOCATION),)
@$(call safe_chown,$(UPLOAD_LOCATION)/photos,-R)
endif
endif
MODULES = e2e server web cli sdk docs .github
# directory to package name mapping function

View File

@@ -21,7 +21,6 @@ services:
# extends:
# file: hwaccel.transcoding.yml
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
user: '${UID:-0}:${GID:-0}'
build:
context: ../
dockerfile: server/Dockerfile.dev
@@ -30,7 +29,6 @@ services:
volumes:
- ..:/usr/src/app
- ${UPLOAD_LOCATION}/photos:/data
- ${UPLOAD_LOCATION}/photos/upload:/data/upload
- /etc/localtime:/etc/localtime:ro
- pnpm-store:/usr/src/app/.pnpm-store
- server-node_modules:/usr/src/app/server/node_modules
@@ -72,17 +70,12 @@ services:
condition: service_started
database:
condition: service_started
init:
condition: service_completed_successfully
healthcheck:
disable: false
immich-web:
container_name: immich_web
image: immich-web-dev:latest
# Needed for rootless docker setup, see https://github.com/moby/moby/issues/45919
# user: 0:0
user: '${UID:-0}:${GID:-0}'
build:
context: ../
dockerfile: server/Dockerfile.dev
@@ -114,8 +107,6 @@ services:
depends_on:
immich-server:
condition: service_started
init:
condition: service_completed_successfully
immich-machine-learning:
container_name: immich_machine_learning
@@ -183,25 +174,6 @@ services:
# volumes:
# - grafana-data:/var/lib/grafana
init:
container_name: init
image: busybox@sha256:ab33eacc8251e3807b85bb6dba570e4698c3998eca6f0fc2ccb60575a563ea74
env_file:
- .env
user: 0:0
command: sh -c 'find /data -maxdepth 1 -type d -exec chown ${UID:-0}:${GID:-0} {} + 2>/dev/null || true; for path in /usr/src/app/.pnpm-store /usr/src/app/server/node_modules /usr/src/app/server/dist /usr/src/app/.github/node_modules /usr/src/app/cli/node_modules /usr/src/app/docs/node_modules /usr/src/app/e2e/node_modules /usr/src/app/open-api/typescript-sdk/node_modules /usr/src/app/web/.svelte-kit /usr/src/app/web/coverage /usr/src/app/node_modules /usr/src/app/web/node_modules; do [ -e "$$path" ] && chown -R ${UID:-0}:${GID:-0} "$$path" || true; done'
volumes:
- pnpm-store:/usr/src/app/.pnpm-store
- server-node_modules:/usr/src/app/server/node_modules
- web-node_modules:/usr/src/app/web/node_modules
- github-node_modules:/usr/src/app/.github/node_modules
- cli-node_modules:/usr/src/app/cli/node_modules
- docs-node_modules:/usr/src/app/docs/node_modules
- e2e-node_modules:/usr/src/app/e2e/node_modules
- sdk-node_modules:/usr/src/app/open-api/typescript-sdk/node_modules
- app-node_modules:/usr/src/app/node_modules
- sveltekit:/usr/src/app/web/.svelte-kit
- coverage:/usr/src/app/web/coverage
volumes:
model-cache:
prometheus-data:

View File

@@ -28,6 +28,12 @@ const guides: CommunityGuidesProps[] = [
description: `synchronize folders in imported library with albums having the folders name.`,
url: 'https://github.com/immich-app/immich/discussions/3382',
},
{
title: 'Immich Podman Quadlets Handbook',
description:
'A rewrite of the original Immich Docker Compose file using Podman Quadlets, with a set of extra guides in the repositorys wiki.',
url: 'https://github.com/linux-universe/immich-podman-quadlets/blob/main/README.md',
},
{
title: 'Podman/Quadlets Install',
description: 'Documentation for simple podman setup using quadlets.',

View File

@@ -423,6 +423,7 @@
"album_remove_user_confirmation": "Are you sure you want to remove {user}?",
"album_search_not_found": "No albums found matching your search",
"album_share_no_users": "Looks like you have shared this album with all users or you don't have any user to share with.",
"album_summary": "Album summary",
"album_updated": "Album updated",
"album_updated_setting_description": "Receive an email notification when a shared album has new assets",
"album_user_left": "Left {album}",
@@ -494,6 +495,8 @@
"asset_restored_successfully": "Asset restored successfully",
"asset_skipped": "Skipped",
"asset_skipped_in_trash": "In trash",
"asset_trashed": "Asset trashed",
"asset_troubleshoot": "Asset Troubleshoot",
"asset_uploaded": "Uploaded",
"asset_uploading": "Uploading…",
"asset_viewer_settings_subtitle": "Manage your gallery viewer settings",
@@ -527,6 +530,7 @@
"autoplay_slideshow": "Autoplay slideshow",
"back": "Back",
"back_close_deselect": "Back, close, or deselect",
"background_backup_running_error": "Background backup is currently running, cannot start manual backup",
"background_location_permission": "Background location permission",
"background_location_permission_content": "In order to switch networks when running in the background, Immich must *always* have precise location access so the app can read the Wi-Fi network's name",
"backup": "Backup",
@@ -738,6 +742,7 @@
"create_user": "Create user",
"created": "Created",
"created_at": "Created",
"creating_linked_albums": "Creating linked albums...",
"crop": "Crop",
"curated_object_page_title": "Things",
"current_device": "Current device",
@@ -887,7 +892,9 @@
"error": "Error",
"error_change_sort_album": "Failed to change album sort order",
"error_delete_face": "Error deleting face from asset",
"error_getting_places": "Error getting places",
"error_loading_image": "Error loading image",
"error_loading_partners": "Error loading partners: {error}",
"error_saving_image": "Error: {error}",
"error_tag_face_bounding_box": "Error tagging face - cannot get bounding box coordinates",
"error_title": "Error - Something went wrong",
@@ -1052,6 +1059,7 @@
"favorites_page_no_favorites": "No favorite assets found",
"feature_photo_updated": "Feature photo updated",
"features": "Features",
"features_in_development": "Features in Development",
"features_setting_description": "Manage the app features",
"file_name": "File name",
"file_name_or_extension": "File name or extension",
@@ -1216,6 +1224,7 @@
"local": "Local",
"local_asset_cast_failed": "Unable to cast an asset that is not uploaded to the server",
"local_assets": "Local Assets",
"local_media_summary": "Local Media Summary",
"local_network": "Local network",
"local_network_sheet_info": "The app will connect to the server through this URL when using the specified Wi-Fi network",
"location_permission": "Location permission",
@@ -1227,6 +1236,7 @@
"location_picker_longitude_hint": "Enter your longitude here",
"lock": "Lock",
"locked_folder": "Locked Folder",
"log_detail_title": "Log Detail",
"log_out": "Log out",
"log_out_all_devices": "Log Out All Devices",
"logged_in_as": "Logged in as {user}",
@@ -1257,6 +1267,7 @@
"login_password_changed_success": "Password updated successfully",
"logout_all_device_confirmation": "Are you sure you want to log out all devices?",
"logout_this_device_confirmation": "Are you sure you want to log out this device?",
"logs": "Logs",
"longitude": "Longitude",
"look": "Look",
"loop_videos": "Loop videos",
@@ -1299,6 +1310,7 @@
"mark_as_read": "Mark as read",
"marked_all_as_read": "Marked all as read",
"matches": "Matches",
"matching_assets": "Matching Assets",
"media_type": "Media type",
"memories": "Memories",
"memories_all_caught_up": "All caught up",
@@ -1363,20 +1375,25 @@
"no_assets_message": "CLICK TO UPLOAD YOUR FIRST PHOTO",
"no_assets_to_show": "No assets to show",
"no_cast_devices_found": "No cast devices found",
"no_checksum_local": "No checksum available - cannot fetch local assets",
"no_checksum_remote": "No checksum available - cannot fetch remote asset",
"no_duplicates_found": "No duplicates were found.",
"no_exif_info_available": "No exif info available",
"no_explore_results_message": "Upload more photos to explore your collection.",
"no_favorites_message": "Add favorites to quickly find your best pictures and videos",
"no_libraries_message": "Create an external library to view your photos and videos",
"no_local_assets_found": "No local assets found with this checksum",
"no_locked_photos_message": "Photos and videos in the locked folder are hidden and won't show up as you browse or search your library.",
"no_name": "No Name",
"no_notifications": "No notifications",
"no_people_found": "No matching people found",
"no_places": "No places",
"no_remote_assets_found": "No remote assets found with this checksum",
"no_results": "No results",
"no_results_description": "Try a synonym or more general keyword",
"no_shared_albums_message": "Create an album to share photos and videos with people in your network",
"no_uploads_in_progress": "No uploads in progress",
"not_available": "N/A",
"not_in_any_album": "Not in any album",
"not_selected": "Not selected",
"note_apply_storage_label_to_previously_uploaded assets": "Note: To apply the Storage Label to previously uploaded assets, run the",
@@ -1587,6 +1604,7 @@
"regenerating_thumbnails": "Regenerating thumbnails",
"remote": "Remote",
"remote_assets": "Remote Assets",
"remote_media_summary": "Remote Media Summary",
"remove": "Remove",
"remove_assets_album_confirmation": "Are you sure you want to remove {count, plural, one {# asset} other {# assets}} from the album?",
"remove_assets_shared_link_confirmation": "Are you sure you want to remove {count, plural, one {# asset} other {# assets}} from this shared link?",
@@ -1862,6 +1880,7 @@
"show_slideshow_transition": "Show slideshow transition",
"show_supporter_badge": "Supporter badge",
"show_supporter_badge_description": "Show a supporter badge",
"show_text_search_menu": "Show text search menu",
"shuffle": "Shuffle",
"sidebar": "Sidebar",
"sidebar_display_description": "Display a link to the view in the sidebar",
@@ -2094,5 +2113,6 @@
"yes": "Yes",
"you_dont_have_any_shared_links": "You don't have any shared links",
"your_wifi_name": "Your Wi-Fi name",
"zoom_image": "Zoom Image"
"zoom_image": "Zoom Image",
"zoom_to_bounds": "Zoom to bounds"
}

View File

@@ -300,7 +300,7 @@ run = "tsc --noEmit"
depends = "web:svelte-kit-sync"
env._.path = "web/node_modules/.bin"
dir = "web"
run = "svelte-check --no-tsconfig --fail-on-warnings --compiler-warnings 'reactive_declaration_non_reactive_property:ignore' --ignore src/lib/components/photos-page/asset-grid.svelte"
run = "svelte-check --no-tsconfig --fail-on-warnings --compiler-warnings 'reactive_declaration_non_reactive_property:ignore' --ignore src/lib/components/timeline/Timeline.svelte"
[tasks."web:checklist"]
run = [

View File

@@ -205,9 +205,9 @@ class BackupControllerPage extends HookConsumerWidget {
}
buildBackgroundBackupInfo() {
return const ListTile(
leading: Icon(Icons.info_outline_rounded),
title: Text("Background backup is currently running, cannot start manual backup"),
return ListTile(
leading: const Icon(Icons.info_outline_rounded),
title: Text('background_backup_running_error'.tr()),
);
}

View File

@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
@@ -249,7 +250,7 @@ class _DriftBackupAlbumSelectionPageState extends ConsumerState<DriftBackupAlbum
mainAxisSize: MainAxisSize.max,
children: [
const CircularProgressIndicator(strokeWidth: 4),
Text("Creating linked albums...", style: context.textTheme.labelLarge),
Text('creating_linked_albums'.tr(), style: context.textTheme.labelLarge),
],
),
),

View File

@@ -1,4 +1,5 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
@@ -58,8 +59,10 @@ class DriftBackupAssetDetailPage extends ConsumerWidget {
overflow: TextOverflow.ellipsis,
);
},
error: (error, stackTrace) =>
Text('Error: $error', style: TextStyle(color: context.colorScheme.error)),
error: (error, stackTrace) => Text(
'error_saving_image'.tr(args: [error.toString()]),
style: TextStyle(color: context.colorScheme.error),
),
loading: () => const SizedBox(height: 16, width: 16, child: CircularProgressIndicator.adaptive()),
),
],
@@ -83,7 +86,7 @@ class DriftBackupAssetDetailPage extends ConsumerWidget {
);
},
error: (Object error, StackTrace stackTrace) {
return Center(child: Text('Error: $error'));
return Center(child: Text('error_saving_image'.tr(args: [error.toString()])));
},
loading: () {
return const SizedBox(height: 48, width: 48, child: Center(child: CircularProgressIndicator.adaptive()));

View File

@@ -1,4 +1,5 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -8,7 +9,6 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/services/immich_logger.service.dart';
import 'package:intl/intl.dart';
@RoutePage()
class AppLogPage extends HookConsumerWidget {
@@ -49,7 +49,7 @@ class AppLogPage extends HookConsumerWidget {
return Scaffold(
appBar: AppBar(
title: const Text("Logs", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0)),
title: Text('logs'.tr(), style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0)),
scrolledUnderElevation: 1,
elevation: 2,
actions: [

View File

@@ -1,4 +1,5 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -36,7 +37,7 @@ class AppLogDetailPage extends HookConsumerWidget {
context.scaffoldMessenger.showSnackBar(
SnackBar(
content: Text(
"Copied to clipboard",
"copied_to_clipboard".tr(),
style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor),
),
),
@@ -97,7 +98,7 @@ class AppLogDetailPage extends HookConsumerWidget {
}
return Scaffold(
appBar: AppBar(title: const Text("Log Detail")),
appBar: AppBar(title: Text("log_detail_title".tr())),
body: SafeArea(
child: ListView(
children: [

View File

@@ -134,7 +134,7 @@ class _SharedToPartnerList extends ConsumerWidget {
);
},
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stack) => Center(child: Text("Error loading partners: $error")),
error: (error, stack) => Center(child: Text('error_loading_partners'.tr(args: [error.toString()]))),
);
}
}

View File

@@ -85,7 +85,7 @@ class PlacesCollectionPage extends HookConsumerWidget {
},
);
},
error: (error, stask) => const Text('Error getting places'),
error: (error, stask) => Text('error_getting_places'.tr()),
loading: () => const Center(child: CircularProgressIndicator()),
),
],

View File

@@ -435,7 +435,7 @@ class SearchPage extends HookConsumerWidget {
}
},
icon: const Icon(Icons.more_vert_rounded),
tooltip: 'Show text search menu',
tooltip: 'show_text_search_menu'.tr(),
);
},
menuChildren: [

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:auto_route/auto_route.dart';
import 'package:drift/drift.dart' hide Column;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
@@ -135,7 +136,7 @@ class FeatInDevPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Features in Development'), centerTitle: true),
appBar: AppBar(title: Text('features_in_development'.tr()), centerTitle: true),
body: Column(
children: [
Flexible(

View File

@@ -15,6 +15,7 @@ class MainTimelinePage extends ConsumerWidget {
return Timeline(
topSliverWidget: const SliverToBoxAdapter(child: DriftMemoryLane()),
topSliverWidgetHeight: hasMemories ? 200 : 0,
showStorageIndicator: true,
);
}
}

View File

@@ -1,5 +1,6 @@
import 'package:auto_route/auto_route.dart';
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
@@ -55,7 +56,7 @@ class LocalMediaSummaryPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Local Media Summary')),
appBar: AppBar(title: Text('local_media_summary'.tr())),
body: Consumer(
builder: (ctx, ref, __) {
final db = ref.watch(driftProvider);
@@ -78,7 +79,7 @@ class LocalMediaSummaryPage extends StatelessWidget {
const Divider(),
Padding(
padding: const EdgeInsets.only(left: 15),
child: Text("Album summary", style: ctx.textTheme.titleMedium),
child: Text("album_summary".tr(), style: ctx.textTheme.titleMedium),
),
],
),
@@ -135,7 +136,7 @@ class RemoteMediaSummaryPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Remote Media Summary')),
appBar: AppBar(title: Text('remote_media_summary'.tr())),
body: Consumer(
builder: (ctx, ref, __) {
final db = ref.watch(driftProvider);
@@ -158,7 +159,7 @@ class RemoteMediaSummaryPage extends StatelessWidget {
const Divider(),
Padding(
padding: const EdgeInsets.only(left: 15),
child: Text("Album summary", style: ctx.textTheme.titleMedium),
child: Text("album_summary".tr(), style: ctx.textTheme.titleMedium),
),
],
),

View File

@@ -1,4 +1,5 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
@@ -14,7 +15,7 @@ class AssetTroubleshootPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(title: const Text("Asset Troubleshoot")),
appBar: AppBar(title: Text('asset_troubleshoot'.tr())),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
@@ -37,20 +38,23 @@ class _AssetDetailsView extends ConsumerWidget {
children: [
_AssetPropertiesSection(asset: asset),
const SizedBox(height: 16),
Text('Matching Assets', style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)),
Text(
'matching_assets'.tr(),
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
),
if (asset.checksum != null) ...[
_LocalAssetsSection(asset: asset),
const SizedBox(height: 16),
_RemoteAssetSection(asset: asset),
] else ...[
const _PropertySectionCard(
_PropertySectionCard(
title: 'Local Assets',
properties: [_PropertyItem(label: 'Status', value: 'No checksum available - cannot fetch local assets')],
properties: [_PropertyItem(label: 'Status', value: 'no_checksum_local'.tr())],
),
const SizedBox(height: 16),
const _PropertySectionCard(
_PropertySectionCard(
title: 'Remote Assets',
properties: [_PropertyItem(label: 'Status', value: 'No checksum available - cannot fetch remote asset')],
properties: [_PropertyItem(label: 'Status', value: 'no_checksum_remote'.tr())],
),
],
],
@@ -222,9 +226,9 @@ class _LocalAssetsSection extends ConsumerWidget {
}
if (localAssets.isEmpty) {
return const _PropertySectionCard(
return _PropertySectionCard(
title: 'Local Assets',
properties: [_PropertyItem(label: 'Status', value: 'No local assets found with this checksum')],
properties: [_PropertyItem(label: 'Status', value: 'no_local_assets_found'.tr())],
);
}
@@ -281,9 +285,9 @@ class _RemoteAssetSection extends ConsumerWidget {
final remoteAsset = snapshot.data;
if (remoteAsset == null) {
return const _PropertySectionCard(
return _PropertySectionCard(
title: 'Remote Assets',
properties: [_PropertyItem(label: 'Status', value: 'No remote asset found with this checksum')],
properties: [_PropertyItem(label: 'Status', value: 'no_remote_assets_found'.tr())],
);
}
@@ -336,7 +340,10 @@ class _PropertyItem extends StatelessWidget {
child: Text('$label:', style: const TextStyle(fontWeight: FontWeight.w500)),
),
Expanded(
child: Text(value ?? 'N/A', style: TextStyle(color: Theme.of(context).colorScheme.secondary)),
child: Text(
value ?? 'not_available'.tr(),
style: TextStyle(color: Theme.of(context).colorScheme.secondary),
),
),
],
),

View File

@@ -1,4 +1,5 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
@@ -302,7 +303,9 @@ class _LocalAlbumsCollectionCard extends ConsumerWidget {
}).toList();
},
error: (error, _) {
return [Center(child: Text('Error: $error'))];
return [
Center(child: Text('error_saving_image'.tr(args: [error.toString()]))),
];
},
loading: () {
return [const Center(child: CircularProgressIndicator())];

View File

@@ -1,4 +1,5 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
@@ -46,9 +47,9 @@ class _AlbumList extends ConsumerWidget {
),
data: (albums) {
if (albums.isEmpty) {
return const SliverToBoxAdapter(
return SliverToBoxAdapter(
child: Center(
child: Padding(padding: EdgeInsets.all(20.0), child: Text('No albums found')),
child: Padding(padding: const EdgeInsets.all(20.0), child: Text('no_albums_yet'.tr())),
),
);
}

View File

@@ -26,6 +26,7 @@ class LocalTimelinePage extends StatelessWidget {
child: Timeline(
appBar: MesmerizingSliverAppBar(title: album.name),
bottomSheet: const LocalAlbumBottomSheet(),
showStorageIndicator: true,
),
);
}

View File

@@ -440,7 +440,7 @@ class DriftSearchPage extends HookConsumerWidget {
}
},
icon: const Icon(Icons.more_vert_rounded),
tooltip: 'Show text search menu',
tooltip: 'show_text_search_menu'.tr(),
);
},
menuChildren: [
@@ -633,6 +633,7 @@ class _SearchResultGrid extends ConsumerWidget {
groupBy: GroupAssetsBy.none,
appBar: null,
bottomSheet: const GeneralBottomSheet(minChildSize: 0.20),
withScrubber: false,
),
),
),

View File

@@ -1,4 +1,5 @@
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
@@ -58,7 +59,7 @@ class LikeActivityActionButton extends ConsumerWidget {
label: "like".t(context: context),
menuItem: menuItem,
),
error: (error, stack) => Text("Error: $error"),
error: (error, stack) => Text('error_saving_image'.tr(args: [error.toString()])),
);
}
}

View File

@@ -504,9 +504,9 @@ class _AlbumList extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
if (albums.isEmpty) {
return const SliverToBoxAdapter(
return SliverToBoxAdapter(
child: Center(
child: Padding(padding: EdgeInsets.all(20.0), child: Text('No albums found')),
child: Padding(padding: const EdgeInsets.all(20.0), child: Text('album_search_not_found'.tr())),
),
);
}
@@ -599,9 +599,9 @@ class _AlbumGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (albums.isEmpty) {
return const SliverToBoxAdapter(
return SliverToBoxAdapter(
child: Center(
child: Padding(padding: EdgeInsets.all(20.0), child: Text('No albums found')),
child: Padding(padding: const EdgeInsets.all(20.0), child: Text('album_search_not_found'.tr())),
),
);
}

View File

@@ -32,7 +32,7 @@ class Timeline extends StatelessWidget {
super.key,
this.topSliverWidget,
this.topSliverWidgetHeight,
this.showStorageIndicator,
this.showStorageIndicator = false,
this.withStack = false,
this.appBar = const ImmichSliverAppBar(floating: true, pinned: false, snap: false),
this.bottomSheet = const GeneralBottomSheet(minChildSize: 0.18),
@@ -42,7 +42,7 @@ class Timeline extends StatelessWidget {
final Widget? topSliverWidget;
final double? topSliverWidgetHeight;
final bool? showStorageIndicator;
final bool showStorageIndicator;
final Widget? appBar;
final Widget? bottomSheet;
final bool withStack;

View File

@@ -98,7 +98,12 @@ class BottomGalleryBar extends ConsumerWidget {
if (isDeleted) {
// Can only trash assets stored in server. Local assets are always permanently removed for now
if (context.mounted && asset.isRemote && isStackPrimaryAsset) {
ImmichToast.show(durationInSecond: 1, context: context, msg: 'Asset trashed', gravity: ToastGravity.BOTTOM);
ImmichToast.show(
durationInSecond: 1,
context: context,
msg: 'asset_trashed'.tr(),
gravity: ToastGravity.BOTTOM,
);
}
removeAssetFromStack();
}

View File

@@ -29,7 +29,7 @@ class CastDialog extends ConsumerWidget {
future: ref.read(castProvider.notifier).getDevices(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error.toString()}');
return Text('error_saving_image'.tr(args: [snapshot.error.toString()]));
} else if (!snapshot.hasData) {
return const SizedBox(height: 48, child: Center(child: CircularProgressIndicator()));
}

View File

@@ -275,7 +275,7 @@ class _MapSheetDragRegion extends StatelessWidget {
child: IconButton(
icon: Icon(Icons.map_outlined, color: context.textTheme.displayLarge?.color),
iconSize: 24,
tooltip: 'Zoom to bounds',
tooltip: 'zoom_to_bounds'.tr(),
onPressed: () => onZoomToAsset?.call(value!),
),
),

206
pnpm-lock.yaml generated
View File

@@ -127,13 +127,13 @@ importers:
dependencies:
'@docusaurus/core':
specifier: ~3.8.0
version: 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
version: 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/preset-classic':
specifier: ~3.8.0
version: 3.8.1(@algolia/client-search@5.29.0)(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(@types/react@19.1.12)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.9.2)
version: 3.8.1(@algolia/client-search@5.29.0)(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(@types/react@19.1.13)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.9.2)
'@docusaurus/theme-common':
specifier: ~3.8.0
version: 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
version: 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mdi/js':
specifier: ^7.3.67
version: 7.4.47
@@ -142,16 +142,16 @@ importers:
version: 1.6.1
'@mdx-js/react':
specifier: ^3.0.0
version: 3.1.0(@types/react@19.1.12)(react@18.3.1)
version: 3.1.0(@types/react@19.1.13)(react@18.3.1)
autoprefixer:
specifier: ^10.4.17
version: 10.4.21(postcss@8.5.6)
docusaurus-lunr-search:
specifier: ^3.3.2
version: 3.6.0(@docusaurus/core@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
version: 3.6.0(@docusaurus/core@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
docusaurus-preset-openapi:
specifier: ^0.7.5
version: 0.7.6(@algolia/client-search@5.29.0)(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(@types/react@19.1.12)(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(redux@4.2.1)(search-insights@2.17.3)(typescript@5.9.2)
version: 0.7.6(@algolia/client-search@5.29.0)(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(@types/react@19.1.13)(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(redux@4.2.1)(search-insights@2.17.3)(typescript@5.9.2)
lunr:
specifier: ^2.3.9
version: 2.3.9
@@ -684,8 +684,8 @@ importers:
specifier: file:../open-api/typescript-sdk
version: link:../open-api/typescript-sdk
'@immich/ui':
specifier: ^0.27.1
version: 0.27.1(@internationalized/date@3.8.2)(svelte@5.35.5)
specifier: ^0.27.2
version: 0.27.2(@internationalized/date@3.8.2)(svelte@5.35.5)
'@mapbox/mapbox-gl-rtl-text':
specifier: 0.2.3
version: 0.2.3(mapbox-gl@1.13.3)
@@ -2405,8 +2405,8 @@ packages:
'@floating-ui/core@1.7.3':
resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==}
'@floating-ui/dom@1.7.3':
resolution: {integrity: sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==}
'@floating-ui/dom@1.7.4':
resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==}
'@floating-ui/utils@0.2.10':
resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
@@ -2589,8 +2589,8 @@ packages:
cpu: [x64]
os: [win32]
'@immich/ui@0.27.1':
resolution: {integrity: sha512-d/LqCpFZwaZ6Vp2wz+DkhMirMle2zL/y4SHyKLmA0QI6pwz+yZaym6DlYkx3ZPKlN10/ugeHi58fXdlMxJiuKA==}
'@immich/ui@0.27.2':
resolution: {integrity: sha512-woPBYtuKFYApOwI9KS6Zj/6p9KkzPJLfzu4zSH7nF7lxVguk8DakHxR08ENnVq34lJHlIjl4PEv7jo69CJkE6w==}
peerDependencies:
svelte: ^5.0.0
@@ -4274,6 +4274,9 @@ packages:
'@types/node@22.18.1':
resolution: {integrity: sha512-rzSDyhn4cYznVG+PCzGe1lwuMYJrcBS1fc3JqSa2PvtABwWo+dZ1ij5OVok3tqfpEBCBoaR4d7upFJk73HRJDw==}
'@types/node@22.18.4':
resolution: {integrity: sha512-UJdblFqXymSBhmZf96BnbisoFIr8ooiiBRMolQgg77Ea+VM37jXw76C2LQr9n8wm9+i/OvlUlW6xSvqwzwqznw==}
'@types/node@24.3.0':
resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==}
@@ -4328,6 +4331,9 @@ packages:
'@types/react@19.1.12':
resolution: {integrity: sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==}
'@types/react@19.1.13':
resolution: {integrity: sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==}
'@types/readdir-glob@1.1.5':
resolution: {integrity: sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==}
@@ -4926,8 +4932,8 @@ packages:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
bits-ui@2.9.4:
resolution: {integrity: sha512-Cqn685P6DDuEyBZT/CWMyS5+8JAnYbctvoEVPcmiut+HUpG3SozVgjoDaUib5VG4ZYUKEi1FPwHxiXo9c6J0PA==}
bits-ui@2.9.8:
resolution: {integrity: sha512-oVAqdhLSuGIgEiT0yu3ShSI7AxncCxX26Gv6Lul94BuKHV2uzHoKfIodtnMQSq+udJ54svuCIRqA58whsv7vaA==}
engines: {node: '>=20'}
peerDependencies:
'@internationalized/date': ^3.8.1
@@ -9991,8 +9997,8 @@ packages:
simple-get@3.1.1:
resolution: {integrity: sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==}
simple-icons@15.14.0:
resolution: {integrity: sha512-eTBZiiwDFN8RPkcmHKoUz1+sckeqNQXv5ujQcgQddDzp3xuDIFWeZh/i0oEv1StOPsf9NPMC0gTBxUzhPqHzag==}
simple-icons@15.15.0:
resolution: {integrity: sha512-ohh1Uo9AjH10WN5wpPmtjnmbSLv6MjiULHS4dYA821uIsPAp0Q3XoluPnjBnQAFsztasmM6z2dezJBrQbtserg==}
engines: {node: '>=0.12.18'}
simple-swizzle@0.2.2:
@@ -12534,14 +12540,14 @@ snapshots:
'@docsearch/css@3.9.0': {}
'@docsearch/react@3.9.0(@algolia/client-search@5.29.0)(@types/react@19.1.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)':
'@docsearch/react@3.9.0(@algolia/client-search@5.29.0)(@types/react@19.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)':
dependencies:
'@algolia/autocomplete-core': 1.17.9(@algolia/client-search@5.29.0)(algoliasearch@5.29.0)(search-insights@2.17.3)
'@algolia/autocomplete-preset-algolia': 1.17.9(@algolia/client-search@5.29.0)(algoliasearch@5.29.0)
'@docsearch/css': 3.9.0
algoliasearch: 5.29.0
optionalDependencies:
'@types/react': 19.1.12
'@types/react': 19.1.13
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
search-insights: 2.17.3
@@ -12617,7 +12623,7 @@ snapshots:
- uglify-js
- webpack-cli
'@docusaurus/core@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/core@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/babel': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/bundler': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
@@ -12626,7 +12632,7 @@ snapshots:
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-common': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-validation': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mdx-js/react': 3.1.0(@types/react@19.1.12)(react@18.3.1)
'@mdx-js/react': 3.1.0(@types/react@19.1.13)(react@18.3.1)
boxen: 6.2.1
chalk: 4.1.2
chokidar: 3.6.0
@@ -12749,13 +12755,13 @@ snapshots:
- uglify-js
- webpack-cli
'@docusaurus/plugin-content-blog@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/plugin-content-blog@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/logger': 3.8.1
'@docusaurus/mdx-loader': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-common': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -12791,13 +12797,13 @@ snapshots:
- utf-8-validate
- webpack-cli
'@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/logger': 3.8.1
'@docusaurus/mdx-loader': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/module-type-aliases': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-common': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -12832,9 +12838,9 @@ snapshots:
- utf-8-validate
- webpack-cli
'@docusaurus/plugin-content-pages@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/plugin-content-pages@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/mdx-loader': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -12863,9 +12869,9 @@ snapshots:
- utf-8-validate
- webpack-cli
'@docusaurus/plugin-css-cascade-layers@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/plugin-css-cascade-layers@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-validation': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -12891,9 +12897,9 @@ snapshots:
- utf-8-validate
- webpack-cli
'@docusaurus/plugin-debug@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/plugin-debug@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
fs-extra: 11.3.0
@@ -12920,9 +12926,9 @@ snapshots:
- utf-8-validate
- webpack-cli
'@docusaurus/plugin-google-analytics@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/plugin-google-analytics@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-validation': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
@@ -12947,9 +12953,9 @@ snapshots:
- utf-8-validate
- webpack-cli
'@docusaurus/plugin-google-gtag@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/plugin-google-gtag@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-validation': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@types/gtag.js': 0.0.12
@@ -12975,9 +12981,9 @@ snapshots:
- utf-8-validate
- webpack-cli
'@docusaurus/plugin-google-tag-manager@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/plugin-google-tag-manager@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-validation': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
@@ -13002,9 +13008,9 @@ snapshots:
- utf-8-validate
- webpack-cli
'@docusaurus/plugin-sitemap@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/plugin-sitemap@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/logger': 3.8.1
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -13034,9 +13040,9 @@ snapshots:
- utf-8-validate
- webpack-cli
'@docusaurus/plugin-svgr@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/plugin-svgr@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-validation': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -13065,22 +13071,22 @@ snapshots:
- utf-8-validate
- webpack-cli
'@docusaurus/preset-classic@3.8.1(@algolia/client-search@5.29.0)(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(@types/react@19.1.12)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.9.2)':
'@docusaurus/preset-classic@3.8.1(@algolia/client-search@5.29.0)(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(@types/react@19.1.13)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-css-cascade-layers': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-debug': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-google-analytics': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-google-gtag': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-google-tag-manager': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-sitemap': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-svgr': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/theme-classic': 3.8.1(@types/react@19.1.12)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/theme-search-algolia': 3.8.1(@algolia/client-search@5.29.0)(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(@types/react@19.1.12)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-css-cascade-layers': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-debug': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-google-analytics': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-google-gtag': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-google-tag-manager': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-sitemap': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-svgr': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/theme-classic': 3.8.1(@types/react@19.1.13)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/theme-search-algolia': 3.8.1(@algolia/client-search@5.29.0)(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(@types/react@19.1.13)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.9.2)
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
@@ -13111,22 +13117,22 @@ snapshots:
'@types/react': 19.1.12
react: 18.3.1
'@docusaurus/theme-classic@3.8.1(@types/react@19.1.12)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
'@docusaurus/theme-classic@3.8.1(@types/react@19.1.13)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)':
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/logger': 3.8.1
'@docusaurus/mdx-loader': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/module-type-aliases': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/theme-translations': 3.8.1
'@docusaurus/types': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-common': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-validation': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mdx-js/react': 3.1.0(@types/react@19.1.12)(react@18.3.1)
'@mdx-js/react': 3.1.0(@types/react@19.1.13)(react@18.3.1)
clsx: 2.1.1
copy-text-to-clipboard: 3.2.0
infima: 0.2.0-alpha.45
@@ -13160,11 +13166,11 @@ snapshots:
- utf-8-validate
- webpack-cli
'@docusaurus/theme-common@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
'@docusaurus/theme-common@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@docusaurus/mdx-loader': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/module-type-aliases': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-common': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@types/history': 4.7.11
@@ -13185,13 +13191,13 @@ snapshots:
- uglify-js
- webpack-cli
'@docusaurus/theme-search-algolia@3.8.1(@algolia/client-search@5.29.0)(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(@types/react@19.1.12)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.9.2)':
'@docusaurus/theme-search-algolia@3.8.1(@algolia/client-search@5.29.0)(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(@types/react@19.1.13)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.9.2)':
dependencies:
'@docsearch/react': 3.9.0(@algolia/client-search@5.29.0)(@types/react@19.1.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docsearch/react': 3.9.0(@algolia/client-search@5.29.0)(@types/react@19.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/logger': 3.8.1
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/theme-translations': 3.8.1
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-validation': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -13544,7 +13550,7 @@ snapshots:
dependencies:
'@floating-ui/utils': 0.2.10
'@floating-ui/dom@1.7.3':
'@floating-ui/dom@1.7.4':
dependencies:
'@floating-ui/core': 1.7.3
'@floating-ui/utils': 0.2.10
@@ -13700,11 +13706,11 @@ snapshots:
'@img/sharp-win32-x64@0.34.3':
optional: true
'@immich/ui@0.27.1(@internationalized/date@3.8.2)(svelte@5.35.5)':
'@immich/ui@0.27.2(@internationalized/date@3.8.2)(svelte@5.35.5)':
dependencies:
'@mdi/js': 7.4.47
bits-ui: 2.9.4(@internationalized/date@3.8.2)(svelte@5.35.5)
simple-icons: 15.14.0
bits-ui: 2.9.8(@internationalized/date@3.8.2)(svelte@5.35.5)
simple-icons: 15.15.0
svelte: 5.35.5
tailwind-merge: 3.3.1
tailwind-variants: 3.1.1(tailwind-merge@3.3.1)(tailwindcss@4.1.12)
@@ -14076,10 +14082,10 @@ snapshots:
- acorn
- supports-color
'@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1)':
'@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1)':
dependencies:
'@types/mdx': 2.0.13
'@types/react': 19.1.12
'@types/react': 19.1.13
react: 18.3.1
'@microsoft/tsdoc@0.15.1': {}
@@ -15443,7 +15449,7 @@ snapshots:
'@types/hoist-non-react-statics@3.3.6':
dependencies:
'@types/react': 19.1.12
'@types/react': 19.1.13
hoist-non-react-statics: 3.3.2
'@types/html-minifier-terser@6.1.0': {}
@@ -15557,6 +15563,10 @@ snapshots:
dependencies:
undici-types: 6.21.0
'@types/node@22.18.4':
dependencies:
undici-types: 6.21.0
'@types/node@24.3.0':
dependencies:
undici-types: 7.10.0
@@ -15609,7 +15619,7 @@ snapshots:
'@types/react-redux@7.1.34':
dependencies:
'@types/hoist-non-react-statics': 3.3.6
'@types/react': 19.1.12
'@types/react': 19.1.13
hoist-non-react-statics: 3.3.2
redux: 4.2.1
@@ -15634,6 +15644,10 @@ snapshots:
dependencies:
csstype: 3.1.3
'@types/react@19.1.13':
dependencies:
csstype: 3.1.3
'@types/readdir-glob@1.1.5':
dependencies:
'@types/node': 22.18.1
@@ -15700,7 +15714,7 @@ snapshots:
'@types/through@0.0.33':
dependencies:
'@types/node': 22.18.1
'@types/node': 22.18.4
'@types/ua-parser-js@0.7.39': {}
@@ -16367,10 +16381,10 @@ snapshots:
binary-extensions@2.3.0: {}
bits-ui@2.9.4(@internationalized/date@3.8.2)(svelte@5.35.5):
bits-ui@2.9.8(@internationalized/date@3.8.2)(svelte@5.35.5):
dependencies:
'@floating-ui/core': 1.7.3
'@floating-ui/dom': 1.7.3
'@floating-ui/dom': 1.7.4
'@internationalized/date': 3.8.2
esm-env: 1.2.2
runed: 0.29.2(svelte@5.35.5)
@@ -17356,9 +17370,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
docusaurus-lunr-search@3.6.0(@docusaurus/core@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
docusaurus-lunr-search@3.6.0(@docusaurus/core@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/core': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
autocomplete.js: 0.37.1
clsx: 2.1.1
gauge: 3.0.2
@@ -17376,10 +17390,10 @@ snapshots:
unified: 9.2.2
unist-util-is: 4.1.0
docusaurus-plugin-openapi@0.7.6(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2):
docusaurus-plugin-openapi@0.7.6(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2):
dependencies:
'@docusaurus/mdx-loader': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/utils': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-common': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/utils-validation': 3.8.1(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -17416,12 +17430,12 @@ snapshots:
docusaurus-plugin-proxy@0.7.6: {}
docusaurus-preset-openapi@0.7.6(@algolia/client-search@5.29.0)(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(@types/react@19.1.12)(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(redux@4.2.1)(search-insights@2.17.3)(typescript@5.9.2):
docusaurus-preset-openapi@0.7.6(@algolia/client-search@5.29.0)(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(@types/react@19.1.13)(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(redux@4.2.1)(search-insights@2.17.3)(typescript@5.9.2):
dependencies:
'@docusaurus/preset-classic': 3.8.1(@algolia/client-search@5.29.0)(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(@types/react@19.1.12)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.9.2)
docusaurus-plugin-openapi: 0.7.6(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
'@docusaurus/preset-classic': 3.8.1(@algolia/client-search@5.29.0)(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(@types/react@19.1.13)(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.9.2)
docusaurus-plugin-openapi: 0.7.6(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
docusaurus-plugin-proxy: 0.7.6
docusaurus-theme-openapi: 0.7.6(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@types/react@19.1.12)(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(redux@4.2.1)(typescript@5.9.2)
docusaurus-theme-openapi: 0.7.6(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@types/react@19.1.13)(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(redux@4.2.1)(typescript@5.9.2)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
transitivePeerDependencies:
@@ -17450,16 +17464,16 @@ snapshots:
- utf-8-validate
- webpack-cli
docusaurus-theme-openapi@0.7.6(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@types/react@19.1.12)(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(redux@4.2.1)(typescript@5.9.2):
docusaurus-theme-openapi@0.7.6(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(@types/react@19.1.13)(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(redux@4.2.1)(typescript@5.9.2):
dependencies:
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mdx-js/react': 3.1.0(@types/react@19.1.12)(react@18.3.1)
'@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2))(acorn@8.15.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mdx-js/react': 3.1.0(@types/react@19.1.13)(react@18.3.1)
'@monaco-editor/react': 4.7.0(monaco-editor@0.31.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@reduxjs/toolkit': 1.9.7(react-redux@7.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
buffer: 6.0.3
clsx: 1.2.1
crypto-js: 4.2.0
docusaurus-plugin-openapi: 0.7.6(@mdx-js/react@3.1.0(@types/react@19.1.12)(react@18.3.1))(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
docusaurus-plugin-openapi: 0.7.6(@mdx-js/react@3.1.0(@types/react@19.1.13)(react@18.3.1))(acorn@8.15.0)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.2)
immer: 9.0.21
lodash: 4.17.21
marked: 11.2.0
@@ -22619,7 +22633,7 @@ snapshots:
simple-concat: 1.0.1
optional: true
simple-icons@15.14.0: {}
simple-icons@15.15.0: {}
simple-swizzle@0.2.2:
dependencies:

View File

@@ -1,8 +1,9 @@
#!/usr/bin/env sh
echo "Build dependencies for Immich Web"
cd /usr/src/app || exit
pnpm --filter @immich/sdk build
COUNT=0
UPSTREAM="${IMMICH_SERVER_URL:-http://immich-server:2283/}"
UPSTREAM="${UPSTREAM%/}"
@@ -14,5 +15,4 @@ until wget --spider --quiet "${UPSTREAM}/api/server/config" > /dev/null 2>&1; do
sleep 1
done
echo "Connected to $UPSTREAM, starting Immich Web..."
pnpm --filter @immich/sdk build
pnpm --filter immich-web exec vite dev --host 0.0.0.0 --port 3000

View File

@@ -9,7 +9,7 @@
"build:stats": "BUILD_STATS=true vite build",
"package": "svelte-kit package",
"preview": "vite preview",
"check:svelte": "svelte-check --no-tsconfig --fail-on-warnings --compiler-warnings 'reactive_declaration_non_reactive_property:ignore' --ignore src/lib/components/photos-page/asset-grid.svelte",
"check:svelte": "svelte-check --no-tsconfig --fail-on-warnings --compiler-warnings 'reactive_declaration_non_reactive_property:ignore' --ignore src/lib/components/timeline/Timeline.svelte",
"check:typescript": "tsc --noEmit",
"check:watch": "npm run check:svelte -- --watch",
"check:code": "npm run format && npm run lint:p && npm run check:svelte && npm run check:typescript",
@@ -28,7 +28,7 @@
"dependencies": {
"@formatjs/icu-messageformat-parser": "^2.9.8",
"@immich/sdk": "file:../open-api/typescript-sdk",
"@immich/ui": "^0.27.1",
"@immich/ui": "^0.27.2",
"@mapbox/mapbox-gl-rtl-text": "0.2.3",
"@mdi/js": "^7.4.47",
"@photo-sphere-viewer/core": "^5.11.5",

View File

@@ -2,8 +2,10 @@
import { shortcut } from '$lib/actions/shortcut';
import CastButton from '$lib/cast/cast-button.svelte';
import AlbumMap from '$lib/components/album-page/album-map.svelte';
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
@@ -17,8 +19,6 @@
import { mdiDownload, mdiFileImagePlusOutline } from '@mdi/js';
import { onDestroy } from 'svelte';
import { t } from 'svelte-i18n';
import DownloadAction from '../photos-page/actions/download-action.svelte';
import AssetGrid from '../photos-page/asset-grid.svelte';
import ControlAppBar from '../shared-components/control-app-bar.svelte';
import ImmichLogoSmallLink from '../shared-components/immich-logo-small-link.svelte';
import ThemeButton from '../shared-components/theme-button.svelte';
@@ -61,7 +61,7 @@
/>
<main class="relative h-dvh overflow-hidden px-2 md:px-6 max-md:pt-(--navbar-height-md) pt-(--navbar-height)">
<AssetGrid enableRouting={true} {album} {timelineManager} {assetInteraction}>
<Timeline enableRouting={true} {album} {timelineManager} {assetInteraction}>
<section class="pt-8 md:pt-24 px-2 md:px-0">
<!-- ALBUM TITLE -->
<h1
@@ -83,7 +83,7 @@
</p>
{/if}
</section>
</AssetGrid>
</Timeline>
</main>
<header>

View File

@@ -19,9 +19,12 @@
import ShareAction from '$lib/components/asset-viewer/actions/share-action.svelte';
import ShowDetailAction from '$lib/components/asset-viewer/actions/show-detail-action.svelte';
import UnstackAction from '$lib/components/asset-viewer/actions/unstack-action.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { AppRoute } from '$lib/constants';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { featureFlags } from '$lib/stores/server-config.store';
import { user } from '$lib/stores/user.store';
import { photoZoomState } from '$lib/stores/zoom-image.store';
@@ -41,6 +44,7 @@
import { IconButton } from '@immich/ui';
import {
mdiAlertOutline,
mdiCheckCircle,
mdiCogRefreshOutline,
mdiCompare,
mdiContentCopy,
@@ -59,12 +63,14 @@
interface Props {
asset: AssetResponseDto;
assetInteraction?: AssetInteraction | null;
album?: AlbumResponseDto | null;
person?: PersonResponseDto | null;
stack?: StackResponseDto | null;
showCloseButton?: boolean;
showDetailButton: boolean;
showSlideshow?: boolean;
onSelectAsset?: (asset: TimelineAsset) => void;
onZoomImage: () => void;
onCopyImage?: () => Promise<void>;
preAction: PreAction;
@@ -79,12 +85,14 @@
let {
asset,
assetInteraction,
album = null,
person = null,
stack = null,
showCloseButton = true,
showDetailButton,
showSlideshow = false,
onSelectAsset,
onZoomImage,
onCopyImage,
preAction,
@@ -102,6 +110,7 @@
let isLocked = $derived(asset.visibility === AssetVisibility.Locked);
let smartSearchEnabled = $derived($featureFlags.loaded && $featureFlags.smartSearch);
let selected = $derived(assetInteraction?.hasSelectedAsset(asset.id));
// $: showEditorButton =
// isOwner &&
// asset.type === AssetTypeEnum.Image &&
@@ -122,149 +131,182 @@
{/if}
</div>
<div class="flex gap-2 overflow-x-auto dark" data-testid="asset-viewer-navbar-actions">
<CastButton />
{#if !asset.isTrashed && $user && !isLocked}
<ShareAction {asset} />
{/if}
{#if asset.isOffline}
<IconButton
shape="round"
color="danger"
icon={mdiAlertOutline}
onclick={onShowDetail}
aria-label={$t('asset_offline')}
/>
{/if}
{#if asset.livePhotoVideoId}
{@render motionPhoto?.()}
{/if}
{#if asset.type === AssetTypeEnum.Image}
<IconButton
class="hidden sm:flex"
color="secondary"
variant="ghost"
shape="round"
icon={$photoZoomState && $photoZoomState.currentZoom > 1 ? mdiMagnifyMinusOutline : mdiMagnifyPlusOutline}
aria-label={$t('zoom_image')}
onclick={onZoomImage}
/>
{/if}
{#if canCopyImageToClipboard() && asset.type === AssetTypeEnum.Image}
<IconButton
color="secondary"
variant="ghost"
shape="round"
icon={mdiContentCopy}
aria-label={$t('copy_image')}
onclick={() => onCopyImage?.()}
/>
{/if}
{#if !isOwner && showDownloadButton}
<DownloadAction asset={toTimelineAsset(asset)} />
{/if}
{#if showDetailButton}
<ShowDetailAction {onShowDetail} />
{/if}
{#if isOwner}
<FavoriteAction {asset} {onAction} />
{/if}
{#if isOwner}
<DeleteAction {asset} {onAction} {preAction} />
<ButtonContextMenu direction="left" align="top-right" color="secondary" title={$t('more')} icon={mdiDotsVertical}>
{#if showSlideshow && !isLocked}
<MenuOption icon={mdiPresentationPlay} text={$t('slideshow')} onClick={onPlaySlideshow} />
{#if !!onSelectAsset && assetInteraction?.selectionActive}
<p class="text-lg text-immich-fg dark:text-immich-dark-fg">
{#if selected}
{$t('selected')}
{:else}
{$t('select')}
{/if}
{#if showDownloadButton}
<DownloadAction asset={toTimelineAsset(asset)} menuItem />
</p>
<button
type="button"
onclick={() => onSelectAsset(toTimelineAsset(asset))}
class={['focus:outline-none']}
role="checkbox"
tabindex={-1}
aria-checked={selected}
>
{#if selected}
<div class="rounded-full bg-[#D9DCEF] dark:bg-[#232932]">
<Icon path={mdiCheckCircle} size="24" class="text-primary" />
</div>
{:else}
<Icon path={mdiCheckCircle} size="24" class="text-white/80 hover:text-white" />
{/if}
</button>
{:else}
<CastButton />
{#if !isLocked}
{#if asset.isTrashed}
<RestoreAction {asset} {onAction} />
{:else}
<AddToAlbumAction {asset} {onAction} />
<AddToAlbumAction {asset} {onAction} shared />
{/if}
{/if}
{#if !asset.isTrashed && $user && !isLocked}
<ShareAction {asset} />
{/if}
{#if asset.isOffline}
<IconButton
shape="round"
color="danger"
icon={mdiAlertOutline}
onclick={onShowDetail}
aria-label={$t('asset_offline')}
/>
{/if}
{#if asset.livePhotoVideoId}
{@render motionPhoto?.()}
{/if}
{#if asset.type === AssetTypeEnum.Image}
<IconButton
class="hidden sm:flex"
color="secondary"
variant="ghost"
shape="round"
icon={$photoZoomState && $photoZoomState.currentZoom > 1 ? mdiMagnifyMinusOutline : mdiMagnifyPlusOutline}
aria-label={$t('zoom_image')}
onclick={onZoomImage}
/>
{/if}
{#if canCopyImageToClipboard() && asset.type === AssetTypeEnum.Image}
<IconButton
color="secondary"
variant="ghost"
shape="round"
icon={mdiContentCopy}
aria-label={$t('copy_image')}
onclick={() => onCopyImage?.()}
/>
{/if}
{#if isOwner}
{#if stack}
<UnstackAction {stack} {onAction} />
<KeepThisDeleteOthersAction {stack} {asset} {onAction} />
{#if stack?.primaryAssetId !== asset.id}
<SetStackPrimaryAsset {stack} {asset} {onAction} />
{#if stack?.assets?.length > 2}
<RemoveAssetFromStack {asset} {stack} {onAction} />
{/if}
{/if}
{#if !isOwner && showDownloadButton}
<DownloadAction asset={toTimelineAsset(asset)} />
{/if}
{#if showDetailButton}
<ShowDetailAction {onShowDetail} />
{/if}
{#if isOwner}
<FavoriteAction {asset} {onAction} />
{/if}
{#if isOwner}
<DeleteAction {asset} {onAction} {preAction} />
<ButtonContextMenu
direction="left"
align="top-right"
color="secondary"
title={$t('more')}
icon={mdiDotsVertical}
>
{#if showSlideshow && !isLocked}
<MenuOption icon={mdiPresentationPlay} text={$t('slideshow')} onClick={onPlaySlideshow} />
{/if}
{#if album}
<SetAlbumCoverAction {asset} {album} />
{/if}
{#if person}
<SetFeaturedPhotoAction {asset} {person} />
{/if}
{#if asset.type === AssetTypeEnum.Image && !isLocked}
<SetProfilePictureAction {asset} />
{#if showDownloadButton}
<DownloadAction asset={toTimelineAsset(asset)} menuItem />
{/if}
{#if !isLocked}
<ArchiveAction {asset} {onAction} {preAction} />
<MenuOption
icon={mdiUpload}
onClick={() => openFileUploadDialog({ multiple: false, assetId: asset.id })}
text={$t('replace_with_upload')}
/>
{#if !asset.isArchived && !asset.isTrashed}
<MenuOption
icon={mdiImageSearch}
onClick={() => goto(`${AppRoute.PHOTOS}?at=${stack?.primaryAssetId ?? asset.id}`)}
text={$t('view_in_timeline')}
/>
{/if}
{#if !asset.isArchived && !asset.isTrashed && smartSearchEnabled}
<MenuOption
icon={mdiCompare}
onClick={() => goto(`${AppRoute.SEARCH}?query={"queryAssetId":"${stack?.primaryAssetId ?? asset.id}"}`)}
text={$t('view_similar_photos')}
/>
{#if asset.isTrashed}
<RestoreAction {asset} {onAction} />
{:else}
<AddToAlbumAction {asset} {onAction} />
<AddToAlbumAction {asset} {onAction} shared />
{/if}
{/if}
{#if !asset.isTrashed}
<SetVisibilityAction asset={toTimelineAsset(asset)} {onAction} {preAction} />
{/if}
<hr />
<MenuOption
icon={mdiHeadSyncOutline}
onClick={() => onRunJob(AssetJobName.RefreshFaces)}
text={$getAssetJobName(AssetJobName.RefreshFaces)}
/>
<MenuOption
icon={mdiDatabaseRefreshOutline}
onClick={() => onRunJob(AssetJobName.RefreshMetadata)}
text={$getAssetJobName(AssetJobName.RefreshMetadata)}
/>
<MenuOption
icon={mdiImageRefreshOutline}
onClick={() => onRunJob(AssetJobName.RegenerateThumbnail)}
text={$getAssetJobName(AssetJobName.RegenerateThumbnail)}
/>
{#if asset.type === AssetTypeEnum.Video}
{#if isOwner}
{#if stack}
<UnstackAction {stack} {onAction} />
<KeepThisDeleteOthersAction {stack} {asset} {onAction} />
{#if stack?.primaryAssetId !== asset.id}
<SetStackPrimaryAsset {stack} {asset} {onAction} />
{#if stack?.assets?.length > 2}
<RemoveAssetFromStack {asset} {stack} {onAction} />
{/if}
{/if}
{/if}
{#if album}
<SetAlbumCoverAction {asset} {album} />
{/if}
{#if person}
<SetFeaturedPhotoAction {asset} {person} />
{/if}
{#if asset.type === AssetTypeEnum.Image && !isLocked}
<SetProfilePictureAction {asset} />
{/if}
{#if !isLocked}
<ArchiveAction {asset} {onAction} {preAction} />
<MenuOption
icon={mdiUpload}
onClick={() => openFileUploadDialog({ multiple: false, assetId: asset.id })}
text={$t('replace_with_upload')}
/>
{#if !asset.isArchived && !asset.isTrashed}
<MenuOption
icon={mdiImageSearch}
onClick={() => goto(`${AppRoute.PHOTOS}?at=${stack?.primaryAssetId ?? asset.id}`)}
text={$t('view_in_timeline')}
/>
{/if}
{#if !asset.isArchived && !asset.isTrashed && smartSearchEnabled}
<MenuOption
icon={mdiCompare}
onClick={() =>
goto(`${AppRoute.SEARCH}?query={"queryAssetId":"${stack?.primaryAssetId ?? asset.id}"}`)}
text={$t('view_similar_photos')}
/>
{/if}
{/if}
{#if !asset.isTrashed}
<SetVisibilityAction asset={toTimelineAsset(asset)} {onAction} {preAction} />
{/if}
<hr />
<MenuOption
icon={mdiCogRefreshOutline}
onClick={() => onRunJob(AssetJobName.TranscodeVideo)}
text={$getAssetJobName(AssetJobName.TranscodeVideo)}
icon={mdiHeadSyncOutline}
onClick={() => onRunJob(AssetJobName.RefreshFaces)}
text={$getAssetJobName(AssetJobName.RefreshFaces)}
/>
<MenuOption
icon={mdiDatabaseRefreshOutline}
onClick={() => onRunJob(AssetJobName.RefreshMetadata)}
text={$getAssetJobName(AssetJobName.RefreshMetadata)}
/>
<MenuOption
icon={mdiImageRefreshOutline}
onClick={() => onRunJob(AssetJobName.RegenerateThumbnail)}
text={$getAssetJobName(AssetJobName.RegenerateThumbnail)}
/>
{#if asset.type === AssetTypeEnum.Video}
<MenuOption
icon={mdiCogRefreshOutline}
onClick={() => onRunJob(AssetJobName.TranscodeVideo)}
text={$getAssetJobName(AssetJobName.TranscodeVideo)}
/>
{/if}
{/if}
{/if}
</ButtonContextMenu>
</ButtonContextMenu>
{/if}
{/if}
</div>
</div>

View File

@@ -10,6 +10,7 @@
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import { closeEditorCofirm } from '$lib/stores/asset-editor.store';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { isShowDetail } from '$lib/stores/preferences.store';
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
@@ -49,6 +50,7 @@
interface Props {
asset: AssetResponseDto;
assetInteraction?: AssetInteraction;
preloadAssets?: TimelineAsset[];
showNavigation?: boolean;
withStacked?: boolean;
@@ -58,6 +60,7 @@
preAction?: PreAction | undefined;
onAction?: OnAction | undefined;
showCloseButton?: boolean;
onSelectAsset?: (asset: TimelineAsset) => void;
onClose: (asset: AssetResponseDto) => void;
onNext: () => Promise<HasAsset>;
onPrevious: () => Promise<HasAsset>;
@@ -67,6 +70,7 @@
let {
asset = $bindable(),
assetInteraction,
preloadAssets = $bindable([]),
showNavigation = true,
withStacked = false,
@@ -76,6 +80,7 @@
preAction = undefined,
onAction = undefined,
showCloseButton,
onSelectAsset,
onClose,
onNext,
onPrevious,
@@ -391,12 +396,14 @@
<div class="col-span-4 col-start-1 row-span-1 row-start-1 transition-transform">
<AssetViewerNavBar
{asset}
{assetInteraction}
{album}
{person}
{stack}
{showCloseButton}
showDetailButton={enableDetailPanel}
showSlideshow={true}
{onSelectAsset}
onZoomImage={zoomToggle}
onCopyImage={copyImage}
preAction={handlePreAction}
@@ -529,7 +536,7 @@
</div>
{/if}
{#if enableDetailPanel && $slideshowState === SlideshowState.None && $isShowDetail && !isShowEditor}
{#if enableDetailPanel && $slideshowState === SlideshowState.None && $isShowDetail && !isShowEditor && !assetInteraction?.selectionActive}
<div
transition:fly={{ duration: 150 }}
id="detail-panel"

View File

@@ -11,6 +11,7 @@
mdiCameraBurst,
mdiCheckCircle,
mdiHeart,
mdiMagnifyPlusOutline,
mdiMotionPauseOutline,
mdiMotionPlayOutline,
mdiRotate360,
@@ -37,6 +38,7 @@
thumbnailHeight?: number;
selected?: boolean;
selectionCandidate?: boolean;
selectionActive?: boolean;
disabled?: boolean;
disableLinkMouseOver?: boolean;
readonly?: boolean;
@@ -45,7 +47,7 @@
imageClass?: ClassValue;
brokenAssetClass?: ClassValue;
dimmed?: boolean;
onClick?: (asset: TimelineAsset) => void;
onClick?: (asset: TimelineAsset, forceView?: boolean) => void;
onSelect?: (asset: TimelineAsset) => void;
onMouseEvent?: (event: { isMouseOver: boolean; selectedGroupIndex: number }) => void;
}
@@ -58,6 +60,7 @@
thumbnailHeight = undefined,
selected = false,
selectionCandidate = false,
selectionActive = false,
disabled = false,
disableLinkMouseOver = false,
readonly = false,
@@ -92,6 +95,12 @@
}
};
const onViewerIconClickedHandler = (e?: MouseEvent) => {
e?.stopPropagation();
e?.preventDefault();
onClick?.($state.snapshot(asset), true);
};
const callClickHandlers = () => {
if (selected) {
onIconClickedHandler();
@@ -344,6 +353,19 @@
</div>
{/if}
<!-- View Asset while selecting -->
{#if selectionActive && (usingMobileDevice || mouseOver)}
<button
type="button"
onclick={onViewerIconClickedHandler}
class={['absolute focus:outline-none bottom-2 end-2', { 'cursor-not-allowed': disabled }]}
tabindex={-1}
{disabled}
>
<Icon path={mdiMagnifyPlusOutline} size="24" class="text-white/80 hover:text-white" />
</button>
{/if}
{#if (!loaded || thumbError) && asset.thumbhash}
<canvas
use:thumbhash={{ base64ThumbHash: asset.thumbhash }}

View File

@@ -6,17 +6,6 @@
import { shortcuts } from '$lib/actions/shortcut';
import MemoryPhotoViewer from '$lib/components/memory-page/memory-photo-viewer.svelte';
import MemoryVideoViewer from '$lib/components/memory-page/memory-video-viewer.svelte';
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte';
import ChangeDate from '$lib/components/photos-page/actions/change-date-action.svelte';
import ChangeDescription from '$lib/components/photos-page/actions/change-description-action.svelte';
import ChangeLocation from '$lib/components/photos-page/actions/change-location-action.svelte';
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte';
import TagAction from '$lib/components/photos-page/actions/tag-action.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
@@ -25,6 +14,17 @@
notificationController,
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
import TagAction from '$lib/components/timeline/actions/TagAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { AppRoute, QueryParameter } from '$lib/constants';
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types';

View File

@@ -75,8 +75,9 @@
assets: TimelineAsset[],
groupTitle: string,
asset: TimelineAsset,
forceView: boolean = false,
) => {
if (isSelectionMode || assetInteraction.selectionActive) {
if (!forceView && (isSelectionMode || assetInteraction.selectionActive)) {
assetSelectHandler(timelineManager, asset, assets, groupTitle);
return;
}
@@ -218,11 +219,11 @@
{showArchiveIcon}
{asset}
{groupIndex}
onClick={(asset) => {
onClick={(asset, forceView: boolean = false) => {
if (typeof onThumbnailClick === 'function') {
onThumbnailClick(asset, timelineManager, dayGroup, _onClick);
} else {
_onClick(timelineManager, dayGroup.getAssets(), dayGroup.groupTitle, asset);
_onClick(timelineManager, dayGroup.getAssets(), dayGroup.groupTitle, asset, forceView);
}
}}
onSelect={(asset) => assetSelectHandler(timelineManager, asset, dayGroup.getAssets(), dayGroup.groupTitle)}
@@ -230,6 +231,7 @@
selected={assetInteraction.hasSelectedAsset(asset.id) ||
dayGroup.monthGroup.timelineManager.albumAssets.has(asset.id)}
selectionCandidate={assetInteraction.hasSelectionCandidate(asset.id)}
selectionActive={assetInteraction.selectionActive}
disabled={dayGroup.monthGroup.timelineManager.albumAssets.has(asset.id)}
thumbnailWidth={position.width}
thumbnailHeight={position.height}

View File

@@ -2,6 +2,9 @@
import { goto } from '$app/navigation';
import type { Action } from '$lib/components/asset-viewer/actions/action';
import ImmichLogoSmallLink from '$lib/components/shared-components/immich-logo-small-link.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import RemoveFromSharedLink from '$lib/components/timeline/actions/RemoveFromSharedLinkAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { AppRoute, AssetAction } from '$lib/constants';
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { Viewport } from '$lib/managers/timeline-manager/types';
@@ -17,9 +20,6 @@
import { mdiArrowLeft, mdiDownload, mdiFileImagePlusOutline, mdiSelectAll } from '@mdi/js';
import { t } from 'svelte-i18n';
import AssetViewer from '../asset-viewer/asset-viewer.svelte';
import DownloadAction from '../photos-page/actions/download-action.svelte';
import RemoveFromSharedLink from '../photos-page/actions/remove-from-shared-link.svelte';
import AssetSelectControlBar from '../photos-page/asset-select-control-bar.svelte';
import ControlAppBar from '../shared-components/control-app-bar.svelte';
import GalleryViewer from '../shared-components/gallery-viewer/gallery-viewer.svelte';
import { NotificationType, notificationController } from '../shared-components/notification/notification';

View File

@@ -494,8 +494,8 @@
>
<Thumbnail
readonly={disableAssetSelect}
onClick={() => {
if (assetInteraction.selectionActive) {
onClick={(asset, forceView: boolean = false) => {
if (assetInteraction.selectionActive && !forceView) {
handleSelectAssets(toTimelineAsset(currentAsset));
return;
}
@@ -507,6 +507,7 @@
asset={toTimelineAsset(currentAsset)}
selected={assetInteraction.hasSelectedAsset(currentAsset.id)}
selectionCandidate={assetInteraction.hasSelectionCandidate(currentAsset.id)}
selectionActive={assetInteraction.selectionActive}
thumbnailWidth={layout.width}
thumbnailHeight={layout.height}
/>
@@ -528,10 +529,12 @@
<Portal target="body">
<AssetViewer
asset={$viewingAsset}
{assetInteraction}
onAction={handleAction}
onPrevious={handlePrevious}
onNext={handleNext}
onRandom={handleRandom}
onSelectAsset={handleSelectAssets}
onClose={() => {
assetViewingStore.showAssetViewer(false);
handlePromiseError(navigate({ targetRoute: 'current', assetId: null }));

View File

@@ -4,13 +4,14 @@
import { resizeObserver, type OnResizeCallback } from '$lib/actions/resize-observer';
import { shortcuts, type ShortcutOptions } from '$lib/actions/shortcut';
import type { Action } from '$lib/components/asset-viewer/actions/action';
import Skeleton from '$lib/components/photos-page/skeleton.svelte';
import type { AbsoluteResult, RelativeResult } from '$lib/components/shared-components/change-date.svelte';
import ChangeDate from '$lib/components/shared-components/change-date.svelte';
import Scrubber from '$lib/components/shared-components/scrubber/scrubber.svelte';
import {
setFocusToAsset as setFocusAssetInit,
setFocusTo as setFocusToInit,
} from '$lib/components/photos-page/actions/focus-actions';
import Skeleton from '$lib/components/photos-page/skeleton.svelte';
import ChangeDate from '$lib/components/shared-components/change-date.svelte';
import Scrubber from '$lib/components/shared-components/scrubber/scrubber.svelte';
} from '$lib/components/timeline/actions/focus-actions';
import { AppRoute, AssetAction } from '$lib/constants';
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { DayGroup } from '$lib/managers/timeline-manager/day-group.svelte';
@@ -36,16 +37,16 @@
import { DateTime } from 'luxon';
import { onMount, type Snippet } from 'svelte';
import type { UpdatePayload } from 'vite';
import AssetDateGroup from '../photos-page/asset-date-group.svelte';
import DeleteAssetDialog from '../photos-page/delete-asset-dialog.svelte';
import Portal from '../shared-components/portal/portal.svelte';
import AssetDateGroup from './asset-date-group.svelte';
import DeleteAssetDialog from './delete-asset-dialog.svelte';
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 */
additionally, update the page location/url with the asset as the timeline is scrolled */
enableRouting: boolean;
timelineManager: TimelineManager;
assetInteraction: AssetInteraction;
@@ -224,14 +225,14 @@
const hmrSupport = () => {
// when hmr happens, skeleton is initialized to true by default
// normally, loading asset-grid is part of a navigation event, and the completion of
// normally, loading timeline is part of a navigation event, and the completion of
// that event triggers a scroll-to-asset, if necessary, when then clears the skeleton.
// this handler will run the navigation/scroll-to-asset handler when hmr is performed,
// preventing skeleton from showing after hmr
if (import.meta && import.meta.hot) {
const afterApdate = (payload: UpdatePayload) => {
const assetGridUpdate = payload.updates.some(
(update) => update.path.endsWith('asset-grid.svelte') || update.path.endsWith('assets-store.ts'),
(update) => update.path.endsWith('Timeline.svelte') || update.path.endsWith('assets-store.ts'),
);
if (assetGridUpdate) {
@@ -252,7 +253,7 @@
};
import.meta.hot?.on('vite:afterUpdate', afterApdate);
import.meta.hot?.on('vite:beforeUpdate', (payload) => {
const assetGridUpdate = payload.updates.some((update) => update.path.endsWith('asset-grid.svelte'));
const assetGridUpdate = payload.updates.some((update) => update.path.endsWith('Timeline.svelte'));
if (assetGridUpdate) {
timelineManager.destroy();
}
@@ -845,13 +846,15 @@
title="Navigate to Time"
initialDate={DateTime.now()}
timezoneInput={false}
onConfirm={async (dateString: string) => {
onConfirm={async (dateString: AbsoluteResult | RelativeResult) => {
isShowSelectDate = false;
const asset = await timelineManager.getClosestAssetToDate(
(DateTime.fromISO(dateString) as DateTime<true>).toObject(),
);
if (asset) {
setFocusAsset(asset);
if (dateString.mode == 'absolute') {
const asset = await timelineManager.getClosestAssetToDate(
(DateTime.fromISO(dateString.date) as DateTime<true>).toObject(),
);
if (asset) {
setFocusAsset(asset);
}
}
}}
onCancel={() => (isShowSelectDate = false)}
@@ -988,6 +991,8 @@
onNext={handleNext}
onRandom={handleRandom}
onClose={handleClose}
onSelectAsset={handleSelectAssets}
{assetInteraction}
/>
{/await}
{/if}

View File

@@ -1,12 +1,12 @@
<script lang="ts">
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import AlbumPickerModal from '$lib/modals/AlbumPickerModal.svelte';
import type { OnAddToAlbum } from '$lib/utils/actions';
import { addAssetsToAlbum, addAssetsToAlbums } from '$lib/utils/asset-utils';
import { modalManager } from '@immich/ui';
import { mdiImageAlbum, mdiShareVariantOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
interface Props {
shared?: boolean;

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import type { OnArchive } from '$lib/utils/actions';
import { archiveAssets } from '$lib/utils/asset-utils';
import { AssetVisibility } from '@immich/sdk';
@@ -6,7 +7,6 @@
import { mdiArchiveArrowDownOutline, mdiArchiveArrowUpOutline, mdiTimerSand } from '@mdi/js';
import { t } from 'svelte-i18n';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
interface Props {
onArchive?: OnArchive;

View File

@@ -4,11 +4,11 @@
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { getAssetJobIcon, getAssetJobMessage, getAssetJobName } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { AssetJobName, runAssetJobs } from '@immich/sdk';
import { t } from 'svelte-i18n';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
interface Props {
jobs?: AssetJobName[];

View File

@@ -3,16 +3,16 @@
type AbsoluteResult,
type RelativeResult,
} from '$lib/components/shared-components/change-date.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { user } from '$lib/stores/user.store';
import { getSelectedAssets } from '$lib/utils/asset-utils';
import { handleError } from '$lib/utils/handle-error';
import { fromTimelinePlainDateTime } from '$lib/utils/timeline-util.js';
import { updateAssets } from '@immich/sdk';
import { mdiCalendarEditOutline } from '@mdi/js';
import { DateTime, Duration } from 'luxon';
import { t } from 'svelte-i18n';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { fromTimelinePlainDateTime } from '$lib/utils/timeline-util.js';
interface Props {
menuItem?: boolean;
}

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import AssetUpdateDescriptionConfirmModal from '$lib/modals/AssetUpdateDescriptionConfirmModal.svelte';
import { user } from '$lib/stores/user.store';
import { getSelectedAssets } from '$lib/utils/asset-utils';
@@ -8,7 +9,6 @@
import { mdiText } from '@mdi/js';
import { t } from 'svelte-i18n';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
interface Props {
menuItem?: boolean;

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import ChangeLocation from '$lib/components/shared-components/change-location.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { user } from '$lib/stores/user.store';
import { getSelectedAssets } from '$lib/utils/asset-utils';
import { handleError } from '$lib/utils/handle-error';
@@ -7,7 +8,6 @@
import { mdiMapMarkerMultipleOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
interface Props {
menuItem?: boolean;

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/photos-page/asset-select-control-bar.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import QrCodeModal from '$lib/modals/QrCodeModal.svelte';
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
import { makeSharedLinkUrl } from '$lib/utils';

View File

@@ -1,12 +1,12 @@
<script lang="ts">
import DeleteAssetDialog from '$lib/components/photos-page/delete-asset-dialog.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { featureFlags } from '$lib/stores/server-config.store';
import { type OnDelete, type OnUndoDelete, deleteAssets } from '$lib/utils/actions';
import { IconButton } from '@immich/ui';
import { mdiDeleteForeverOutline, mdiDeleteOutline, mdiTimerSand } from '@mdi/js';
import { t } from 'svelte-i18n';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import DeleteAssetDialog from '../delete-asset-dialog.svelte';
import { IconButton } from '@immich/ui';
interface Props {
onAssetDelete: OnDelete;

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { shortcut } from '$lib/actions/shortcut';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { downloadArchive, downloadFile } from '$lib/utils/asset-utils';
import { getAssetInfo } from '@immich/sdk';
@@ -8,7 +9,6 @@
import { mdiDownload } from '@mdi/js';
import { t } from 'svelte-i18n';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
interface Props {
filename?: string;

View File

@@ -4,13 +4,13 @@
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import type { OnFavorite } from '$lib/utils/actions';
import { handleError } from '$lib/utils/handle-error';
import { updateAssets } from '@immich/sdk';
import { IconButton } from '@immich/ui';
import { mdiHeartMinusOutline, mdiHeartOutline, mdiTimerSand } from '@mdi/js';
import { t } from 'svelte-i18n';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { IconButton } from '@immich/ui';
interface Props {
onFavorite?: OnFavorite;

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/photos-page/asset-select-control-bar.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
import type { OnLink, OnUnlink } from '$lib/utils/actions';

View File

@@ -3,12 +3,12 @@
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { getAlbumInfo, removeAssetFromAlbum, type AlbumResponseDto } from '@immich/sdk';
import { IconButton, modalManager } from '@immich/ui';
import { mdiDeleteOutline, mdiImageRemoveOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
interface Props {
album: AlbumResponseDto;

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { handleError } from '$lib/utils/handle-error';
import { removeSharedLinkAssets, type SharedLinkResponseDto } from '@immich/sdk';
@@ -6,7 +7,6 @@
import { mdiDeleteOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
import { NotificationType, notificationController } from '../../shared-components/notification/notification';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
interface Props {
sharedLink: SharedLinkResponseDto;

View File

@@ -3,13 +3,13 @@
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import type { OnRestore } from '$lib/utils/actions';
import { handleError } from '$lib/utils/handle-error';
import { restoreAssets } from '@immich/sdk';
import { mdiHistory } from '@mdi/js';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
import { t } from 'svelte-i18n';
import { Button } from '@immich/ui';
import { mdiHistory } from '@mdi/js';
import { t } from 'svelte-i18n';
interface Props {
onRestore: OnRestore | undefined;

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/photos-page/asset-select-control-bar.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import type { OnSetVisibility } from '$lib/utils/actions';
import { handleError } from '$lib/utils/handle-error';

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { getAssetControlContext } from '$lib/components/photos-page/asset-select-control-bar.svelte';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import type { OnStack, OnUnstack } from '$lib/utils/actions';
import { deleteStack, stackAssets } from '$lib/utils/asset-utils';

View File

@@ -1,11 +1,11 @@
<script lang="ts">
import { shortcut } from '$lib/actions/shortcut';
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
import AssetTagModal from '$lib/modals/AssetTagModal.svelte';
import { IconButton, modalManager } from '@immich/ui';
import { mdiTagMultipleOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
import MenuOption from '../../shared-components/context-menu/menu-option.svelte';
import { getAssetControlContext } from '../asset-select-control-bar.svelte';
interface Props {
menuItem?: boolean;

View File

@@ -9,21 +9,6 @@
import ActivityStatus from '$lib/components/asset-viewer/activity-status.svelte';
import ActivityViewer from '$lib/components/asset-viewer/activity-viewer.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte';
import ChangeDate from '$lib/components/photos-page/actions/change-date-action.svelte';
import ChangeDescription from '$lib/components/photos-page/actions/change-description-action.svelte';
import ChangeLocation from '$lib/components/photos-page/actions/change-location-action.svelte';
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte';
import RemoveFromAlbum from '$lib/components/photos-page/actions/remove-from-album.svelte';
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
import SetVisibilityAction from '$lib/components/photos-page/actions/set-visibility-action.svelte';
import TagAction from '$lib/components/photos-page/actions/tag-action.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
@@ -32,6 +17,21 @@
notificationController,
} from '$lib/components/shared-components/notification/notification';
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
import RemoveFromAlbum from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte';
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
import TagAction from '$lib/components/timeline/actions/TagAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import { AlbumPageViewMode, AppRoute } from '$lib/constants';
import { activityManager } from '$lib/managers/activity-manager.svelte';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
@@ -443,7 +443,7 @@
<div class="flex overflow-hidden" use:scrollMemoryClearer={{ routeStartsWith: AppRoute.ALBUMS }}>
<div class="relative w-full shrink">
<main class="relative h-dvh overflow-hidden px-2 md:px-6 max-md:pt-(--navbar-height-md) pt-(--navbar-height)">
<AssetGrid
<Timeline
enableRouting={viewMode === AlbumPageViewMode.SELECT_ASSETS ? false : true}
{album}
{timelineManager}
@@ -544,7 +544,7 @@
</section>
{/if}
{/if}
</AssetGrid>
</Timeline>
{#if showActivityStatus && !activityManager.isLoading}
<div class="absolute z-2 bottom-0 end-0 mb-6 me-6 justify-self-end">

View File

@@ -1,19 +1,19 @@
<script lang="ts">
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte';
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte';
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import { AssetAction } from '$lib/constants';
import SetVisibilityAction from '$lib/components/photos-page/actions/set-visibility-action.svelte';
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetVisibility } from '@immich/sdk';
@@ -47,7 +47,7 @@
</script>
<UserPageLayout hideNavbar={assetInteraction.selectionActive} title={data.meta.title} scrollbar={false}>
<AssetGrid
<Timeline
enableRouting={true}
{timelineManager}
{assetInteraction}
@@ -57,7 +57,7 @@
{#snippet empty()}
<EmptyPlaceholder text={$t('no_archived_assets_message')} />
{/snippet}
</AssetGrid>
</Timeline>
</UserPageLayout>
{#if assetInteraction.selectionActive}

View File

@@ -1,21 +1,21 @@
<script lang="ts">
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte';
import ChangeDate from '$lib/components/photos-page/actions/change-date-action.svelte';
import ChangeDescription from '$lib/components/photos-page/actions/change-description-action.svelte';
import ChangeLocation from '$lib/components/photos-page/actions/change-location-action.svelte';
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte';
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
import SetVisibilityAction from '$lib/components/photos-page/actions/set-visibility-action.svelte';
import TagAction from '$lib/components/photos-page/actions/tag-action.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
import TagAction from '$lib/components/timeline/actions/TagAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import { AssetAction } from '$lib/constants';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
@@ -51,7 +51,7 @@
</script>
<UserPageLayout hideNavbar={assetInteraction.selectionActive} title={data.meta.title} scrollbar={false}>
<AssetGrid
<Timeline
enableRouting={true}
withStacked={true}
{timelineManager}
@@ -62,7 +62,7 @@
{#snippet empty()}
<EmptyPlaceholder text={$t('no_favorites_message')} />
{/snippet}
</AssetGrid>
</Timeline>
</UserPageLayout>
<!-- Multiselection mode app bar -->

View File

@@ -2,24 +2,24 @@
import { afterNavigate, goto, invalidateAll } from '$app/navigation';
import SkipLink from '$lib/components/elements/buttons/skip-link.svelte';
import UserPageLayout, { headerId } from '$lib/components/layouts/user-page-layout.svelte';
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte';
import AssetJobActions from '$lib/components/photos-page/actions/asset-job-actions.svelte';
import ChangeDate from '$lib/components/photos-page/actions/change-date-action.svelte';
import ChangeDescription from '$lib/components/photos-page/actions/change-description-action.svelte';
import ChangeLocation from '$lib/components/photos-page/actions/change-location-action.svelte';
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte';
import TagAction from '$lib/components/photos-page/actions/tag-action.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
import Breadcrumbs from '$lib/components/shared-components/tree/breadcrumbs.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 Sidebar from '$lib/components/sidebar/sidebar.svelte';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import AssetJobActions from '$lib/components/timeline/actions/AssetJobActions.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
import TagAction from '$lib/components/timeline/actions/TagAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { AppRoute, QueryParameter } from '$lib/constants';
import type { Viewport } from '$lib/managers/timeline-manager/types';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';

View File

@@ -1,16 +1,16 @@
<script lang="ts">
import { goto } from '$app/navigation';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import ChangeDate from '$lib/components/photos-page/actions/change-date-action.svelte';
import ChangeLocation from '$lib/components/photos-page/actions/change-location-action.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
import SetVisibilityAction from '$lib/components/photos-page/actions/set-visibility-action.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import { AppRoute, AssetAction } from '$lib/constants';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
@@ -58,7 +58,7 @@
</Button>
{/snippet}
<AssetGrid
<Timeline
enableRouting={true}
{timelineManager}
{assetInteraction}
@@ -68,7 +68,7 @@
{#snippet empty()}
<EmptyPlaceholder text={$t('no_locked_photos_message')} title={$t('nothing_here_yet')} />
{/snippet}
</AssetGrid>
</Timeline>
</UserPageLayout>
<!-- Multi-selection mode app bar -->

View File

@@ -1,12 +1,12 @@
<script lang="ts">
import { goto } from '$app/navigation';
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte';
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import { AppRoute } from '$lib/constants';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
@@ -43,7 +43,7 @@
</script>
<main class="relative h-dvh overflow-hidden px-2 md:px-6 max-md:pt-(--navbar-height-md) pt-(--navbar-height)">
<AssetGrid enableRouting={true} {timelineManager} {assetInteraction} onEscape={handleEscape} />
<Timeline enableRouting={true} {timelineManager} {assetInteraction} onEscape={handleEscape} />
</main>
{#if assetInteraction.selectionActive}

View File

@@ -8,20 +8,6 @@
import EditNameInput from '$lib/components/faces-page/edit-name-input.svelte';
import MergeFaceSelector from '$lib/components/faces-page/merge-face-selector.svelte';
import UnMergeFaceSelector from '$lib/components/faces-page/unmerge-face-selector.svelte';
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte';
import ChangeDate from '$lib/components/photos-page/actions/change-date-action.svelte';
import ChangeDescription from '$lib/components/photos-page/actions/change-description-action.svelte';
import ChangeLocation from '$lib/components/photos-page/actions/change-location-action.svelte';
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte';
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
import SetVisibilityAction from '$lib/components/photos-page/actions/set-visibility-action.svelte';
import TagAction from '$lib/components/photos-page/actions/tag-action.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
@@ -30,6 +16,20 @@
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
import TagAction from '$lib/components/timeline/actions/TagAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import { AppRoute, PersonPageViewMode, QueryParameter, SessionStorageKey } from '$lib/constants';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
@@ -386,7 +386,7 @@
}}
>
{#key person.id}
<AssetGrid
<Timeline
enableRouting={true}
{person}
{timelineManager}
@@ -498,7 +498,7 @@
{/if}
</div>
{/if}
</AssetGrid>
</Timeline>
{/key}
</main>

View File

@@ -1,26 +1,26 @@
<script lang="ts">
import { beforeNavigate } from '$app/navigation';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte';
import AssetJobActions from '$lib/components/photos-page/actions/asset-job-actions.svelte';
import ChangeDate from '$lib/components/photos-page/actions/change-date-action.svelte';
import ChangeDescription from '$lib/components/photos-page/actions/change-description-action.svelte';
import ChangeLocation from '$lib/components/photos-page/actions/change-location-action.svelte';
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte';
import LinkLivePhotoAction from '$lib/components/photos-page/actions/link-live-photo-action.svelte';
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
import SetVisibilityAction from '$lib/components/photos-page/actions/set-visibility-action.svelte';
import StackAction from '$lib/components/photos-page/actions/stack-action.svelte';
import TagAction from '$lib/components/photos-page/actions/tag-action.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import MemoryLane from '$lib/components/photos-page/memory-lane.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import AssetJobActions from '$lib/components/timeline/actions/AssetJobActions.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
import LinkLivePhotoAction from '$lib/components/timeline/actions/LinkLivePhotoAction.svelte';
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
import StackAction from '$lib/components/timeline/actions/StackAction.svelte';
import TagAction from '$lib/components/timeline/actions/TagAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import { AssetAction } from '$lib/constants';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
@@ -89,7 +89,7 @@
</script>
<UserPageLayout hideNavbar={assetInteraction.selectionActive} showUploadButton scrollbar={false}>
<AssetGrid
<Timeline
enableRouting={true}
{timelineManager}
{assetInteraction}
@@ -103,7 +103,7 @@
{#snippet empty()}
<EmptyPlaceholder text={$t('no_assets_message')} onClick={() => openFileUploadDialog()} />
{/snippet}
</AssetGrid>
</Timeline>
</UserPageLayout>
{#if assetInteraction.selectionActive}

View File

@@ -4,24 +4,24 @@
import { shortcut } from '$lib/actions/shortcut';
import AlbumCardGroup from '$lib/components/album-page/album-card-group.svelte';
import Icon from '$lib/components/elements/icon.svelte';
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte';
import AssetJobActions from '$lib/components/photos-page/actions/asset-job-actions.svelte';
import ChangeDate from '$lib/components/photos-page/actions/change-date-action.svelte';
import ChangeDescription from '$lib/components/photos-page/actions/change-description-action.svelte';
import ChangeLocation from '$lib/components/photos-page/actions/change-location-action.svelte';
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte';
import SetVisibilityAction from '$lib/components/photos-page/actions/set-visibility-action.svelte';
import TagAction from '$lib/components/photos-page/actions/tag-action.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import AssetJobActions from '$lib/components/timeline/actions/AssetJobActions.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
import ChangeDescription from '$lib/components/timeline/actions/ChangeDescriptionAction.svelte';
import ChangeLocation from '$lib/components/timeline/actions/ChangeLocationAction.svelte';
import CreateSharedLink from '$lib/components/timeline/actions/CreateSharedLinkAction.svelte';
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
import DownloadAction from '$lib/components/timeline/actions/DownloadAction.svelte';
import FavoriteAction from '$lib/components/timeline/actions/FavoriteAction.svelte';
import SetVisibilityAction from '$lib/components/timeline/actions/SetVisibilityAction.svelte';
import TagAction from '$lib/components/timeline/actions/TagAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import { AppRoute, QueryParameter } from '$lib/constants';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types';

View File

@@ -2,11 +2,11 @@
import { goto } from '$app/navigation';
import SkipLink from '$lib/components/elements/buttons/skip-link.svelte';
import UserPageLayout, { headerId } from '$lib/components/layouts/user-page-layout.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import Breadcrumbs from '$lib/components/shared-components/tree/breadcrumbs.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 Sidebar from '$lib/components/sidebar/sidebar.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import { AppRoute, AssetAction, QueryParameter } from '$lib/constants';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import TagCreateModal from '$lib/modals/TagCreateModal.svelte';
@@ -117,11 +117,11 @@
<section class="mt-2 h-[calc(100%-(--spacing(20)))] overflow-auto immich-scrollbar">
{#if tag.hasAssets}
<AssetGrid enableRouting={true} {timelineManager} {assetInteraction} removeAction={AssetAction.UNARCHIVE}>
<Timeline enableRouting={true} {timelineManager} {assetInteraction} removeAction={AssetAction.UNARCHIVE}>
{#snippet empty()}
<TreeItemThumbnails items={tag.children} icon={mdiTag} onClick={handleNavigation} />
{/snippet}
</AssetGrid>
</Timeline>
{:else}
<TreeItemThumbnails items={tag.children} icon={mdiTag} onClick={handleNavigation} />
{/if}

View File

@@ -2,16 +2,16 @@
import { goto } from '$app/navigation';
import empty3Url from '$lib/assets/empty-3.svg';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
import RestoreAssets from '$lib/components/photos-page/actions/restore-assets.svelte';
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import {
notificationController,
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
import RestoreAssets from '$lib/components/timeline/actions/RestoreAction.svelte';
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import { AppRoute } from '$lib/constants';
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
@@ -116,14 +116,14 @@
</HStack>
{/snippet}
<AssetGrid enableRouting={true} {timelineManager} {assetInteraction} onEscape={handleEscape}>
<Timeline enableRouting={true} {timelineManager} {assetInteraction} onEscape={handleEscape}>
<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>
{#snippet empty()}
<EmptyPlaceholder text={$t('trash_no_results_message')} src={empty3Url} />
{/snippet}
</AssetGrid>
</Timeline>
</UserPageLayout>
{/if}

View File

@@ -1,8 +1,8 @@
<script lang="ts">
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import ChangeLocation from '$lib/components/shared-components/change-location.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import Timeline from '$lib/components/timeline/Timeline.svelte';
import { AssetAction } from '$lib/constants';
import { authManager } from '$lib/managers/auth-manager.svelte';
import type { DayGroup } from '$lib/managers/timeline-manager/day-group.svelte';
@@ -185,7 +185,7 @@
</div>
{/if}
<AssetGrid
<Timeline
isSelectionMode={true}
enableRouting={true}
{timelineManager}
@@ -209,5 +209,5 @@
{#snippet empty()}
<EmptyPlaceholder text={$t('no_assets_message')} onClick={() => {}} />
{/snippet}
</AssetGrid>
</Timeline>
</UserPageLayout>