Fitness Tracker Dashboard

31 of 51

Include multiple grids on the same page, and conditionally highlight different types of information in each of them.

Result Full HTML CSS JS
Edit Download

Fitness Tracker Dashboard

Monitor your heart rate, calorie consumption, and activity logs in one place with a dashboard overview of your data.


Heart Rate Tracker[[index.restingHeartRate]] bpm Calorie Tracker[[index.breakfast]] cal[[index.lunch]] cal[[index.dinner]] cal[[index.snacks]] cal
Activity Tracker[[index.distance]] mi

Full Code

<!DOCTYPE html>
<html class="zg-html">

<head>
  <meta charset="utf-8">
  <title>ZingGrid: Blank Grid</title>
  <script src="https://cdn.zinggrid.com/dev/zinggrid-dev.min.js" defer></script>
  <style>
    .zg-body {
      background: #F3F3F3;
      padding: 30px;
      font-family: 'Heebo', sans-serif;
    }

    .zg-body .dashboard-container {
      max-width: 1000px;
      margin: 0 auto;
    }

    .zg-body h1 {
      color: #606470;
      margin-bottom: 10px;
      font-weight: 300;
    }

    .zg-body p {
      color: #606470;
      margin: 0 0 10px 0;
      font-weight: 300;
    }

    .zg-body hr {
      display: block;
      height: 1px;
      border: 0;
      border-top: 1px solid #dddddd;
      margin: 1em 0;
      padding: 0;
      margin: 0 0 30px 0;
    }

    .zg-body .columns {
      display: grid;
      grid-template-columns: 1fr 1fr;
      grid-auto-rows: 2em;
      grid-gap: 2em;
      min-height: 440px;
      width: 100%;
    }

    .zg-body .fas {
      padding-right: 5px;
      font-size: 15px;
    }

    .zg-body .blue {
      color: #2f89fc;
    }

    .zg-body .gold {
      color: #f4b342;
    }

    .zg-body .green {
      color: #4bbb8b;
    }

    .zg-body .grey {
      color: #ccc;
    }

    .zg-body .red {
      color: #ff5759;
    }

    /* Grid */

    zing-grid {
      max-width: 1000px;
      margin: 0 auto;
      font-family: 'Heebo', sans-serif;
      font-size: 11px;
      background: #ffffff;
      border: none;
      color: #ffffff;
      --theme-color-primary: #606470;
      --zg-cell-background_sorted: #eee;
      --zg-head-cell-background_sorted: #ccc;
      --zg-icon-init-fill: #606470;
      --zg-head-cell-icon-color_sorted: #606470;
      --zg-select-arrow-color: #606470;
      box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.05), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
      opacity: 1;
    }

    zing-grid.loading {
      opacity: 0;
      transition: opacity .3s ease-out;
    }

    zg-caption {
      border-bottom: 1px solid #efefef;
      font-weight: 400;
      background: #ffffff;
      color: #606470;
      border-radius: 8px 8px 0 0;
      -webkit-border-radius: 8px 8px 0 0;
      -moz-border-radius: 8px 8px 0 0;
    }

    zg-control-bar {
      display: none;
    }

    zg-head,
    zg-head-cell {
      background: #ffffff;
      color: #606470;
      font-size: 9px;
      font-weight: bold;
      text-transform: none;
    }

    zg-icon {
      width: 15px;
    }

    zg-head,
    zg-body {
      border: none;
    }

    zg-row {
      border-bottom: 1px solid #efefef;
      background: #ffffff;
      color: #414141;
    }

    zg-row,
    zg-cell {
      padding: 0 15px;
      height: 40px;
    }

    zg-body zg-row:last-child {
      border-radius: 0 0 8px 8px;
      -moz-border-radius: 0 0 8px 8px;
      -webkit-border-radius: 0 0 8px 8px;
    }

    zg-pager {
      background: #ffffff;
      margin-top: 0px;
      color: #606470;
      border-radius: 0 0 8px 8px;
      -webkit-border-radius: 0 0 8px 8px;
      -moz-border-radius: 0 0 8px 8px;
      font-size: 10px;
    }

    .zg-body .bike {
      color: #2f89fc;
      font-weight: bold;
    }

    zg-row.outdoor-bike {
      color: #2f89fc;
      font-weight: normal;
    }

    .zg-body .run,
    .zg-body .peak {
      color: #ff5759;
      font-weight: bold;
    }

    zg-row.run {
      color: #ff5759;
      font-weight: normal;
    }

    zg-row.peak {
      color: #ff5759;
      font-weight: normal;
    }

    .zg-body .sport {
      color: #4bbb8b;
      font-weight: bold;
    }

    zg-row.sport {
      color: #4bbb8b;
      font-weight: normal;
    }

    .zg-body .not-peak {
      color: #cccccc;
    }

    .zg-body .calorie-goal {
      color: #f4b342;
      font-weight: bold;
    }

    .zg-body .bold {
      font-weight: bold;
    }

    @media screen and (max-width: 650px) {
      .columns {
        display: block;
        margin-bottom: 30px;
      }
      .zg-body .columns zing-grid:first-child {
        margin-bottom: 30px;
      }
    }

    zing-grid[loading] {
      height: 1073px;
    }
  </style>
