Slightly modified version of https://svelte.dev/repl/3bf15c868aa94743b5f1487369378cf3?version=3.21.0 :
- Used typescript & scss
- Updated some logic & styles
- Font awesome icon
Slightly modified version of https://svelte.dev/repl/3bf15c868aa94743b5f1487369378cf3?version=3.21.0 :
<script lang="ts"> | |
import { faGripLines } from '@fortawesome/free-solid-svg-icons'; | |
import Fa from 'svelte-fa'; | |
type List = $$Generic<Array<any>>; | |
export let list: List; | |
let hovering: number | null = null; | |
const drop = (event: DragEvent, target: number) => { | |
event.dataTransfer.dropEffect = 'move'; | |
const start = parseInt(event.dataTransfer.getData('text/plain')); | |
const newList = list; | |
if (start < target) { | |
newList.splice(target + 1, 0, newList[start]); | |
newList.splice(start, 1); | |
} else { | |
newList.splice(target, 0, newList[start]); | |
newList.splice(start + 1, 1); | |
} | |
list = newList; | |
hovering = null; | |
}; | |
const dragstart = (event: DragEvent, start: number) => { | |
event.dataTransfer.effectAllowed = 'move'; | |
event.dataTransfer.dropEffect = 'move'; | |
event.dataTransfer.setData('text/plain', start.toString()); | |
}; | |
</script> | |
<div class="list"> | |
{#each list as item, index (index)} | |
<div | |
class="item" | |
draggable={true} | |
on:dragstart={(event) => dragstart(event, index)} | |
on:drop|preventDefault={(event) => drop(event, index)} | |
on:dragover|preventDefault={() => {}} | |
on:dragenter={() => (hovering = index)} | |
class:active={hovering === index}> | |
<Fa icon={faGripLines} color="rgba(var(--text-rgb), 0.25)" /> | |
<slot {item} /> | |
</div> | |
{/each} | |
</div> | |
<style lang="scss"> | |
.list { | |
border: 2px solid var(--background-secondary); | |
border-radius: 12px; | |
overflow: hidden; | |
margin: 4px 0px; | |
.item { | |
display: flex; | |
align-items: center; | |
gap: 8px; | |
cursor: grab; | |
padding: 10px 14px; | |
font-size: 1.1rem; | |
font-weight: 500; | |
&:active, | |
&:focus { | |
cursor: grabbing; | |
} | |
&:not(:last-child) { | |
border-bottom: 2px solid var(--background-secondary); | |
} | |
&.active { | |
background-color: var(--primary); | |
} | |
} | |
} | |
</style> |