obsidian-visualiser/components/SearchView.client.vue

47 lines
2.3 KiB
Vue

<script setup lang="ts">
const { data: nav } = await useAsyncData('search', () => fetchContentNavigation());
const input = ref('');
const pos = ref<DOMRect>();
function getPos(e: Event) {
pos.value = (e.currentTarget as HTMLElement)?.getBoundingClientRect();
}
function flatten(val: NavItem[]): NavItem[] {
return val.flatMap ? val?.flatMap((e: NavItem) => e.children ? flatten(e.children) : e) : val;
}
function clear(text: string): string
{
return text.toLowerCase().trim().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
}
const navigation = computed(() => {
return flatten(nav.value ?? []);
})
const results = computed(() => {
return navigation.value?.filter((e) => clear(e.title).includes(clear(input.value))) ?? [];
})
</script>
<template>
<div class="search-view-outer">
<div class="search-view-container">
<span class="published-search-icon"></span>
<input class="search-bar" type="text" placeholder="Recherche" v-model="input" @input="getPos">
</div>
</div>
<Teleport to="body" v-if="input !== ''">
<div class="search-results" :style="{top: (pos.bottom + 4) + 'px', left: pos.left + 'px', width: pos.width + 'px'}">
<div class="suggestion-item" v-if="results.length > 0" v-for="result of results" :key="result._path" @mouseenter="(e) => (e.target as HTMLElement).classList.add('is-selected')" @mouseleave="(e) => (e.target as HTMLElement).classList.remove('is-selected')" @mousedown.prevent="navigateTo('/explorer' + result._path); input = ''">
<div class="suggestion-content">
<div class="suggestion-title">
<ProseA :href="result._path">
{{ result.title.substring(0, clear(result.title).indexOf(clear(input))) }}<span class="suggestion-highlight">{{ result.title.substring(clear(result.title).indexOf(clear(input)), clear(result.title).indexOf(clear(input)) + clear(input).length + 1) }}</span>{{ result.title.substring(clear(result.title).indexOf(clear(input)) + clear(input).length + 1) }}
</ProseA>
</div>
</div>
</div>
<div class="suggestion-empty" v-else>
Aucun résultat
</div>
</div>
</Teleport>
</template>