feat(ui): footer is persistent and can be hidden
parent
724004be4b
commit
d392e41550
|
@ -14,8 +14,8 @@
|
|||
const history = createHistory(createHashSource());
|
||||
|
||||
let footerHeight = "0";
|
||||
function setBottomMargin(size: CustomEvent<ResizeObserverEntry>) {
|
||||
footerHeight = `${size.detail.contentRect.height}px`;
|
||||
function setBottomMargin(size: CustomEvent<number>) {
|
||||
footerHeight = `${size.detail}px`;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,22 +1,72 @@
|
|||
<script lang="ts">
|
||||
import { createEventDispatcher, onMount } from "svelte";
|
||||
import IconButton from "../utils/IconButton.svelte";
|
||||
import Jobs from "./Jobs.svelte";
|
||||
import Notifications from "./Notifications.svelte";
|
||||
import { i18n } from "../../i18n";
|
||||
import { get_root_for_style } from "svelte/internal";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let root: HTMLElement;
|
||||
let rootEl: HTMLElement;
|
||||
let contentEl: HTMLElement;
|
||||
let contentHeight = 0;
|
||||
let hidden = false;
|
||||
|
||||
let activeJobs: number;
|
||||
|
||||
onMount(() => {
|
||||
const observer = new ResizeObserver((entries) => {
|
||||
entries.forEach((entry) => dispatch("resize", entry));
|
||||
// should be only one
|
||||
entries.forEach((entry) => {
|
||||
contentHeight = contentEl?.getBoundingClientRect()?.height;
|
||||
dispatch("resize", entry.contentRect.height);
|
||||
});
|
||||
});
|
||||
observer.observe(root);
|
||||
observer.observe(rootEl);
|
||||
});
|
||||
|
||||
function toggleHidden() {
|
||||
if (hidden) {
|
||||
rootEl.style.top = "unset";
|
||||
}
|
||||
hidden = !hidden;
|
||||
}
|
||||
|
||||
function onTransitionEnd(ev: TransitionEvent) {
|
||||
if (ev.propertyName === "bottom" && hidden) {
|
||||
rootEl.style.top = `${rootEl.getBoundingClientRect().top}px`;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<footer id="footer" bind:this={root}>
|
||||
<Notifications />
|
||||
<Jobs />
|
||||
<footer
|
||||
id="footer"
|
||||
bind:this={rootEl}
|
||||
class:hidden
|
||||
style="--contentHeight: {contentHeight}px"
|
||||
on:transitionend={onTransitionEnd}
|
||||
>
|
||||
<div class="status">
|
||||
<div class="info">
|
||||
{#if activeJobs > 0}
|
||||
{$i18n.t("Active jobs:")} {activeJobs}
|
||||
{:else}
|
||||
{$i18n.t("No active jobs.")}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="icons">
|
||||
{#if contentHeight > 0}
|
||||
<IconButton
|
||||
name="{hidden ? 'up' : 'down'}-arrow"
|
||||
on:click={toggleHidden}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="content" bind:this={contentEl}>
|
||||
<Notifications />
|
||||
<Jobs bind:active={activeJobs} />
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -27,10 +77,28 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--background);
|
||||
border-top: 1px solid var(--foreground);
|
||||
border-top: 1px solid var(--foreground-lighter);
|
||||
|
||||
transition: 0.7s bottom ease;
|
||||
}
|
||||
|
||||
:global(#footer > *) {
|
||||
margin: 1rem 0.5rem;
|
||||
footer.hidden {
|
||||
bottom: calc(var(--contentHeight) * -1);
|
||||
}
|
||||
|
||||
.status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 2em;
|
||||
padding: 0.2em;
|
||||
|
||||
.info {
|
||||
flex-grow: 1;
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
|
||||
:global(#footer .content > *) {
|
||||
margin: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
|
||||
let jobs: IJob[] = [];
|
||||
let activeJobs: JobWithId[] = [];
|
||||
|
||||
export let active = 0;
|
||||
$: active = activeJobs.length;
|
||||
|
||||
let timeout: NodeJS.Timeout;
|
||||
async function updateJobs() {
|
||||
clearTimeout(timeout);
|
||||
|
@ -66,4 +70,8 @@
|
|||
margin-right: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.job-annotation {
|
||||
opacity: 0.75;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -25,22 +25,6 @@ html {
|
|||
margin: 0 2rem;
|
||||
}
|
||||
|
||||
#footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
background: var(--background);
|
||||
}
|
||||
|
||||
#footer > * {
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
|
|
@ -93,10 +93,9 @@
|
|||
gap: 1rem;
|
||||
padding: 0 1rem;
|
||||
|
||||
// header margin magic
|
||||
height: calc(100% - 3.5rem - 2 * 1rem - 1px);
|
||||
// header margin footer
|
||||
height: calc(100% - 3.5rem - 2 * 1rem - var(--footer-height));
|
||||
margin-top: 1rem;
|
||||
margin-bottom: var(--footer-height);
|
||||
}
|
||||
|
||||
.column {
|
||||
|
|
Loading…
Reference in New Issue