Vue Pokemons!

Features: API fetching, array filtering, recursive component

by tlopasha

HTML

<div id="vue">
  <div>
    <h2>
  Types
  </h2>
    <ul>
      <li @click="selected = undefined" :class="{clickable:true, current:!selected}">All</li>
      <li v-for="type in types" @click="selected = type" :class="{clickable:true, current:type == selected}">{{type}}</li>
    </ul>
  </div>
  <div>
    <h2>
  Pokemon
  </h2>
    <ul>
      <li v-for="pokemon in filtered" @click="showPokemon = pokemon" :class="{clickable:true,current:pokemon == showPokemon}">
        {{pokemon.Name}}
        <div class="types">{{pokemon.Types && pokemon.Types.join(' ')}}</div>
      </li>
    </ul>
  </div>
  <div v-if="showPokemon">
    <h2>{{showPokemon.Name}}</h2>
    <img :src="'https://github.com/PokeAPI/sprites/raw/master/sprites/pokemon/' + Number(showPokemon.Number) + '.png'">
    <json :data="showPokemon"></json>
  </div>
</div>

CSS

body{
  margin:0
}
#vue{
  display:flex;
  font-family:sans-serif;
}
#vue > div{
  width:33%;
  padding:5px;
  display:flex;
  flex-direction:column;
  box-sizing:border-box;
  max-height:100vh;
}
ul{
  list-style:none;
  padding:0;
  box-shadow:0px 1px 5px #aaa;
  background:white;
  overflow:auto;
}
li{
  padding:10px;
  display:flex;
  flex-wrap:wrap;
}
li:nth-child(even){
  background:#f8f8f8;
}
.clickable:hover{
  cursor:pointer;
  background:#cfc;
}
li.current, .clickable.current{
  background:#afa;
}
li > ul{
  width:100%
}
b{
  margin-right:auto;
}
b ~ ul{
  margin-top:5px;
}
img{
  display:block;
  height:96px;
  margin:0 auto;
  transform:scale(2);
  image-rendering:pixelated;
}
.types{
  font-size:12px;
  color:grey;
  margin-left:auto;
}

JavaScript

new Vue({
  el: '#vue',
  data() {
    return {
      selected: undefined,
      pokemons: [],
      types: [],
      showPokemon:undefined
    }
  },
  created(){
  	fetch('https://raw.githubusercontent.com/BrunnerLivio/PokemonDataGraber/master/output.json')
    .then(res => res.json()).then(pokemons => {
    	this.pokemons = pokemons.filter(pokemon => pokemon.Name)
      for(var pokemon of this.pokemons){
        for(var type of pokemon.Types){
          if(!this.types.includes(type)){
            this.types.push(type)
          }
        }
        this.types = this.types.sort()
      }
    })
  },
  computed: {
    filtered() {
      return this.selected ? this.pokemons.filter(pokemon => pokemon.Types && pokemon.Types.includes(this.selected)) : this.pokemons
    }
  },
  components:{
  	json:{
    	name:'json',
      props:['data'],
    	template:
      `<ul v-if="typeof data == 'object'">
      	<li v-for="item, key in data">
        	<b v-if="!Array.isArray(data)">{{key}}</b>
          <json :data="item"></json>
        </li>
      </ul>
      <span v-else>{{data}}</span>
      `
    }
  }
})