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)
      //...