A Pen by Nels Setterlund on CodePen.
Created
January 4, 2022 20:42
-
-
Save neisdev/9a015b63e3c691d06c8f254bd2ecfd8a to your computer and use it in GitHub Desktop.
Drag and drop builder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()); | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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