mirror of
https://github.com/immich-app/immich.git
synced 2025-12-28 17:24:56 +03:00
feat: Added shortcuts, shift-multi select and missing menu options to Search (Galleryviewer) (#14213)
feat: Added shortcuts, shift-multi select and missing menu options to GalleryViewer (Search, Share, Memories) Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { page } from '$app/stores';
|
||||
import UserPageLayout, { headerId } from '$lib/components/layouts/user-page-layout.svelte';
|
||||
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
|
||||
import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
||||
import SideBarSection from '$lib/components/shared-components/side-bar/side-bar-section.svelte';
|
||||
import TreeItemThumbnails from '$lib/components/shared-components/tree/tree-item-thumbnails.svelte';
|
||||
import TreeItems from '$lib/components/shared-components/tree/tree-items.svelte';
|
||||
@@ -10,7 +11,6 @@
|
||||
import type { Viewport } from '$lib/stores/assets.store';
|
||||
import { foldersStore } from '$lib/stores/folders.store';
|
||||
import { buildTree, normalizeTreePath } from '$lib/utils/tree-utils';
|
||||
import { type AssetResponseDto } from '@immich/sdk';
|
||||
import { mdiFolder, mdiFolderHome, mdiFolderOutline } from '@mdi/js';
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
let { data }: Props = $props();
|
||||
|
||||
let selectedAssets: Set<AssetResponseDto> = $state(new Set());
|
||||
const viewport: Viewport = $state({ width: 0, height: 0 });
|
||||
|
||||
let pathSegments = $derived(data.path ? data.path.split('/') : []);
|
||||
@@ -32,6 +31,8 @@
|
||||
let currentPath = $derived($page.url.searchParams.get(QueryParameter.PATH) || '');
|
||||
let currentTreeItems = $derived(currentPath ? data.currentFolders : Object.keys(tree));
|
||||
|
||||
const assetInteractionStore = createAssetInteractionStore();
|
||||
|
||||
onMount(async () => {
|
||||
await foldersStore.fetchUniquePaths();
|
||||
});
|
||||
@@ -79,7 +80,7 @@
|
||||
<div bind:clientHeight={viewport.height} bind:clientWidth={viewport.width} class="mt-2">
|
||||
<GalleryViewer
|
||||
assets={data.pathAssets}
|
||||
bind:selectedAssets
|
||||
{assetInteractionStore}
|
||||
{viewport}
|
||||
disableAssetSelect={true}
|
||||
showAssetName={true}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.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 { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||
import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
||||
import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte';
|
||||
import { AppRoute, QueryParameter } from '$lib/constants';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
@@ -58,13 +60,15 @@
|
||||
let isLoading = $state(true);
|
||||
let scrollY = $state(0);
|
||||
let scrollYHistory = 0;
|
||||
let selectedAssets: Set<AssetResponseDto> = $state(new Set());
|
||||
|
||||
const assetInteractionStore = createAssetInteractionStore();
|
||||
const { selectedAssets } = assetInteractionStore;
|
||||
|
||||
type SearchTerms = MetadataSearchDto & Pick<SmartSearchDto, 'query'>;
|
||||
|
||||
let isMultiSelectionMode = $derived(selectedAssets.size > 0);
|
||||
let isAllArchived = $derived([...selectedAssets].every((asset) => asset.isArchived));
|
||||
let isAllFavorite = $derived([...selectedAssets].every((asset) => asset.isFavorite));
|
||||
let isMultiSelectionMode = $derived($selectedAssets.size > 0);
|
||||
let isAllArchived = $derived([...$selectedAssets].every((asset) => asset.isArchived));
|
||||
let isAllFavorite = $derived([...$selectedAssets].every((asset) => asset.isFavorite));
|
||||
let searchQuery = $derived($page.url.searchParams.get(QueryParameter.QUERY));
|
||||
|
||||
onMount(() => {
|
||||
@@ -81,7 +85,7 @@
|
||||
}
|
||||
|
||||
if (isMultiSelectionMode) {
|
||||
selectedAssets = new Set();
|
||||
$selectedAssets = new Set();
|
||||
return;
|
||||
}
|
||||
if (!$preventRaceConditionSearchBar) {
|
||||
@@ -125,7 +129,7 @@
|
||||
searchResultAssets = searchResultAssets.filter((a: AssetResponseDto) => !assetIdSet.has(a.id));
|
||||
};
|
||||
const handleSelectAll = () => {
|
||||
selectedAssets = new Set(searchResultAssets);
|
||||
assetInteractionStore.selectAssets(searchResultAssets);
|
||||
};
|
||||
|
||||
async function onSearchQueryUpdate() {
|
||||
@@ -216,8 +220,10 @@
|
||||
const triggerAssetUpdate = () => (searchResultAssets = searchResultAssets);
|
||||
|
||||
const onAddToAlbum = (assetIds: string[]) => {
|
||||
const assetIdSet = new Set(assetIds);
|
||||
searchResultAssets = searchResultAssets.filter((a: AssetResponseDto) => !assetIdSet.has(a.id));
|
||||
if (terms.isNotInAlbum.toString() == 'true') {
|
||||
const assetIdSet = new Set(assetIds);
|
||||
searchResultAssets = searchResultAssets.filter((a: AssetResponseDto) => !assetIdSet.has(a.id));
|
||||
}
|
||||
};
|
||||
|
||||
function getObjectKeys<T extends object>(obj: T): (keyof T)[] {
|
||||
@@ -230,7 +236,7 @@
|
||||
<section>
|
||||
{#if isMultiSelectionMode}
|
||||
<div class="fixed z-[100] top-0 left-0 w-full">
|
||||
<AssetSelectControlBar assets={selectedAssets} clearSelect={() => (selectedAssets = new Set())}>
|
||||
<AssetSelectControlBar assets={$selectedAssets} clearSelect={() => cancelMultiselect(assetInteractionStore)}>
|
||||
<CreateSharedLink />
|
||||
<CircleIconButton title={$t('select_all')} icon={mdiSelectAll} onclick={handleSelectAll} />
|
||||
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
|
||||
@@ -321,7 +327,7 @@
|
||||
{#if searchResultAssets.length > 0}
|
||||
<GalleryViewer
|
||||
assets={searchResultAssets}
|
||||
bind:selectedAssets
|
||||
{assetInteractionStore}
|
||||
onIntersected={loadNextPage}
|
||||
showArchiveIcon={true}
|
||||
{viewport}
|
||||
|
||||
Reference in New Issue
Block a user