Skip to content
Snippets Groups Projects
App.vue 14 KiB
Newer Older
Julian's avatar
Julian committed
<script setup>
Julian's avatar
Julian committed
import DragGrid from "../../src/DragGrid.vue";
Julian's avatar
Julian committed
import CircularCard from "./components/CircularCard.vue";
import Example1Generic from "./Example1Generic.vue";
import Example2TicTacToe from "./Example2TicTacToe.vue";
import Example3Counters from "./Example3Counters.vue";
Julian's avatar
Julian committed
</script>

<template>
  <div id="app">
Julian's avatar
Julian committed
    <h1><code>DragGrid</code> Examples</h1>
    <h2>Example 1</h2>
    <p>
      Grid with two programmatically blocked cells and one programmatically
      blocked item
    </p>
    <example1-generic></example1-generic>
Julian's avatar
Julian committed

    <h2>Example 2: "Tic-Tac-Toe"</h2>
    <p>
      A grid functioning as a playing field and another functioning as a
      container for playing pieces. You can drag as many pieces as you want from
      the container to the field.
    </p>

    <example2-tic-tac-toe></example2-tic-tac-toe>
Julian's avatar
Julian committed

    <h2>Example 3: Counters</h2>
    <p>
      Showcasing local and global state: The local state of the counter
      components doesn't change when moved inside one grid, but is cleared when
      moved to the other. The global state is in the <code>data</code> attribute
      of each item and gets transferred as well. Both grids have also custom
      highlights.
    </p>

    <example3-counters></example3-counters>
Julian's avatar
Julian committed

    <h2>Example 4: Dynamic lessons</h2>
    <p>
      These lessons are loaded from <code>computed</code> to simulate a
      non-editable source like an API. they are changed using the method
      <code>handleLessonMoved</code>. Try changing the sizes of Lesson1, the
      grid and the texts of the items! The lesson container on the side doesn't
      have a highlight and doesn't keep track of the item position. Try moving
      <code>item3</code> back and forth!
    </p>
    <div class="ttt-container">
      <div>
        <label>
          Lesson 1 has length: {{ lesson1Length }}
          <input
            type="range"
            v-model="lesson1Length"
            min="1"
            max="5"
            step="1"
          />
        </label>
        <input type="text" v-model="lessonData.lesson1" />
      </div>
      <div>
        <label>
          Lesson grid has width: {{ lesson1Cols }}
          <input type="range" v-model="lesson1Cols" min="2" max="5" step="1" />
        </label>
        <input type="text" v-model="lessonData.lesson2" />
      </div>
      <div>
        <label>
          Lesson grid has height: {{ lesson1Rows }}
          <input type="range" v-model="lesson1Rows" min="6" max="10" step="1" />
          <input type="text" v-model="lessonData.lesson3.inside" />
          <input type="text" v-model="lessonData.lesson3.outside" />
        </label>
      </div>

      <drag-grid
        :value="lessons1"
        :cols="parseInt(lesson1Cols)"
        :rows="parseInt(lesson1Rows)"
        class="bordered"
        context="lesson"
Julian's avatar
Julian committed
        grid-id="lesson-plan"
        @itemChanged="handleLessonMoved"
      >
        <template #item="item">
          <div class="container">{{ item }}</div>
        </template>
      </drag-grid>
Julian's avatar
Julian committed
      <drag-grid
        :value="lessons1"
        :cols="1"
        :rows="10"
        context="lesson"
        grid-id="lesson-storage"
        @itemChanged="handleLessonDropInContainer"
Julian's avatar
Julian committed
        no-highlight
Julian's avatar
Julian committed
      >
        <template #item="item">
          <div class="container">{{ item }}</div>
        </template>
      </drag-grid>
    </div>
Julian's avatar
Julian committed

    <h2>Example 5: Dynamic colors</h2>
    <p>
      This example showcases the <code>rawItem</code> with the custom method
      <code>getColor</code>. Both grids on the outside call the method with
      <code>"red"</code> while the one in the middle uses <code>"green"</code>.
      We use arrays called <code>placedA</code>, <code>placedB</code> and
      <code>placedC</code> to save, which item is contained in which grid.
      Notice: the third grid doesn't save the item position, they are always
      positioned automatically.
    </p>
Julian's avatar
Julian committed
    <div class="ttt-container">
      <drag-grid
        :value="colorGrid"
        :cols="4"
        :rows="4"
        grid-id="gridA"
        context="colors"
        class="bordered color-grid"
        @itemChanged="handleColorItemChange"
      >
        <template #item="item">
          <div
            :style="{
              background: item.rawItem.getColor('red'),
              color: 'white',
            }"
          >
            {{ item.data.name }}
          </div>
        </template>
      </drag-grid>
      <drag-grid
        :value="colorGrid"
        :cols="4"
        :rows="4"
        grid-id="gridB"
        context="colors"
        class="bordered color-grid"
        @itemChanged="handleColorItemChange"
      >
        <template #item="item">
          <div
            :style="{
              background: item.rawItem.getColor('green'),
              color: 'black',
            }"
          >
            {{ item.data.name }}
          </div>
        </template>
      </drag-grid>
      <drag-grid
        :value="colorGrid"
        :cols="4"
        :rows="4"
        grid-id="gridC"
        context="colors"
        class="bordered color-grid"
        @itemChanged="handleColorItemChange"
      >
        <template #item="item">
          <div
            :style="{
              background: item.rawItem.getColor('red'),
              color: 'white',
            }"
          >
            {{ item.data.name }}
          </div>
        </template>
      </drag-grid>
    </div>
