Skip to content

Commit

Permalink
feat(web): search improvements and refactor (#7291)
Browse files Browse the repository at this point in the history
  • Loading branch information
michelheusschen committed Feb 21, 2024
1 parent 06c1349 commit d3e14fd
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 211 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,18 @@
import { AppRoute } from '$lib/constants';
import Icon from '$lib/components/elements/icon.svelte';
import { goto } from '$app/navigation';
import {
isSearchEnabled,
preventRaceConditionSearchBar,
savedSearchTerms,
searchQuery,
} from '$lib/stores/search.store';
import { isSearchEnabled, preventRaceConditionSearchBar, savedSearchTerms } from '$lib/stores/search.store';
import { clickOutside } from '$lib/utils/click-outside';
import { mdiClose, mdiMagnify, mdiTune } from '@mdi/js';
import IconButton from '$lib/components/elements/buttons/icon-button.svelte';
import SearchHistoryBox from './search-history-box.svelte';
import SearchFilterBox from './search-filter-box.svelte';
import type { MetadataSearchDto, SmartSearchDto } from '@immich/sdk';
import { getMetadataSearchQuery } from '$lib/utils/metadata-search';
export let value = '';
export let grayTheme: boolean;
export let searchQuery: MetadataSearchDto | SmartSearchDto = {};
let input: HTMLInputElement;
Expand All @@ -30,8 +27,7 @@
showHistory = false;
showFilter = false;
$isSearchEnabled = false;
$searchQuery = payload;
goto(`${AppRoute.SEARCH}?${params}`, { invalidateAll: true });
goto(`${AppRoute.SEARCH}?${params}`);
};
const clearSearchTerm = (searchTerm: string) => {
Expand Down Expand Up @@ -87,11 +83,11 @@
};
</script>

<div role="button" class="w-full" use:clickOutside on:outclick={onFocusOut} on:escape={onFocusOut}>
<div class="w-full relative" use:clickOutside on:outclick={onFocusOut} on:escape={onFocusOut}>
<form
draggable="false"
autocomplete="off"
class="relative select-text text-sm"
class="select-text text-sm"
action={AppRoute.SEARCH}
on:reset={() => (value = '')}
on:submit|preventDefault={onSubmit}
Expand Down Expand Up @@ -148,9 +144,9 @@
on:selectSearchTerm={({ detail: searchTerm }) => onHistoryTermClick(searchTerm)}
/>
{/if}

