Skip to content

Instantly share code, notes, and snippets.

@math3vz
Last active September 13, 2016 15:51
Show Gist options
  • Select an option

  • Save math3vz/c01d859efdb1ece6aeea08bbfb75f97f to your computer and use it in GitHub Desktop.

Select an option

Save math3vz/c01d859efdb1ece6aeea08bbfb75f97f to your computer and use it in GitHub Desktop.

Usar component:

<menu
  :items="items"
  :visible="true"
  title="PredictorApp - Teams">
</menu>

Itens do menu:

data () {
  return {
    items: [
      {
        value: 'Home',
        path: '/home'
      },
      {
        value: 'Criar',
        path: '/create'
      },
      {
        value: 'Has Submenu',
        children: [
          {
            value: 'Outro sub',
            children: [
              {
                value: 'Outra pagina',
                path: '/page'
              }
            ]
          },
          {
            value: 'Página X',
            path: '/pagex'
          },
          {
            value: 'Submenu irmão',
            children: [
              {
                value: 'Página Y',
                path: '/pagey'
              }
            ]
          }
        ]
      }
    ]
  }
}

Menu Component:

<template>
  <aside
    id="menu"
    :class="{'visible': isVisible}"
    :style="{'padding-right': width}"
    :click="togglePadding">

    <div
      class="menu-inner"
      :style="{'width': definedWidth}">

      <button
        type="button"
        class="toggle-menu-button btn"
        v-on:click="toggleVisible">

        <i class="glyphicon glyphicon-menu-hamburger"></i>
      </button>

      <h1>
        {{ title }}
      </h1>

      <div class="menu-content">
        <slot></slot>

        <ul class="menu-list">
          <item :model="items"></item>
        </ul>
      </div>
    </div>
  </aside>
</template>

<script>
import Item from './Item'

export default {
  props: {
    'items': {
      type: Array,
      default: []
    },
    'title': {
      type: String,
      default: 'Menu'
    },
    'visible': {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      isVisible: this.visible,
      definedWidth: null,
      width: '300px'
    }
  },
  methods: {
    toggleVisible: function (event) {
      this.isVisible = !this.isVisible
    },
    togglePadding: function (event) {
      this.width = '50px'

      if (this.isVisible) {
        this.width = this.definedWidth
      }
    }
  },
  created () {
    this.definedWidth = this.width
  },
  components: {
    Item
  }
}
</script>

<style>
  #menu {
    height: 100vh;
    margin-right: 20px;
    position: fixed;
  }

  .menu-inner {
    background-color: #ddd;
    height: 100%;
    left: 0;
    position: absolute;
    top: 0;
    transform: translateX(-83%);
    transition: all .2s;
    width: 100%;
    vertical-align: top;
  }

  #menu.visible .menu-inner {
    transform: translateX(0);
  }

  .btn.toggle-menu-button {
    color: #666;
    font-size: 1.2em;
    line-height: 1;
    position: absolute;
    right: 5px;
    top: 5px;
  }

  #menu h1 {
    font-size: 1.5em;
    font-weight: bold;
    margin-left: 20px;
    margin-top: 0;
    padding-top: 10px;
    text-align: left;
  }

  #menu .menu-list {
    padding: 0;
  }

  #menu .menu-content {
    display: none;
    margin: 40px auto 0;
    width: 90%;
  }

  #menu.visible .menu-content {
    display: block;
  }

  .menu-item,
  .menu-item.has-submenu > div {
    color: #2c3e50;
    display: block;
    font-size: 1.6rem;
    list-style: none;
    text-align: left;
    width: 100%;
  }

  .menu-item a,
  .menu-item.has-submenu > div {
    display: block;
    width: 100%;
    height: 100%;
    padding: 2% 2% 2% 10%;
    color: inherit;
  }

  .has-submenu ul {
    padding: 0;
  }

  .has-submenu ul li {
    padding-left: 15px;
  }

  .has-submenu > div {
    cursor: pointer;
  }

  #menu.visible .menu-item:not(.has-submenu):hover a,
  #menu.visible .menu-item.has-submenu > div:hover,
  #menu.visible .menu-item a.active {
    background-color: #2c3e50;
    color: #fff;
    text-decoration: none;
  }

  #menu + * {
    margin-left: 50px;
  }

  #menu.visible + * {
    margin-left: 330px;
  }
</style>

Item Component:

<template>
  <li
    v-for="item in model"
    class="menu-item"
    :class="{'has-submenu': isSubmenu(item)}">

    <a
      v-link="{ path: item.path, activeClass: 'active' }"
      v-if="!isSubmenu(item)">

      {{ item.value }}
    </a>

    <div
      v-else
      @click="toggle(item)">

      {{ item.value }}

      <span class="show-submenu">
        [{{ isOpened(item) ? '-' : '+' }}]
      </span>
    </div>

    <ul
      v-show="isOpened(item)"
      v-if="isSubmenu(item)">

      <item :model="item.children"></item>
    </ul>
  </li>
</template>

<script>
  export default {
    name: 'Item',
    props: {
      model: Array
    },
    data () {
      return {
        openedItems: []
      }
    },
    methods: {
      isOpened: function (item) {
        return this.openedItems.indexOf(item) !== -1
      },
      _openOrClose: function (item) {
        if (this.isOpened(item)) {
          this.openedItems.splice(this.openedItems.indexOf(item), 1)

          return true
        }

        this.openedItems.push(item)
      },
      isSubmenu: function (item) {
        return item.children && item.children.length
      },
      toggle: function (item) {
        if (!this.isSubmenu(item)) {
          return false
        }

        this._openOrClose(item)
      }
    }
  }
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment