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

110 lines
1.8 KiB
Svelte

<script lang="ts">
import Icon from '../utils/Icon.svelte';
import Jobs from './Jobs.svelte';
import Notifications from './Notifications.svelte';
import { i18n } from '$lib/i18n';
let hidden = true;
let activeJobs: number;
$: togglable = activeJobs > 0 || !hidden;
</script>
<footer id="footer" class:hidden>
<div class="notifications">
<Notifications />
</div>
<div
class="status"
class:togglable
on:click={() => (hidden = !hidden)}
on:keydown={(ev) => {
if (['Space', 'Enter'].includes(ev.key)) hidden = !hidden;
}}
role="button"
tabindex="-1"
>
<div class="info">
{#if activeJobs > 0}
{$i18n.t('Active jobs:')} {activeJobs}
{:else}
{$i18n.t('No active jobs.')}
{/if}
</div>
<div class="icons">
<Icon name="{hidden ? 'up' : 'down'}-arrow" />
</div>
</div>
<div class="jobs">
<Jobs bind:active={activeJobs} />
</div>
</footer>
<style lang="scss">
footer {
position: fixed;
bottom: 0;
width: 100%;
z-index: 9;
display: flex;
flex-direction: column;
& > * {
padding: 0 0.5rem;
}
background: var(--background);
border-top: 1px solid var(--foreground-lighter);
transition: 0.7s bottom ease;
--height: calc(100vh / 6);
}
footer.hidden {
bottom: calc(var(--height) * -1);
}
.status {
height: 2rem;
width: 100%;
display: flex;
align-items: center;
cursor: pointer;
&:not(.togglable) {
cursor: unset;
pointer-events: none;
opacity: 0.66;
}
transition: opacity 0.7s ease;
.info {
flex-grow: 1;
}
}
.notifications,
.jobs {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
:global(.notifications > *:first-child) {
padding-top: 0.5rem;
}
.jobs {
overflow-y: scroll;
height: var(--height);
padding-top: 0.5rem;
background: var(--background-lighter);
}
</style>