// Point of entry for Vue
#app
  window-manager

// Vindue Plugin Templates
template#taskbar
  .taskbar
    .start-menu(v-show='startMenuOpen')
      .title Vindue98
      .items
        .item(@mousedown="open('help')") #[i.fa.fa-fw.fa-lg.fa-question]Help
        .item(@mousedown="open('settings')") #[i.fa.fa-fw.fa-lg.fa-cog]Settings
        .divider
        .item #[i.fa.fa-fw.fa-lg.fa-power-off]Shut Down
    button(@click='toggleStartMenu' @blur='closeStartMenu' v-bind:class='{pressed: startMenuOpen}') #[i.fa.fa-fw.fa-bars]Start
    .divider
    .section
      button.item(v-for='(w, key) in windows' @click='focusWindow(key)' v-bind:title='w' v-bind:class='{pressed: focus === key}') {{$parent.$refs['key-' + key][0].title}}
    .info
      .time(v-bind:title="moment(now).format('dddd, MMMM D, YYYY')") {{moment(now).format(timeCode)}}

template#windowManager
  .window-manager(@touchstart='onTouch' @touchmove='onTouch' @touchend='onTouch' v-bind:style='state.style')
    taskbar(@open='open' @focus-window='focusWindow' v-bind:windows='windows' v-bind:focus='focus' v-bind:time-code='state.timeCode')
    template(v-for='(w, key) in windows')
      window(v-bind:component='w' v-bind:key-val='key' v-bind:top='start.top' v-bind:left='start.left' v-bind:class='{focus: focus === key}' v-bind:ref="'key-' + key" v-bind:vindue-state.sync='state')

template#help
  .help {{text}}

// App Components
template#tabControl
  .tab-control-wrapper
    .tab-control
      .anchor
        .header
          button(v-for='(value, key) in $slots' v-bind:class='{focus: focus === key}' @click='focusTab(key)'): span {{key}}
      .pane(v-for="(value, key) in $slots" v-show='focus === key')
        slot(:name='key')

template#settings
  .settings
    tab-control
      template(slot='Background')
        .color-box(v-bind:style='{background: color}')
        .drop-down
          select(v-model='color' v-on:change='changeBackground')
            option(value='#1C1F2B') Blue
            option(value='#1b5e20') Green
            option(value='#7f0000') Red
      template(slot='Theme') Theme Stuff
      template(slot='Time')
        .row
          .col.labels
            label(for='hours') Hours
            label(for='minutes') Minutes
            label(for='seconds') Seconds
            label(for='month') Month
            label(for='day') Day
            label(for='year') Year
          .col.inputs
            .row
              .drop-down(v-bind:class='{disabled: !hoursEnabled}')
                select(id='hours' v-model='hours' @change='changeTime')
                  option(value='h') 12
                  option(value='k') 24
              input(type='checkbox' v-model='hoursEnabled' @change='changeTime')
            .row
              .drop-down(v-bind:class='{disabled: !minutesEnabled}')
                select(id='minutes' v-model='minutes' @change='changeTime')
                  option(value='mm') 00 01...
                  option(value='m') 0 1...
              input(type='checkbox' v-model='minutesEnabled' @change='changeTime')
            .row
              .drop-down(v-bind:class='{disabled: !secondsEnabled}')
                select(id='seconds' v-model='seconds' @change='changeTime')
                  option(value='ss') 00 01...
                  option(value='s') 0 1...
              input(type='checkbox' v-model='secondsEnabled' @change='changeTime')
            .row
              .drop-down(v-bind:class='{disabled: !monthEnabled}')
                select(id='month' v-model='month' @change='changeTime')
                  option(value='M') 1 2...
                  option(value='MM') 01 02...
                  option(value='Mo') 1st...
                  option(value='MMM') Jan
                  option(value='MMMM') January
              input(type='checkbox' v-model='monthEnabled' @change='changeTime')
            .row
              .drop-down(v-bind:class='{disabled: !dayEnabled}')
                select(id='day' v-model='day' @change='changeTime')
                  option(value='D') 1 2...
                  option(value='DD') 01 02...
              input(type='checkbox' v-model='dayEnabled' @change='changeTime')
            .row
              .drop-down(v-bind:class='{disabled: !yearEnabled}')
                select(id='year' v-model='year' @change='changeTime')
                  option(value='YY') 70 71...
                  option(value='YYYY') 1970 1971...
              input(type='checkbox' v-model='yearEnabled' @change='changeTime')
    .buttons
      button(@click='$parent.close()') OK