</head>

<body class="zg-body">

  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
  <link href="https://fonts.googleapis.com/css?family=Heebo:300,400,700" rel="stylesheet">

  <div class="dashboard-container">
    <h1>Fitness Tracker Dashboard</h1>
    <p>Monitor your heart rate, calorie consumption, and activity logs in one place with a dashboard overview of your data.</p>
    <hr>
    <div class="columns">
      <zing-grid src="https://zinggrid-examples.firebaseio.com/fitness-dashboard/1/heartRateTracker" layout="row" sort pager page-size="6" page-size-options="6,12,8,24" class="loading">
        <zg-caption>
          <i class="fas fa-heartbeat"></i> Heart Rate Tracker
        </zg-caption>
        <zg-colgroup>
          <zg-column index="date"></zg-column>
          <zg-column index="restingHeartRate">
            [[index.restingHeartRate]] bpm
          </zg-column>
          <zg-column index="timeInHeartRateZones.fatBurn" header="Fat Burn"></zg-column>
          <zg-column index="timeInHeartRateZones.cardio" header="Cardio"></zg-column>
          <zg-column index="timeInHeartRateZones.peak" header="Peak" renderer="renderPeak"></zg-column>
        </zg-colgroup>
      </zing-grid>

      <zing-grid src="https://zinggrid-examples.firebaseio.com/fitness-dashboard/2/calorieTracker" layout="row" sort pager page-size="6" page-size-options="6,12,8,24" class="loading">
        <zg-caption>
          <i class="fas fa-burn"></i> Calorie Tracker
        </zg-caption>
        <zg-colgroup>
          <zg-column type="text" index="date"></zg-column>
          <zg-column type="number" index="breakfast">
            [[index.breakfast]] cal
          </zg-column>
          <zg-column type="number" index="lunch">
            [[index.lunch]] cal
          </zg-column>
          <zg-column type="number" index="dinner">
            [[index.dinner]] cal
          </zg-column>
          <zg-column type="number" index="snacks">
            [[index.snacks]] cal
          </zg-column>
          <zg-column type="number" index="total" renderer="renderCalorieGoal">
          </zg-column>
        </zg-colgroup>
      </zing-grid>
    </div>

    <zing-grid src="https://zinggrid-examples.firebaseio.com/fitness-dashboard/0/activityTracker" row-class="_renderClassActivity" layout="row" sort pager page-size="6" page-size-options="6,12,8,24" class="loading">
      <zg-caption>
        <i class="fas fa-child"></i> Activity Tracker
      </zg-caption>
      <zg-colgroup>
        <zg-column index="date"></zg-column>
        <zg-column index="activityType" renderer="renderActivityType"></zg-column>
        <zg-column index="city"></zg-column>
        <zg-column index="state"></zg-column>
        <zg-column index="distance" header="Distance">
          [[index.distance]] mi
        </zg-column>
        <zg-column index="elapsedTime"></zg-column>
        <zg-column index="movingTime"></zg-column>
      </zg-colgroup>
    </zing-grid>
  </div>

  <script>
    // Add Row Classes
    function _renderClassActivity(record, $cell) {
      return record.activityType.replace(' ', '-').toLowerCase();
    }

    // Cell Renderers
    function renderPeak(value) {
      const match = value === "00:00:00";
      const classes = match ? 'grey' : 'red';
      const peak = match ? 'not-peak' : 'peak';
      return `<i class="fas fa-heartbeat ${classes}"></i> <span class="${peak}">${value}</span>`;
    }

    function renderCalorieGoal(value, $cellRef, cell) {
      const match = value > "2,350";
      const classes = match ? 'grey' : 'gold';
      const total = match ? 'not-peak' : 'calorie-goal';
      return `<i class="fas fa-star ${classes}"></i> <span class="${total}">${value}</span>`;
    }

    function renderActivityType(value) {
      let classes, type;
      switch (value) {
        case 'Run':
          classes = 'fa-shoe-prints red';
          type = 'run';
          break;
        case 'Sport':
          classes = 'fa-volleyball-ball green';
          type = 'sport';
          break;
        default:
          classes = 'fa-bicycle blue';
          type = 'bike';
      }
      return `<i class="fas ${classes}"></i> <span class="${type}">${value}</span>`;
    }


    // Custom loading class for CSS handling
    const zgLoaded = document.querySelectorAll('zing-grid');
    zgLoaded.forEach(zg => showGrid(zg));
    // ---
    function showGrid(grid) {
      grid.addEventListener('grid:ready', () => {
        setTimeout(() => grid.classList.remove('loading'), 250);
      });
    }
  </script>