Julian's avatar
Julian committed

    <div class="ttt-container">
      <div>
        <h2>Example 6: Disabled grid</h2>
        <p>
          This uses the same data as the tic tac toe but is completely disabled.
          Notice how the items still move if the tic tac toe grid above is
          changed. Uncheck the checkbox to enable:
        </p>

        <label>
          <input type="checkbox" v-model="gridDisabled" />
          Grid disabled?
        </label>

        <drag-grid
          v-model="ticTacToe"
Julian's avatar
Julian committed
          :cols="3"
          :rows="3"
          :disabled="gridDisabled"
          class="tic-tac-toe"
          context="ticTacToe"
        >
          <template #item="item">
            <CircularCard>
              {{ item.key.startsWith("a") ? "X" : "O" }}
            </CircularCard>
          </template>
        </drag-grid>
      </div>
      <div>
        <h2>Example 7: Disabled fields and items with props</h2>
Julian's avatar
Julian committed
        <p>
          This is a grid with disabled fields and items. Red items are disabled
          and cannot be moved.
        </p>
        <drag-grid
          v-model="someDisabledItems"
          :cols="4"
          :rows="4"
          class="tic-tac-toe"
          :disabled-fields="disabledFields"
        >
          <template #item="{ rawItem }">
            <div
              class="container"
              :style="{ background: rawItem.disabled ? 'red' : 'green' }"
            ></div>
          </template>
          <template #disabledField
            ><div class="container">This field is disabled!</div></template
          >
        </drag-grid>
Julian's avatar
Julian committed
      </div>
    </div>
Julian's avatar
Julian committed
  </div>
</template>