// Profile link styling for self-shilling
a.shill(href='https://codepen.io/milesmanners' target='_blank' title='Made by Miles Manners')
View Compiled
@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700');

$clr-bg: #1C1F2B;
$clr-bg-light: lighten($clr-bg, 10%);
$clr-bg-lighter: lighten($clr-bg, 15%);
$clr-bg-dark: darken($clr-bg, 2.5%);
$clr-bg-darker: darken($clr-bg, 5%);
$clr-text: $clr-black;
$clr-text-hint: rgba($clr-text, .6);
$clr-primary: $clr-blue;
$clr-secondary: $clr-green;

$clr-taskbar: #C2C2C2;
$clr-taskbar-dark: #BEBEBE;
$clr-taskbar-darker: #A1A1A1;
$clr-taskbar-border: #E3E3E3;

$anim-dur: 200ms;

$border-radius: 4px;

*, *::before, *::after {
  box-sizing: border-box;
}

html, body {
  width: 100%;
  height: 100%;
}

body {
  background: $clr-bg;
  //color: $clr-text;
  margin: 0px;
  font-family: 'Open Sans', sans-serif;
}

.anchor {
  height: 0;
}

.row {
  display: flex;
}

.fa {
  display: inline-block;
}

.window-manager {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  overflow: hidden;
  background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/726875/Vindue.png);
  background-repeat: no-repeat;
  background-position: center center;
  background-size: 40vmin;
  
  .window {
    position: absolute;
    background: $clr-taskbar;
    border: 2px outset $clr-taskbar-border;
    will-change: left, top;
    z-index: 5;
    display: flex;
    flex-direction: column;
    
    &.focus {
      z-index: 6;
      
      .title {
        background: linear-gradient(to right, #00007F, #0F80CF);
        color: $clr-white;
      }
    }
    
    .border {
      position: absolute;
      
      &.top, &.bottom {
        width: 100%;
        height: 6px;
        cursor: ns-resize;
      }
      
      &.left, &.right {
        height: 100%;
        width: 6px;
        cursor: ew-resize;
      }
      
      &.top-right, &.bottom-right, &.bottom-left, &.top-left {
        width: 6px;
        height: 6px;
      }
      
      &.top-right, &.bottom-left {
        cursor: nesw-resize;
      }
      
      &.bottom-right, &.top-left {
        cursor: nwse-resize;
      }
      
      &.top { top: -6px }
      &.right { right: -6px }
      &.bottom { bottom: -6px }
      &.left { left: -6px }
      
      &.top-right {
        top: -6px;
        right: -6px;
      }
      
      &.bottom-right {
        bottom: -6px;
        right: -6px;
      }
      
      &.bottom-left {
        bottom: -6px;
        left: -6px;
      }
      
      &.top-left {
        top: -6px;
        left: -6px;
      }
    }
    
    .title {
      display: flex;
      background: $clr-taskbar-darker;
      padding: 2px;
      padding-left: 4px;
      user-select: none;
      
      .actions {
        display: flex;
        margin-left: auto;
        
        button {
          padding: 0;
        }
      }
    }
    
    .content {
      overflow: auto;
    }
  }
}

