upend/webui/src/lib/components/layout/Header.svelte

162 lines
3.5 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';
import { onMount } from 'svelte';
import { vaultInfo } from '$lib/util/info';
import HeaderUserDropdown from '$lib/components/layout/HeaderUserDropdown.svelte';
let selector: Selector;
let userDropdown = false;
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 | undefined>) {
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));
}
}
onMount(() => {
addEmitter.on('choose', () => fileInput.click());
});
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 on:click={() => addEmitter.emit('choose')}>
<Icon name="upload" />
<input type="file" multiple bind:this={fileInput} on:change={onFileChange} />
</button>
<button on:click={() => rescan()} title="Rescan vault">
<Icon name="refresh" />
</button>
<button
class="user"
disabled={$vaultInfo?.public}
on:click|stopPropagation={() => (userDropdown = true)}
>
<Icon name="user" />
</button>
<HeaderUserDropdown bind:open={userDropdown} />
</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>