JSFiddle - React, Tailwind, and code Playground
by Victor Alekseev
HTML
<div id="grid">
<div class="site">
<a class="link" href="#">
<span class="thumbnail" style="color:'+randomColor+'">Item 1</span>
</a>
<span class="title">Item 1</span>
</div>
<div class="site">
<a class="link" href="#">
<span class="thumbnail" style="color:'+randomColor+'">Item 2</span>
</a>
<span class="title">Item 2</span>
</div>
<div class="site">
<a class="link" href="#">
<span class="thumbnail" style="color:'+randomColor+'">Item 3</span>
</a>
<span class="title">Item 3</span>
</div>
<div class="site">
<a class="link" href="#">
<span class="thumbnail" style="color:'+randomColor+'">Item 4</span>
</a>
<span class="title">Item 4</span>
</div>
<div class="site">
<a class="link" href="#">
<span class="thumbnail" style="color:'+randomColor+'">Item 5</span>
</a>
<span class="title">Item 5</span>
</div>
</div>
CSS
#grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
grid-row-gap: 30px;
grid-column-gap: 30px;
margin: 60px 60px 60px 120px;
align-content: start;
justify-content: space-between;
}
.site {
position: relative;
width: 190px;
height: 124px;
}
.ghost {
opacity: .4;
}
.link {
display: block;
max-height: 100%;
max-width: 100%;
border-radius: 5px;
box-shadow: 0 7px 15px rgba(0,0,0,.5);
overflow: hidden;
text-decoration: none;
background: #666;
}
.thumbnail {
max-height: 100%;
max-width: 100%;
display: block;
line-height: 124px;
text-align: center;
font-size: xx-large;
font-weight: 600;
filter: invert(100%);
}
.title {
display: block;
text-align: center;
color: #eee;
padding: 10px 0 0 0;
width: 190px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 14px;
}
JavaScript
function sortable(rootEl, onUpdate){
var dragEl, nextEl;
// Делаем всех детей перетаскиваемыми
[].slice.call(rootEl.children).forEach(function (itemEl){
itemEl.draggable = true;
});
// Фнукция отвечающая за сортировку
function _onDragOver(evt){
evt.preventDefault();
evt.dataTransfer.dropEffect = 'move';
var target = evt.target;
if( target && target !== dragEl && target.nodeName == 'DIV' ){
// Сортируем
var rect = target.getBoundingClientRect();
var next = (evt.clientY - rect.top)/(rect.bottom - rect.top) > .5;
rootEl.insertBefore(dragEl, next && target.nextSibling || target);
}
}
// Окончание сортировки
function _onDragEnd(evt){
evt.preventDefault();
dragEl.classList.remove('ghost');
rootEl.removeEventListener('dragover', _onDragOver, false);
rootEl.removeEventListener('dragend', _onDragEnd, false);
if( nextEl !== dragEl.nextSibling ){
// Сообщаем об окончании сортировки
onUpdate(dragEl);
}
}
// Начало сортировки
rootEl.addEventListener('dragstart', function (evt){
dragEl = evt.target; // Запоминаем элемент который будет перемещать
nextEl = dragEl.nextSibling;
// Ограничиваем тип перетаскивания
evt.dataTransfer.effectAllowed = 'move';
evt.dataTransfer.setData('Text', dragEl.textContent);
// Пописываемся на события при dnd
rootEl.addEventListener('dragover', _onDragOver, false);
rootEl.addEventListener('dragend', _onDragEnd, false);
setTimeout(function (){
// Если выполнить данное действие без setTimeout, то
// перетаскиваемый объект, будет иметь этот класс.
dragEl.classList.add('ghost');
}, 0)
}, false);
}
// Используем
sortable(...