.taskbar {
  position: absolute;
  bottom: 0;
  background: $clr-taskbar;
  color: $clr-black;
  width: 100%;
  height: 38px;
  border: 2px outset $clr-taskbar-border;
  display: flex;
  user-select: none;
  
  .start-menu {
    position: absolute;
    bottom: 38px;
    background: inherit;
    border: inherit;
    padding-right: 3px;
    display: flex;
    z-index: 999999;
    
    .title {
      background: linear-gradient(to top, #1715FB, #060579);
      color: $clr-white;
      writing-mode: tb-rl;
      transform: scale(-1, -1);
      width: 40px;
      font-weight: 700;
      font-size: 28px;
      padding: 10px 0;
    }
    
    .divider {
      width: 100%;
      height: 0px;
      border-width: 1px;
      border-style: inset;
    }
    
    .item {
      padding: 5px 10px 5px 0;
      
      &:hover {
        background: $clr-primary;
      }
      
      .fa {
        padding-right: 5px;
      }
    }
  }
  
  button {
    height: 30px;
    margin-top: 2px;
    padding: 0px 4px 0px 2px;
    background: inherit;
    font-size: 16px;
    
    &.pressed {
      border-style: inset;
    }
    
    &.item {
      width: 100px;
      text-align: left;
      padding-left: 4px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      margin-left: 3px;
      
      &:first-child {
        margin-left: 0;
      }
    }
  }
  
  .divider {
    background: inherit;
    width: 2px;
    height: 30px;
    margin: 2px 2px 0 2px;
    border: inherit;
  }
  
  .info {
    margin-top: 2px;
    padding: 0 3px;
    height: 30px;
    background: #BEBEBE;
    border: 2px inset $clr-taskbar-border;
    margin-left: auto;
  }
}

.window .help {
  padding: 5px;
}

.tab-control-wrapper {
  padding: 35px 10px 5px;
  
  .tab-control {
    height: 100%;
    border: 2px outset $clr-taskbar-border;

    .header {
      position: relative;
      top: -26px;
      white-space: nowrap;
      display: inline-block;

      button {
        height: 24px;
        background: $clr-taskbar;
        border-radius: $border-radius $border-radius 0 0;
        border-bottom: none;

        &.focus {
          height: 26px;

          span {
            position: relative;
            top: -1px;
          }
        }
      }
    }

    .pane {
      margin: 10px;
    }
  }
}

.color-box {
  height: 100px;
  border: 2px inset $clr-taskbar-border;
  margin-bottom: 5px;
}

.drop-down {
  position: relative;
  pointer-events: none;
  
  &:after {
    content: '>';
    font: 17px "Consolas", monospace;
    font-weight: bold;
    color: $clr-black;
    transform: rotate(90deg);
    background: $clr-taskbar;
    width: 21px;
    top: -1px;
    right: 5px;
    text-align: center;

    padding: 0 0 2px;
    border: 2px outset $clr-taskbar-border;

    position: absolute;
    pointer-events: none;
  }
  
  select {
    appearance: none;
    pointer-events: auto;

    border: 2px inset $clr-taskbar-border;
    
    display: block;
    width: 100%;
    height: 25px;
    float: right;
    margin: 0;
    padding: 0px;
    font-size: 16px;
    line-height: 1.75;
    color: $clr-black;
    background-color: $clr-white;
  }
  
  &.disabled {
    &:after {
      color: $clr-text-hint;
    }
    
    select {
      background: $clr-taskbar;
      color: $clr-text-hint;
    }
  }
}

.window .settings {
  .pane {
    display: flex;
    flex-direction: column;

    .col {
      display: flex;
      flex-direction: column;
    }

    .row {
      display: flex;
    }

    .labels {
      padding-right: 5px;

      label {
        height: 30px;
      }
    }

    .inputs {
      flex-grow: 1;

      .row {
        height: 30px;
      }

      .drop-down {
        width: 100%;
      }
    }
  }
  
  .buttons {
    margin-right: 10px;
    
    button {
      height: 30px;
      padding: 0px 4px 0px 2px;
      background: inherit;
      font-size: 16px;

      width: 80px;
      padding-left: 4px;
      white-space: nowrap;
      overflow: hidden;
      text-align: center;
      float: right;
      margin-bottom: 10px;
      margin-left: 3px;
      
      &:last-child {
        margin-left: 0;
      }
    }
  }
}

// Profile link styling for self-shilling
.shill {
  position: fixed;
  background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/726875/profile/profile-512.jpg?100000');
  background-size: cover;
  width: 40px;
  height: 40px;
  bottom: 50px;
  right: 10px;
  border-radius: 20px;
  opacity: .4;
  filter: blur(.5px);
  transition: opacity $anim-dur, blur $anim-dur;
  
  &:hover {
    opacity: 1;
    filter: none;
  }
}
View Compiled
// Plugin Definition
let Vindue = {
  install (vue, options) {
    Vue.component('window', {
      props: [
        'top',
        'left',
        'component',
        'key-val',
        'vindue-state'
      ],
      data () {
        return {
          title: '',
          resizable: false,
          helpText: '',
          style: {
            top: 0,
            left: 0,
            'min-width': '150px',
            'min-height': '100px',
            width: 'auto',
            height: 'auto',
            'z-index': 1,
            'user-select': 'auto'
          }
        }
      },
      render (h) {
        let comps = []

        // Resizable Borders
        const border = (c, ...on) =>
          h('div', {
            style: { display: this.resizable ? 'block' : 'none' },
            'class': { border: true, [c]: true },
            on: { mousedown: (e) => on.forEach(f => f(e)) }
          })
        
        comps.push(border('top', this.resizeTop))
        comps.push(border('right', this.resizeRight))
        comps.push(border('bottom', this.resizeBottom))
        comps.push(border('left', this.resizeLeft))
        comps.push(border('top-right', this.resizeTop, this.resizeRight))
        comps.push(border('bottom-right', this.resizeBottom, this.resizeRight))
        comps.push(border('bottom-left', this.resizeBottom, this.resizeLeft))
        comps.push(border('top-left', this.resizeTop, this.resizeLeft))
        
        // Window Actions
        let buttons = []
        // Help Button
        buttons.push(h('button', {
          style: { display: this.helpText && this.helpText.length > 0 ? 'block' : 'none' },
          on: {
            click: e => {
              e.stopPropagation()
              this.help()
            }
          }
        }, [
          h('i', { 'class': { fa: true, 'fa-fw': true, 'fa-question': true } })
        ]))
        // Close Button
        buttons.push(h('button', {
          on: {
            click: e => {
              e.stopPropagation()
              this.close()
            }
          }
        }, [
          h('i', { 'class': { fa: true, 'fa-fw': true, 'fa-times': true } })
        ]))
        
        // Title
        comps.push(h('div', {
          'class': { title: true },
          on: {
            mousedown: e => {
              if (e.target !== e.currentTarget) return

              this.startDrag(e)
            }
          }
        }, [this.title, h('div', { 'class': { actions: true } }, buttons)]))

        // Content
        let dynamic = h(this.component, {
          tag: 'component',
          props: {
            styleObj: this.style,
            vindueState: this.vindueState
          },
          on: {
            'update:title': val => { this.title = val },
            'update:resizable': val => { this.resizable = val },
            'update:help-text': val => { this.helpText = val },
            'update:style-obj': val => { this.style = val },
            'update:vindue-state': val => { this.vindueState = val }
          },
          ref: 'child'
        })

        // Content Container
        comps.push(h('div', { 'class': { content: true } }, [dynamic]))

        // Window
        return h('div', {
          'class': { window: true },
          style: this.style,
          on: { mousedown: e => { this.focusWindow() } }
        }, comps)
      },
      methods: {
        focusWindow () {
          this.$parent.focusWindow(this.keyVal)
        },
        startDrag (e) {
          let el = this.$el
          let style = this.style

          let startX = el.offsetLeft
          let startY = el.offsetTop
          let initialMouseX = e.clientX
          let initialMouseY = e.clientY

          function mouseMove (e) {
            let dx = e.clientX - initialMouseX
            let dy = e.clientY - initialMouseY
            style.top = startY + dy + 'px'
            style.left = startX + dx + 'px'
          }

          function mouseUp () {
            document.removeEventListener('mousemove', mouseMove)
            document.removeEventListener('mouseup', mouseUp)

            if (parseInt(style.left) < 0) {
              style.left = 0
            } else if (parseInt(style.left) + el.offsetWidth > window.innerWidth) {
              style.left = `${window.innerWidth - el.offsetWidth}px`
            }

            if (parseInt(style.top) < 0) {
              style.top = 0
            } else if (parseInt(style.top) + el.offsetHeight + 38 > window.innerHeight) {
              style.top = `${window.innerHeight - el.offsetHeight - 38}px`
            }
          }

          document.addEventListener('mousemove', mouseMove)
          document.addEventListener('mouseup', mouseUp)
        },
        help () {
          this.$parent.help(this.helpText)
        },
        close () {
          this.$parent.close(this.keyVal)
        },
        resizeTop (e) {
          this.style['user-select'] = 'none'
          let el = this.$el
          let style = this.style

          let startY = el.offsetTop
          let startH = parseInt(style.height)
          let initialMouseY = e.clientY

          function mouseMove (e) {
            let dy = e.clientY - initialMouseY

            if (startH - dy >= parseInt(style['min-height'])) {
              style.height = startH - dy + 'px'
              style.top = startY + dy + 'px'
            }
          }

          function mouseUp () {
            document.removeEventListener('mousemove', mouseMove)
            document.removeEventListener('mouseup', mouseUp)

            if (parseInt(style.top) < 0) {
              style.height = parseInt(style.height) + parseInt(style.top) + 'px'
              style.top = 0
            }

            style['user-select'] = 'auto'
          }

          document.addEventListener('mousemove', mouseMove)
          document.addEventListener('mouseup', mouseUp)
        },
        resizeRight (e) {
          this.style['user-select'] = 'none'
          let el = this.$el
          let style = this.style

          let startX = el.offsetLeft
          let startW = parseInt(style.width)
          let initialMouseX = e.clientX

          function mouseMove (e) {
            let dx = e.clientX - initialMouseX

            if (startW + dx >= parseInt(style['min-width'])) {
              style.width = startW + dx + 'px'
            }
          }

          function mouseUp () {
            document.removeEventListener('mousemove', mouseMove)
            document.removeEventListener('mouseup', mouseUp)

            style['user-select'] = 'auto'

            if (startX + parseInt(style.width) > window.innerWidth) {
              style.width = window.innerWidth - startX + 'px'
            }
          }

          document.addEventListener('mousemove', mouseMove)
          document.addEventListener('mouseup', mouseUp)
        },
        resizeBottom (e) {
          this.style['user-select'] = 'none'
          let el = this.$el
          let style = this.style

          let startY = el.offsetTop
          let startH = parseInt(style.height)
          let initialMouseY = e.clientY

          function mouseMove (e) {
            let dy = e.clientY - initialMouseY

            if (startH + dy >= parseInt(style['min-height'])) {
              style.height = startH + dy + 'px'
            }
          }

          function mouseUp () {
            document.removeEventListener('mousemove', mouseMove)
            document.removeEventListener('mouseup', mouseUp)

            if (startY + parseInt(style.height) + 38 > window.innerHeight) {
              style.height = window.innerHeight - startY - 38 + 'px'
            }
            style['user-select'] = 'auto'
          }

          document.addEventListener('mousemove', mouseMove)
          document.addEventListener('mouseup', mouseUp)
        },
        resizeLeft (e) {
          this.style['user-select'] = 'none'
          let el = this.$el
          let style = this.style

          let startX = el.offsetLeft
          let startW = parseInt(style.width)
          let initialMouseX = e.clientX

          function mouseMove (e) {
            let dx = e.clientX - initialMouseX

            if (startW - dx >= parseInt(style['min-width'])) {
              style.width = startW - dx + 'px'
              style.left = startX + dx + 'px'
            }
          }

          function mouseUp () {
            document.removeEventListener('mousemove', mouseMove)
            document.removeEventListener('mouseup', mouseUp)

            if (parseInt(style.left) < 0) {
              style.width = parseInt(style.width) + parseInt(style.left) + 'px'
              style.left = 0
            }
            style['user-select'] = 'auto'
          }

          document.addEventListener('mousemove', mouseMove)
          document.addEventListener('mouseup', mouseUp)
        }
      },
      mounted () {
        this.title = this.$refs.child.title
        this.resizable = this.$refs.child.resizable
        this.helpText = this.$refs.child.helpText
        
        this.style.top = this.top + 'px'
        this.style.left = this.left + 'px'
        
        this.$nextTick(function () {
          this.style.width = this.$el.offsetWidth + 1 + 'px'
          this.style.height = this.$el.offsetHeight + 1 + 'px'
        })

        this.style['z-index'] = this.keyVal
      }
    })

    Vue.component('taskbar', {
      template: '#taskbar',
      props: [
        'windows',
        'focus',
        'timeCode'
      ],
      data () {
        return {
          startMenuOpen: false,
          now: new Date()
        }
      },
      created () {
        setInterval(() => this.now = new Date, 1000)
      },
      methods: {
        toggleStartMenu () {
          this.startMenuOpen = !this.startMenuOpen
        },
        closeStartMenu () {
          this.startMenuOpen = false
        },
        open (name) {
          this.$emit('open', name)
        },
        focusWindow (w) {
          this.$emit('focus-window', w)
        }
      }
    })

    Vue.component('window-manager', {
      template: '#windowManager',
      data () {
        return {
          focus: null,
          windows: [],
          start: {
            top: 0,
            left: 0
          },
          state: {
            timeCode: 'h:mm A',
            style: {
              'background-color': '#1C1F2B'
            }
          },
          mousedown: []
        }
      },
      methods: {
        open (w) {
          this.focus = this.windows.length
          this.windows.push(w)
          this.start.top += 15
          this.start.left += 15
        },
        close (key) {
          this.windows.splice(key, 1)

          this.$nextTick(function () {
            let max = null
            for (let k in this.$refs) {
              let r = this.$refs[k][0]
              if (r && (!max || (max.style['z-index'] < r.style['z-index']))) {
                max = r
              }
            }
            this.focus = max ? max.keyVal : null
          })
        },
        help (text) {
          this.open('help')

          this.$nextTick(function () {
            this.$refs['key-' + this.focus][0].$refs.child.text = text
          })
        },
        focusWindow (key) {
          this.focus = key

          let ref = this.$refs['key-' + key][0]
          for (let k in this.$refs) {
            let r = this.$refs[k][0]
            if (r && r.style['z-index'] >= ref.style['z-index']) {
              r.style['z-index'] = parseInt(r.style['z-index']) - 1
            }
          }
          ref.style['z-index'] = this.windows.length
        },
        onTouch (e) {
          if (e.target.tagName === 'SELECT')
            return true

          e.preventDefault()
          if (e.touches.length > 1 || (e.type == 'touchend' && e.touches.length > 0))
            return

          let type = null
          let touch = e.changedTouches[0]

          switch (e.type) {
            case 'touchstart': 
              type = 'mousedown'
              this.mousedown.push(e.target)
              break
            case 'touchmove':
              type = 'mousemove'
              break
            case 'touchend':
              type = 'mouseup'
              break
          }

          if (type === 'mouseup') {
            if (this.mousedown.includes(e.target)) {
              this.mousedown.splice(this.mousedown.indexOf(e.target), 1)

              e.target.dispatchEvent(new MouseEvent('click', {
                screenX: touch.screenX,
                screenY: touch.screenY,
                clientX: touch.clientX,
                clientY: touch.clientY,
                ctrlKey: e.ctrlKey,
                shiftKey: e.shiftKey,
                altKey: e.altKey,
                metaKey: e.metaKey,
                button: 0,
                bubbles: true,
                cancelable: true
              }))
            }
          }

          e.target.dispatchEvent(new MouseEvent(type, {
            screenX: touch.screenX,
            screenY: touch.screenY,
            clientX: touch.clientX,
            clientY: touch.clientY,
            ctrlKey: e.ctrlKey,
            shiftKey: e.shiftKey,
            altKey: e.altKey,
            metaKey: e.metaKey,
            button: 0,
            bubbles: true,
            cancelable: true
          }))
        }
      }
    })
    
    Vue.component('help', {
      template: '#help',
      props: {
        'style-obj': Object
      },
      data () {
        return {
          title: 'Help',
          text: "Welcome to Vindue 98, the world's most advanced operating system."
        }
      },
      mounted () {
        Object.assign(this.styleObj, this.style, {
          'width': '250px'
        })
      }
    })
  }
}

Vue.use(Vindue)

// Component Definitions
Vue.component('tab-control', {
  template: '#tabControl',
  data () {
    return {
      panes: [],
      focus: ''
    }
  },
  mounted () {
    this.focus = Object.keys(this.$slots)[0]
  },
  methods: {
    focusTab (key) {
      this.focus = key
    }
  }
})

Vue.component('settings', {
  template: '#settings',
  props: {
    title: { default: 'Settings' },
    resizable: { default: true },
    'help-text': { default: 'Change system settings' },
    'style-obj': Object,
    'vindue-state': Object
  },
  data () {
    return {
      color: '#1C1F2B',
      hoursEnabled: true,
      hours: 'h',
      minutesEnabled: true,
      minutes: 'mm',
      secondsEnabled: false,
      seconds: 'ss',
      monthEnabled: false,
      month: 'M',
      dayEnabled: false,
      day: 'D',
      yearEnabled: false,
      year: 'YYYY'
    }
  },
  methods: {
    changeBackground () {
      this.vindueState.style['background-color'] = this.color
    },
    changeTime () {
      let timeCode = ''

      if (this.hoursEnabled)
        timeCode += this.hours

      if (this.hoursEnabled && this.minutesEnabled)
        timeCode += ':'

      if (this.minutesEnabled)
        timeCode += this.minutes

      if (this.minutesEnabled && this.secondsEnabled)
        timeCode += ':'

      if (this.secondsEnabled)
        timeCode += this.seconds

      if (this.hours === 'h')
        timeCode += ' A'

      if (timeCode.length > 0 && (this.monthEnabled || this.dayEnabled || this.yearEnabled))
        timeCode += ' '

      if (this.monthEnabled)
        timeCode += this.month

      if (this.monthEnabled && this.dayEnabled)
        timeCode += '/'

      if (this.dayEnabled)
        timeCode += this.day

      if (this.dayEnabled && this.yearEnabled)
        timeCode += '/'

      if (this.yearEnabled)
        timeCode += this.year
      
      this.vindueState.timeCode = timeCode
    }
  },
  mounted () {
    Object.assign(this.styleObj, this.style, {
      'min-width': '250px',
      'min-height': '250px'
    })
    this.color = this.vindueState.style['background-color']
  }
})

// Point of entry
new Vue({
  el: '#app'
})
Run Pen

External CSS

  1. https://raw.githubusercontent.com/mrmlnc/material-color/master/material-color.scss
  2. https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.2/moment.min.js