</body>

</html>
<!DOCTYPE html>
<html class="zg-html">
  <head>
    <meta charset="utf-8">
    <title>ZingGrid: Blank Grid</title>
    <script src="https://cdn.zinggrid.com/dev/zinggrid-dev.min.js" defer></script>
  </head>
  <body class="zg-body">
    
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
    <link href="https://fonts.googleapis.com/css?family=Heebo:300,400,700" rel="stylesheet">

    <div class="dashboard-container">
      <h1>Fitness Tracker Dashboard</h1>
      <p>Monitor your heart rate, calorie consumption, and activity logs in one place with a dashboard overview of your data.</p>  
      <hr>
      <div class="columns">
        <zing-grid 
          src="https://zinggrid-examples.firebaseio.com/fitness-dashboard/1/heartRateTracker" 
          layout="row"
          sort
          pager
          page-size="6"
          page-size-options="6,12,8,24"
          class="loading"
        >
          <zg-caption>
            <i class="fas fa-heartbeat"></i> Heart Rate Tracker
          </zg-caption>
          <zg-colgroup>
            <zg-column index="date"></zg-column>
            <zg-column index="restingHeartRate">
              [[index.restingHeartRate]] bpm
            </zg-column>
            <zg-column index="timeInHeartRateZones.fatBurn" header="Fat Burn"></zg-column>
            <zg-column index="timeInHeartRateZones.cardio" header="Cardio"></zg-column>
            <zg-column index="timeInHeartRateZones.peak" header="Peak" renderer="renderPeak"></zg-column>
          </zg-colgroup>
        </zing-grid> 

        <zing-grid 
          src="https://zinggrid-examples.firebaseio.com/fitness-dashboard/2/calorieTracker" 
          layout="row"
          sort
          pager
          page-size="6"
          page-size-options="6,12,8,24"
          class="loading"
        >
          <zg-caption>
            <i class="fas fa-burn"></i> Calorie Tracker
          </zg-caption>
          <zg-colgroup>
            <zg-column type="text" index="date"></zg-column>
            <zg-column type="number" index="breakfast">
              [[index.breakfast]] cal
            </zg-column>
            <zg-column type="number" index="lunch">
              [[index.lunch]] cal
            </zg-column>
            <zg-column type="number" index="dinner">
              [[index.dinner]] cal
            </zg-column>
            <zg-column type="number" index="snacks">
              [[index.snacks]] cal
            </zg-column>
            <zg-column type="number" index="total" renderer="renderCalorieGoal">
            </zg-column>
          </zg-colgroup>
        </zing-grid> 
      </div>

      <zing-grid 
        src="https://zinggrid-examples.firebaseio.com/fitness-dashboard/0/activityTracker" 
        row-class="_renderClassActivity"
        layout="row"
        sort
        pager
        page-size="6"
        page-size-options="6,12,8,24"
        class="loading"
      >
        <zg-caption>
          <i class="fas fa-child"></i> Activity Tracker
        </zg-caption>
        <zg-colgroup>
        <zg-column index="date"></zg-column>
          <zg-column index="activityType" renderer="renderActivityType"></zg-column>
          <zg-column index="city"></zg-column>
          <zg-column index="state"></zg-column>
          <zg-column index="distance" header="Distance">
            [[index.distance]] mi
          </zg-column>
          <zg-column index="elapsedTime"></zg-column>
          <zg-column index="movingTime"></zg-column>
        </zg-colgroup>
      </zing-grid>
    </div>
    
  </body>
