JSFiddle - React, Tailwind, and code Playground

by Joulence

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<div id="app">
  <v-slider :slides-data="slidesData"></v-slider>
</div>

CSS

body {
  margin: 0;
}

.slider {
  height: 100vh;
  overflow: hidden;
  position: relative;
}

.slide {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  transition: transform 0.2s ease-in;
  position: absolute;
  color: white;
  font: bold 48px monospace;
}

.slider > button {
  position: absolute;
}

button.up,
button.down {
  left: 50%;
  transform: translateX(-50%);
}
button.up { top: 25px; }
button.down { bottom: 25px; }

button.left,
button.right {
  top: 50%;
  transform: translateY(-50%);
}
button.left { left: 25px; }
button.right { right: 25px; }


.down-enter {
  transform: translateY(100%);
}
.down-enter-to,
.down-leave {
  transform: translateY(0);
}
.down-leave-to {
  transform: translateY(-100%);
}

.up-enter {
  transform: translateY(-100%);
}
.up-enter-to,
.up-leave {
  transform: translateY(0);
}
.up-leave-to {
  transform: translateY(100%);
}

.left-enter {
  transform: translateX(-100%);
}
.left-enter-to,
.left-leave {
  transform: translateX(0);
}
.left-leave-to {
  transform: translateX(100%);
}

.right-enter {
  transform: translateX(100%);
}
.right-enter-to,
.right-leave {
  transform: translateX(0);
}
.right-leave-to {
  transform: translateX(-100%);
}

JavaScript

Vue.component('v-slider', {
  template: `
<div class="slider">
  <transition :name="animation">
    <div
      :key="\`\${iRow}.\${iCol}\`"
      :style="{ background: slide.color }"
      class="slide"
    >{{ slide.text }}</div>
  </transition>
  <button
    v-for="{ name, rowChange = 0, colChange = 0 } in buttons"
    v-show="slidesData[iRow + rowChange]?.[iCol + colChange]"
    :class="name"
    @click="onClick(name, rowChange, colChange)"
  >{{ name }}</button>
</div>`,
  props: [ 'slidesData' ],
  data: () => ({
    animation: null,
    iRow: 0,
    iCol: 0,
    buttons: [
      { name: 'up', rowChange: -1, },
      { name: 'right', colChange: 1, },
      { name: 'down', rowChange: 1, },
      { name: 'left', colChange: -1, },
    ],
  }),
  computed: {
    slide() {
      return this.slidesData[this.iRow][this.iCol];
    },
  },
  methods: {
    onClick(animation, rowChange, colChange) {
      this.animation = animation;
      this.iRow += rowChange;
      this.iCol += colChange;
    },
  },
});

new Vue({
  el: '#app',
  data: {
    slidesData: [
      [
        { text: 'hello, world!!', color: 'black' },
        { text: 69, color: 'silver' },
      ],
      [
        { text: 'fuck the world', color: 'red' },
        { text: 187, color: 'blue' },
        { text: '!!!', color: 'brown' },
        { text: '???', color: 'magenta' },
      ],
      [
        { text: 'fuck everything', color: 'green' },
        { text: 666, color: 'aqua' },
        { text: '@@@', color: 'orange' },
      ],
    ],
  },
});