Explaining Keys - Part 1

by skirtle

HTML

<h4>Explaining Keys - Part 1</h4>
<div class="main">
  <div class="left">
    <div class="caption">Original<br>VNodes</div>
    <div class="node element">ul</div>
    <div class="node element indent1">li</div>
    <div class="node text indent2">Red</div>
    <div class="node element indent1">li</div>
    <div class="node text indent2">Green</div>
    <div class="node element indent1">li</div>
    <div class="node text indent2">Blue</div>
  </div>
  <div class="middle">
    <div class="caption">VNode<br>pairings</div>
    <div class="arrow ul"></div>
    <div class="arrow li"></div>
    <div class="arrow txt"></div>
    <div class="arrow li incorrect"></div>
    <div class="arrow txt incorrect"></div>
    <div class="arrow li incorrect"></div>
    <div class="arrow txt incorrect"></div>
    <div class="add li"></div>
    <div class="add txt"></div>
  </div>
  <div class="right">
    <div class="caption">New<br>VNodes</div>
    <div class="node element">ul</div>
    <div class="node element indent1">li</div>
    <div class="node text indent2">Red</div>
    <div class="node element indent1 highlight">li</div>
    <div class="node text indent2 highlight final-highlight">Yellow</div>
    <div class="node element indent1">li</div>
    <div class="node text indent2 final-highlight">Green</div>
    <div class="node element indent1 final-highlight">li</div>
    <div class="node text indent2 final-highlight">Blue</div>
  </div>
  <div class="explanation">
    <div class="exp1">
      <fieldset>
        <legend>
          Data:
        </legend>
        <div>
          <code>['Red', 'Green', 'Blue']</code>
        </div>
      </fieldset>
      <br>
      <br>
      <br>
      <fieldset>
        <legend>
          Template:
        </legend>
        <div>
          <code>
            &lt;ul&gt;<br>
            &nbsp;&nbsp;&lt;li v-for="item in array"&gt;{{ item }}&lt;/li&gt;<br>
            &lt;/ul&gt;<br>
          </code>
        </div>
      </fieldset>
    </div>
   ...

SCSS

*, *::before, *::after {
  box-sizing: border-box;
  font-family: Arial;
}

.main {
  border: 1px solid #000;
  display: flex;
  width: 700px;
  position: relative;
}

.main > * {
  margin: 10px;
}

.left, .middle, .right {
  display: flex;
  flex-direction: column;
  align-items: start;
  border: 1px solid #ccc;
  padding: 5px;
}

fieldset {
  border: 1px solid #ccc;
}

.middle {
  border-color: transparent;
  align-items: center;
}

.caption {
  font-size: 16px;
  text-align: center;
  align-self: center;
}

.node {
  font-family: monospace;
  font-weight: bold;
  font-size: 1.2em;
  background: #3AB881;
  border: 1px solid #23AC70;
  padding: 5px;
  width: 80px;
  border-radius: 5px;
  margin: 2px;
  color: #fff;
}

.element::before {
  content: '<';
}

.element::after {
  content: '>';
}

.text::before {
  content: '#';
}

.text {
  background-color: #fff;
  border-width: 2px;
  color: #3AB881;
  font-weight: normal;
  padding: 4px 5px;
}

.indent1 {
  margin-left: 15px;
}

.indent2 {
  margin-left: 30px;
}

.arrow, .add {
  color: #9AA9B2;
  display: flex;
  height: 38px;
  flex-direction: column;
  justify-content: center;
  font-weight: bold;
}

.arrow::before {
  content: '-------->';
}

.add {
  /* color: #F2781E; */
  color: #DB5B62;
  
  &::before {
    content: '+';
  }
}

.incorrect {
  color: #DB5B62;
  position: relative;
}

/*
.incorrect::after {
  background: #fff;
  content: 'X';
  position: absolute;
  left: 20px;
}
*/

.explanation {
  position: absolute;
  left: 126px;
  right: 0;
  top: 0;
  bottom: 0;
  visibility: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.change {
  background: #FF8228;
  border-color: #F2781E;
}

code {
  font-family: monospace;
}

.exp1, .exp2, .exp3, .exp4, .exp5, .exp6, .exp7 {
  display: none;
}

.stage1 {
  .middle, .right {
    visibility: hidden;
  }
  
  .explanation {
    visibility: visible;
  }
  
  .exp1 {
    display: block;
  }
}

.stage2 {
 ...

JavaScript

(() => {
  const back = document.getElementById('back')
  const next = document.getElementById('next')
  const main = document.querySelector('.main')
  const progress = document.getElementById('progress')
  
  const steps = 7
  
  let stage = 1

  const update = () => {
    main.className = `main stage${stage}`
    progress.innerHTML = `${stage} / ${steps}`
  }

  next.addEventListener('click', () => {
    stage = (stage % steps) + 1
    
    update()
  })

  back.addEventListener('click', () => {
    stage = (stage + steps - 2) % steps + 1
    
    update()
  })

  update()
})()