</html>
.zg-body {
  background: #F3F3F3;
  padding: 30px;
  font-family: 'Heebo', sans-serif;
}
.zg-body .dashboard-container {
  max-width: 1000px;
  margin: 0 auto;
}
.zg-body h1 {
  color: #606470;
  margin-bottom: 10px;
  font-weight: 300;
}
.zg-body p {
  color: #606470;
  margin: 0 0 10px 0;
  font-weight: 300;
}
.zg-body hr {
  display: block;
  height: 1px;
  border: 0;
  border-top: 1px solid #dddddd;
  margin: 1em 0;
  padding: 0; 
  margin: 0 0 30px 0; 
}
.zg-body .columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: 2em;
  grid-gap: 2em;
  min-height: 440px;
  width: 100%;
}
.zg-body .fas { padding-right:5px; font-size:15px; }
.zg-body .blue { color:#2f89fc; }
.zg-body .gold { color: #f4b342; }
.zg-body .green { color: #4bbb8b; }
.zg-body .grey { color: #ccc; }
.zg-body .red { color: #ff5759; }

/* Grid */
zing-grid {
  max-width: 1000px;
  margin: 0 auto;
  font-family: 'Heebo', sans-serif;
  font-size: 11px;
  background: #ffffff;
  border: none;
  color: #ffffff;
  --theme-color-primary: #606470;
  --zg-cell-background_sorted: #eee;
  --zg-head-cell-background_sorted: #ccc;
  --zg-icon-init-fill: #606470;
  --zg-head-cell-icon-color_sorted: #606470;
  --zg-select-arrow-color: #606470;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.05), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
  opacity: 1;
}
zing-grid.loading { opacity:0; transition:opacity .3s ease-out; }

zg-caption {
  border-bottom: 1px solid #efefef;
  font-weight: 400;
  background: #ffffff;
  color: #606470;
  border-radius: 8px 8px 0 0;
  -webkit-border-radius: 8px 8px 0 0;
  -moz-border-radius: 8px 8px 0 0;
}
zg-control-bar {
  display: none;
}
zg-head, zg-head-cell {
  background: #ffffff;
  color: #606470;
  font-size: 9px;
  font-weight: bold;
  text-transform: none;
}
zg-icon {
  width: 15px;
}
zg-head,
zg-body {
  border: none;
}
zg-row {
  border-bottom: 1px solid #efefef;
  background: #ffffff;
  color: #414141;
}
zg-row, zg-cell {
 padding: 0 15px; 
  height: 40px;
}
zg-body zg-row:last-child {
  border-radius: 0 0 8px 8px;
  -moz-border-radius: 0 0 8px 8px;
  -webkit-border-radius: 0 0 8px 8px;
}
zg-pager {
  background: #ffffff;
  margin-top: 0px;
  color: #606470;
  border-radius: 0 0 8px 8px;
  -webkit-border-radius: 0 0 8px 8px;
  -moz-border-radius: 0 0 8px 8px;
  font-size: 10px;
}

.zg-body .bike {
  color: #2f89fc;
  font-weight: bold;
}
zg-row.outdoor-bike  {
  color: #2f89fc;
  font-weight: normal;
}
.zg-body .run,
.zg-body .peak {
  color: #ff5759;
  font-weight: bold;
}
zg-row.run  {
  color: #ff5759;
  font-weight: normal;
}
zg-row.peak  {
  color: #ff5759;
  font-weight: normal;
}
.zg-body .sport {
  color: #4bbb8b;
  font-weight: bold;
}
zg-row.sport  {
  color: #4bbb8b;
  font-weight: normal;
}
.zg-body .not-peak {
  color: #cccccc;
}
.zg-body .calorie-goal {
  color: #f4b342;
  font-weight: bold;
}
.zg-body .bold {
  font-weight: bold;
}
@media screen and (max-width: 650px) {
  .columns {
    display: block;
    margin-bottom: 30px;
  }
  .zg-body .columns zing-grid:first-child {
    margin-bottom: 30px;
  }
}
// Add Row Classes
function _renderClassActivity(record, $cell) {
  return record.activityType.replace(' ', '-').toLowerCase();
}

// Cell Renderers
function renderPeak(value) {
  const match = value === "00:00:00";
  const classes = match ? 'grey' : 'red';
  const peak = match ? 'not-peak' : 'peak';
  return `<i class="fas fa-heartbeat ${classes}"></i> <span class="${peak}">${value}</span>`;
}
function renderCalorieGoal(value, $cellRef, cell) {
  const match = value > "2,350";
  const classes = match ? 'grey' : 'gold';
  const total = match ? 'not-peak' : 'calorie-goal';
  return `<i class="fas fa-star ${classes}"></i> <span class="${total}">${value}</span>`;
}
function renderActivityType(value) {
  let classes, type;
  switch (value) {
    case 'Run':
      classes = 'fa-shoe-prints red';
      type = 'run';
      break;
    case 'Sport':
      classes = 'fa-volleyball-ball green';
      type = 'sport';
      break;
    default:
      classes = 'fa-bicycle blue';
      type = 'bike';
  }
  return `<i class="fas ${classes}"></i> <span class="${type}">${value}</span>`;
}


// Custom loading class for CSS handling
const zgLoaded = document.querySelectorAll('zing-grid');
zgLoaded.forEach(zg => showGrid(zg));
// ---
function showGrid(grid) {
  grid.addEventListener('grid:ready', () => {
    setTimeout(() => grid.classList.remove('loading'), 250);
  });
}

Interested in this demo? Modify it to your needs in ZingSoft Studio, our testing sandbox. It's free to sign up, and you can come back and edit at any time!

Edit in Studio