obsidian-visualiser/components/SearchView.vue

88 lines
3.9 KiB
Vue

<script setup lang="ts">
import type { Search, File, Project, User } from '~/types/api';
const input = ref(''), results = ref<Search>({ projects: [], files: [], users: [] });
const pos = ref<DOMRect>(), loading = ref(false);
let timeout: NodeJS.Timeout;
function search(e: Event)
{
pos.value = (e.currentTarget as HTMLElement)?.getBoundingClientRect();
loading.value = true;
clearTimeout(timeout);
timeout = setTimeout(debounced, 250);
}
async function debounced()
{
if(!input.value)
return;
try
{
const fetch = await useFetch(`/api/search`, {
query: {
"search": `%${input.value}%`
}
});
results.value = fetch.data.value;
}
catch (e) {
results.value = { projects: [], files: [], users: [] };
}
loading.value = false;
}
</script>
<template>
<div class="w-full border border-light-30 dark:border-dark-30">
<input class="caret-light-50 dark:caret-dark-50 text-light-100 dark:text-dark-100 placeholder:text-light-50 dark:placeholder:text-dark-50 bg-light-20 dark:bg-dark-20 appearance-none w-full outline-none px-3 py-1 focus:shadow-raw transition-[box-shadow] focus:shadow-light-40 dark:focus:shadow-dark-40" type="text" placeholder="Recherche" v-model="input" @input="search">
</div>
<Teleport to="#teleports" v-if="input !== '' && !!pos">
<div class=""
:style="{top: (pos.bottom + 4) + 'px', left: pos.left + 'px', width: pos.width + 'px'}">
<div class="loading" v-if="loading"></div>
<template v-else>
<div class="" v-for="result of results.projects" :key="result.id"
@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.id}${result.home}`); input = ''">
<div class="">
<BoldContent class="" :text="result.name" :matched="input" />
<div class="">
<div class="">{{ result.username }}</div>
<div class="">{{ result.pages }} pages</div>
</div>
</div>
</div>
<div class="" v-for="result of results.files" :key="result.id"
@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.project}${result.path}`); input = ''">
<div class="">
<BoldContent class="" :text="result.title" :matched="input" />
<div class="">
<div class="">{{ result.username }}</div>
<div class="">{{ result.comments }} commentaires</div>
</div>
</div>
</div>
<div class="" v-for="result of results.users" :key="result.id"
@mouseenter="(e) => (e.target as HTMLElement).classList.add('is-selected')"
@mouseleave="(e) => (e.target as HTMLElement).classList.remove('is-selected')"
@mousedown.prevent="navigateTo(`/user/${result.id}`); input = ''">
<div class="">
<BoldContent class="" :text="result.username" :matched="input" />
</div>
</div>
<div class=""
v-if="results.projects.length === 0 && results.files.length === 0 && results.users.length === 0">
Aucun résultat
</div>
</template>
</div>
</Teleport>
</template>