127 lines
2.8 KiB
Svelte
127 lines
2.8 KiB
Svelte
<script lang="ts">
|
|
import { draggable } from "@neodrag/svelte";
|
|
import { onMount } from "svelte";
|
|
import { tweened } from "svelte/motion";
|
|
import { sineIn, sineOut } from "svelte/easing";
|
|
// import { invoke } from "@tauri-apps/api";
|
|
export let progress = 0;
|
|
|
|
export let withSetpoint = false;
|
|
export let setpoint = 0;
|
|
export let onSetpointChange = (_: number) => {};
|
|
|
|
let bar: HTMLDivElement;
|
|
let point: HTMLDivElement;
|
|
let pos = { x: 0, y: 0 };
|
|
const tweenedProgress = tweened(0, { duration: 100, easing: sineOut });
|
|
|
|
onMount(async () => {
|
|
let rect = bar.getBoundingClientRect();
|
|
let prect = point.getBoundingClientRect();
|
|
pos.y = -(setpoint / 100) * rect.height + prect.height;
|
|
});
|
|
|
|
$: if (bar) {
|
|
let pxProgress = (progress / 100) * bar.getBoundingClientRect().height;
|
|
if (pxProgress > $tweenedProgress) {
|
|
tweenedProgress
|
|
.set(pxProgress, {
|
|
duration: 30,
|
|
easing: sineOut,
|
|
})
|
|
.then();
|
|
} else {
|
|
$tweenedProgress = pxProgress;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<svelte:window
|
|
on:resize={async () => {
|
|
// await invoke("log", {
|
|
// msg: `Resized`,
|
|
// });
|
|
|
|
pos = { x: 0, y: 0 };
|
|
let rect = bar.getBoundingClientRect();
|
|
let prect = point.getBoundingClientRect();
|
|
pos.y = -(setpoint / 100) * rect.height + prect.height;
|
|
}}
|
|
/>
|
|
|
|
<div class="box">
|
|
<div bind:this={bar} class="bar-container">
|
|
{#if withSetpoint}
|
|
<div
|
|
bind:this={point}
|
|
class="setpoint"
|
|
use:draggable={{
|
|
onDragStart: () => (pos = undefined),
|
|
handle: ".handle",
|
|
position: pos,
|
|
axis: "y",
|
|
bounds: "parent",
|
|
onDragEnd: (e) => {
|
|
let rect = bar.getBoundingClientRect();
|
|
let y = (e.domRect.y - rect.y + e.domRect.height / 2) / rect.height;
|
|
onSetpointChange(1.0 - y);
|
|
},
|
|
}}
|
|
>
|
|
<div class="handle" />
|
|
</div>
|
|
{/if}
|
|
<div class="bar" style="height: {$tweenedProgress}px;" />
|
|
</div>
|
|
<slot class="icon" />
|
|
</div>
|
|
|
|
<style lang="scss">
|
|
.box {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 1vh;
|
|
:global(img) {
|
|
width: var(--bar-width, 5vh);
|
|
}
|
|
}
|
|
|
|
.setpoint {
|
|
position: absolute;
|
|
background-color: black;
|
|
width: var(--bar-width, 5vh);
|
|
height: 0.5vh;
|
|
.handle {
|
|
position: absolute;
|
|
border-top: 2vh solid transparent;
|
|
border-bottom: 2vh solid transparent;
|
|
border-left: 2vh solid var(--handle-color, forestgreen);
|
|
left: -2.2vh;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
}
|
|
}
|
|
|
|
.bar-container {
|
|
border-radius: var(--bar-radius, 0px);
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: flex-end;
|
|
background-color: white;
|
|
border: 2px solid black;
|
|
height: 80vh;
|
|
width: var(--bar-width, 5vh);
|
|
}
|
|
|
|
.bar {
|
|
border-radius: inherit;
|
|
user-select: none;
|
|
width: 100%;
|
|
border: 0;
|
|
margin: 0;
|
|
background-color: var(--bar-color, blue);
|
|
transition: background-color 0.1s;
|
|
}
|
|
</style>
|