Vue

by leonsaysHi

HTML

<div class="wrapper" id="app">  
  <dashboard-grid :items="items" :focus="focus">    
    <template v-slot:items>
      <div 
        v-for="(item, idx) in items" 
        :key="idx" 
        @click="handleSelect(item)" 
        class="item"
      >{{ item.id }}</div>
    </template>
    <template v-slot:articles>
      <div 
        v-if="focus" 
        @click="focus=null"
      >Focus {{ focus.id }}</div>
    </template>
  </dashboard-grid>
</div>

CSS

.wrapper {
  margin: 5rem 3rem;
}

.container {
  display: grid;
  margin: 0 -0.5rem;  
}

.item {
  height: 150px;
  margin: .5rem;
  padding: 1rem;
  border: solid 1px grey;
  border-radius: .2rem;
}

.focus {  
  height: auto;
  background: pink;
}

Vue

Vue.component('dashboard-grid', {
  template: '<div><button @click="columns = 1">1</button><button @click="columns = 3">3</button><button @click="columns = 5">5</button><div class="container" :style="containerStyle"><slot name="items"/><div v-if="focus" class="item focus" :style="focusStyle"><slot name="articles"/></div></div></div>',
 	props: {
  	items: { type: Array, required: true },
    focus: { type: Object, default: null}
  },
  data() {
    return {
      columns: 5,
    }
  },
  computed:{
  	containerStyle() {
    	return "grid-template-columns: repeat(" + this.columns + ", 1fr);"
    },
    focusStyle() {
    	const res = []
      if (this.focus) {
        res.push("grid-column-start: " + this.columns)
        res.push("grid-column-end: span 1")
        const row = Math.floor(this.items.findIndex(i => this.focus.id === i.id) / this.columns) + 1
        res.push("grid-row-start: " + row)
        res.push("grid-row-end: span 2")
      }
      return res.join(";")
    }
 }
})

new Vue({
  el: "#app",
  components: {  },
  data() {
    return {
        focus: null,
        items: [
          { id:1 },
          { id:2 },
          { id:3 },
          { id:4 },
          { id:5 },
          { id:6 },
          { id:7 },
          { id:8 },
          { id:9 },
        ]
    }
  },
  computed: {
  	
  },
  methods: {
    handleSelect(item){
      this.focus = item
    }
  }
});