Files
fnx_web/svelte/src/filesystem/SearchView.svelte

207 lines
4.3 KiB
Svelte
Raw Normal View History

2023-05-25 17:06:17 +02:00
<script>
import { createEventDispatcher } from "svelte";
import { fs_search, fs_encode_path, fs_thumbnail_url } from "./FilesystemAPI";
2023-05-25 17:06:17 +02:00
export let nav
2023-05-25 17:06:17 +02:00
let dispatch = createEventDispatcher()
2023-05-25 17:32:59 +02:00
let error = ""
2023-05-25 17:06:17 +02:00
let search_term = ""
let search_results = []
let searching = false
let last_searched_term = ""
let last_limit = 10
const search = async (limit = 10) => {
if (search_term.length < 2 || search_term.length > 100) {
// These are the length limits defined by the API
search_results = []
return
} else if (search_term === last_searched_term && limit === last_limit) {
// If the term is the same we don't have to search
return
} else if (searching) {
// If a search is already running we also don't search
return
}
console.debug("Searching for", search_term)
2023-05-25 17:32:59 +02:00
error = ""
2023-05-25 17:06:17 +02:00
last_searched_term = search_term
last_limit = limit
2023-05-25 17:06:17 +02:00
searching = true
nav.set_loading(true)
2023-05-25 17:06:17 +02:00
try {
search_results = await fs_search(nav.base.path, search_term, limit)
2023-05-25 17:06:17 +02:00
} catch (err) {
2023-05-30 23:35:18 +02:00
if (err.value) {
error = err.value
} else {
2023-05-25 17:32:59 +02:00
alert(err)
console.error(err)
}
2023-05-25 17:06:17 +02:00
}
searching = false
nav.set_loading(false)
2023-05-25 17:06:17 +02:00
// It's possible that the user entered another letter while we were
// performing the search reqeust. If this happens we run the search function
// again
if (last_searched_term !== search_term) {
console.debug("Search term changed during search. Searching again")
await search()
}
}
2023-05-29 12:33:22 +02:00
const keyup = e => {
if (e.key === "Escape") {
dispatch("done")
} else {
search()
}
}
2023-05-25 17:06:17 +02:00
// Submitting opens the first result
const submit_search = () => {
if (search_results.length !== 0) {
2023-05-29 12:33:22 +02:00
open_result(0)
2023-05-25 17:06:17 +02:00
}
}
2023-05-29 12:33:22 +02:00
const open_result = index => {
nav.navigate(search_results[index], true)
2023-05-29 12:33:22 +02:00
dispatch("done")
2023-05-25 17:06:17 +02:00
}
</script>
2023-05-25 17:32:59 +02:00
{#if error === "path_not_found" || error === "node_is_a_directory"}
<div class="highlight_yellow center">
Search index not found. The search index is a file called
'.search_index.gz' in your home directory. If you delete this file then
search will not work. The file is regenerated 10 minutes after modifying
a file in your filesystem.
</div>
{:else if error !== ""}
<div class="highlight_red center">
An error ocurred while executing the search request: {error}
</div>
{/if}
2023-05-29 12:33:22 +02:00
<div class="search_bar highlight_shaded center">
<form class="search_form" on:submit|preventDefault={submit_search}>
<i class="icon">search</i>
<!-- svelte-ignore a11y-autofocus -->
<input
class="term"
type="text"
placeholder="Type to search in {$nav.base.name}"
style="width: 100%;"
bind:value={search_term}
on:keyup={keyup}
autofocus
/>
2023-05-29 12:33:22 +02:00
</form>
</div>
2023-05-25 17:06:17 +02:00
<div class="results center">
2023-05-25 17:06:17 +02:00
{#each search_results as result, index}
<a
href={"/d"+fs_encode_path(result)}
2023-05-29 12:33:22 +02:00
on:click|preventDefault={() => open_result(index)}
2023-05-25 17:06:17 +02:00
class="node"
>
<img src={fs_thumbnail_url(result, 32, 32)} class="node_icon" alt="icon"/>
<span class="node_name">
<!-- Remove the search directory from the result -->
{result.slice($nav.base.path.length+1)}
</span>
2023-05-25 17:06:17 +02:00
</a>
{/each}
{#if search_results.length === last_limit}
<div class="node">
<div class="node_name" style="text-align: center;">
2023-05-25 17:06:17 +02:00
<button on:click={() => {search(last_limit + 100)}}>
<i class="icon">expand_more</i>
More results
</button>
</div>
2023-05-25 17:06:17 +02:00
</div>
{/if}
</div>
<style>
2023-05-25 17:32:59 +02:00
.center {
margin: auto;
width: 1000px;
max-width: 100%;
}
2023-05-25 17:06:17 +02:00
.search_bar {
2023-05-29 12:33:22 +02:00
display: flex;
flex-direction: column;
margin-top: 10px;
}
.search_form {
2023-05-25 17:06:17 +02:00
display: flex;
flex-direction: row;
align-items: center;
}
.term {
flex: 1 1 auto;
}
.results {
display: flex;
flex-direction: column;
2023-05-25 17:06:17 +02:00
position: relative;
overflow: hidden;
margin: 8px auto 16px auto;
text-align: left;
background: var(--body_color);
border-collapse: collapse;
border-radius: 8px;
}
.results > * {
display: flex;
flex-direction: row;
2023-05-25 17:06:17 +02:00
}
.node {
display: flex;
flex-direction: row;
align-items: center;
gap: 6px;
2023-05-25 17:06:17 +02:00
text-decoration: none;
color: var(--text-color);
padding: 4px;
2023-05-25 17:06:17 +02:00
}
.node:not(:last-child) {
border-bottom: 1px solid var(--separator);
}
.node:hover:not(.node_selected) {
background: var(--input_background);
color: var(--input_text);
text-decoration: none;
}
.node_icon {
flex: 0 0 auto;
2023-05-25 17:06:17 +02:00
height: 32px;
width: 32px;
vertical-align: middle;
border-radius: 4px;
}
.node_name {
flex: 1 1 auto;
2023-05-25 17:06:17 +02:00
width: 100%;
overflow: hidden;
line-height: 1.2em;
word-break: break-all;
}
</style>