Kaynağa Gözat

add GalleryMap component in Gallery

axolotle 2 yıl önce
ebeveyn
işleme
af1dc1320c

+ 4 - 4
src/components/layouts/SideView.vue

@@ -7,11 +7,11 @@
     :body-class="{ paddings: !noCross }"
     backdrop backdrop-variant="light"
   >
-    <template #default="{ hide }">
+    <template #default="{ hide, visible }">
       <div v-if="!noCross" class="btn-close-wrapper">
         <button-close @click="hide()" />
       </div>
-      <slot name="default" v-bind="{ hide }" />
+      <slot name="default" v-bind="{ hide, visible }" />
     </template>
   </b-sidebar>
 </template>
@@ -38,11 +38,11 @@ export default {
       background-color: red;
       width: auto;
 
-      @include media-breakpoint-down($size-bp-down) {
+      @media (orientation: portrait) {
         width: 100%;
       }
 
-      @include media-breakpoint-up($size-bp) {
+      @media (orientation: landscape)  {
         max-width: 50%;
 
         &:not(.b-sidebar-right) {

+ 20 - 4
src/pages/Gallery.vue

@@ -1,11 +1,18 @@
 <template>
   <div class="gallery">
-    <b-button v-b-toggle.gallery-map variant="creation" class="btn-side left">
+    <b-button v-b-toggle.gallery-map-side variant="creation" class="btn-side left">
       {{ $t('map') }}
     </b-button>
 
-    <side-view id="gallery-map">
-      MAP
+    <side-view id="gallery-map-side">
+      <template #default="{ hide, visible }">
+        <gallery-map
+          v-if="creations"
+          :nodes="creations" :node="creation"
+          :visible="visible"
+          @open-creation="openCreation($event, hide)"
+        />
+      </template>
     </side-view>
 
     <gallery-view
@@ -47,7 +54,7 @@ import { mapGetters } from 'vuex'
 import { getRelation } from '@/store/utils'
 import { SideView } from '@/components/layouts'
 import { NodeViewTitle } from '@/components/nodes'
-import { GalleryView } from '@/pages/gallery'
+import { GalleryView, GalleryMap } from '@/pages/gallery'
 
 
 export default {
@@ -56,6 +63,7 @@ export default {
   components: {
     SideView,
     GalleryView,
+    GalleryMap,
     NodeViewTitle
   },
 
@@ -138,6 +146,14 @@ export default {
   }
 }
 
+::v-deep #gallery-map-side {
+  width: 100%;
+
+  .btn-close {
+    float: unset;
+  }
+}
+
 #gallery-index {
   ul {
     padding: 0;

+ 141 - 0
src/pages/gallery/GalleryMap.vue

@@ -0,0 +1,141 @@
+<template>
+  <div class="gallery-map wh-100">
+    <div class="gallery-map-wrapper" :style="`--max: ${max}px;`">
+      <div class="rows" v-if="dots && max">
+        <div
+          v-for="(row, y) in dots" :key="y"
+          class="row"
+          :class="{ sub: y % 2 === 0 }"
+        >
+          <div
+            v-for="(dot, x) in row" :key="`${y}-${x}`"
+            class="dot" :class="{ current: dot === node }"
+          >
+            <img
+              v-if="dot"
+              :src="dot.image.url"
+              :alt="dot.image.alt"
+              @click="$emit('open-creation', dot.id)"
+            >
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { shuffle } from '@/helpers/common'
+
+
+export default {
+  name: 'GalleryMap',
+
+  props: {
+    nodes: { type: Array, required: true },
+    node: { type: Object, required: true },
+    visible: { type: Boolean, required: true }
+  },
+
+  data () {
+    return {
+      dots: undefined,
+      size: [0, 0],
+      max: undefined
+    }
+  },
+
+  watch: {
+    visible (visible) {
+      if (visible) {
+        this.defineSize()
+      }
+    }
+  },
+
+  methods: {
+    setDots () {
+      const nodesLen = this.nodes.length
+      const sqrt = Math.ceil(Math.sqrt(nodesLen))
+      const rows = Math.floor(Math.sqrt(Math.pow(sqrt, 2) / 2))
+      const len = rows + 1
+      let max = rows * len * 2
+      let extra = 0
+      while (max - nodesLen < 0) {
+        extra += 1
+        max += extra % 2 === 0 ? rows : len
+      }
+
+      const nodes = shuffle([...this.nodes, ...Array(max - nodesLen).fill(undefined)])
+      const dots = []
+      for (var y = 0; y < len + rows + extra; y++) {
+        const x = y % 2 === 0 ? rows : len
+        dots.push(nodes.splice(0, x))
+      }
+      this.size = [len, len + rows + extra]
+      this.dots = dots
+    },
+
+    defineSize () {
+      const [x, y] = this.size
+      const { offsetWidth, offsetHeight } = document.querySelector('.gallery-map-wrapper')
+      const h = offsetHeight / (y * 2 - 1)
+      const w = offsetWidth / (x * 2 - 1)
+      this.max = Math.min(Math.min(h, w), 100)
+    }
+  },
+
+  created () {
+    this.setDots()
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.gallery-map {
+
+  &-wrapper {
+    width: 100%;
+    position: relative;
+    height: 100%;
+  }
+
+  .rows {
+      position: absolute;
+      display: flex;
+      flex-direction: column;
+      justify-content: space-between;
+      align-items: center;
+      height: 100%;
+      width: 100%;
+  }
+
+  .row {
+    display: flex;
+    justify-content: space-between;
+    width: 100%;
+
+    &.sub {
+      justify-content: space-around;
+    }
+  }
+
+  .dot {
+    display: flex;
+    width: var(--max);
+    height: var(--max);
+
+    img {
+      max-width: 100%;
+      max-height: 100%;
+      margin: auto;
+      cursor: pointer;
+    }
+
+    &.current {
+      border: 5px solid theme-color('creation');
+      background-color: theme-color('creation');
+    }
+  }
+}
+</style>

+ 4 - 1
src/pages/gallery/GalleryView.vue

@@ -159,8 +159,11 @@ export default {
   &-caption {
     height: 100%;
     text-align: center;
-    font-size: 1.15rem;
     font-family: $font-family-text;
+
+    @include media-breakpoint-up($size-bp) {
+      font-size: 1.5rem;
+    }
   }
 
   .gallery-view-btn-wrapper {

+ 1 - 0
src/pages/gallery/index.js

@@ -1 +1,2 @@
 export { default as GalleryView } from './GalleryView'
+export { default as GalleryMap } from './GalleryMap'