{#if showFilter}
<SearchFilterBox on:search={({ detail }) => onSearch(detail)} />
{/if}
</form>

{#if showFilter}
<SearchFilterBox {searchQuery} on:search={({ detail }) => onSearch(detail)} />
{/if}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import { fly } from 'svelte/transition';
import Combobox, { type ComboBoxOption } from '../combobox.svelte';
import { DateTime } from 'luxon';
import { searchQuery } from '$lib/stores/search.store';
enum MediaType {
All = 'all',
Expand All @@ -44,7 +43,7 @@
type SearchFilter = {
context?: string;
people: PersonResponseDto[];
people: (PersonResponseDto | Pick<PersonResponseDto, 'id'>)[];
location: {
country?: ComboBoxOption;
Expand All @@ -69,6 +68,8 @@
mediaType: MediaType;
};
export let searchQuery: MetadataSearchDto | SmartSearchDto;
let suggestions: SearchSuggestion = {
people: [],
country: [],
Expand Down Expand Up @@ -112,19 +113,19 @@
populateExistingFilters();
});
const showSelectedPeopleFirst = () => {
suggestions.people.sort((a, _) => {
function orderBySelectedPeopleFirst<T extends Pick<PersonResponseDto, 'id'>>(people: T[]) {
return people.sort((a, _) => {
if (filter.people.some((p) => p.id === a.id)) {
return -1;
}
return 1;
});
};
}
const getPeople = async () => {
try {
const { people } = await getAllPeople({ withHidden: false });
suggestions.people = people;
suggestions.people = orderBySelectedPeopleFirst(people);
} catch (error) {
handleError(error, 'Failed to get people');
}
Expand All @@ -133,14 +134,12 @@
const handlePeopleSelection = (id: string) => {
if (filter.people.some((p) => p.id === id)) {
filter.people = filter.people.filter((p) => p.id !== id);
showSelectedPeopleFirst();
return;
}
const person = suggestions.people.find((p) => p.id === id);
if (person) {
filter.people = [...filter.people, person];
showSelectedPeopleFirst();
}
};
Expand Down Expand Up @@ -280,35 +279,36 @@
};
function populateExistingFilters() {
if ($searchQuery) {
if (searchQuery) {
const personIds = 'personIds' in searchQuery && searchQuery.personIds ? searchQuery.personIds : [];
filter = {
context: 'query' in $searchQuery ? $searchQuery.query : '',
people:
'personIds' in $searchQuery ? ($searchQuery.personIds?.map((id) => ({ id })) as PersonResponseDto[]) : [],
context: 'query' in searchQuery ? searchQuery.query : '',
people: orderBySelectedPeopleFirst(personIds.map((id) => ({ id }))),
location: {
country: $searchQuery.country ? { label: $searchQuery.country, value: $searchQuery.country } : undefined,
state: $searchQuery.state ? { label: $searchQuery.state, value: $searchQuery.state } : undefined,
city: $searchQuery.city ? { label: $searchQuery.city, value: $searchQuery.city } : undefined,
country: searchQuery.country ? { label: searchQuery.country, value: searchQuery.country } : undefined,
state: searchQuery.state ? { label: searchQuery.state, value: searchQuery.state } : undefined,
city: searchQuery.city ? { label: searchQuery.city, value: searchQuery.city } : undefined,
},
camera: {
make: $searchQuery.make ? { label: $searchQuery.make, value: $searchQuery.make } : undefined,
model: $searchQuery.model ? { label: $searchQuery.model, value: $searchQuery.model } : undefined,
make: searchQuery.make ? { label: searchQuery.make, value: searchQuery.make } : undefined,
model: searchQuery.model ? { label: searchQuery.model, value: searchQuery.model } : undefined,
},
date: {
takenAfter: $searchQuery.takenAfter
? DateTime.fromISO($searchQuery.takenAfter).toUTC().toFormat('yyyy-MM-dd')
takenAfter: searchQuery.takenAfter
? DateTime.fromISO(searchQuery.takenAfter).toUTC().toFormat('yyyy-MM-dd')
: undefined,
takenBefore: $searchQuery.takenBefore
? DateTime.fromISO($searchQuery.takenBefore).toUTC().toFormat('yyyy-MM-dd')
takenBefore: searchQuery.takenBefore
? DateTime.fromISO(searchQuery.takenBefore).toUTC().toFormat('yyyy-MM-dd')
: undefined,
},
isArchive: $searchQuery.isArchived,
isFavorite: $searchQuery.isFavorite,
isNotInAlbum: 'isNotInAlbum' in $searchQuery ? $searchQuery.isNotInAlbum : undefined,
isArchive: searchQuery.isArchived,
isFavorite: searchQuery.isFavorite,
isNotInAlbum: 'isNotInAlbum' in searchQuery ? searchQuery.isNotInAlbum : undefined,
mediaType:
$searchQuery.type === AssetTypeEnum.Image
searchQuery.type === AssetTypeEnum.Image
? MediaType.Image
: $searchQuery.type === AssetTypeEnum.Video
: searchQuery.type === AssetTypeEnum.Video
? MediaType.Video
: MediaType.All,
};
Expand Down Expand Up @@ -344,7 +344,7 @@
{#each peopleList as person (person.id)}
<button
type="button"
class="w-20 text-center rounded-3xl border-2 border-transparent hover:bg-immich-gray dark:hover:bg-immich-dark-primary/20 p-2 flex-col place-items-center transition-all {filter.people.some(
class="w-20 text-center rounded-3xl border-2 border-transparent hover:bg-immich-gray dark:hover:bg-immich-dark-primary/20 p-2 transition-all {filter.people.some(
(p) => p.id === person.id,
)
? 'dark:border-slate-500 border-slate-300 bg-slate-200 dark:bg-slate-800 dark:text-white'
Expand All @@ -356,9 +356,9 @@
shadow
url={getPeopleThumbnailUrl(person.id)}
altText={person.name}
widthStyle="100px"
widthStyle="100%"
/>
<p class="mt-2 text-ellipsis text-sm font-medium dark:text-white">{person.name}</p>
<p class="mt-2 line-clamp-2 text-sm font-medium dark:text-white">{person.name}</p>
</button>
{/each}
</div>
Expand Down Expand Up @@ -498,7 +498,7 @@
</div>

<hr class="border-slate-300 dark:border-slate-700" />
<div class="py-3 grid grid-cols-2">
<div class="py-3 grid grid-cols-[repeat(auto-fill,minmax(21rem,1fr))] gap-x-16 gap-y-8">
<!-- MEDIA TYPE -->
<div id="media-type-selection">
<p class="immich-form-label">MEDIA TYPE</p>
Expand Down
1 change: 0 additions & 1 deletion web/src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export enum QueryParameter {
PREVIOUS_ROUTE = 'previousRoute',
QUERY = 'query',
SEARCHED_PEOPLE = 'searchedPeople',
SEARCH_TERM = 'q',
SMART_SEARCH = 'smartSearch',
PAGE = 'page',
}
Expand Down
2 changes: 0 additions & 2 deletions web/src/lib/stores/search.store.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import type { MetadataSearchDto, SmartSearchDto } from '@immich/sdk';
import { persisted } from 'svelte-local-storage-store';
import { writable } from 'svelte/store';

export const savedSearchTerms = persisted<string[]>('search-terms', [], {});
export const isSearchEnabled = writable<boolean>(false);
export const preventRaceConditionSearchBar = writable<boolean>(false);
export const searchQuery = writable<SmartSearchDto | MetadataSearchDto | undefined>(undefined);

0 comments on commit d3e14fd

Please sign in to comment.