JSFiddle - React, Tailwind, and code Playground
Modkit Position Framework
by nilloc
HTML
<modkit-container id="editor" row="1" col="1">
<modkit-container id="toolbar" row="1" col="n">
<modkit-container id="controls" row="1" col="n">
<modkit-container data-type="button" id="play" class="icon"><span class="fa fa-play"></span></modkit-container>
<modkit-container data-type="button" id="pause" class="icon"><span class="fa fa-pause"></span></modkit-container>
<modkit-container data-type="button" id="stop" class="icon"><span class="fa fa-stop"></span></modkit-container>
<modkit-container data-type="button" id="board-select" row="1" col="n">
<modkit-container data-type="button" id="download" class="icon">
<span class="fa fa-download"></span>
</modkit-container>
<modkit-container id="board-image"></modkit-container>
<modkit-container id="board-name">
<span id="robot-name">V.A.R.</span><span id="slot-name">Slot 1</span></modkit-container>
<modkit-container data-type="button" id="board-select-dropdown" class="icon">
<span class="fa fa-chevron-down"></span>
</modkit-container>
</modkit-container>
<!-- end of board-select -->
</modkit-container>
<!-- end of controls -->
<modkit-container id="spacer1"></modkit-container>
<modkit-container id="project-name-holder" row="1" col="n">
<modkit-container data-type="input" id="project-name" contenteditable="true">PLTW Project</modkit-container>
<modkit-container data-type="button" id="project-dropdown" class="icon" contenteditable="false"><span class="fa fa-chevron-down"></span></modkit-container>
</modkit-container>
<modkit-container id="spacer2"></modkit-container>
<modkit-container id="view-tabs" row="1" col="n">
<modkit-container data-type="button" id="hardware-tab" class="tab-button " row="1" col="n">
<!-- <modkit-container id="hardware-tab-icon"...
CSS
/* Framework Styles */
*,
*::before,
*::after
{box-sizing:border-box;}
modkit-container{
display:block;
position:relative;
user-select:none;
overflow:hidden;
}
modkit-style{
display:none;
}
/* stack */
modkit-container[row="1"][col="1"] > *{
position:absolute;
}
/* horizonal and vertical containers*/
modkit-container[row="1"][col="n"], modkit-container[col="1"][row="n"]{
display: flex;
flex-wrap: nowrap;
}
modkit-container[row="1"][col="n"]{
flex-direction: row;
}
modkit-container[col="1"][row="n"]{
flex-direction: column;
}
modkit-container[data-type="button"]{
cursor:pointer;
transition: all 200ms;
}
modkit-container[data-type="button"]:hover{
opacity:0.7;
}
/* editor styles */
anchor{
display:none;
position:absolute;
height:20px;
width:100px;
background:white;
border:1px solid darkgray;
border-radius:4px;
text-align:center;
outline: none;
overflow:hidden;
}
anchor.top, anchor.bottom, anchor.height, anchor.width{left:calc(50% - 50px);}
anchor.left, anchor.right{top:calc(50% - 20px);}
anchor.top, anchor.left, anchor.right{border-radius:0 0 4px 4px;}
anchor.top{top:0;}
anchor.bottom{bottom:0; border-radius:4px 4px 0 0;}
anchor.left{ left:-40px; transform:rotate(-90deg); }
anchor.right{ right:-40px; transform:rotate(90deg); }
anchor.width{top:calc(50% - 50px);}
anchor.height{top:calc(50%);}
.hidden{display:none !important; visibility:none;}
/* End of Framework styles */
/* App specific styles */
#editor{
position:absolute;
background:darkgray;
top:0;
left:0;
bottom:0;
right:0;
font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
}
#modal-blocker{
position:fixed;
top:0;
bottom:0;
left:0;
right:0;
background-color: rgba(0, 153, 229, 0.15);
z-index: 916;
display:none;
}
#toolbar{
top:0;
left:0;
right:0;
height:60px;
background:lightgray;
padding:4px;
/* header bg: */
background-image: linear-gradient(-180deg, #C1C1C1 0%, #AFAFAF 100%);
box-shadow:0...
JavaScript
$(document).ready(function() {
// Add better position methods to $
// All positions are PX from left and top all edges will include margin if parameter is true
$.prototype.top = function (margin = false){
return this.offset().top - ((margin === true)? this.css('margin-top'):0);
}
// returns the left edge of the margin
$.prototype.left = function (margin = false){
//console.log("left:", this.offset().left)
return this.offset().left - ((margin === true)? this.css('margin-left'):0);
}
// returns the X position of the right edge of the element
$.prototype.right = function (margin = false){
//console.log('alinging to right edge:', this.outerWidth(margin))
return this.offset().left + this.outerWidth(margin);
}
// returns the Y position of the bottom of the element
$.prototype.bottom = function (margin = false){
// console.log('aligning to bottom edge');
return this.offset().top + this.outerHeight(margin);
}
// this handles updates to the position of edges of modkit-containers with anchors
$('anchor').on('input', function(){
//TODO: Add supports for limits.
// console.log($(this).parent(), "changed:", this.textContent.length);
var $parent = $(this).parent();
var setting = this.textContent;
// if no setting assume 0
if(this.textContent.length < 1){
setting = '0';
}
if(setting.indexOf('%') > -1){ // handle % values
$parent.css(this.className, setting); // make %
this.dataset.setting = setting;
// TODO: Could split on . when there is a word first and use a different target for position (width or height depending on anchor)
}else if(setting == parseFloat(setting)){ // handle numerical values
$parent.css(this.className, setting+"px"); // make abs (px)
this.dataset.setting = setting;
}else{ // search for id and attach based on edge
// console.log('new $target:', setting, 'edge:', this.className)
//...