TierList - Drag and drop
<!DOCTYPE html><html lang="en">    <head>        <meta charset="UTF-8" />        <meta name="viewport" content="width=device-width, initial-scale=1.0" />        <title>Tier Maker</title>        <style>            :root {                --color-s: #ff7f80;                --color-a: #ffc07f;                --color-b: #ffdf80;                --color-c: #fdff7f;                --color-d: #bfff7f;                --color-e: #7fff7f;            }
            *, /* CSS Reset */            *::before,            *::after {                box-sizing: border-box;            }
            button {                /* CSS Reset */                background: transparent;                border: 0;                color: #fff;                cursor: pointer;            }
            body {                background: #111;                color: #fff;                font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,                    'Open Sans', 'Helvetica Neue', sans-serif;                margin: 0 auto;                max-width: 500px;                padding-inline: 32px; /* Padding left and right */                user-select: none; /* Disable text selection */            }
            #top-header {                display: flex;                justify-content: center;                align-items: center;                padding: 32px 0 16px;
                & img {                    max-width: 125px;                    height: auto;                }            }
            .tier {                border: 1px solid #444;                display: flex;                flex-direction: column;                background: #1f1f1f;            }
            .row {                display: flex;                flex-direction: row;                border-bottom: 1px solid #111;                transition: all 0.3s ease;
                &.drag-over {                    background: #555;                    scale: 1.01;                }            }
            .label {                cursor: pointer;                background: var(--level, #09f);                color: #333;                font-weight: bold;                width: 50px;                height: 50px;
                display: flex;                align-items: center;                justify-content: center;
                & span:focus {                    outline: 1px solid #fff;                }            }
            #selector {                display: flex;                flex-direction: column;                align-items: center;                gap: 16px;                margin-top: 16px;            }
            #selector-buttons {                display: flex;                gap: 8px;                justify-content: center;
                & button,                & label {                    cursor: pointer;                    transition: all 0.3s ease;                    background: #222;                    display: flex;                    justify-content: center;                    align-items: center;                    width: 24px;                    height: 24px;                    padding: 4px;
                    &:hover {                        background: #444;                        scale: 1.1;                    }                }
                & svg {                    width: 100%;                    height: 100%;                }            }
            #selector-items {                border: 1px solid #666;                width: 100%;                height: 100px;                margin-bottom: 100px;                display: flex;                flex-wrap: wrap;
                &.drag-files {                    background: #555;                    border-style: dashed;                }            }
            .item-image {                width: 50px;                height: 50px;                object-fit: cover;                background: #fff;                cursor: grab;
                &.drag-preview {                    opacity: 0.5;                    pointer-events: none;                }            }        </style>
        <script type="module">            const $ = (el) => document.querySelector(el) // Helper function to select elements            const $$ = (el) => document.querySelectorAll(el) // Helper function to select multiple elements
            const imageInput = $('#image-input')            const itemsSection = $('#selector-items')            const resetButton = $('#reset-tier-button')            const saveButton = $('#save-tier-button')
            function createItem(src) {                const imgElement = document.createElement('img')                imgElement.draggable = true                imgElement.src = src                imgElement.className = 'item-image'
                imgElement.addEventListener('dragstart', handleDragStart)                imgElement.addEventListener('dragend', handleDragEnd)
                itemsSection.appendChild(imgElement)                return imgElement            }
            function useFilesToCreateItems(files) {                if (files && files.length > 0) {                    Array.from(files).forEach((file) => {                        const reader = new FileReader()
                        reader.onload = (eventReader) => {                            createItem(eventReader.target.result)                        }
                        reader.readAsDataURL(file)                    })                }            }
            imageInput.addEventListener('change', (event) => {                const { files } = event.target                useFilesToCreateItems(files)            })
            let draggedElement = null            let sourceContainer = null
            const rows = $$('.tier .row')
            rows.forEach((row) => {                row.addEventListener('dragover', handleDragOver)                row.addEventListener('drop', handleDrop)                row.addEventListener('dragleave', handleDragLeave)            })
            itemsSection.addEventListener('dragover', handleDragOver)            itemsSection.addEventListener('drop', handleDrop)            itemsSection.addEventListener('dragleave', handleDragLeave)
            itemsSection.addEventListener('drop', handleDropFromDesktop)            itemsSection.addEventListener('dragover', handleDragOverFromDesktop)
            function handleDragOverFromDesktop(event) {                event.preventDefault()
                const { currentTarget, dataTransfer } = event
                if (dataTransfer.types.includes('Files')) {                    currentTarget.classList.add('drag-files')                }            }
            function handleDropFromDesktop(event) {                event.preventDefault()                const { currentTarget, dataTransfer } = event
                if (dataTransfer.types.includes('Files')) {                    currentTarget.classList.remove('drag-files')                    const { files } = dataTransfer                    useFilesToCreateItems(files)                }            }
            function handleDrop(event) {                event.preventDefault()
                const { currentTarget, dataTransfer } = event
                if (sourceContainer && draggedElement) {                    sourceContainer.removeChild(draggedElement)                }
                if (draggedElement) {                    const src = dataTransfer.getData('text/plain')                    const imgElement = createItem(src)                    currentTarget.appendChild(imgElement)                }
                currentTarget.classList.remove('drag-over')                currentTarget.querySelector('.drag-preview')?.remove()            }
            function handleDragOver(event) {                event.preventDefault()
                const { currentTarget, dataTransfer } = event                if (sourceContainer === currentTarget) return
                currentTarget.classList.add('drag-over')
                const dragPreview = document.querySelector('.drag-preview')
                if (draggedElement && !dragPreview) {                    const previewElement = draggedElement.cloneNode(true)                    previewElement.classList.add('drag-preview')                    currentTarget.appendChild(previewElement)                }            }
            function handleDragLeave(event) {                event.preventDefault()
                const { currentTarget } = event                currentTarget.classList.remove('drag-over')                currentTarget.querySelector('.drag-preview')?.remove()            }
            function handleDragStart(event) {                draggedElement = event.target                sourceContainer = draggedElement.parentNode                event.dataTransfer.setData('text/plain', draggedElement.src)            }
            function handleDragEnd(event) {                draggedElement = null                sourceContainer = null            }
            resetButton.addEventListener('click', () => {                const items = $$('.tier .item-image')                items.forEach((item) => {                    item.remove()                    itemsSection.appendChild(item)                })            })
            saveButton.addEventListener('click', () => {                const tierContainer = $('.tier')                const canvas = document.createElement('canvas')                const ctx = canvas.getContext('2d')
                import('https://cdn.jsdelivr.net/npm/html2canvas-pro@1.5.8/+esm').then(({ default: html2canvas }) => {                    html2canvas(tierContainer).then((canvas) => {                        ctx.drawImage(canvas, 0, 0)                        const imgURL = canvas.toDataURL('image/png')
                        const downloadLink = document.createElement('a')                        downloadLink.download = 'tier.png'                        downloadLink.href = imgURL                        downloadLink.click()                    })                })            })        </script>    </head>
    <body>        <header id="top-header">            <img src="https://tiermaker.com/images/tiermaker-logo.png" />        </header>
        <section class="tier">            <div class="row">                <aside class="label" style="--level: var(--color-s)">                    <span contenteditable="true">S</span>                </aside>            </div>
            <div class="row">                <aside class="label" style="--level: var(--color-a)">                    <span contenteditable="true">A</span>                </aside>            </div>
            <div class="row">                <aside class="label" style="--level: var(--color-b)">                    <span contenteditable="true">B</span>                </aside>            </div>
            <div class="row">                <aside class="label" style="--level: var(--color-c)">                    <span contenteditable="true">C</span>                </aside>            </div>
            <div class="row">                <aside class="label" style="--level: var(--color-d)">                    <span contenteditable="true">D</span>                </aside>            </div>
            <div class="row">                <aside class="label" style="--level: var(--color-e)">                    <span contenteditable="true">E</span>                </aside>            </div>        </section>
        <footer id="selector">            <section id="selector-buttons">                <label>                    <svg                        xmlns="http://www.w3.org/2000/svg"                        width="24"                        height="24"                        viewBox="0 0 24 24"                        fill="none"                        stroke="currentColor"                        stroke-width="1"                        stroke-linecap="round"                        stroke-linejoin="round">                        <path stroke="none" d="M0 0h24v24H0z" fill="none" />                        <path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" />                        <path d="M9 12h6" />                        <path d="M12 9v6" />                    </svg>                    <input multiple accept="image/*" id="image-input" type="file" hidden />                </label>
                <button id="reset-tier-button">                    <svg                        xmlns="http://www.w3.org/2000/svg"                        width="24"                        height="24"                        viewBox="0 0 24 24"                        fill="none"                        stroke="currentColor"                        stroke-width="1"                        stroke-linecap="round"                        stroke-linejoin="round">                        <path stroke="none" d="M0 0h24v24H0z" fill="none" />                        <path d="M4.05 11a8 8 0 1 1 .5 4m-.5 5v-5h5" />                    </svg>                </button>
                <button id="save-tier-button">                    <svg                        xmlns="http://www.w3.org/2000/svg"                        width="24"                        height="24"                        viewBox="0 0 24 24"                        fill="none"                        stroke="currentColor"                        stroke-width="1"                        stroke-linecap="round"                        stroke-linejoin="round"                        class="icon icon-tabler icons-tabler-outline icon-tabler-device-floppy">                        <path stroke="none" d="M0 0h24v24H0z" fill="none" />                        <path d="M6 4h10l4 4v10a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2" />                        <path d="M12 14m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />                        <path d="M14 4l0 4l-6 0l0 -4" />                    </svg>                </button>            </section>
            <section id="selector-items"></section>        </footer>    </body></html>