<script lang="ts">
import { onMount } from "svelte";
import MovableIcon from "../../icons/MovableIcon.svelte";
import ChevronDown from "../../icons/ChevronDown.svelte";
import ChevronUp from "../../icons/ChevronUp.svelte";
import Button from "./Button.svelte";
import createDebug from "debug";
let clazz = "";
export { clazz as class };
export let style = "";
export let centered = false;
export let id;
export let title;
export let notitle = false;
export let draggable = false;
export let minimizable = false;
let header;
let popup;
let pos1 = 0;
let pos2 = 0;
let pos3 = 0;
let pos4 = 0;
let minimized = false;
onMount(() => {
if (draggable) {
pos1 = parseInt(window.localStorage.getItem(`pop-${id}top`));
pos2 = parseInt(window.localStorage.getItem(`pop-${id}left`));
// Correct illegally placed draggables
// Disabled until I can find a nice way to run this after the dynamic
// content injection by svelte
//[pos1, pos2] = dragBoundsEnforce();
// I hate JS for letting me pull crap like this
popup.style.top = `${pos1}px`;
popup.style.left = `${pos2}px`;
}
if (minimizable) {
minimized = window.localStorage.getItem(`pop-${id}minim`) === "yes";
}
});
function dragMouseDown(e) {
if (!draggable) {
return;
}
let popup_dimensions = popup.getBoundingClientRect();
pos3 = e.clientX - popup_dimensions.left;
pos4 = e.clientY - popup_dimensions.top;
e.target.onmouseup = function () {
closeDragElement(e.target);
};
e.target.onmousemove = elementDrag;
}
function elementDrag(e) {
e.preventDefault();
pos1 = e.clientX - pos3;
pos2 = e.clientY - pos4;
let [left, top, bounds_violated] = dragBoundsEnforce();
popup.style.left = left + "px";
popup.style.top = top + "px";
}
function dragBoundsEnforce() {
let left = pos1;
let top = pos2;
let popup_dimensions = popup.getBoundingClientRect();
// This was originally meant to specify the amount of error acceptable
// before snapping to an edge or corner, but now it seems to merely adjust
// the amount of pixels between the screen edge and the bounds.
let snap_distance = 0; //16;
let bounds = {
top: 8 + snap_distance,
left: 8 + snap_distance,
bottom: window.innerHeight - popup_dimensions.height - 8 - snap_distance,
right: window.innerWidth - popup_dimensions.width - 8 - snap_distance,
};
let bounds_violated = false;
// Add cases for snapping here
if (left >= bounds.right) {
// Too far right!
left = bounds.right;
bounds_violated = true;
} else if (left <= bounds.left) {
// Too far left!
left = bounds.left;
bounds_violated = true;
}
if (top >= bounds.bottom) {
// Too far down!
top = bounds.bottom;
bounds_violated = true;
} else if (top <= bounds.top) {
// Too far up!
top = bounds.top;
bounds_violated = true;
}
return [left, top, bounds_violated];
}
function closeDragElement(el) {
el.onmouseup = null;
el.onmousemove = null;
window.localStorage.setItem(`pop-${id}top`, popup.style.top);
window.localStorage.setItem(`pop-${id}left`, popup.style.left);
}
function toggleMinimized() {
if (minimizable) {
minimized = !minimized;
window.localStorage.setItem(`pop-${id}minim`, minimized ? "yes" : "no");
}
}
</script>
<div bind:this={popup} class="popup {clazz}" class:centered {style} {id}>
{#if !notitle}
<div bind:this={header} on:mousedown|preventDefault={dragMouseDown}>
<h1>
{#if draggable}
<MovableIcon class="hdr-icon" />
{/if}
{title}
</h1>
{#if minimizable}
<Button class="hdrbtn" on:click={toggleMinimized}>
{#if minimized}
<ChevronDown class="hdrbtn-icon" />
{:else}
<ChevronUp class="hdrbtn-icon" />
{/if}
</Button>
{/if}
</div>
{/if}
{#if !minimized}
<slot />
{/if}
</div>
<style lang="scss">
.popup {
background-color: var(--bg-secondary-1);
padding: 1em;
height: min-content;
border-radius: 5px;
z-index: 100000;
}
:global(.hdr-icon) {
color: var(--headline);
vertical-align: middle;
display: inline-block;
width: 1rem;
height: 1rem;
margin-bottom: 0.1rem;
}
:global(.hdrbtn) {
position: absolute;
width: 2rem;
height: 2rem;
right: 1em;
top: 1em;
}
:global(.hdrbtn-icon) {
color: var(--links);
width: 1.5rem;
height: 1.5rem;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.popup :global(h1) {
margin: 0;
}
.popup :global(h2) {
margin: 0 0 0.5em;
color: var(--sub-headline);
}
.centered {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
</style>