Materialize Cards

Re-working of Summary Cards to use Materialize

HTML

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-debug.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.css">
<div class="deck">
  <div class="scrollable">
    <div data-bind="">
      <div class="card property summary number aggregate hoverable waves-effect waves-block">
        <div class="card-content">
          <span class="card-title">Number</span>
          <div class="preloader-wrapper small active right" data-bind="{ visible: isLoading }">
            <div class="spinner-layer spinner-blue-only">
              <div class="circle-clipper left">
                <div class="circle"></div>
              </div>
              <div class="gap-patch">
                <div class="circle"></div>
              </div>
              <div class="circle-clipper right">
                <div class="circle"></div>
              </div>
            </div>
          </div>
          <div class="container" data-bind="">
						<div class="row">
							<div class="col s6"><span class="label">Min</span><span class="value" data-bind="dl-siformat: min">143.2k</span></div>
							<div class="col s6"><span class="label">Sum</span><span class="value" data-bind="dl-siformat: sum">122.2k</span></div>
							<div class="col s6"><span class="label">Max</span><span class="value" data-bind="dl-siformat: max">365.9k</span></div>
							<div class="col s6"><span class="label">Average</span><span class="value" data-bind="dl-siformat: average">68.5k</span></div>
						</div>
          </div>
        </div>
      </div>
    </div>

    <div data-bind="">
      <div class="card property summary date aggregate hoverable waves-effect waves-block">
        <div class="card-content">
        ...

CSS

.pulse {
  display: block;
  position: absolute;
  background: #555;
  border-radius: 100%;
  -moz-transform: scale(0);
  -ms-transform: scale(0);
  -o-transform: scale(0);
  -webkit-transform: scale(0);
  transform: scale(0);
  /*animation effect*/
  z-index: 100;
}

.pulse.animate {
  -moz-animation: ripple 0.65s linear;
  -o-animation: ripple 0.65s linear;
  -webkit-animation: ripple 0.65s linear;
  animation: ripple 0.65s linear;
}

@keyframes ripple {
  
  100% {
    opacity: 0;
    -moz-transform: scale(2.5);
    -ms-transform: scale(2.5);
    -o-transform: scale(2.5);
    -webkit-transform: scale(2.5);
    transform: scale(2.5);
  }
}

.filtered .notification:before {
  position: absolute;
  font-family: FontAwesome;
  top: -1px;
  right: 10px;
  color: #4285f4;
  font-size: 20px;
  content: "\f0b0";
}

.filtered.invalid .notification:before {
  position: absolute;
  font-family: FontAwesome;
  top: -1px;
  right: 10px;
  color: #fc1501;
  font-size: 20px;
  content: "\f06a";
}

.state.row {
  margin-bottom: 3px;
}

.state .circle {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  float: left;
  margin: 5px 15px 5px 0px;
}

body {
  background: white;
}

.deck {
  background: #fafafb;
  width: 345px;
  padding: 5px;
  height: 100%;
  position: absolute;
  left: -15px;
  padding-top: 0px;
}

.preloader-wrapper.small {
  right: -12px;
  width: 20px;
  height: 20px;
  top: 2px;
}

.summary .card-content {
  padding-top: 0px;
  padding-bottom: 0px;
  margin-bottom: -5px;
}

.label {
  float: left;
}

.value {
  float: right;
  color: #8BC34A;
}

.card .card-title {
  font-size: 20px;
}

.graph {
  padding-top: 5px;
  padding-left: 12px;
  padding-right: 12px;
  font-size: 12px;
  padding-bottom: 28px;
}

.graph .bar {
  float: left;
  height: 12px;
  -webkit-transition: width 1s;
  -moz-transition: width 1s;
  -o-transition: width 1s;
  transition: width 1s;
}

JavaScript

// Sets up a pulsing affect on any invalid icons within the Deck
    (function() {

      setInterval(function() {

        var cardErrors = $(".card.invalid .card-content");
        if (cardErrors.length === 0) return;

        function pulse(selection, size, position) {

          var selectionWithNoPulse = selection.filter(function(index, element) {
            return $(element).find(".pulse").length === 0
          });

          selectionWithNoPulse.prepend("<span class='pulse'></span>");

          // Find the pulse and remove the animation class
          var pulse = selection.find(".pulse");
          pulse.removeClass("animate");

          // Define the pulse size if it's not done already
          if (!pulse.filter(function(index, element) {
              return !pulse.height() && !pulse.width()
            }).length !== 0) {
            pulse.css(size);
          }

          //set the position and add class .animate
          pulse.css(position).addClass("animate");
        };

        pulse(cardErrors, {
          height: 12,
          width: 12
        }, {
          top: 8 + 'px',
          left: 311 + 'px'
        });

      }, 2500);
    })();