145 lines
3.1 KiB
Svelte
145 lines
3.1 KiB
Svelte
<script lang="ts">
|
|
import { addEmitter } from '../AddModal.svelte';
|
|
import Icon from '../utils/Icon.svelte';
|
|
import { jobsEmitter } from './Jobs.svelte';
|
|
import api from '$lib/api';
|
|
import Selector, { type SelectorValue } from '../utils/Selector.svelte';
|
|
import { i18n } from '$lib/i18n';
|
|
import { goto } from '$app/navigation';
|
|
|
|
let selector: Selector;
|
|
|
|
let lastSearched: SelectorValue[] = [];
|
|
|
|
function addLastSearched(value: SelectorValue) {
|
|
switch (value.t) {
|
|
case 'Address':
|
|
lastSearched = lastSearched.filter((v) => v.t !== 'Address' || v.c !== value.c);
|
|
break;
|
|
case 'Attribute':
|
|
lastSearched = lastSearched.filter((v) => v.t !== 'Attribute' || v.name !== value.name);
|
|
break;
|
|
}
|
|
lastSearched.unshift(value);
|
|
lastSearched = lastSearched.slice(0, 10);
|
|
}
|
|
|
|
async function onInput(event: CustomEvent<SelectorValue>) {
|
|
const value = event.detail;
|
|
if (!value) return;
|
|
|
|
switch (value.t) {
|
|
case 'Address':
|
|
addLastSearched(value);
|
|
goto(`/browse/${value.c}`);
|
|
break;
|
|
case 'Attribute':
|
|
addLastSearched(value);
|
|
{
|
|
const attributeAddress = await api.componentsToAddress({
|
|
t: 'Attribute',
|
|
c: value.name
|
|
});
|
|
goto(`/browse/${attributeAddress}`);
|
|
}
|
|
break;
|
|
}
|
|
selector.reset();
|
|
|
|
// searchQuery = event.detail;
|
|
|
|
// if (searchQuery.length > 0) {
|
|
// navigate(`/search/${encodeURIComponent(searchQuery)}`, {
|
|
// replace: $location.pathname.includes("search"),
|
|
// });
|
|
// }
|
|
}
|
|
|
|
let fileInput: HTMLInputElement;
|
|
function onFileChange() {
|
|
if (fileInput.files?.length) {
|
|
addEmitter.emit('files', Array.from(fileInput.files));
|
|
}
|
|
}
|
|
|
|
async function rescan() {
|
|
await api.refreshVault();
|
|
jobsEmitter.emit('reload');
|
|
}
|
|
</script>
|
|
|
|
<div class="header">
|
|
<h1>
|
|
<a href="/">
|
|
<img class="logo" src="/assets/upend.svg" alt="UpEnd logo" />
|
|
<div class="name">UpEnd</div>
|
|
</a>
|
|
</h1>
|
|
<div class="input">
|
|
<Selector
|
|
types={['Address', 'NewAddress', 'Attribute']}
|
|
placeholder={$i18n.t('Search or add') || ''}
|
|
on:input={onInput}
|
|
bind:this={selector}
|
|
emptyOptions={lastSearched}
|
|
>
|
|
<Icon name="search" slot="prefix" />
|
|
</Selector>
|
|
</div>
|
|
<button class="button" on:click={() => fileInput.click()}>
|
|
<Icon name="upload" />
|
|
<input type="file" multiple bind:this={fileInput} on:change={onFileChange} />
|
|
</button>
|
|
<button class="button" on:click={() => rescan()} title="Rescan vault">
|
|
<Icon name="refresh" />
|
|
</button>
|
|
</div>
|
|
|
|
<style lang="scss">
|
|
.header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.5rem;
|
|
height: 3.5rem;
|
|
border-bottom: 1px solid var(--foreground);
|
|
|
|
background: var(--background);
|
|
|
|
h1 {
|
|
font-size: 16pt;
|
|
font-weight: normal;
|
|
margin: 0;
|
|
|
|
:global(a) {
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
color: var(--foreground-lightest);
|
|
text-decoration: none;
|
|
font-weight: normal;
|
|
}
|
|
|
|
img {
|
|
margin-right: 0.5em;
|
|
}
|
|
}
|
|
|
|
.logo {
|
|
display: inline-block;
|
|
height: 1.5em;
|
|
}
|
|
|
|
.input {
|
|
flex-grow: 1;
|
|
min-width: 3rem;
|
|
}
|
|
}
|
|
|
|
@media screen and (max-width: 600px) {
|
|
.name {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|