JSFiddle - React, Tailwind, and code Playground

by Barry Carter

HTML

<script src="https://github.com/knockout/knockout/releases/download/v3.4.0/knockout-3.4.0.js"></script>
<div id="page">
<!-- ko if: processing -->
  <div class="processing" data-bind="style: { height: subHeightCss }">
      <p><span data-bind="text: processingText"></span><span class="spinner"></span></p>
  </div>
  <!-- /ko -->
</div>
  
<div id="subheader" class="subheader" data-bind="animateHeight: window.pageModel.subHeightCss">
<div class="control-group-row">
    <ul class="control-group">
      <li>
          <button>
            Add
          </button>
      </li>
      <li>
          <button>
            Delete
          </button>
      </li>
    </ul>
    <ul class="control-group control-group-right">
      <li>
          <button  data-bind="click: advanced_click">
            Advanced
          </button>
      </li>
      <li>
        <input value="search..."/>
      </li>
      <li>
          <button data-bind="click: save_click">
            Save
          </button>
      </li>
    </ul>
</div>
<div class="control-group-row">
    <ul class="control-group">
      <li>
          <button>
            Second
          </button>
      </li>
      <li>
          <button>
            Row
          </button>
      </li>
    </ul>
  </div>
</div>

<h2>Entirely flex subheader</h2>
<pre>
With avanced multirow.
Can add as many rows as you need and call the page viewmodel from any other view model
the overlay for saving is scaled appropriately
</pre>

CSS

.subheader {
  background-color: white;
  border-bottom: 1px solid black;
  height: 60px;
  overflow: hidden;
}

.control-group-row {
  display: flex;
}

.control-group {
  display:flex;  
  list-style:none;
}

.control-group li {
  margin: 0 5px 0 5px;
}

.control-group-right {
  margin-left: auto;
}


.processing {
  position: absolute;
  left: 0px;
  top: 0px;
  height: 67px;
  opacity: 0.7;
  background-color: black;
  width: 100%;
  line-height: 60px;
  margin: 3px;
}

.processing p {
  opacity: 1;
  font-size: 1.5em;
  font-weight: 2;
  color: white;
  width: 320px;
  margin: auto;
  vertical-align: middle;
}

.processing .spinner {
  background-image: url("https://www.usana.com/images/loading-spinner-black.gif");
  background-size: 30px 30px;
  background-repeat: no-repeat;
  width: 30px;
  height: 30px;
  display: inline-block;
  vertical-align: middle;
  margin-left: 20px;
}

JavaScript

ko.bindingHandlers.animateHeight = {
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        $(element).stop(true, false);
        var value = valueAccessor();
        var valu = ko.utils.unwrapObservable(value);
        $(element).animate({ height: valu } , 500);
   }
};



// standard function every page has and will need.
// example deals withsaving banner and also expanded advanced options
var PageViewModel = function(parm) {
   var pself = this;
   this.processing = ko.observable(false);
   this.processingText = ko.observable("Please Wait...");
   
   this.defaultHeight = 60;
   this.submenuHeight = ko.observable(pself.defaultHeight);
   this.submenuExpanded = ko.observable(false);
   
   this.startAction = function(displayText) {
      pself.processingText(displayText)
   		pself.processing(true);
   }
   
   this.endAction = function() {
   		pself.processing(false);
   }
   
   this.toggleSubHeader = function(height) {
   		if (!pself.submenuExpanded()) {
      		pself.defaultHeight = pself.submenuHeight();
   				pself.submenuHeight(height);
   				pself.submenuExpanded(true);
      }
      else {
      		pself.submenuHeight(pself.defaultHeight);
      		pself.submenuExpanded(false);
      }     
   }
   
   this.subHeightCss = ko.computed(function() {
   		var h = pself.submenuHeight();
      return (h) + "px";
   });
}

var NormalViewModel = function(parm) {
   var self = this;
  
   this.save_click = function(data,event) {
   		pageModel.startAction("Saving...");
      setTimeout(function() {
      		pageModel.endAction();
      }, 3000)
   }
   
   this.advanced_click = function(data, event) {
   		pageModel.toggleSubHeader(120);
   }
}
window.pageModel = new PageViewModel()
ko.applyBindings(pageModel, document.getElementById("page"));

ko.applyBindings(new NormalViewModel(), document.getElementById("subheader"));