0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-03-11 02:23:09 -05:00

feat(web): metadata search

This commit is contained in:
Alex Tran 2025-01-31 15:17:06 -06:00
parent 1b141d5ca9
commit 1d0df97c13
3 changed files with 96 additions and 1 deletions

View file

@ -0,0 +1,19 @@
<script lang="ts">
interface Props {
value: string;
description: string;
example: string;
}
let { value, description, example }: Props = $props();
</script>
<div class="flex justify-between bg-gray-100 p-2 w-full rounded-lg">
<div class="">
<p class="font-semibold text-[10px] text-primary">{description.toUpperCase()}</p>
<code class="italic text-[12px]">{example}</code>
</div>
<code class="bg-immich-primary/15 px-2 rounded-lg flex place-items-center place-content-center font-bold"
>{value}</code
>
</div>

View file

@ -32,6 +32,7 @@
let showFilter = $state(false);
let isSearchSuggestions = $state(false);
let selectedId: string | undefined = $state();
let showMetadataSuggestions = $state(false);
const listboxId = generateId();
@ -128,6 +129,15 @@
const onInput = () => {
openDropdown();
searchHistoryBox?.clearSelection();
const hasMetadataShortcut = value.startsWith('m:');
if (hasMetadataShortcut) {
showMetadataSuggestions = true;
isSearchSuggestions = true;
} else {
showMetadataSuggestions = false;
}
};
const openDropdown = () => {
@ -204,6 +214,7 @@
id={listboxId}
searchQuery={value}
isOpen={showSuggestions}
{showMetadataSuggestions}
onClearAllSearchTerms={clearAllSearchTerms}
onClearSearchTerm={(searchTerm) => clearSearchTerm(searchTerm)}
onSelectSearchTerm={(searchTerm) => handlePromiseError(onHistoryTermClick(searchTerm))}

View file

@ -2,15 +2,17 @@
import Icon from '$lib/components/elements/icon.svelte';
import { savedSearchTerms } from '$lib/stores/search.store';
import { mdiMagnify, mdiClose } from '@mdi/js';
import { fly } from 'svelte/transition';
import { fade, fly } from 'svelte/transition';
import { t } from 'svelte-i18n';
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import MetadataSuggestionTip from '$lib/components/shared-components/search-bar/metadata-suggestion-tip.svelte';
interface Props {
id: string;
searchQuery?: string;
isSearchSuggestions?: boolean;
isOpen?: boolean;
showMetadataSuggestions?: boolean;
onSelectSearchTerm: (searchTerm: string) => void;
onClearSearchTerm: (searchTerm: string) => void;
onClearAllSearchTerms: () => void;
@ -22,6 +24,7 @@
searchQuery = '',
isSearchSuggestions = $bindable(false),
isOpen = false,
showMetadataSuggestions = false,
onSelectSearchTerm,
onClearSearchTerm,
onClearAllSearchTerms,
@ -89,6 +92,57 @@
}
return `${id}-${index}`;
};
type MetadataSuggestion = {
value: string;
description: string;
example: string;
};
let metadataExample: Array<MetadataSuggestion> = [
{ value: 'm:name:', description: 'File Name', example: 'm:name:img123.jpg' },
{ value: 'm:ctx', description: 'Context', example: 'm:ctx:sunrise on the beach' },
{
value: 'm:desc:',
description: 'Description',
example: 'm:desc:a table full of cats',
},
{
value: 'm:orien:',
description: 'Orientation',
example: 'm:orientation:landscape',
},
{
value: 'm:width:',
description: 'Media width',
example: 'm:width:1920',
},
{
value: 'm:height:',
description: 'Media height',
example: 'm:height:1080',
},
{
value: 'm:size:',
description: 'File size',
example: 'm:size:1MB, m:size:1GB',
},
{
value: 'm:date-from:',
description: 'Date from',
example: 'm:date-from:2020-01-01',
},
{
value: 'm:date-to:',
description: 'Date to',
example: 'm:date-to:2024-12-31',
},
{
value: 'm:rating:',
description: 'Rating',
example: 'm:rating:5',
},
];
</script>
<div role="listbox" {id} aria-label={$t('recent_searches')} bind:this={element}>
@ -97,6 +151,17 @@
transition:fly={{ y: 25, duration: 150 }}
class="absolute w-full rounded-b-3xl border-2 border-t-0 border-gray-200 bg-white pb-5 shadow-2xl transition-all dark:border-gray-700 dark:bg-immich-dark-gray dark:text-gray-300"
>
{#if showMetadataSuggestions}
<div in:fly={{ x: -50 }} class="flex items-center justify-between px-5 pt-5 text-xs">
<p class="py-2" aria-hidden={true}>{'searchable metadata'.toUpperCase()}</p>
</div>
<div in:fly={{ x: 50 }} class="px-5 grid grid-rows-3 grid-cols-2 gap-1 justify-items-start text-xs mt-1">
{#each metadataExample as example}
<MetadataSuggestionTip value={example.value} description={example.description} example={example.example} />
{/each}
</div>
{/if}
<div class="flex items-center justify-between px-5 pt-5 text-xs">
<p class="py-2" aria-hidden={true}>{$t('recent_searches').toUpperCase()}</p>
{#if showClearAll}