Sortable and Resizable Dashboard Zones
Using DIVS to implement dashboard zones.
by humanzing
HTML
<div id="outer">
<table id="sortable">
<tr>
<td>
<div class="span6 zone">a</div>
<div class="span6 zone">bb</div>
<div class="span6 zone">ccc</div>
<div class="span6 zone">ddd</div>
<div class="span6 zone">eeee</div>
<div class="span6 zone">fffff</div>
<div class="span6 zone">gggggg</div>
</td>
</tr>
</table>
</div>
CSS
@import url('https://fonts.googleapis.com/css?family=Baloo+Da&display=swap');
:root {
--widget-bg: #777;
--zone-bg: #252525;
--zone-bord: #000;
--placeholder: rgba(0, 0, 0, 0.5);
--no-drag: rgba(100, 100, 100, 0.2);
--wig-color: #222;
}
.widget-holder-label {
position: absolute;
color: white;
font-weight: bold;
top: 5px;
right: 10px;
width: 208px;
}
.widget-holder {
position: absolute;
right: 10px;
top: 30px;
width: 208px;
height: 200px;
background: #333;
border-radius: 5px;
overflow-y: scroll;
}
.widget-holder .ui-sortable-placeholder {
visibility: hidden !important;
}
.widget-holder .fg-widget {
height: 100px;
width: 100px;
position: relative;
display: inline-block;
float: left;
}
.custom-widget .fg-widget-inner {
background: #e04c8a;
}
.inner-icon {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-size: 30px;
}
.fg-widget-handle {
cursor: move;
}
.fg-nested-container {
width: 100%;
height: 100%;
}
.move-widget {
position: absolute;
left: 10px;
top: 10px;
color: #222;
z-index: 9;
}
.line1, .line2 {
position: absolute;
top: 0;
bottom: 0;
width: 1px;
background: red;
}
.line2 {
background: blue;
}
.zone_div {
width: 100%;
}
.flexgrid-container {
position: absolute;
left: 50%;
top: 0;
transform: translate(-50%, 0);
background: var(--zone-bg);
border: 2px solid var(--zone-bord);
}
.flexgrid-container * {
user-select: none;
}
.add-row, .remove-row {
position: absolute;
left: 10px;
top: 10px;
cursor: pointer;
height: 30px;
width: 30px;
border-radius: 50%;
background: #fff;
border: 2px solid #222;
}
.remove-row {
left: 50px;
}
.add-row::after, .remove-row::after {
font-family: 'Font Awesome 5 Free';
font-weight: 900;
content: "\f067";
display: inline-block;
color: #222;
z-index: 1;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
.remove-row::after {
content: "\f068";
}
body {
background: #111;
padding-bottom: 50px;
}
.btn...
JavaScript
$(function() {
// grid/zone refers to the container
// widget refers to the blocks within a grid/zone
// TODO:
// - resize axis
// - redo save widget functionality to fit plugin system
// - fix placeholder position, currently follows mouse rather than widget
// - optional size / position values passed with widgets from widget holder
// - add nested functionality
// - - optional height passed with nested widget to push other widgets down
// - widgets from html
$.fn.setFlexGrid = function(options) {
var defaults = { // default options for grid
cols: 12, // starting amount of columns across a grid
rows: 12, // starting amount of rows in a grid
fixedGrid: false, // determines whether the grid can be resized or not (adding more rows)
defaultHeight: 3, // amount of rows a widget will span upon creation
defaultWidth: 3, // amount of columns a widget will span upon creation
minHeight: 1, // minimum number of rows a widget can span ~ should be <= defaultHeight
maxHeight: null, // if set to numeric value: maximum number of rows a widget can span
minWidth: 1, // minimum number of columns a widget can span ~ should be <= defaultWidth
maxWidth: null, // if set to numeric value: maximum number of columns a widget can span
rowHeight: 1, // value times column width
nested: true, // if true, widgets will allow nested widget to be dropped into them
showGridlines: true, // if true, show gridlines on initialization
animate: true, // determines wether or not the widgets should be animated
nextAxis: 'x', // determines which axis the widget should find an open column. When X: widget will go to the first open column. When Y: widget will go to the first row that has an open column of x.
resizeHandles: 'se', // determines resize handles (n, e, s, w, ne, se, sw, nw, all) ~ default is "se"
checkRevert: false // if widget cannot be dropped in pos (going to revert) because of minWidth / minHeight, placeholder will turn...