Skip to content

Instantly share code, notes, and snippets.

@neisdev
Created January 4, 2022 20:42
Show Gist options
  • Save neisdev/9a015b63e3c691d06c8f254bd2ecfd8a to your computer and use it in GitHub Desktop.
Save neisdev/9a015b63e3c691d06c8f254bd2ecfd8a to your computer and use it in GitHub Desktop.
Drag and drop builder
<div id="sidebar">
<h3>Template</h3>
<label><input type="radio" value="1" name="template" checked> one column</label>
<label><input type="radio" value="2" name="template"> two column</label>
<label><input type="radio" value="3" name="template"> two column w/header</label>
<label><input type="radio" value="4" name="template"> two column w/header & footer</label>
<h3>Background</h3>
<input class="color" value="#f9fafc" name="background-color" data-control="#main" data-attribute="background-color">
<h3>Frame</h3>
<label><input type="radio" value="100%" name="frame-width"> Full width</label>
<label for="custom-width"><input type="radio" value="600px" name="frame-width" checked="checked" id="custom-width"> 600px</label>
<br>
<h4>Background</h4>
<input class="color" value="#fff" name="frame-background-color" data-control=".frame-container" data-attribute="background-color">
<h4>Border</h4>
Width <select name="frame-border">
<option value="0">0</option>
<option value="1" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<br>
<br>
<input class="color" value="#B1BDC6" name="frame-frame-border-color" data-control=".frame-container" data-attribute="border-color">
</div>
<div id="main">
<div class="frame-container">
<div class="frame">
</div>
</div>
</div>
<div class="right-sidebar">
<h3>Elements</h3>
<div id="A" class="list-group">
<div class="list-group-item heading">
<span class="title">Heading</span>
<div class="edit-area">
<h1>Heading 1</h1>
</div>
<span class="drag-handle"></span>
<a class="delete" href="#"></a>
</div>
<div class="list-group-item paragraph">
<span class="title">Paragraph</span>
<div class="edit-area">
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Architecto voluptatum eveniet fugiat iste neque, nemo error ratione animi adipisci minus iusto pariatur tempore quibusdam obcaecati ut odit. Voluptatibus, explicabo excepturi.</p>
</div>
<span class="drag-handle"></span>
<a class="delete" href="#"></a>
</div>
<div class="list-group-item border">
<span class="title">Divider</span>
<hr>
<span class="drag-handle"></span>
<a class="delete" href="#"></a>
</div>
<div class="list-group-item button">
<span class="title">Button</span>
<a class="button">Button</a>
<span class="drag-handle"></span>
<a class="delete" href="#"></a>
</div>
<div class="list-group-item image">
<span class="title">Image</span>
<img src="//via.placeholder.com/600x150">
<span class="drag-handle"></span>
<a class="delete" href="#"></a>
</div>
</div>
<div class="controls">
<a href="#" class="control-close">X</a>
<div class="button-controls">
<h3>Edit Button</h3>
<h4>Background</h4>
<label><input type="radio" value="ffffff" name="button-background-color"> white</label>
<label><input type="radio" value="ff0000" name="button-background-color"> red</label>
<label><input type="radio" value="0000ff" name="button-background-color"> blue</label>
<label><input type="radio" value="00ff00" name="button-background-color"> green</label>
<label><input type="radio" value="000000" name="button-background-color"> black</label>
<h4>Text Color</h4>
<label><input type="radio" value="ffffff" name="button-text-color" checked> white</label>
<label><input type="radio" value="ff0000" name="button-text-color"> red</label>
<label><input type="radio" value="0000ff" name="button-text-color"> blue</label>
<label><input type="radio" value="00ff00" name="button-text-color"> green</label>
<label><input type="radio" value="000000" name="button-text-color"> black</label>
<br>
<br>
<label for="button-text">Text</label>
<input name="button-text" type="text" value="Button">
<br>
<label for="button-link">Link</label>
<input name="button-link" type="text" placeholder="https://app.mobilecause.com">
<br>
<h4>Button Size</h4>
<label><input type="radio" value="big" name="button-size"> big</label>
<label><input type="radio" value="medium" name="button-size" checked> medium</label>
<label><input type="radio" value="small" name="button-size"> small</label>
<h4>Button Align</h4>
<label><input type="radio" value="left" name="button-align"> left</label>
<label><input type="radio" value="center" name="button-align" checked> center</label>
<label><input type="radio" value="right" name="button-align"> right</label>
</div>
<div class="image-controls">
<h3>Edit Image</h3>
<label for="image-url">Image URL</label>
<input name="image-url" type="text" placeholder="http://via.placeholder.com/600x150">
<p>ex: https://source.unsplash.com/random/600x150</p>
<h4>Image Size</h4>
<label><input type="radio" value="600px" name="img-width" checked> full</label>
<label><input type="radio" value="400px" name="img-width"> big</label>
<label><input type="radio" value="300px" name="img-width"> medium</label>
<label><input type="radio" value="200px" name="img-width"> small</label>
</div>
<div class="border-controls">
<h3>Edit Divider</h3>
<label for="border-thickness">Thickness</label>
<select name="border-thickness">
<option value="1" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
<h4>Divider Color</h4>
<label><input type="radio" value="ffffff" name="border-color"> white</label>
<label><input type="radio" value="ff0000" name="border-color"> red</label>
<label><input type="radio" value="0000ff" name="border-color"> blue</label>
<label><input type="radio" value="00ff00" name="border-color"> green</label>
<label><input type="radio" value="000000" name="border-color" checked> black</label>
<h4>Divider Style</h4>
<label><input type="radio" value="solid" name="border-style" checked> solid</label>
<label><input type="radio" value="dashed" name="border-style"> dashed</label>
<label><input type="radio" value="dotted" name="border-style"> dotted</label>
<label><input type="radio" value="double" name="border-style"> double</label>
</div>
</div>
</div>
var itemEl; //container for elements
var frameContent = '';
//change the template
$('input[name="template"]').change(function() {
$('.frame').each(function() {
frameContent += $(this).html();
console.log(frameContent);
});
if ($(this).val() == 1) {
$('.frame-container').html('<div class="frame">'+frameContent+'</div>');
initSortable('.frame');
} else if ($(this).val() == 2) {
$('.frame-container').html('<div class="frame half">'+frameContent+'</div><div class="frame half"></div>');
initSortable('.frame');
} else if ($(this).val() == 3) {
$('.frame-container').html('<div class="frame header">'+frameContent+'</div><div class="frame half"></div><div class="frame half"></div>');
initSortable('.frame');
} else if ($(this).val() == 4) {
$('.frame-container').html('<div class="frame header">'+frameContent+'</div><div class="frame half"></div><div class="frame half"></div><div class="frame footer"></div>');
initSortable('.frame');
}
tinymce.init({
selector: '.edit-area',
inline: true
});
frameContent = '';
});
//change the frame border
$('select[name="frame-border"]').change(function() {
$('.frame-container').css('border-width', $(this).val());
});
//change the frame width
$('input[name="frame-width"]').change(function() {
$('.frame-container').css('width', $(this).val());
});
//update the button background color
$('input[name="button-background-color"]').change(function() {
$('#'+$('.button-controls').attr('data-editing')+' a.button').css('background-color', '#'+$(this).val());
});
//update the button text color
$('input[name="button-text-color"]').change(function() {
$('#'+$('.button-controls').attr('data-editing')+' a.button').css('color', '#'+$(this).val());
});
//update the button text
$('input[name="button-text"]').on('keyup', function() {
$('#'+$('.button-controls').attr('data-editing')+' a.button').text($(this).val());
});
//update the button size
$('input[name="button-size"]').change(function() {
var buttonPadding, buttonSize;
if ($(this).val() == 'big') {
buttonPadding = '16px 48px';
buttonSize = '24px';
} else if ($(this).val() == 'medium') {
buttonPadding = '8px 24px';
buttonSize = '16px';
} else if ($(this).val() == 'small') {
buttonPadding = '4px 12px';
buttonSize = '12px';
}
$('#'+$('.button-controls').attr('data-editing')+' a.button').css({
'padding': buttonPadding,
'font-size': buttonSize
});
});
//update the button text color
$('input[name="button-align"]').change(function() {
$('#'+$('.button-controls').attr('data-editing')).css('text-align', $(this).val());
});
//update the image url
$('input[name="image-url"]').on('keyup', function() {
$('#'+$('.image-controls').attr('data-editing')+' img').attr('src', $(this).val());
});
//update the image size
$('input[name="img-width"]').change(function() {
$('#'+$('.image-controls').attr('data-editing')+' img').css('max-width', $(this).val());
});
//update the border size
$('select[name="border-thickness"]').change(function() {
$('#'+$('.border-controls').attr('data-editing')+' hr').css('border-width', $(this).val());
});
//update the border style
$('input[name="border-style"]').change(function() {
$('#'+$('.border-controls').attr('data-editing')+' hr').css('border-bottom-style', $(this).val());
});
//change the frame border color
$('input[name="border-color"]').change(function() {
$('#'+$('.border-controls').attr('data-editing')+' hr').css('border-bottom-color', '#'+$(this).val());
});
$('.frame-container').on('click', '.delete', function() {
$(this).closest('.list-group-item').remove();
return false;
});
Sortable.create(A, {
animation: 200,
group: {
name: "shared",
pull: "clone",
put: false,
revertClone: true,
},
sort: false,
ghostClass: 'ghost'
});
initSortable('.frame');
function initSortable(element) {
$(element).each(function(i,e) {
var sortable = Sortable.create(e, {
animation: 200,
group: {
name: "shared",
//pull: false
},
sort: true,
dragClass: 'dragging',
handle: '.drag-handle',
ghostClass: 'ghost',
onAdd: function(evt) {
itemEl = evt.item;
itemEl.id = 'item-'+elementCount;
if (itemEl.className.indexOf('border') == -1 && itemEl.className.indexOf('button') == -1 && itemEl.className.indexOf('image') == -1) {
tinymce.init({
selector: '.edit-area',
inline: true
});
}
++elementCount;
$('.frame .list-group-item').find('.title').remove();
}
});
});
};
var elementCount = 0;
$('.frame-container').on('click', '.button', function() {
openControls();
$('.button-controls').show().attr('data-editing', $(this).attr('id'));
});
$('.frame-container').on('click', '.image', function() {
openControls();
$('.image-controls').show().attr('data-editing', $(this).attr('id'));
});
$('.frame-container').on('click', '.border', function() {
openControls();
$('.border-controls').show().attr('data-editing', $(this).attr('id'));
});
$('.control-close').click(function() {
$('.controls').removeClass('open');
return false;
})
function closeControls() {
$('.button-controls, .image-controls, .border-controls').hide().removeAttr('data-editing');
$('.controls').removeClass('open');
}
function openControls() {
closeControls();
$('.controls').addClass('open');
}
$('.color').colorPicker({
renderCallback: function($elm, toggled) {
$($elm.attr('data-control')).css($elm.attr('data-attribute'), this.color.toString());
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.6.0/Sortable.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cloud.tinymce.com/stable/tinymce.min.js?apiKey=qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tinyColorPicker/1.1.1/jqColorPicker.min.js"></script>
body {
font-family: Helvetica;
padding: 0;
margin: 0;
}
.color {
width: 30px;
height: 30px;
border-radius: 100%;
border: none;
color: transparent;
overflow: hidden;
border: 1px solid #ccc;
text-indent: 100px;
cursor: pointer;
}
label {
display: inline-block;
margin-right: 10px;
margin-bottom: 4px;
}
input[type="text"] {
display: block;
padding: 4px 8px;
border-radius: 3px;
border: 1px solid #B1BDC6;
font-size: 16px;
line-height: 1.5;
box-sizing: border-box;
width: 100%;
}
#sidebar {
background-color: #fff;
border-right: 1px solid #D6DCE0;
width: 25%;
height: 100vh;
float: left;
box-sizing: border-box;
padding: 20px;
}
#main {
background: #f9fafc;
width: 50%;
height: 100vh;
float: left;
transition: all 0.2s ease;
&.right-open {
width: 50%;
}
}
.frame-container {
width: 600px;
background-color: #fff;
border: 1px solid #B1BDC6;
margin: 60px auto;
border-radius: 3px;
padding: 20px;
overflow: hidden;
}
.frame {
border: 2px dashed #D6DCE0;
min-height: 300px;
box-sizing: border-box;
&.half {
float: left;
width: 50%;
}
&.header,
&.footer {
clear: left;
min-height: 100px;
}
.list-group-item {
padding: 0;
outline: 2px dashed #D6DCE0;
border: none;
margin: 20px 0;
position: relative;
&:hover {
.drag-handle {
right: 10px;
opacity: 1;
}
.delete {
opacity: 1;
right: 44px;
}
}
&.ghost {
height: 0;
outline: 0;
border-top: 4px solid #2EA3F2;
margin: 10px 0;
overflow: hidden;
.drag-handle {
right: 10px;
opacity: 1;
}
}
.drag-handle,
.delete {
position: absolute;
display: block;
height: 24px;
width: 24px;
background: #FFB459;
top: 5px;
right: 0;
border-radius: 15px;
opacity: 0;
transition: all 0.2s ease;
&:hover {
cursor: move;
}
}
.delete {
background-color: #f00;
right: 34px;
cursor: pointer !important;
}
.title {
display: none;
}
&.border {
padding: 4px 0;
}
}
.border hr {
border: 0;
border-bottom: 1px solid #000;
}
.button {
text-align: center;
}
.button a.button {
display: inline-block;
padding: 8px 24px;
font-size: 16px;
color: #fff;
background: #2EA3F2;
border-radius: 3px;
margin: 0 auto;
text-align: center;
text-decoration: none;
}
.image img {
width: 100%;
max-width: 600px;
display: block;
margin: 0 auto;
}
}
.list-group-item {
padding: 8px;
border: 1px solid #D6DCE0;
margin-bottom: 10px;
&:hover {
background: #eee;
}
&.ghost {
opacity: 0.5;
* {
display: block;
}
.title {
display: none;
}
}
}
.dragging {
opacity: 1;
}
.right-sidebar {
position: relative;
background-color: #fff;
width: 25%;
padding: 20px;
height: 100vh;
float: left;
box-sizing: border-box;
border-left: 1px solid #D6DCE0;
.list-group-item {
opacity: 1;
.title {
display: block;
}
* {
display: none;
}
}
}
.controls {
position: absolute;
top: 0;
right: -100%;
width: 0;
box-sizing: border-box;
transition: right 0.2s ease;
height: 100vh;
background: #fff;
overflow: scroll;
padding: 20px;
width: 100%;
.control-close {
float: right;
display: block;
font-weight: bold;
font-size: 18px;
height: 18px;
width: 18px;
padding: 10px;
border-radius: 50px;
text-align: center;
line-height: 1;
background: #eee;
color: #000;
text-decoration: none;
}
&.open {
right: 0;
}
}
.button-controls,
.image-controls,
.border-controls {
display: none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment