JSON API: Olympic Medals Tracker

Query JSON of 2014 Sochi Winter Olympics participant country data. Listing country names, sorted alphabetically, and allowing user to select any number of countries to add to their "Favorite Countries". This favorite list is stored in persistent browser storage and can be viewed after closing and re-opening the browser. Table displays medals won by each of user’s selected Favorite Countries, sorted by gold medals, then by total medals. When the user adds a new Favorite Country, that country is inserted into the medal standings in correct sorting location. User can also remove a country from their medal standings watch-list.

by Allen N.

HTML

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.js"></script>
<script src="https://semantic-ui.com/javascript/library/tablesort.js"></script>
<div class='ui modal'>
  <i class="close icon"></i>
  <div class="table-wrap">
    <table class='full-list ui sortable unstackable collapsing table'>
      <thead>
        <tr>
          <th>Add/Remove</th>
          <th class='default-sort'>All Countries</th>
        </tr>
      </thead>
      <tbody>

      </tbody>
    </table>
  </div>
</div>

<div class='table-wrap'>
  <table class='fav-list ui sortable unstackable table'>
    <thead>
      <tr>
        <th class="ui header" colspan="6">Winter Olympics <i class="trophy icon"></i> Sochi 2014</th>
      </tr>
      <tr class='sticky'>
        <th>Country</th>
        <th class='default-sort descending'>Gold</th>
        <th>Silver</th>
        <th>Bronze</th>
        <th class='secondary-sort descending'>Total</th>
      </tr>
    </thead>
    <tbody>

    </tbody>
  </table>
</div>


<div class='ui message empty-fav-list-msg fav-selector'>
  <div class='header'>
    No Countries Selected
  </div>
  <p>Click here or button below to add countries to your watchlist to keep track of how many medals everyone is winning.</p>
</div>

<button class='fav-selector ui button green'><i class="list icon"></i><span class='empty-fav-list-text'>Select </span><span class='not-empty-fav-list'>Add or Remove </span> Countries</button>

SCSS

html,
body {
  margin: 0;
  padding: 0;
  font-size: 16px;
  
  *[class*="empty-fav-list-"] {
    display: none;
  }
  &.empty-fav-list {
    .empty-fav-list-msg {
      position: absolute;
      top: 50%;
      right: 50%;
      display: block;
      background-color: whitesmoke;
      width: 77vw;
      max-width: 333px;
      margin: 0 auto;
      transform: translate(50%, -50%);
      transition: all 333ms;
      text-align: center;
      
      &:hover {
        background-color: palegreen;
      }
    }
    .empty-fav-list-text {
      display: inline-block;
      
      & + .not-empty-fav-list {
        display: none;
      }
    }
  }
}

.fav-selector {
  cursor: pointer;
  
  &.ui.message {
    
  }
}

// Tables.
.table-wrap {
    display: inline-block;
    width: 100%;
    max-width: none;
    height: calc(100vh - 82px);
    overflow: auto;
    box-shadow: 0px 1px 1px lightgrey;
    vertical-align: top;

    .ui.table {
        margin: 0;
        border: none;
        
        thead {
            tr {
                &:first-child > th:first-child,
                &:first-child > th:last-child {
                    border: none;
                    border-radius: 0;
                }
                &.stuck > th {
                    position: sticky !important;
                    top: 0;
                    z-index: 3;
                }
            }
            th {
                &.header {
                    text-align: center;
                    
                    i {
                        margin: 0;
                        color: gold;
                        font-size: 22px;
                        text-shadow: 0 1px 1px darkslategray;
                        transform: translateY(-5px);
                    }
                }
                &,
                &.sorted {
                    padding: 8px;
                    white-space: normal;
                    background-color: #1283c6;
                    color: white;
             ...

JavaScript

$.ajax({
  url: 'https://gist.githubusercontent.com/allenski88/78ce093c2f786a2e2b6d1c3248fba4e3/raw/2abe8e0bb37b84c2feb05fa982212d9f9cd6f130/sochi2014.json',
  method: 'GET',
  dataType: 'json'
}).then(function(data) {
  render(data);
});

var favTable = $('.fav-list.ui.table'),
		favList = $('.fav-list tbody');

render = function(olympicsData) {

  for (var i = 0; i < olympicsData.length; i++) {

    // Create table row.
    var newTR = document.createElement('tr'),
        favSwitchTD = document.createElement("td"),
        countryData = olympicsData[i],
        countryID = countryData.abbr,
        countryName = countryData.name.split(',')[0],
        flagImgPath = countryData.flag,
        selected = 'checked',
        fav = (retrieveFromLocalStorage() != null) ? retrieveFromLocalStorage().split(',') : [],
        checked = (fav.includes(countryID)) ? selected : null;

    $('.full-list tbody').append(newTR);

    // Favorite on/off switch.
    $(favSwitchTD).append('<div class="ui slider checkbox ' + checked + '"><input type="checkbox" tabindex="0" ' + checked + ' /><label></label></div>')
      .find('.ui.checkbox').checkbox({
        onChecked: function() {
          var tr = $(this).parents('tr');
          tr.addClass(selected);
          fav.push(tr.data('country'));
          updateLocalStorage(fav);
          updateFavs(tr.data('index'));
        },
        onUnchecked: function() {
          var tr = $(this).parents('tr');
          tr.removeClass(selected);
          fav.splice($.inArray(tr.data('country'), fav), 1);
          updateLocalStorage(fav);
          updateFavs(tr.data('index'));
        }
      });

    $(newTR)
      // Data-attr used to help remember favorited countries.
      .attr('data-country', countryID)
      // Data-index used to help remember favorited countries.
      .attr('data-index', i)

      // Add Fav on/off switch column.
      .append(favSwitchTD)

      // Add 'checked' class if in fav list.
     ...