mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
feat(web): remember search context (#16614)
* Retain search context in LocalStorage. * Remove debug logging * Prettier * Added QueryType and VALID_QUERY_TYPES to $lib/constants * Prettier * Renamed VALID_QUERY_TYPES to fit the codestyle. Ran prettier * show current search type on search bar * fix: linting --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
parent
2f8e89c7ec
commit
70a08707d2
@ -32,6 +32,7 @@
|
|||||||
let showFilter = $state(false);
|
let showFilter = $state(false);
|
||||||
let isSearchSuggestions = $state(false);
|
let isSearchSuggestions = $state(false);
|
||||||
let selectedId: string | undefined = $state();
|
let selectedId: string | undefined = $state();
|
||||||
|
let isFocus = $state(false);
|
||||||
|
|
||||||
const listboxId = generateId();
|
const listboxId = generateId();
|
||||||
|
|
||||||
@ -98,7 +99,25 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = () => {
|
const onSubmit = () => {
|
||||||
handlePromiseError(handleSearch({ query: value }));
|
const searchType = getSearchType();
|
||||||
|
let payload: SmartSearchDto | MetadataSearchDto = {} as SmartSearchDto | MetadataSearchDto;
|
||||||
|
|
||||||
|
switch (searchType) {
|
||||||
|
case 'smart': {
|
||||||
|
payload = { query: value } as SmartSearchDto;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'metadata': {
|
||||||
|
payload = { originalFileName: value } as MetadataSearchDto;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'description': {
|
||||||
|
payload = { description: value } as MetadataSearchDto;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePromiseError(handleSearch(payload));
|
||||||
saveSearchTerm(value);
|
saveSearchTerm(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -132,10 +151,12 @@
|
|||||||
|
|
||||||
const openDropdown = () => {
|
const openDropdown = () => {
|
||||||
showSuggestions = true;
|
showSuggestions = true;
|
||||||
|
isFocus = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeDropdown = () => {
|
const closeDropdown = () => {
|
||||||
showSuggestions = false;
|
showSuggestions = false;
|
||||||
|
isFocus = false;
|
||||||
searchHistoryBox?.clearSelection();
|
searchHistoryBox?.clearSelection();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -143,6 +164,26 @@
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
onSubmit();
|
onSubmit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getSearchType(): 'smart' | 'metadata' | 'description' {
|
||||||
|
const t = localStorage.getItem('searchQueryType');
|
||||||
|
return t === 'smart' || t === 'description' ? t : 'metadata';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSearchTypeText(): string {
|
||||||
|
const searchType = getSearchType();
|
||||||
|
switch (searchType) {
|
||||||
|
case 'smart': {
|
||||||
|
return $t('context');
|
||||||
|
}
|
||||||
|
case 'metadata': {
|
||||||
|
return $t('filename');
|
||||||
|
}
|
||||||
|
case 'description': {
|
||||||
|
return $t('description');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window
|
<svelte:window
|
||||||
@ -214,6 +255,21 @@
|
|||||||
<div class="absolute inset-y-0 {showClearIcon ? 'right-14' : 'right-2'} flex items-center pl-6 transition-all">
|
<div class="absolute inset-y-0 {showClearIcon ? 'right-14' : 'right-2'} flex items-center pl-6 transition-all">
|
||||||
<CircleIconButton title={$t('show_search_options')} icon={mdiTune} onclick={onFilterClick} size="20" />
|
<CircleIconButton title={$t('show_search_options')} icon={mdiTune} onclick={onFilterClick} size="20" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{#if isFocus}
|
||||||
|
<div
|
||||||
|
class="absolute inset-y-0 flex items-center"
|
||||||
|
class:right-16={isFocus}
|
||||||
|
class:right-28={isFocus && value.length > 0}
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="bg-immich-primary text-white dark:bg-immich-dark-primary/90 dark:text-black/75 rounded-full px-3 py-1 text-xs z-10"
|
||||||
|
>
|
||||||
|
{getSearchTypeText()}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if showClearIcon}
|
{#if showClearIcon}
|
||||||
<div class="absolute inset-y-0 right-0 flex items-center pr-2">
|
<div class="absolute inset-y-0 right-0 flex items-center pr-2">
|
||||||
<CircleIconButton onclick={onClear} icon={mdiClose} title={$t('clear')} size="20" />
|
<CircleIconButton onclick={onClear} icon={mdiClose} title={$t('clear')} size="20" />
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import type { SearchLocationFilter } from './search-location-section.svelte';
|
import type { SearchLocationFilter } from './search-location-section.svelte';
|
||||||
import type { SearchDisplayFilters } from './search-display-section.svelte';
|
import type { SearchDisplayFilters } from './search-display-section.svelte';
|
||||||
import type { SearchDateFilter } from './search-date-section.svelte';
|
import type { SearchDateFilter } from './search-date-section.svelte';
|
||||||
import { MediaType } from '$lib/constants';
|
import { MediaType, QueryType, validQueryTypes } from '$lib/constants';
|
||||||
|
|
||||||
export type SearchFilter = {
|
export type SearchFilter = {
|
||||||
query: string;
|
query: string;
|
||||||
@ -55,9 +55,18 @@
|
|||||||
return value === null ? undefined : value;
|
return value === null ? undefined : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function storeQueryType(type: SearchFilter['queryType']) {
|
||||||
|
localStorage.setItem('searchQueryType', type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function defaultQueryType(): QueryType {
|
||||||
|
const storedQueryType = localStorage.getItem('searchQueryType') as QueryType;
|
||||||
|
return validQueryTypes.has(storedQueryType) ? storedQueryType : QueryType.SMART;
|
||||||
|
}
|
||||||
|
|
||||||
let filter: SearchFilter = $state({
|
let filter: SearchFilter = $state({
|
||||||
query: 'query' in searchQuery ? searchQuery.query : searchQuery.originalFileName || '',
|
query: 'query' in searchQuery ? searchQuery.query : searchQuery.originalFileName || '',
|
||||||
queryType: 'smart',
|
queryType: defaultQueryType(),
|
||||||
personIds: new SvelteSet('personIds' in searchQuery ? searchQuery.personIds : []),
|
personIds: new SvelteSet('personIds' in searchQuery ? searchQuery.personIds : []),
|
||||||
tagIds: new SvelteSet('tagIds' in searchQuery ? searchQuery.tagIds : []),
|
tagIds: new SvelteSet('tagIds' in searchQuery ? searchQuery.tagIds : []),
|
||||||
location: {
|
location: {
|
||||||
@ -90,7 +99,7 @@
|
|||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
filter = {
|
filter = {
|
||||||
query: '',
|
query: '',
|
||||||
queryType: 'smart',
|
queryType: defaultQueryType(), // retain from localStorage or default
|
||||||
personIds: new SvelteSet(),
|
personIds: new SvelteSet(),
|
||||||
tagIds: new SvelteSet(),
|
tagIds: new SvelteSet(),
|
||||||
location: {},
|
location: {},
|
||||||
@ -142,8 +151,14 @@
|
|||||||
|
|
||||||
const onsubmit = (event: Event) => {
|
const onsubmit = (event: Event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
storeQueryType(filter.queryType);
|
||||||
search();
|
search();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Will be called whenever queryType changes, not just onsubmit.
|
||||||
|
$effect(() => {
|
||||||
|
storeQueryType(filter.queryType);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FullScreenModal icon={mdiTune} width="extra-wide" title={$t('search_options')} {onClose}>
|
<FullScreenModal icon={mdiTune} width="extra-wide" title={$t('search_options')} {onClose}>
|
||||||
|
@ -119,6 +119,14 @@ export const fallbackLocale = {
|
|||||||
name: 'English (US)',
|
name: 'English (US)',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum QueryType {
|
||||||
|
SMART = 'smart',
|
||||||
|
METADATA = 'metadata',
|
||||||
|
DESCRIPTION = 'description',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validQueryTypes = new Set([QueryType.SMART, QueryType.METADATA, QueryType.DESCRIPTION]);
|
||||||
|
|
||||||
export const locales = [
|
export const locales = [
|
||||||
{ code: 'af-ZA', name: 'Afrikaans (South Africa)' },
|
{ code: 'af-ZA', name: 'Afrikaans (South Africa)' },
|
||||||
{ code: 'sq-AL', name: 'Albanian (Albania)' },
|
{ code: 'sq-AL', name: 'Albanian (Albania)' },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user