Jambricks

An #energyhack19

by loleg

HTML

<link rel="stylesheet" href="https://unpkg.com/[email protected]/index.css">
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<section class="brickapp"><div class="todoapp">

  <header class="header">
    <h1>🧱 Jambricks</h1>
    <input class="new-todo"
      autofocus autocomplete="off"
      placeholder="Identify yourself or device"
      v-model="newNamer"
      @keyup.enter="addBrick">
    <input class="brick-value"
      autocomplete="off"
      placeholder="How many Watts? (W = Volts x Amperes)"
      v-model="newWatts"
      @keyup.enter="addBrick">
    <input class="brick-value"
      autocomplete="off"
      placeholder="How many Grams? (g)"
      v-model="newGrams"
      @keyup.enter="addBrick">
  </header>
  
  <section class="main" v-show="bricks.length" v-cloak>
    <ul class="brick-list">
      <li v-for="brick in bricks"
        class="todo"
        :key="brick.id"
        :class="{ editing: brick == editedBrick }">
        <div class="view" @dblclick="editBrick(brick)">
          <button class="destroy" @click="removeBrick(brick)">â™·</button>
          <label class="brick-name">{{ brick.namer }}</label>
          <label class="brick-num"><i>{{ brick.watts }}</i> W</label>
          <label class="brick-num"><i>{{ brick.grams }}</i> g</label>
        </div>
        <!--<input class="edit" type="text"
          v-model="brick.watts"
          v-brick-focus="brick == editedBrick"
          @blur="doneEdit(brick)"
          @keyup.enter="doneEdit(brick)"
          @keyup.esc="cancelEdit(brick)">-->
      </li>
    </ul>
  </section>
  
  <footer class="footer" v-show="bricks.length" v-cloak>
    <span class="brick-count">
      <strong><a href="https://jsfiddle.net/loleg/npdxs52f/">🧱</a> {{ remaining }}</strong> {{ remaining | pluralize }} |
      <strong>{{ totalWatts }}</strong> W |
      <strong>{{ totalGrams }}</strong> g
    </span>
  </footer>
  
</div></section>

<footer class="info">
  <button class="copybtn"...

CSS

[v-cloak] { display: none; }

.destroy {
  color: darkred;
  float: right;
  opacity: 0.4;
}

.brick-value {
  width: 48%;
  border: none;
  text-align: center;
}

button:hover { opacity: 1.0; }

.brick-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.brick-list li {
  display: inline-block;
  width: 7em;
  border: 2px solid red;
  box-shadow: 2px 2px 0px red;
  background: lightyellow;
  margin: 5px;
  padding: 10px;
  vertical-align: top;
}

.brick-list .brick-name {
  font-size: 140%;
  display: block;
  margin-bottom: 0.5em;
  color: green;
}

.brick-list .brick-num i {
  color: brown;
  font-style: normal;
  font-size: 125%;
}

JavaScript

var STORAGE_KEY = 'jambricks'
var brickStorage = {
  fetch: function () {
    var bricks = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')
    bricks.forEach(function (brick, index) {
      brick.id = index
    })
    brickStorage.uid = bricks.length
    return bricks
  },
  save: function (bricks) {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(bricks))
  }
}

// app Vue instance
var app = new Vue({
  // app initial state
  data: {
    bricks: brickStorage.fetch(),
    newNamer: '',
    newWatts: '',
    newGrams: '',
    editedBrick: null
  },

  // watch todos change for localStorage persistence
  watch: {
    bricks: {
      handler: function (bricks) {
        brickStorage.save(bricks)
      },
      deep: true
    }
  },

  // computed properties
  // http://vuejs.org/guide/computed.html
  computed: {
    remaining: function () {
      return this.bricks.length
    },
    totalWatts: function () {
      return this.bricks.reduce((a,o,i,p) => a + o.watts, 0);
    },
    totalGrams: function() {
    	return this.bricks.reduce((a,o,i,p) => a + o.grams, 0);
    }
  },

  filters: {
    pluralize: function (n) {
      return n === 1 ? 'brick' : 'bricks'
    }
  },

  // methods that implement data logic.
  // note there's no DOM manipulation here at all.
  methods: {
    addBrick: function () {
      if (!(this.newNamer && this.newNamer.trim() &&
      		  this.newWatts && this.newWatts.trim() &&
        		this.newGrams && this.newGrams.trim())) {
        return
      }
      this.bricks.push({
        id: brickStorage.uid++,
        namer: this.newNamer.trim(),
        watts: parseFloat(this.newWatts),
        grams: parseFloat(this.newGrams)
      })
      this.newNamer = ''
      this.newWatts = ''
      this.newGrams = ''
    },

    removeBrick: function (brick) {
      this.bricks.splice(this.bricks.indexOf(brick), 1)
    },

    editBrick: function (brick) {
      this.beforeEditCache = JSON.parse(JSON.stringify(brick))
      this.editedBrick...