Updated to work with live site Added components from somewhere fixed some css background image
This commit is contained in:
parent
faf1fb29b8
commit
a046f7c3f2
16 changed files with 885 additions and 4 deletions
249
src/components/SortableList.svelte
Normal file
249
src/components/SortableList.svelte
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
<script>
|
||||
|
||||
import {quintOut} from "svelte/easing";
|
||||
import {crossfade} from "svelte/transition";
|
||||
import {flip} from "svelte/animate";
|
||||
// FLIP ANIMATION
|
||||
const [send, receive] = crossfade({
|
||||
duration: d => Math.sqrt(d * 200),
|
||||
fallback(node, params) {
|
||||
const style = getComputedStyle(node);
|
||||
const transform = style.transform === "none" ? "" : style.transform;
|
||||
return {
|
||||
duration: 600,
|
||||
easing: quintOut,
|
||||
css: t => `
|
||||
transform: ${transform} scale(${t});
|
||||
opacity: ${t}
|
||||
`
|
||||
};
|
||||
}
|
||||
});
|
||||
// DRAG AND DROP
|
||||
let isOver = false;
|
||||
let isDragging = false;
|
||||
const getDraggedParent = (node) => {
|
||||
return node.dataset && node.dataset.index
|
||||
? node.dataset
|
||||
: getDraggedParent(node.parentNode)
|
||||
};
|
||||
const click = ev => {
|
||||
dispatch("slotclick", {
|
||||
source: ev.target.parentElement.dataset.index,
|
||||
sourceItem: list[ev.target.parentElement.dataset.index]
|
||||
});
|
||||
};
|
||||
const start = ev => {
|
||||
isDragging = true;
|
||||
ev.dataTransfer.setData("source", ev.target.dataset.index);
|
||||
};
|
||||
const over = ev => {
|
||||
ev.preventDefault();
|
||||
let dragged = getDraggedParent(ev.target);
|
||||
if (isOver !== dragged.id) isOver = JSON.parse(dragged.id);
|
||||
};
|
||||
const leave = ev => {
|
||||
let dragged = getDraggedParent(ev.target);
|
||||
if (isOver === dragged.id) isOver = false;
|
||||
};
|
||||
const drop = ev => {
|
||||
isOver = false;
|
||||
ev.preventDefault();
|
||||
let dragged = getDraggedParent(ev.target);
|
||||
let from = ev.dataTransfer.getData("source");
|
||||
let to = dragged.index;
|
||||
reorder({from, to});
|
||||
isDragging = false;
|
||||
};
|
||||
// DISPATCH REORDER
|
||||
import {createEventDispatcher, onMount, afterUpdate, beforeUpdate, tick} from "svelte";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const reorder = ({from, to}) => {
|
||||
let newList = [...list];
|
||||
let temp = newList[from];
|
||||
newList[from] = newList[to];
|
||||
newList[to] = temp;
|
||||
//newList[from] = [newList[to], (newList[to] = newList[from])][0];
|
||||
dispatch("sort", {data: newList, from: from, to: to});
|
||||
};
|
||||
// UTILS
|
||||
const getKey = item => (key ? item[key] : item);
|
||||
// PROPS
|
||||
export let list;
|
||||
export let key;
|
||||
export let ulclass;
|
||||
|
||||
export let breakon;
|
||||
|
||||
export let breakComponent;
|
||||
// return `<><li class='${breakClass}' style='height:100%; grid-column: span 5;'><div style='width:100%;height:inherit;'></li>`;
|
||||
|
||||
// export let breakPosition = "beforebegin";
|
||||
let breakClass = "group-break";
|
||||
|
||||
const Elements = () => document.getElementsByClassName(key);
|
||||
|
||||
const removeOldBreaks = (parent) => {
|
||||
if (breakon == null) return;
|
||||
if (isDragging) return;
|
||||
|
||||
if (parent.length) {
|
||||
const old = parent[0].getElementsByClassName(breakClass);
|
||||
|
||||
for (let i = 0; i < old.length; i = 0) {
|
||||
old[i].remove(); // removing the node from the DOM also removes it from this array (WTF??)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let lastCollection;
|
||||
|
||||
let updatingBreakPoints = false;
|
||||
|
||||
const updateBreak = () => {
|
||||
if (isDragging || updatingBreakPoints) return;
|
||||
if (breakon == null) return;
|
||||
|
||||
try {
|
||||
updatingBreakPoints = true;
|
||||
|
||||
let breaks = 0;
|
||||
let last = null;
|
||||
let carry = 0;
|
||||
let elements = Elements();
|
||||
|
||||
|
||||
for (let x = 0; x < list.length; x++) {
|
||||
|
||||
if (last != null) {
|
||||
if (list[x][breakon] > last) {
|
||||
|
||||
if (elements.length) {
|
||||
let targetIndex = x + breaks;
|
||||
|
||||
if (list.length !== elements[0].children.length - breaks) {
|
||||
if (lastCollection)
|
||||
if (lastCollection.length)
|
||||
targetIndex += lastCollection.length;
|
||||
}
|
||||
// elements[0].children[targetIndex].insertAdjacentHTML(breakPosition, breakHtml(carry + 1));
|
||||
breaks++;
|
||||
carry = 0;
|
||||
}
|
||||
} else {
|
||||
carry++;
|
||||
}
|
||||
}
|
||||
|
||||
last = list[x][breakon] > last ? list[x][breakon] : last;
|
||||
}
|
||||
|
||||
lastCollection = list;
|
||||
} finally {
|
||||
updatingBreakPoints = false;
|
||||
}
|
||||
};
|
||||
|
||||
//beforeUpdate(() => {updateBreak()});
|
||||
|
||||
let updating = false;
|
||||
|
||||
afterUpdate(async () => {
|
||||
if (isDragging) return;
|
||||
if (breakon == null) return;
|
||||
|
||||
updating = true;
|
||||
removeOldBreaks(Elements());
|
||||
await tick();
|
||||
updateBreak();
|
||||
|
||||
updating = false;
|
||||
|
||||
});
|
||||
|
||||
const getClass = () => {
|
||||
let ret = "";
|
||||
if (key)
|
||||
ret += ` ${key}`;
|
||||
if (ulclass)
|
||||
ret += ` ${ulclass}`;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
ul {
|
||||
display: inline-grid;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
border: 2px dotted transparent;
|
||||
transition: border 0.1s linear;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: .5%;
|
||||
}
|
||||
|
||||
.startsNewGroup {
|
||||
grid-column-start: 1;
|
||||
}
|
||||
|
||||
.small {
|
||||
grid-column-end: span 1;
|
||||
grid-row: span 1;
|
||||
}
|
||||
|
||||
.medium {
|
||||
grid-column-end: span 2;
|
||||
grid-row: span 1;
|
||||
}
|
||||
|
||||
.large {
|
||||
grid-column-end: span 2;
|
||||
/*grid-row: span 2; large buttons are double height, but they also push the row below them down (they dont fit around eachother like css-grid) */
|
||||
}
|
||||
|
||||
.over {
|
||||
border-color: rgba(48, 12, 200, 0.2);
|
||||
}
|
||||
</style>
|
||||
|
||||
{#if list && list.length}
|
||||
<ul class={getClass()}>
|
||||
{#each list as item, index (getKey(item))}
|
||||
<li
|
||||
class:small={item.displayTileSize === 2}
|
||||
class:medium={item.displayTileSize === 3}
|
||||
class:large={item.displayTileSize === 4}
|
||||
class:startsNewGroup={item.startsNewGroup}
|
||||
class:endsGroup={item.endsGroup}
|
||||
data-index={index}
|
||||
data-item={JSON.stringify(item)}
|
||||
data-id={JSON.stringify(getKey(item))}
|
||||
draggable="true"
|
||||
on:dragstart={start}
|
||||
on:dragover={over}
|
||||
on:dragleave={leave}
|
||||
on:drop={drop}
|
||||
on:click={click}
|
||||
in:receive={{ key: getKey(item) }}
|
||||
out:send={{ key: getKey(item) }}
|
||||
animate:flip={{ duration: 300 }}
|
||||
class:over={getKey(item) === isOver}>
|
||||
|
||||
<slot {item} {index}>
|
||||
<p>{getKey(item)}</p>
|
||||
</slot>
|
||||
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
Loading…
Reference in a new issue