feat(ui): footer is persistent and can be hidden

feat/type-attributes
Tomáš Mládek 2023-01-02 00:33:10 +01:00
parent 724004be4b
commit d392e41550
5 changed files with 89 additions and 30 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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;
}

View File

@ -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 {