JSFiddle - React, Tailwind, and code Playground

Vue board foot calculator

by Christopher O

HTML

<div id="app">
  <h2>Board foot and price calculator</h2>
  Wood species: <select v-model="woodSpecies" @change="formUpdate($event)">
<option v-for="w in wood" v-bind:key="w.i" :value="w.i">{{w.n}} (${{w.p}}/bf)</option>
</select><br>

  <strong>Length:</strong> <input v-model.trim="length" autocomplete="off" autocorrect="off" name="length" type="number" maxlength="4" @change="formUpdate($event)" class="num" /> <select v-model="lengthMe" @change="formUpdate($event)">
<option v-for="m in measurement" v-bind:key="m" :value="m">{{m}}</option>
</select><br>

<strong>Width:</strong> <input v-model.trim="width" autocomplete="off" autocorrect="off" name="width" type="number" maxlength="4" @change="formUpdate($event)" class="num" /> <select v-model="widthMe" @change="formUpdate($event)">
<option v-for="m in measurement" v-bind:key="m" :value="m">{{m}}</option>
</select><br>

<strong>Finish:</strong> <select v-model="finish" @change="formUpdate($event)">
<option v-for="f in finishes" v-bind:key="f.i" :value="f.i">{{f.n}}</option>
</select><!-- river width --><br>

<div v-if="bf">
<strong>Total Board foot:</strong> {{bf}}<br>
<strong>Lumber per board foot:</strong> ${{bfp}}<br><br>

<strong>Finished price:</strong> ${{finished}}<br><br>

<strong>Raw lumber price:</strong> ${{raw}}
</div>

  <!-- ol>
    <li v-for="todo in todos">
      <label>
        <input type="checkbox"
          v-on:change="toggle(todo)"
          v-bind:checked="todo.done">

        <del v-if="todo.done">
          {{ todo.text }}
        </del>
        <span v-else>
          {{ todo.text }}
        </span>
      </label>
    </li>
  </ol -->
</div>

CSS

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
  line-height: 1.5;
}

.num {
  width: 50px;
}


input {
  border: 1px solid silver;
  border-radius: 4px;
  background: white;
  padding: 5px 10px;
}

.error {
  border-color: red;
  background: #FDD;
}

.error:focus {
  outline-color: #F99;
}

.valid {
  border-color: #5A5;
  background: #EFE;
}

.valid:focus {
  outline-color: #8E8;
}

Vue

new Vue({
  el: "#app",
  data: {
  	woodSpecies: "rw-2.5",
    width: "",
    widthMe: "IN",
    length: "",
    lengthMe: "IN",
    thick: "", // inches
    finish: "pg",
    
    bf: 0,
    bfp: 0,
    finished: 0,
    raw: 0,
    //shipping: 0, // to do live quote
    
    wood: [
      { i: "rw-2.5", n: "Redwood 2.5\" thick", p: 10, t: 2.5, lm: 156, wm: 45},
      { i: "rw-3", n: "Redwood 3\" thick", p: 10, t: 3, lm: 216, wm: 52},
      { i: "sq-2.5", n: "Sequoia 2.5\" thick", p: 12, t: 2.5, lm: 130, wm: 40 },
      { i: "dc-2.5", n: "Deodar Cedar 2.5\" thick", p: 10, t: 2.5, lm: 156, wm: 45 },
      { i: "bw-2.5", n: "Black Walnut 2.5\" thick", p: 18, t: 2.5, lm: 156, wm: 24 }
    ],
    
    finishes: [
      { i: "pg", n: "Polyurethane Gloss (Indoor) [$]", pm: 2.21},
      { i: "psg", n: "Polyurethane Semi-Gloss (Indoor) [$]", pm: 2.21},
      { i: "pm", n: "Polyurethane Matte (Indoor) [$]", pm: 2.21},
      
      { i: "sg", n: "Spar Urethane Gloss (Outdoor) [$$]", pm: 2.2},
      { i: "ssg", n: "Spar Urethane Semi-Gloss (Outdoor) [$$]", pm: 2.2},
      { i: "sm", n: "Spar Urethane Matte (Outdoor) [$$]", pm: 2.2},
      
      { i: "rm", n: "Preimum Deep Matte (Indoor/Outdoor) [$$]", pm: 2.3},
      
      { i: "ep", n: "Epoxy Preimum (Indoor/Outdoor) [$$$]", pm: 4},
      { i: "ee", n: "Epoxy Economy (Indoor/Outdoor) [$$$]", pm: 3},

    ],
    
    measurement: ["IN","FT","M","MM"],
  },
  
  methods: {
    $id: function(id) {
      return document.getElementById(id);
    },
    formUpdate: function(e){
    	let self = this;
      
      console.log("Begin");
      
      // reset
    	self.bf = self.bfp = self.finished = self.raw = 0;
      
      if(self.woodSpecies && self.length && self.lengthMe && self.width && self.widthMe && self.thick && self.finish){
      	console.log("-- Good data");
        
      	let L = self.convertM(self.length, self.lengthMe);
        let W = self.convertM(self.width, self.widthMe);
        
        self.bfp =...