<script>
export default {
  name: "App",
  methods: {
    handleLessonMoved(lesson) {
      this.logInput(lesson);
      switch (lesson.key) {
        case "lesson1":
          this.lesson1X = lesson.x;
          this.lesson1Y = lesson.y;
          break;
        case "lesson2":
          this.lesson2X = lesson.x;
          this.lesson2Y = lesson.y;
          break;
Julian's avatar
Julian committed
        case "lesson3":
          this.lesson3X = lesson.x;
          this.lesson3Y = lesson.y;
          this.lesson3inPlan = true;
          break;
        default:
          console.error("Something is wrong here!");
      }
    },
Julian's avatar
Julian committed
    handleLessonDropInContainer(lesson) {
      if (lesson.key === "lesson3") this.lesson3inPlan = false;
    },
Julian's avatar
Julian committed
    contains(array, search) {
      return array.filter((obj) => obj === search).length > 0;
    },
    findAndRemove(array, element) {
      let index = array.findIndex((i) => {
        return i === element;
      });
      if (index >= 0) array.splice(index, 1);
    },
    handleColorItemChange(item) {
      this[item.key].x = item.x;
      this[item.key].y = item.y;

      if (item.gridId === item.originGridId) return;

      switch (item.gridId) {
        case "gridA":
          // Moved to gridA
          this.findAndRemove(
            item.originGridId === "gridB" ? this.placedB : this.placedC,
            item.key
          );
          this.placedA.push(item.key);
          break;
        case "gridB":
          // Moved to gridB
          this.findAndRemove(
            item.originGridId === "gridA" ? this.placedA : this.placedC,
            item.key
          );
          this.placedB.push(item.key);
          break;
        case "gridC":
          // Moved to gridC
          this.findAndRemove(
            item.originGridId === "gridB" ? this.placedB : this.placedA,
            item.key
          );
          this.placedC.push(item.key);
          break;
      }
    },
Julian's avatar
Julian committed
        { x: 1, y: 1, w: 1, h: 1, key: "a1", data: { text: "X" } },
        { x: 3, y: 3, w: 1, h: 1, key: "b1", data: { text: "O" } },
Julian's avatar
Julian committed
      ],
      lesson1Length: 1,
      lesson1Cols: 4,
      lesson1Rows: 6,
      lesson1X: 1,
      lesson1Y: 1,
      lesson2X: 2,
      lesson2Y: 1,
Julian's avatar
Julian committed
      lesson3X: -1,
      lesson3Y: -1,
      lesson3inPlan: false,
      lessonData: {
        lesson1: "Nothing",
        lesson2: "Hallo",
        lesson3: {
          inside: "This is lesson 3 inside the plan",
          outside: "This is lesson3 outside of the plan",
        },
      },
Julian's avatar
Julian committed
      placedA: ["item1", "item2"],
      placedB: ["item3", "item4"],
      placedC: ["item5", "item6"],
      item1: {
        x: 1,
        y: 1,
      },
      item2: {
        x: 2,
        y: 2,
      },
      item3: {
        x: 1,
        y: 1,
      },
      item4: {
        x: 3,
        y: 3,
      },
      item5: {
        x: 2,
        y: 4,
      },
      item6: {
        x: 4,
        y: 2,
      },
Julian's avatar
Julian committed
      gridDisabled: true,
Julian's avatar
Julian committed
      someDisabledItems: [
        { key: "key1", x: 1, y: 3, w: 1, h: 1, data: {} },
        { key: "key2", x: 2, y: 2, w: 1, h: 1, data: {} },
        { key: "key3", x: 3, y: 1, w: 1, h: 1, data: {}, disabled: true },
        { key: "key4", x: 1, y: 2, w: 1, h: 1, data: {}, disabled: true },
      ],
      disabledFields: [
        { x: 1, y: 1 },
        { x: 2, y: 3 },
      ],
  computed: {
    lessons1() {
      return [
        {
Julian's avatar
Julian committed
          x: (grid) => {
            return grid.gridId === "lesson-plan" ? this.lesson1X : 0;
          },
          y: (grid) => {
            return grid.gridId === "lesson-plan" ? this.lesson1Y : 0;
          },
          w: 1,
          h: this.lesson1Length,
          key: "lesson1",
          data: {
            text: this.lessonData.lesson1,
          },
        },
        {
          x: (grid) => {
Julian's avatar
Julian committed
            return grid.gridId === "lesson-plan" ? this.lesson2X : 0;
          },
          y: (grid) => {
            return grid.gridId === "lesson-plan" ? this.lesson2Y : 0;
          },
          w: 1,
          h: parseInt(this.lesson1Length) + 1,
          key: "lesson2",
          data: {
            text: this.lessonData.lesson2,
          },
Julian's avatar
Julian committed
        {
          x: (grid) => {
            if (this.lesson3inPlan) {
              return grid.gridId === "lesson-plan" ? this.lesson3X : -1;
            }
            return grid.gridId === "lesson-plan" ? -1 : 0;
          },
          y: (grid) => {
            if (this.lesson3inPlan) {
              return grid.gridId === "lesson-plan" ? this.lesson3Y : -1;
            }
            return grid.gridId === "lesson-plan" ? -1 : 0;
          },
          w: 1,
          h: parseInt(this.lesson1Length) + 1,
          key: "lesson3",
          data: (grid) => {
            return {
              text:
                grid.gridId === "lesson-storage"
                  ? this.lessonData.lesson3.outside
                  : this.lessonData.lesson3.inside,
            };
          },
Julian's avatar
Julian committed
        },
Julian's avatar
Julian committed
    colorGrid() {
      let items = ["item1", "item2", "item3", "item4", "item5", "item6"];
      let greens = [
        "green",
        "seagreen",
        "greenyellow",
        "darkolivegreen",
        "limegreen",
        "palegreen",
      ];
      let reds = [
        "darkred",
        "indianred",
        "orangered",
        "red",
        "maroon",
        "firebrick",
      ];
      return items.map((itemName) => {
        return {
          key: itemName,
          x: (grid) => {
            if (grid.gridId === "gridA") {
              return this.contains(this.placedA, itemName)
                ? this[itemName].x
                : -1;
            } else if (grid.gridId === "gridB") {
              return this.contains(this.placedB, itemName)
                ? this[itemName].x
                : -1;
            } else {
              // gridC
              return this.contains(this.placedC, itemName) ? 0 : -1;
            }
          },
          y: (grid) => {
            if (grid.gridId === "gridA") {
              return this.contains(this.placedA, itemName)
                ? this[itemName].y
                : -1;
            } else if (grid.gridId === "gridB") {
              return this.contains(this.placedB, itemName)
                ? this[itemName].y
                : -1;
            } else {
              // gridC
              return this.contains(this.placedC, itemName) ? 0 : -1;
            }
          },
          w: 1,
          h: 1,
          data: {
            name: itemName,
          },
          getColor: (a) =>
            a === "red"
              ? reds[parseInt(itemName[4]) - 1]
              : greens[parseInt(itemName[4]) - 1],
        };
      });
    },
};
</script>

<style scoped>
.container {
  background: lightcoral;
  width: 100%;
  height: 100%;
}
Julian's avatar
Julian committed

.tic-tac-toe {
  max-width: 400px;
}

.ttt-container {
  display: flex;
  justify-content: space-between;
}

.bordered {
  border: 2px solid grey;
}
Julian's avatar
Julian committed

.color-grid {
  min-height: 11em;
  line-height: 2em;
  box-sizing: content-box;
}
Julian's avatar
Julian committed

h2 {
  padding-top: 1em;
}

h2 + p {
  padding-bottom: 0.5em;
}

code {
  background: lightgray;
  padding: 0.2em;
  border-radius: 3px;
}
</style>