<template lang="pug">
  div
    transition(name='fade', mode='out-in')
      loader(v-if='!instanciate', key='loading')

      entries(v-else-if='instanciate && !current', key='entries')

      info-displayer(v-else-if='instanciate && current', key='current', :current='current', :return-cb='resetCurrent')
</template>

<script>
// Components
import Entries from '@/components/feed/entries.vue'
import Loader from '@/components/feed/loader.vue'
import InfoDisplayer from '@/components/info/layout.vue'

export default {
  name: 'Feed',

  components: { Entries, Loader, InfoDisplayer },

  computed: {
    params: {
      get () {
        return this.$store.state.releases.params
      },
      set () {}
    },
    current: {
      get () {
        return this.$store.state.releases.current
      },
      set () {}
    },
    instanciate: {
      get () {
        return this.$store.state.releases.instanciate
      },
      set () {}
    }
  },

  methods: {
    resetCurrent () {
      this.$store.commit('releases/setCurrent', null)
    }
  }
}
</script>

<style lang="stylus" scoped>
  .fade-enter, .fade-leave-to
    opacity 0

  .fade-enter-active, .fade-leave
    transition all .5s
</style>

Fix overflow on feed loader

<template lang="pug">
  .feed-container
    transition(name='fade', mode='out-in')
      loader(v-if='!instanciate', key='loading')

      entries(v-else-if='instanciate && !current', key='entries')

      info-displayer(v-else-if='instanciate && current', key='current', :current='current', :return-cb='resetCurrent')
</template>

<script>
// Components
import Entries from '@/components/feed/entries.vue'
import Loader from '@/components/feed/loader.vue'
import InfoDisplayer from '@/components/info/layout.vue'

export default {
  name: 'Feed',

  components: { Entries, Loader, InfoDisplayer },

  computed: {
    params: {
      get () {
        return this.$store.state.releases.params
      },
      set () {}
    },
    current: {
      get () {
        return this.$store.state.releases.current
      },
      set () {}
    },
    instanciate: {
      get () {
        return this.$store.state.releases.instanciate
      },
      set () {}
    }
  },

  methods: {
    resetCurrent () {
      this.$store.commit('releases/setCurrent', null)
    }
  }
}
</script>

<style lang="stylus" scoped>
  .fade-enter, .fade-leave-to
    opacity 0

  .fade-enter-active, .fade-leave
    transition all .5s

  .feed-container
    overflow hidden
</style>


<template>

  <!-- no extra whitespace inside link -->
  <a
    :class="buttonClasses"
    :href="href"
    :download="download"
    dir="auto"
  >
    {{ text }}
  </a>

</template>

<script>

  import { validator } from './appearances.js';
  import buttonClassesMixin from './buttonClassesMixin.js';

  /**
   * KExternalLink creates a styled external link
   */
  export default {
    name: 'KExternalLink',
    mixins: [buttonClassesMixin],
    props: {
      /**
       * Link text
       */
      text: {
        type: String,
        required: true,
      },
      /**
       * URL string
       */
      href: {
        type: String,
        required: true,
      },
      /**
       * Link appearance: 'raised-button', 'flat-button', or 'basic-link'
       */
      appearance: {
        type: String,
        default: 'basic-link',
        validator,
      },
      /**
       * For 'raised-button' and 'flat-button' appearances: show as primary or secondary style
       */
      primary: {
        type: Boolean,
        default: false,
      },
      /**
       * Specifies that the file is meant to be downloaded, not displayed in a separate tab.
       */
      download: {
        type: String,
        required: false,
      },
    },
  };

</script>

<style lang="scss" scoped>

  @import './buttons';

</style>

Update external link component to open external links in new tabs by default.

<template>

  <!-- no extra whitespace inside link -->
  <a
    :class="buttonClasses"
    :href="href"
    :download="download"
    :target="download ? '_self' : '_blank'"
    dir="auto"
  >
    {{ text }}
  </a>

</template>

<script>

  import { validator } from './appearances.js';
  import buttonClassesMixin from './buttonClassesMixin.js';

  /**
   * KExternalLink creates a styled external link
   */
  export default {
    name: 'KExternalLink',
    mixins: [buttonClassesMixin],
    props: {
      /**
       * Link text
       */
      text: {
        type: String,
        required: true,
      },
      /**
       * URL string
       */
      href: {
        type: String,
        required: true,
      },
      /**
       * Link appearance: 'raised-button', 'flat-button', or 'basic-link'
       */
      appearance: {
        type: String,
        default: 'basic-link',
        validator,
      },
      /**
       * For 'raised-button' and 'flat-button' appearances: show as primary or secondary style
       */
      primary: {
        type: Boolean,
        default: false,
      },
      /**
       * Specifies that the file is meant to be downloaded, not displayed in a separate tab.
       */
      download: {
        type: String,
        required: false,
      },
    },
  };

</script>

<style lang="scss" scoped>

  @import './buttons';

</style>


<template>

  <nav :aria-label="ariaLabel">
    <ul
      ref="navbarUl"
      class="items"
      tabindex="-1"
    >
      <!-- Contains NavbarLink components -->
      <slot></slot>
    </ul>
  </nav>

</template>

<script>

  /**
   * Used for navigation between sub-pages of a top-level Kolibri section
   */
  export default {
    name: 'Navbar',
  };

</script>

<style lang="scss" scoped>

  @import '~kolibri-design-system/lib/styles/definitions';

  .items {
    display: flex;
    padding: 0;
    margin-bottom: 4px;
    margin-left: 16px;
    overflow-x: hidden;
    overflow-y: hidden;
    white-space: nowrap;
  }

  @media (max-width: 840px) {
    .items {
      margin-top: 0;
    }
  }

</style>

Fix media query to responsiveWindowMixin

<template>

  <nav :aria-label="ariaLabel">
    <ul
      ref="navbarUl"
      class="items"
      tabindex="-1"
      :style="mediumAndSmallStyleOverrides"
    >
      <!-- Contains NavbarLink components -->
      <slot></slot>
    </ul>
  </nav>

</template>

<script>

  import responsiveWindowMixin from 'kolibri.coreVue.mixins.responsiveWindowMixin';
  /**
   * Used for navigation between sub-pages of a top-level Kolibri section
   */
  export default {
    name: 'Navbar',
    mixins: [responsiveWindowMixin],
    computed: {
      mediumAndSmallStyleOverrides() {
        return !this.windowIsLarge ? { marginTop: 0 } : {};
      },
    },
  };

</script>

<style lang="scss" scoped>

  @import '~kolibri-design-system/lib/styles/definitions';

  .items {
    display: flex;
    padding: 0;
    margin-bottom: 4px;
    margin-left: 16px;
    overflow-x: hidden;
    overflow-y: hidden;
    white-space: nowrap;
  }

</style>


<template>

    {{ badge }}
    {{ duration }}
    {{ assignees.length }}

      <span :class="{ 'is-light': scoutsForPeriod(n).length < 1 }">
        {{ scoutsForPeriod(n).length }}

      <router-link :to="'/administration/classes/' + eventId + '/' + id">
        Details
      </router-link>

</template>

Make sure assignees list is reactive


<template>

  <button class="icon-button">
    <slot></slot>
    {{ text }}
  </button>

</template>

Adjust left margin for btn-text so collectively it looks more centered


<template>

 {{ $store.state.title }}

</template>

Add dark theme to splash page (oops, forgot this one)


<template>
  <v-date-picker v-model="value" locale="hu" is-inline />
</template>

<script>
export default {
  data() {
    return {
      value: null,
      masks: {
        title: 'MM YYYY',
      },
    };
  },
  mounted() {
    // console.log(this.$vc.locales);
  },
};
</script>

Remove commented code in example

<template>
  <v-date-picker v-model="value" locale="hu" is-inline />
</template>

<script>
export default {
  data() {
    return {
      value: null,
      masks: {
        title: 'MM YYYY',
      },
    };
  },
};
</script>


<template>

  <KEmptyPlaceholder v-if="!items.length" />

    {{ items[0] }}

    {{ $tr('twoItems', {item1: items[0], item2: items[1]}) }}

    {{ $tr('threeItems', {item1: items[0], item2: items[1], item3: items[2]}) }}

    {{ $tr('manyItems', {item1: items[0], item2: items[1], count: items.length-2}) }}

</template>

Truncate long groupnames in truncated item list

<template>

  <KEmptyPlaceholder v-if="!items.length" />

      {{ items[0] }}

      {{ $tr('twoItems', {item1: items[0], item2: items[1]}) }}

      {{ $tr('threeItems', {item1: items[0], item2: items[1], item3: items[2]}) }}

      {{ $tr('manyItems', {item1: items[0], item2: items[1], count: items.length - 2}) }}

</template>


<template>

      <KCircularLoader
        type="indeterminate"
        :delay="false"
      />

{{ $tr('loadingBook') }}

</template>

Remove flexbox centered loading status


<template src='./courses-list.html'></template>

<style scoped src='./courses-list.css'></style>

<script>
import courseCard from '../course-card/course-card'
import gql from 'graphql-tag'

// GraphQL query
// const courseList = gql`
//    query CourseList($test: String!) {
//        courses(title: $test)
//    }
// `

const courseList = gql`
    {
        courses {
            title
            pitch
            member_limit
            member_count
        }
    }
`

export default {
    name: 'courses-list',
    data: function () {
        return {
            courses: ''
        }
    },
    props: {
        subject: {
            type: String
        }
    },
    components: {
        courseCard
    },
    watch: {
        subject: function (itemToSearch) {
            this.$apollo.query({
                query: courseList
                // variables: {
                //    courses: {
                //        test: 'casa'
                //    }
                // }
            })
            .then(res => {
                this.courses = res.data.courses
            })
        }
    }
}
</script>

Add course id to course-list

<template src='./courses-list.html'></template>

<style scoped src='./courses-list.css'></style>

<script>
import courseCard from '../course-card/course-card'
import gql from 'graphql-tag'

// GraphQL query
// const courseList = gql`
//    query CourseList($test: String!) {
//        courses(title: $test)
//    }
// `

const courseList = gql`
    {
        courses {
            id
            title
            pitch
            member_limit
            member_count
        }
    }
`

export default {
    name: 'courses-list',
    data: function () {
        return {
            courses: ''
        }
    },
    props: {
        subject: {
            type: String
        }
    },
    components: {
        courseCard
    },
    watch: {
        subject: function (itemToSearch) {
            this.$apollo.query({
                query: courseList
                // variables: {
                //    courses: {
                //        test: 'casa'
                //    }
                // }
            })
            .then(res => {
                this.courses = res.data.courses
            })
        }
    }
}
</script>


<template>

        <card-header>

                    {{ tab.label }}

        </card-header>
        <card-body>

                <slot></slot>

        </card-body>

</template>

Add console log for debugging


<template>
  <div>
    <e-select v-model="optionsScheduleEntry" :items="scheduleEntries" />
  </div>
</template>

<script>
export default {
  name: 'ActivityConfig',
  props: {
    value: { type: Object, required: true },
    camp: { type: Object, required: true },
  },
  data() {
    return {}
  },
  computed: {
    options: {
      get() {
        return this.value
      },
      set(v) {
        this.$emit('input', v)
      },
    },
    optionsScheduleEntry: {
      get() {
        return {
          activity: this.options.activity,
          scheduleEntry: this.options.scheduleEntry,
        }
      },
      set(val) {
        this.options.activity = val.activity
        this.options.scheduleEntry = val.scheduleEntry
      },
    },
    scheduleEntries() {
      let scheduleEntries = []

      this.camp.periods().items.forEach((p) => {
        const periodScheduleEntries = p.scheduleEntries().items.map((se) => ({
          value: { activity: se.activity()._meta.self, scheduleEntry: se._meta.self },
          text: '(' + se.number + ') ' + se.activity().title,
        }))
        scheduleEntries = [...scheduleEntries, ...periodScheduleEntries]
      })

      return scheduleEntries
    },
  },
  defaultOptions() {
    return {
      activity: null,
      scheduleEntry: null,
    }
  },
}
</script>

Fix n+1 query when adding single activity to print config

<template>
  <div>
    <e-select v-if="!loading" v-model="optionsScheduleEntry" :items="scheduleEntries" />
    <v-skeleton-loader v-else type="image" height="56" />
  </div>
</template>

<script>
export default {
  name: 'ActivityConfig',
  props: {
    value: { type: Object, required: true },
    camp: { type: Object, required: true },
  },
  computed: {
    options: {
      get() {
        return this.value
      },
      set(v) {
        this.$emit('input', v)
      },
    },
    optionsScheduleEntry: {
      get() {
        return {
          activity: this.options.activity,
          scheduleEntry: this.options.scheduleEntry,
        }
      },
      set(val) {
        this.options.activity = val.activity
        this.options.scheduleEntry = val.scheduleEntry
      },
    },
    scheduleEntries() {
      let scheduleEntries = []

      this.camp.periods().items.forEach((p) => {
        const periodScheduleEntries = p.scheduleEntries().items.map((se) => ({
          value: { activity: se.activity()._meta.self, scheduleEntry: se._meta.self },
          text: '(' + se.number + ') ' + se.activity().title,
        }))
        scheduleEntries = [...scheduleEntries, ...periodScheduleEntries]
      })

      return scheduleEntries
    },
    loading() {
      return [
        this.camp.activities(),
        ...this.camp.periods().items.map((period) => period.scheduleEntries()),
      ].some((entity) => entity._meta.loading)
    },
  },
  defaultOptions() {
    return {
      activity: null,
      scheduleEntry: null,
    }
  },
}
</script>


<template>

{{ name }}

Logout

Login

</template>

Reduce avatar size right from the request.


<template>

  Concept To Clinic

        Open image

        Detect and Select

        Annotate and Segment

        Report and Export

</template>

Fix incorrect path to asset


<template>
  <div class="custom-radio-input btn-group btn-group-toggle" role="group" :id="id" :class="{ 'is-invalid': isError }" >
    <label v-for="option in options" class="btn btn-secondary" :class="{ active: option.value == value, 'btn-danger': isError }" >
      <input v-model="changedValue" type="radio" :value="option.value" autocomplete="off" @change="change"> {{option.text}}
    </label>
  </div>
</template>

<script type="text/javascript">
/*
   *  @props options: An array of Objects in the format {value: "value", text: "text"} such that value is the Form Value and Text is the text displayed to the user
   *  @props value: value to set the currently selected option. Best used with v-model
   *  @props id: id of the ButtonGroup
   *  @props is-error: Boolean, defines whether error styles should be displayed
   */

export default {
  data() {
    return {
      changedValue: this.value,
    };
  },
  props: {
    options: {
      type: Array,
      required: true,
    },
    value: {
      type: [String, Number],
      default: '',
    },
    id: {
      type: String,
      default: '',
    },
    isError: {
      type: Boolean,
      default: false,
    },
  },
  methods: {
    change: function() {
      this.$emit('input', this.changedValue);
    },
  },
};
</script>

Allow boolean values since 0 / 1 are mutated into false / true

<template>
  <div class="custom-radio-input btn-group btn-group-toggle" role="group" :id="id" :class="{ 'is-invalid': isError }" >
    <label v-for="option in options" class="btn btn-secondary" :class="{ active: option.value == value, 'btn-danger': isError }" >
      <input v-model="changedValue" type="radio" :value="option.value" autocomplete="off" @change="change"> {{option.text}}
    </label>
  </div>
</template>

<script type="text/javascript">
/*
   *  @props options: An array of Objects in the format {value: "value", text: "text"} such that value is the Form Value and Text is the text displayed to the user
   *  @props value: value to set the currently selected option. Best used with v-model
   *  @props id: id of the ButtonGroup
   *  @props is-error: Boolean, defines whether error styles should be displayed
   */

export default {
  data() {
    return {
      changedValue: this.value,
    };
  },
  props: {
    options: {
      type: Array,
      required: true,
    },
    value: {
      type: [String, Number, Boolean],
      default: '',
    },
    id: {
      type: String,
      default: '',
    },
    isError: {
      type: Boolean,
      default: false,
    },
  },
  methods: {
    change: function() {
      this.$emit('input', this.changedValue);
    },
  },
};
</script>


<template>
  <div
    class="v-map-toggler"
    :class="{ 'v-map-toggler--active': active }"
    @click.stop="$emit('change', !active)"
  >
    <div class="v-map-toggler__switch">
      {{ actionText }}
    </div>
  </div>
</template>
<script>
export default {
  model: {
    event: 'change',
    prop: 'active'
  },
  props: {
    active: {
      type: Boolean,
      required: true
    },
    onText: {
      type: String,
      default: 'ON',
    },
    offText: {
      type: String,
      default: 'OFF'
    }
  },
  computed: {
    actionText () {
      if (this.active) {
        return this.onText
      }

      return this.offText
    }
  }
}
</script>

Improve usability of the toggler component

<template>
  <div
    class="v-map-toggler"
    tabindex="0"
    :class="{ 'v-map-toggler--active': active }"
    @keyup.enter.stop.prevent="toggle"
    @click.stop="toggle"
  >
    <div class="v-map-toggler__switch">
      {{ actionText }}
    </div>
  </div>
</template>
<script>
export default {
  model: {
    event: 'change',
    prop: 'active'
  },
  props: {
    active: {
      type: Boolean,
      required: true
    },
    onText: {
      type: String,
      default: 'ON',
    },
    offText: {
      type: String,
      default: 'OFF'
    }
  },
  computed: {
    actionText () {
      if (this.active) {
        return this.onText
      }

      return this.offText
    }
  },
  methods: {
    toggle (newState) {
      if (typeof newState === 'boolean') {
        this.$emit('change', newState)
      } else {
        this.$emit('change', !this.active)
      }
    }
  }
}
</script>


<template functional>
<img
  class="thumbnail-picture"
  :style="{
    width: props.width + 'px',
    height: props.height + 'px'
  }"
  v-lazy="'/api/pictures/' + props.type + '/preview-files/' + props.previewFileId + '.png'"
  :key="props.previewFileId"
  v-bind="data.attrs"
  v-if="props.previewFileId"
/>
<span
  :class="{
    'thumbnail-picture': true,
    'thumbnail-empty': true
  }"
  :style="{
    width: props.width + 'px',
    height: props.height + 'px',
  }"
  v-bind="data.attrs"
  v-else>
</span>
</template>

<script>
export default {
  name: 'light-entity-thumbnail',
  functional: true,

  props: {
    previewFileId: {
      default: '',
      type: String
    },
    width: {
      default: 150,
      type: Number
    },
    height: {
      default: 50,
      type: Number
    },
    type: {
      default: 'thumbnails',
      type: String
    }
  }
}
</script>

<style lang="scss">
.dark .thumbnail-picture {
  background-color: $dark-grey-lighter;
  border-color: $dark-grey-light;
}

span.thumbnail-empty {
  background: $white-grey;
  display: block;
  margin: 0;
}
</style>

Allow to use auto height/width for thumbnail widget

<template functional>
<img
  class="thumbnail-picture"
  :style="{
    width: props.width,
    height: props.height
  }"
  v-lazy="'/api/pictures/' + props.type + '/preview-files/' + props.previewFileId + '.png'"
  :key="props.previewFileId"
  v-bind="data.attrs"
  v-if="props.previewFileId"
/>
<span
  :class="{
    'thumbnail-picture': true,
    'thumbnail-empty': true
  }"
  :style="{
    width: props.width,
    height: props.emptyHeight ? props.emptyHeight : props.height,
  }"
  v-bind="data.attrs"
  v-else>
</span>
</template>

<script>
export default {
  name: 'light-entity-thumbnail',
  functional: true,

  props: {
    previewFileId: {
      default: '',
      type: String
    },
    width: {
      default: '150px',
      type: String
    },
    height: {
      default: '50px',
      type: String
    },
    emptyHeight: {
      type: String
    },
    type: {
      default: 'thumbnails',
      type: String
    }
  }
}
</script>

<style lang="scss">
.dark .thumbnail-picture {
  background-color: $dark-grey-lighter;
  border-color: $dark-grey-light;
}

span.thumbnail-empty {
  background: $white-grey;
  display: block;
  margin: 0;
}
</style>


<template>

{{ projectName }}

</template>

Fix worm import path in vue project


<template>

"Slide" Transition

        Click
        Tap
        on the Toggle below to see the transition in action.

        <q-toggle v-model="visible" label="Visible image" />

      <q-slide-transition @show="log('show')" @hide="log('hide')">

      </q-slide-transition>

</template>

Add QSlideTransition test-case with v-if

<template>

"Slide" Transition

        Click
        Tap
        on the Toggle below to see the transition in action.

        <q-toggle v-model="visibleVShow" label="Visible with v-show" />

      <q-slide-transition @show="log('show')" @hide="log('hide')">

      </q-slide-transition>

        <q-toggle v-model="visibleVIf" label="Visible with v-if" />

      <q-slide-transition @show="log('show')" @hide="log('hide')">

      </q-slide-transition>

</template>


<template>
  <v-list three-line>
    <v-list-item v-for="option in activityContent.options().items" :key="option.id" class="px-0">
      <v-list-item-action>
        <api-checkbox fieldname="checked" :uri="option._meta.self" />
      </v-list-item-action>
      <v-list-item-content>
        <v-list-item-title>{{ $tc(`activityContent.laThematicArea.entity.option.${option.translateKey}.name`) }}</v-list-item-title>
        <v-list-item-subtitle>{{ $tc(`activityContent.laThematicArea.entity.option.${option.translateKey}.description`) }}</v-list-item-subtitle>
      </v-list-item-content>
    </v-list-item>
  </v-list>
</template>

<script>

import ApiCheckbox from '@/components/form/api/ApiCheckbox'

export default {
  name: 'LAThematicArea',
  components: { ApiCheckbox },
  props: {
    activityContent: { type: Object, required: true }
  },
  methods: {
    async refreshContent () {
      await this.api.reload(this.activityContent)
    }
  }
}
</script>

Implement vuetify active list item

<template>
  <v-list three-line>
    <v-list-item v-for="option in activityContent.options().items" :key="option.id" class="px-0">
      <template #default="{ active }">
        <v-list-item-action>
          <api-checkbox fieldname="checked" :value="active" :uri="option._meta.self" />
        </v-list-item-action>
        <v-list-item-content>
          <v-list-item-title>{{ $tc(`activityContent.laThematicArea.entity.option.${option.translateKey}.name`) }}</v-list-item-title>
          <v-list-item-subtitle>{{ $tc(`activityContent.laThematicArea.entity.option.${option.translateKey}.description`) }}</v-list-item-subtitle>
        </v-list-item-content>
      </template>
    </v-list-item>
  </v-list>
</template>

<script>

import ApiCheckbox from '@/components/form/api/ApiCheckbox'

export default {
  name: 'LAThematicArea',
  components: { ApiCheckbox },
  props: {
    activityContent: { type: Object, required: true }
  },
  methods: {
    async refreshContent () {
      await this.api.reload(this.activityContent)
    }
  }
}
</script>


<template>
<component v-if="!to"
  class="veui-link"
  :class="klass"
  :is="fallback"
  @click="handleRedirect"><slot :disabled="disabled"></slot></component>
<router-link v-else-if="$router && !native"
  class="veui-link"
  :class="klass"
  :to="to"
  :replace="replace">
  <slot></slot>
</router-link>
<a v-else
  class="veui-link"
  :class="klass"
  :href="to"
  @click="handleRedirect">
  <slot></slot>
</a>
</template>
<script>
export default {
  name: 'veui-link',
  components: {
    'veui-element': Element
  },
  props: {
    to: {
      type: String,
      default: ''
    },
    replace: Boolean,
    native: Boolean,
    fallback: {
      type: String,
      default: 'span'
    },
    disabled: Boolean
  },
  computed: {
    klass () {
      return {
        'veui-disabled': this.disabled
      }
    }
  },
  methods: {
    handleRedirect (event) {
      if (this.disabled) {
        event.preventDefault()
        return
      }
      if (this.to) {
        this.$emit('click', event)

        if (this.replace && !event.defaultPrevented) {
          event.preventDefault()
          location.replace(this.to)
        }
      } else {
        event.preventDefault()
        this.$emit('click', event)
      }
    }
  }
}
</script>

Remove props from veui-link slot

<template>
<component v-if="!to"
  class="veui-link"
  :class="klass"
  :is="fallback"
  @click="handleRedirect"><slot></slot></component>
<router-link v-else-if="$router && !native"
  class="veui-link"
  :class="klass"
  :to="to"
  :replace="replace">
  <slot></slot>
</router-link>
<a v-else
  class="veui-link"
  :class="klass"
  :href="to"
  @click="handleRedirect">
  <slot></slot>
</a>
</template>
<script>
export default {
  name: 'veui-link',
  components: {
    'veui-element': Element
  },
  props: {
    to: {
      type: String,
      default: ''
    },
    replace: Boolean,
    native: Boolean,
    fallback: {
      type: String,
      default: 'span'
    },
    disabled: Boolean
  },
  computed: {
    klass () {
      return {
        'veui-disabled': this.disabled
      }
    }
  },
  methods: {
    handleRedirect (event) {
      if (this.disabled) {
        event.preventDefault()
        return
      }
      if (this.to) {
        this.$emit('click', event)

        if (this.replace && !event.defaultPrevented) {
          event.preventDefault()
          location.replace(this.to)
        }
      } else {
        event.preventDefault()
        this.$emit('click', event)
      }
    }
  }
}
</script>


<template>
<inline-dropdown v-if="!loading"
                 :displayKey="'event'"
                 :objects="readableEvents"
                 :initial="currentEventText"
                 @select="selectEvent($event)"></inline-dropdown>
</template>

<script>
import { mapGetters } from 'vuex';

export default {
  data() {
    return {
      loading: true
    };
  },
  computed: {
    ...mapGetters([
      'orderedEvents',
      'currentEvent'
    ]),
    readableEvents() {
      return _.map(this.orderedEvents, (event) => {
        return {
          id: event.id,
          event: event.semester + ' ' + event.year
        };
      });
    },
    currentEventText() {
      if (!this.currentEvent.id) {
        return undefined;
      }

      return {
        id: this.currentEvent.id,
        event: this.currentEvent.semester + ' ' + this.currentEvent.year
      };
    }
  },
  methods: {
    selectEvent(selectedId) {
      let selectedEvent = _.find(this.orderedEvents, (event) => {
        return event.id === selectedId;
      });

      this.$emit('select', selectedEvent);
    }
  },
  mounted() {
    this.$store.dispatch('getEvents')
      .then(() => {
        return this.$store.dispatch('getCurrentEvent');
      })
      .then(() => {
        this.loading = false;
        this.$emit('select', this.currentEvent);
      })
      .catch(() => {
        if (this.orderedEvents.length > 0) {
          this.loading = false;
          this.$emit('select', this.orderedEvents[0]);
        } else {
          this.$emit('select', {});
        }
      });
  }
}
</script>


Add a Vue text match highlighting component

<!--
  Licensed to Cloudera, Inc. under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  Cloudera, Inc. licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->

<!-- eslint-disable vue/no-v-html -->
<template>
  <span v-html="content" />
</template>
<!-- eslint-enable -->

<script lang="ts">
  import { Suggestion } from './AutocompleteResults';
  import Vue from 'vue';
  import Component from 'vue-class-component';
  import { Prop } from 'vue-property-decorator';

  @Component
  export default class Spinner extends Vue {
    @Prop({ required: true })
    suggestion!: Suggestion;
    @Prop({ required: true })
    filter!: string;
    @Prop({ required: false, default: false })
    isComment?: boolean;

    get content(): string {
      const value =
        (this.isComment
          ? (<{ comment?: string }>this.suggestion.details).comment
          : this.suggestion.value) || '';
      if (
        this.filter &&
        typeof this.suggestion.matchIndex !== 'undefined' &&
        this.suggestion.matchIndex > -1 &&
        typeof this.suggestion.matchLength !== 'undefined' &&
        ((!this.isComment && !this.suggestion.matchComment) ||
          (this.isComment && this.suggestion.matchComment))
      ) {
        const before = value.substring(0, this.suggestion.matchIndex);
        const match = value.substring(
          this.suggestion.matchIndex,
          this.suggestion.matchIndex + this.suggestion.matchLength
        );
        const after = value.substring(this.suggestion.matchIndex + this.suggestion.matchLength);
        return `${before}<b>${match}</b>${after}`;
      }
      return value || '';
    }
  }
</script>

<style lang="scss" scoped></style>


<template>
  <Page class="page--settings">

      <SettingsSidebar class="grid-cell--col4" :userModel="user" :baseUrl="baseUrl" />

        <SettingsTabs></SettingsTabs>
        <router-view></router-view>

  </Page>
</template>


<template>

			<input class="column_label" type="text" :value="column.name" />

</template>


<template>

      {{ title }}

    <slot />

</template>


Add Bootstrap-vue Select2 component (currently unused).

<template>
    <b-select :value="value" @input="this.$emit('input', $event.target.value)" v-bind="$attrs"
              :class="{ 'select2-hidden-accessible': true }" plain>
        <slot v-for="(_, name) in $slots" :name="name" :slot="name"/>
        <template v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData">
            <slot :name="name" v-bind="slotData"/>
        </template>
    </b-select>
</template>
<script>
import _ from 'lodash';

export default {
    name: 'BSelect2',
    inheritAttrs: false,
    props: {
        value: {},
        selectOptions: {
            type: Object,
            default () {
                return {};
            }
        }
    },
    mounted () {
        $(this.$el)
            .select2(this.allSelectOptions)
            .val(this.value);
    },
    computed: {
        allSelectOptions () {
            let options = _.clone(this.selectOptions);
            _.defaults(options, {
                width: '100%',
                theme: 'bootstrap4',
                language: App.lang.locale_short
            });
            return options;
        }
    },
    destroyed: function () {
        $(this.$el)
            .off()
            .select2('destroy');
    }
};
</script>


Add an autoscrolling log panel Vue component

<template>

    {{ logs }}
    {{ I18n('There are currently no logs available.') }}

</template>


<template lang="pug">
  div
    input(
      v-model="cFilter"
      debounce="200"
    )
</template>

<script>
  export default {
    computed: {
      cFilter: {
        get() {
          return this.filter;
        },

        set(value) {
          this.setFilter(value);
        },
      },
    },

    vuex: {
      getters: {
        filter: state => state.pool.filter,
      },
      actions: {
        setFilter({ dispatch }, value) {
          // Don't dispatch if filter is the same
          if (value === this.filter) return;

          // Dispatch with new filter object
          dispatch('SET_FILTER', {
            filter: value,
          });
        },
      },
    },
  };
</script>


<template>
  <button class="button is-rounded"
    :class="checked ? checked_class : unchecked_class"
    v-on:click="click"
    >
      <slot></slot>
  </button>
</template>

<script>
export default {
  name: 'button-checkbox',
  props: {
    checked_class: {
      default: 'is-info'
    },
    unchecked_class: {
      default: ''
    }
  },
  data () {
    return {
      checked: true
    }
  },
  methods: {
    click () {
      this.checked = !this.checked
    }
  }
}
</script>

<style>

</style>


<template>
  <div class="notification">
    <!--
        Notifications component storing notifications that can be triggered by sending event 'notification' to Event Bus
    -->
  </div>
</template>

<script>
export default {
  name: 'notification',
  data () {
    return {
      notifications: []
    }
  },
  methods: {
    action (action, id) {
      switch (action) {
        case 'close':
          this.notifications.splice(id, 1)
      }
    }
  }
}
</script>

Fix after removing listener on notificaions ;x

<template>
  <div class="notification">
    <!--
        Notifications component storing notifications that can be triggered by sending event 'notification' to Event Bus
    -->
  </div>
</template>

<script>
export default {
  name: 'notification',
  data () {
    return {
      notifications: []
    }
  },
  created () {
    this.$bus.$on('notification', data => {
      this.notifications.push(data)
      setTimeout(() => {
        this.action('close', this.notifications.length - 1)
      }, data.timeToLive || 5000)
    })
  },
  methods: {
    action (action, id) {
      switch (action) {
        case 'close':
          this.notifications.splice(id, 1)
      }
    }
  }
}
</script>


Add a component for custom multi-selects (so we can add custom filtering, labels and markup for each item).

<template>
	<el-select
		v-model="selected"
		multiple
		filterable
		:placeholder="placeholder"
		:filter-method="filterItems"
	>
		<el-option
			v-for="item in filteredItems"
			:key="_.get(item, keyPath)"
			:label="_.get(item, labelPath)"
			:value="_.get(item, valuePath)"
		>
			<slot name="item" :item="item"></slot>
		</el-option>
	</el-select>
</template>

<script>
import _ from 'lodash';

export default {

	name: 'custom-multi-select',

	props: [
		'value',
		'items',
		'label-path',
		'value-path',
		'key-path',
		'placeholder'
	],

	data() {
		return {
			searchFor: ''
		};
	},

	computed: {

		// slightly hacky way of using lodash directly in template
		_() {
			return _;
		},

		selected: {
			get() {
				return this.value;
			},
			set(value) {
				this.$emit('input', value);
			}
		},

		// TODO: make generic (based on props)
		filteredItems() {
			return this.searchFor !== '' ? this.items.filter(
				item => ['name', 'username', 'email'].some(
					key => item.user[key].toLowerCase().indexOf(this.searchFor.toLowerCase()) !== -1
				)
			) : this.items;
		}

	},

	methods: {

		filterItems(value) {
			this.searchFor = value;
		}

	}
};
</script>


Add missing file to delete user functionality

<template>
    <app-dialog
            ref="dialogBox"
            :title="`Delete ${subjectType}`">
        <template>
                Are you sure you want to permanently delete {{subjectType}} {{subjectName}}?
        </template>
        <template #actions>
            <button
                    type="button"
                    class="mdl-button"
                    @click="remove">
                OK
            </button>
            <button
                    type="button"
                    class="mdl-button"
                    @click="hide">
                Cancel
            </button>
        </template>
    </app-dialog>
</template>

<script>
import userService from '@/service/user'
import groupService from '@/service/user'

export default {
    name: "DialogDeleteSubject",
    data() {
        return {
            subject: null
        }
    },
    computed: {
        subjectType() {
            return !this.subject || this.subject.login ? 'user' : 'group'
        },
        subjectName() {
            return this.subject && (this.subject.login ? this.subject.login : this.subject.name)
        }
    },
    methods: {
        setSubject(value) {
            this.subject = value
        },
        show(subject) {
            if (subject) {
                this.setSubject(subject)
            }
            this.$refs.dialogBox.show()
        },
        hide() {
            this.$refs.dialogBox.hide()
        },
        remove() {
            let service = this.subject.login ? userService : groupService
            service.remove(this.subject.id)
            this.$emit('change')
            this.hide()
        }
    }
}
</script>


<script>
  export default {
    props: {
      formState: {
        type: Object,
        required: true,
      },
    },
  };
</script>

<template>
  <fieldset class="checkbox">
    <label for="issue_confidential">
      <input
        type="checkbox"
        value="1"
        id="issue_confidential"
        v-model="formState.confidential" />
      This issue is confidential and should only be visible to team members with at least Reporter access.
    </label>
  </fieldset>
</template>

Use dash instead of underscore

<script>
  export default {
    props: {
      formState: {
        type: Object,
        required: true,
      },
    },
  };
</script>

<template>
  <fieldset class="checkbox">
    <label for="issue-confidential">
      <input
        type="checkbox"
        value="1"
        id="issue-confidential"
        v-model="formState.confidential" />
      This issue is confidential and should only be visible to team members with at least Reporter access.
    </label>
  </fieldset>
</template>


<template>

  {{ label }}

    <textarea
      class="input"
      :class="'input ' + inputClass"
      ref="input"
      :placeholder="placeholder"
      :type="type"
      :value="value"
      @input="updateValue()"
      @keyup.enter="emitEnter()"
    />

</template>


Add edit comment modal to available modals

<template>

        {{ $t("comments.edit_title") }}

      <form v-on:submit.prevent>
        <textarea-field
          ref="textField"
          :label="$t('comments.fields.text')"
          v-model="form.text"
          @enter="runConfirmation"
          v-focus
        >
        </textarea-field>
      </form>

          {{ $t("main.confirmation") }}

        <router-link
          :to="cancelRoute"
          class="button is-link">
          {{ $t("main.cancel") }}
        </router-link>

        {{ $t("assets.edit_fail") }}

</template>


Add component for easily debugging bbreakpoints

<template>

xs

{{ xs }}

s

{{ s }}

ns

{{ ns }}

m

{{ m }}

l

{{ l }}

</template>


Add a simple component to scroll inputs all the way to the right (extends element's input component).

<script>
/*
 * This scrolls input elements when they are mounted to reveal the last bit
 * of text. This is especially useful for differentiating URLs, which was the
 * case with MenuEditor.vue (where this is used).
 */
import { Input } from 'element-ui';

export default {
	name: 'scroll-el-input',

	extends: Input,

	mounted() {
		const input = this.$refs['input'];
		input.scrollLeft = input.scrollWidth;
	}
};
</script>


<template>
<input name="entry-date"
       type="text"
       class="form-control form-control-sm date-input"
       v-model="date"
       placeholder="Date" />
</template>

<script>
export default {
    mounted() {
        let vm = this;
        $('.date-input').pickadate({
            format: 'yyyy-mm-dd',
            onStart: function() {
                let currentDate = new Date();
                this.set('select', currentDate);
                vm.$emit('date-select', moment(currentDate).format('YYYY-MM-DD'));
            },
            onSet: function() {
                vm.$emit('date-select', $('.date-input').val());
            }
        });
    }
};
</script>

Use el for datepicker instead of class

<template>
<input name="entry-date"
       type="text"
       class="form-control form-control-sm date-input"
       v-model="date"
       placeholder="Date" />
</template>

<script>
export default {
    mounted() {
        let vm = this;
        $(this.$el).pickadate({
            format: 'yyyy-mm-dd',
            onStart: function() {
                let currentDate = new Date();
                this.set('select', currentDate);
                vm.$emit('date-select', moment(currentDate).format('YYYY-MM-DD'));
            },
            onSet: function() {
                vm.$emit('date-select', $(vm.$el).val());
            }
        });
    }
};
</script>


<template>
  <svg></svg>
</template>

<script>
  import * as d3 from 'd3';
  import {tip} from './utilities/tip';

  export default {
    name: 'DroughtMap',

    data() {
      return {
        graph_height: 500 - this.margins().top -this. margins().bottom,
        graph_width: 600 - this.margins().left - this.margins().right,
        graph_translate: `translate(${this.margins().left},${this.margins().top})`
      }
    },

    props: {
      dataFile: String,
      mapFile: String
    },

    methods: {
      draw() {
        let vm = this;
        let tip_div = tip.tipDiv();

        let svg = d3.select('#map');
        let width = svg.attr('width');
        let height = svg.attr('height');

        let scale = 1,
          projection = d3.geoAlbers()
            .scale(scale)
            .translate([0,0]);

        d3.queue()
          .defer(d3.json, `static/data/maps/${this.mapFile}`)
         // .defer(d3.csv, `static/data/drought/${this.dataFile}`)
          .await(function(error, map, stations, data) {
            let path = d3.geoPath().projection(projection);
            let bounds = path.bounds(map);
            scale = .95 / Math.max((bounds[1][0] - bounds[0][0]) / width, (bounds[1][1] - bounds[0][1]) / height);

            let state = vm.whichState;

            let translation = [(width - scale * (bounds[1][0] + bounds[0][0])) / 2,
              (height - scale * (bounds[1][1] + bounds[0][1])) / 2];

            // update projection
            projection = d3.geoAlbersUsa()
              .scale(scale)
              .translate(translation);
            path = path.projection(projection);

            let maps = svg.selectAll('path')
              .data(map.features).call(zoom);

            maps.enter()
              .append('path')
              .merge(maps)
              .attr('d', path);

            maps.exit().remove();
          });
      }
    }
  }
</script>


<template>

Click "Start" then use QInput

{{ i }}

      <q-btn label="start" @click="start" />
      <q-btn label="stop" @click="stop" />

    <q-input filled v-model="text" debounce="300" label="Label" />

      {{ text }}

</template>


Add component for editing/displaying menu items in our menu editor.

<template>

	<scroll-input
		:placeholder="placeholder"
		v-model="item[nestedKey]"
		@blur="validate(index)"
		@change="validate(index)"
	>
		<template slot="prepend">{{ name }}</template>
	</scroll-input>

		{{ errors[index][nestedKey].map((error) => error.message).join(' ') }}

</template>


<template>

Processing Job Parameters for Job ID: {{this.id}}

</template>


<template>
    <li class="nav-item" @click="onclick">
        <b-link :is="itemType" :class="classObject" :to="to" :href="href" :exact="exact">
            <slot></slot>
        </b-link>
    </li>
</template>

<script>
    import bLink from './link.vue';

    export default {
        components: {bLink},
        computed: {
            itemType() {
                return (this.href || this.to) ? 'b-link' : 'button';
            },
            classObject() {
                return [
                    'nav-link',
                    this.active ? 'active' : '',
                    this.disabled ? 'disabled' : ''
                ];
            }
        },
        props: {
            active: {
                type: Boolean,
                default: false
            },
            disabled: {
                type: Boolean,
                default: false
            },
            to: {
                type: [String, Object]
            },
            href: {
                type: String
            },
            exact: {
                type: Boolean
            }
        },
        methods: {
            onclick(e) {
                // Hide all drop-downs including navbar-toggle
                this.$root.$emit('shown::dropdown', this);
                this.$emit('click', e);
            }
        }
    };
</script>

Revert "[NavItem] Change the component type to 'button' if 'href' or 'to' props are not defined"

<template>
    <li class="nav-item" @click="onclick">
        <b-link :class="classObject" :to="to" :href="href" :exact="exact">
            <slot></slot>
        </b-link>
    </li>
</template>

<script>
    import bLink from './link.vue';

    export default {
        components: {bLink},
        computed: {
            classObject() {
                return [
                    'nav-link',
                    this.active ? 'active' : '',
                    this.disabled ? 'disabled' : ''
                ];
            }
        },
        props: {
            active: {
                type: Boolean,
                default: false
            },
            disabled: {
                type: Boolean,
                default: false
            },
            to: {
                type: [String, Object]
            },
            href: {
                type: String
            },
            exact: {
                type: Boolean
            }
        },
        methods: {
            onclick(e) {
                // Hide all drop-downs including navbar-toggle
                this.$root.$emit('shown::dropdown', this);
                this.$emit('click', e);
            }
        }
    };
</script>


<template>

                This component was loaded async trigged by vue-router

              <template v-if="isVisible">
                This component was loaded at:

                Seccond item:

                <template v-for="item in list">

                    Using many itens inside a template with loop
                </template>
              </template>

              Toggle

            Edit
            Delete

</template>


<template>

  <help-circle-icon />

    {{ text }}

</template>


<template>

   0">

    {{ text }}

</template>


<template>

  <KIcon :icon="icon" />

</template>

<script>

  import { LearningActivityKinds } from 'kolibri.coreVue.vuex.constants';

  const LearningActivityKindToIconMap = {
    [LearningActivityKinds.CREATE]: 'create',
    [LearningActivityKinds.LISTEN]: 'listen',
    [LearningActivityKinds.REFLECT]: 'reflect',
    [LearningActivityKinds.PRACTICE]: 'practice',
    [LearningActivityKinds.READ]: 'read',
    [LearningActivityKinds.WATCH]: 'watch',
    [LearningActivityKinds.EXPLORE]: 'interact',
  };

  export default {
    name: 'LearningActivityIcon',
    props: {
      /**
       * Learning activity constant
       */
      kind: {
        type: String,
        required: true,
        validator(value) {
          return Object.values(LearningActivityKinds).includes(value);
        },
      },
      /**
       * Icon is solid by default.
       * Set to `true` to make it shaded.
       */
      shaded: {
        type: Boolean,
        required: false,
        default: false,
      },
    },
    computed: {
      icon() {
        const icon = LearningActivityKindToIconMap[this.kind];
        if (this.shaded) {
          return icon + 'Shaded';
        }
        return icon + 'Solid';
      },
    },
  };

</script>


<template>
  <div class="category-tile center-xs middle-xs flex fs-large extrabold bg-accent bg-accent-hover c-on-accent">
    {{ label }}
  </div>
</template>

<script>
// not in Core
export default {
  props: {
    label: {
      type: String,
      required: true
    },
    img: {
      type: String,
      required: true
    }
  }
}
</script>

<style lang="scss" scoped>
@import '~theme/css/vars/additional';
.category-tile {
    height: 150px;
    @media ( min-width: $md ) {
      height: 350px;
    }
}
</style>

Remove unused prop causing an error

<template>
  <div class="category-tile center-xs middle-xs flex fs-large extrabold bg-accent bg-accent-hover c-on-accent">
    {{ label }}
  </div>
</template>

<script>
// not in Core
export default {
  props: {
    label: {
      type: String,
      required: true
    }
  }
}
</script>

<style lang="scss" scoped>
@import '~theme/css/vars/additional';
.category-tile {
    height: 150px;
    @media ( min-width: $md ) {
      height: 350px;
    }
}
</style>


Implement a component for auto-generating a table of content

<template>

        {{ anchor.label }}

</template>


<template>
  <button
    type="submit"
    :class="{ 'action-button': true, 'block': block, 'medium': medium }"
    v-on:click="$emit('click')"
  >
    <slot />
  </button>
</template>

<script>
export default {
  name: 'action-button',
  props: {
    block: {
      type: Boolean,
      value: false,
    },
    medium: {
      type: Boolean,
      value: false,
    },
  },
};
</script>

<style lang="scss" scoped>
.action-button {
  font: inherit;
  background-color: #FF5722;
  border: 1px solid #FF5722;
  color: white;
  cursor: pointer;
  border-radius: 4px;
  width: 100px;
  outline: none;

  &.block {
    width: 100%;
  }

  &.medium {
    height: 30px;
  }
}

.action-button:hover {
  background-color: #FF6833;
}

.action-button:active {
  background-color: #EE4611;
}
</style>


<template>

            <template v-for="column in columns">
              {{ humanizeColumnName(column) }}
            </template>

            <template v-for="column in columns">

                <router-link v-bind:to="prefix + uid">
                  {{ item[column] }}
                </router-link>

                {{ item[column] }}

                None

            </template>

      <loading-spinner></loading-spinner>

</template>


<template>

  {{tab.name}}

</template>

Make close/changed icon more accessible


<template>
  <input
    type="text"
    :id="id"
    :name="name"
    :placeholder="placeholder"
    :autofocus="autofocus"
    v-model="email"
    @change="$emit('change')"
    @input="$emit('input', email)">
</template>

<script>
export default {
  name: 'text-input',
  watch: {
    value(newValue) {
      this.email = newValue;
    },
  },
  data() {
    return {
      email: this.value,
    };
  },
  props: {
    name: {
      type: String,
      value: '',
    },
    placeholder: {
      type: String,
      value: '',
    },
    id: {
      type: String,
      value: '',
    },
    autofocus: {
      type: Boolean,
      value: false,
    },
  },
};
</script>

<style lang="scss" scoped>
input {
  flex: 1 1 auto;
  padding: 4px;
  font: inherit;
  color: inherit;
  border: 1px solid #2c3e50;
  border-radius: 4px;
}
</style>


<script>
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import eventHub from '../eventhub';

export default {
  components: {
    loadingIcon,
  },
  props: {
    deployKey: {
      type: Object,
      required: true,
    },
    btnCssClass: {
      type: String,
      required: false,
      default: 'btn-secondary',
    },
  },
  data() {
    return {
      isLoading: false,
    };
  },
  methods: {
    doAction() {
      this.isLoading = true;

      eventHub.$emit(`${this.type}.key`, this.deployKey, () => {
        this.isLoading = false;
      });
    },
  },
};
</script>

<template>
  <button
    class="btn"
    :class="[{ disabled: isLoading }, btnCssClass]"
    :disabled="isLoading"
    @click="doAction">
    <slot></slot>
    <loading-icon
      v-if="isLoading"
      :inline="true"
    />
  </button>
</template>

Fix bad merge from master

<script>
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import eventHub from '../eventhub';

export default {
  components: {
    loadingIcon,
  },
  props: {
    deployKey: {
      type: Object,
      required: true,
    },
    type: {
      type: String,
      required: true,
    },
    btnCssClass: {
      type: String,
      required: false,
      default: 'btn-secondary',
    },
  },
  data() {
    return {
      isLoading: false,
    };
  },
  methods: {
    doAction() {
      this.isLoading = true;

      eventHub.$emit(`${this.type}.key`, this.deployKey, () => {
        this.isLoading = false;
      });
    },
  },
};
</script>

<template>
  <button
    class="btn"
    :class="[{ disabled: isLoading }, btnCssClass]"
    :disabled="isLoading"
    @click="doAction">
    <slot></slot>
    <loading-icon
      v-if="isLoading"
      :inline="true"
    />
  </button>
</template>


Add component to simplify list page headers

<template>

    <page-title :text="title" />

    <button-simple
      class="level-item"
      icon="plus"
      :text="newEntryLabel"
      @click="$emit('new-clicked')"
    />

</template>


Add a shim to receive a resize event, even if only scrollbars are added.

<template>
	<iframe ref="hidden-frame" :style="styles" />
</template>

<script>
/*
 * A shim to fire an event on resize, even when scrollbars are added/removed.
 */
export default {

	name: 'scrollbar-resize-shim',

	props: {
		onResize: {
			default: () => {}
		}
	},

	created() {
		this.styles = {
			height: 0,
			margin: 0,
			padding: 0,
			overflow: 'hidden',
			borderWidth: 0,
			position: 'absolute',
			backgroundColor: 'transparent',
			width: '100%'
		};
	},

	mounted() {
		this.$refs['hidden-frame'].contentWindow.addEventListener('resize', this.onResize, false);
	},

	beforeDestroy() {
		this.$refs['hidden-frame'].contentWindow.removeEventListener('resize', this.onResize);
	}
};
</script>


<template>

{{ project.name }}

 100 ? 'bg-danger' : '']]"
                 v-bind:style="{ width: project.percent_done + '%' }">
                {{ project.percent_done }}%

        {{ project.total_duration }}

        {{ project.total_entries }}

        <button name="project-change"
                class="btn btn-warning btn-sm w-100">
            Edit
        </button>

</template>


Add the root component that brings in all the other components

<template>

        <router-view></router-view>

</template>


<template>
  <list
    :data="data"
    :auto-refresh="false"
    :options="options"
    type="Poll" />
</template>
<script>
import List from '~/components/List'

export default {
  components: {
    List
  },
  async asyncData({ app: { $resource } }) {
    const options = {}
    const data = await $resource()
    return {
      data: {
        ...data,
        data: [data.data]
      },
      options
    }
  }
}
</script>


<template>

    Inicial
    <input class="mr-10" type="text" id="dateInitial" value="" v-model="dateInitial" placeholder="MM/YYYY" v-on:keyup="inputDateInitial(dateInitial, $event)">
    Final
    <input class="mr-10" type="text" name="dateEnd" id="dateEnd" value="" v-model="dateEnd" placeholder="MM/YYYY" v-on:keyup="inputDateEnd(dateEnd, $event)">
    <button class="ui primary button" :disabled="isDisabled" type="button" v-on:click="getValues('POST',{'dateInitial':'28/'+dateInitial,'dateEnd':'28/'+dateEnd})">Atualizar data</button>

</template>


<template>

    <form id="mc-embedded-subscribe-form"
          action="https://OFReport.us6.list-manage.com/subscribe/post?u=1e0c65850b60905f65b151819&id=97b9f6a559"
          method="post"
          name="mc-embedded-subscribe-form"
          class="validate"
          target="_blank"
          novalidate
    >

        <input id="mce-EMAIL"
               type="email"
               value=""
               name="EMAIL"
               class="w-full py-2 px-4 rounded xs:rounded-r-none border border-gray-200 xs:border-r-0 placeholder-gray-600 focus:placeholder-gray-300 focus:outline-none focus:shadow-outline"
               placeholder="you@example.com"
               required
        >

          <input type="text"
                 name="b_1e0c65850b60905f65b151819_97b9f6a559"
                 tabindex="-1"
                 value=""
          >

          <input id="mc-embedded-subscribe"
                 type="submit"
                 value="Subscribe"
                 name="subscribe"
                 class="w-full mt-2 xs:mt-0 py-2 px-4 font-bold btn-blue rounded xs:rounded-l-none xs:border xs:border-blue-600 cursor-pointer"
          >

    </form>

</template>


<template>

{{ _('Your harvester has been created') }}

{{ _('Your harvester is now pending for team review.') }}

{{ _('You'll be notified on approval (or refusal)') }}

        <button class="btn btn-primary btn-flat" v-route="/harvester/{{source.id}}/">
            {{ _('See in the administration') }}
        </button>

</template>

Fix new harvester workflow last screen

<template>

{{ _('Your harvester has been created') }}

{{ _('Your harvester is now pending for team review.') }}

{{ _("You'll be notified on approval (or refusal)") }}

        <button class="btn btn-primary btn-flat" v-route="/harvester/{{source.id}}/">
            {{ _('See in the administration') }}
        </button>

</template>


<template>

      {{ ancestor.name }} >
       {{ ancestor.name }}

</template>

Make breadcrumbs' list prop required.


<!--
  Licensed to Cloudera, Inc. under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  Cloudera, Inc. licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->

<template>
  <div
    v-if="spin"
    :class="{
      'hue-spinner-overlay': overlay,
      'hue-spinner-inline': inline,
      'hue-spinner': !overlay && !inline,
      'hue-spinner-blackout': blackout
    }"
  >
    <i
      v-if="!overlay"
      class="fa fa-spinner fa-spin"
      :style="{ width: center && inline ? '100%' : null }"
      :class="{
        'hue-spinner-large': size === 'large',
        'hue-spinner-xlarge': size === 'xlarge',
        'hue-spinner-center': center
      }"
    />
  </div>
</template>

<script lang="ts">
  import Vue from 'vue';
  import Component from 'vue-class-component';
  import { Prop } from 'vue-property-decorator';

  @Component
  export default class Spinner extends Vue {
    @Prop({ required: false, default: true })
    spin?: boolean;
    @Prop({ required: false, default: 'default' })
    size?: string;
    @Prop({ required: false, default: false })
    center?: boolean;
    @Prop({ required: false, default: false })
    overlay?: boolean;
    @Prop({ required: false, default: false })
    inline?: boolean;
    @Prop({ required: false, default: false })
    blackout?: boolean;
  }
</script>

<style lang="scss" scoped></style>


<template>
    <li class="nav-item" @click="onclick">
        <b-link :class="classObject" :to="to" :href="href" :exact="exact">
            <slot></slot>
        </b-link>
    </li>
</template>

<script>
    import bLink from './link.vue';

    export default {
        components: {bLink},
        computed: {
            classObject() {
                return [
                    'nav-link',
                    this.active ? 'active' : '',
                    this.disabled ? 'disabled' : ''
                ];
            }
        },
        props: {
            active: {
                type: Boolean,
                default: false
            },
            disabled: {
                type: Boolean,
                default: false
            },
            to: {
                type: [String, Object]
            },
            href: {
                type: String
            },
            exact: {
                type: Boolean
            }
        },
        methods: {
            onclick(e) {
                // Hide all drop-downs including navbar-toggle
                this.$root.$emit('shown::dropdown', this);
                this.$emit('click', e);
            }
        }
    };
</script>

Change the component type to 'button' if 'href' or 'to' props are not defined

<template>
    <li class="nav-item" @click="onclick">
        <b-link :is="itemType" :class="classObject" :to="to" :href="href" :exact="exact">
            <slot></slot>
        </b-link>
    </li>
</template>

<script>
    import bLink from './link.vue';

    export default {
        components: {bLink},
        computed: {
            itemType() {
                return (this.href || this.to) ? 'b-link' : 'button';
            },
            classObject() {
                return [
                    'nav-link',
                    this.active ? 'active' : '',
                    this.disabled ? 'disabled' : ''
                ];
            }
        },
        props: {
            active: {
                type: Boolean,
                default: false
            },
            disabled: {
                type: Boolean,
                default: false
            },
            to: {
                type: [String, Object]
            },
            href: {
                type: String
            },
            exact: {
                type: Boolean
            }
        },
        methods: {
            onclick(e) {
                // Hide all drop-downs including navbar-toggle
                this.$root.$emit('shown::dropdown', this);
                this.$emit('click', e);
            }
        }
    };
</script>


<template>

        {{ $t("playlists.edit_title") }} {{ playlistToEdit.name }}

        {{ $t("playlists.no_playlist") }}

      <form v-on:submit.prevent>
        <text-field
          ref="nameField"
          :label="$t('playlists.fields.name')"
          v-model="form.name"
          @enter="runConfirmation"
          v-focus
        >
        </text-field>
      </form>

          {{ $t("main.confirmation") }}

        <router-link
          :to="cancelRoute"
          class="button is-link">
          {{ $t("main.cancel") }}
        </router-link>

        {{ $t("assets.edit_fail") }}

</template>


<script>
import { mapGetters } from 'vuex';

export default {
    computed: {
        ...mapGetters(['taintedGetter', 'untaintedGetter'])
    },
    methods: {
        sinks() {
            sink(this.taintedGetter); // NOT OK
            sink(this.untaintedGetter); // OK
        }
    }
};
</script>


<template>

        {{ anchor.label }}

</template>

Add comments for the 'route' data


<template>
  <div class="input-control-buttons" ref="container">
    <el-button
      :disabled="isRecording"
      :size="buttonSize"
      :type="startButtonType"
      @click="handleStartRecording"
    >
      Start Recording
    </el-button>

  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { ElementUIComponentSize } from 'element-ui/types/component';
import { ButtonType } from 'element-ui/types/button';

@Component({
  name: 'input-control-buttons-simple',
})
export default class InputControlButtonsSimple extends Vue {
  @Prop({ required: false, type: String, default: 'small' })
  buttonSize!: ElementUIComponentSize;

  @Prop({ required: false, type: String, default: 'primary' })
  startButtonType!: ButtonType;

  get isRecording(): boolean {
    return this.$assistant.data.isRecording;
  }

  get hasAnyAudioOutput(): boolean {
    return this.isPlayingAudio || this.isSpeakingText;
  }

  get isSpeakingText(): boolean {
    return this.$assistant.data.isSpeakingText;
  }

  get isPlayingAudio(): boolean {
    return this.$assistant.data.isPlayingAudio;
  }

  handleStartRecording() {
    if (!this.isRecording) {
      this.$assistant.startRecording();
      this.$emit('startRecording')
    }
  }

  handleStopRecording() {
    this.$assistant.stopRecording();
  }

  handleAbortRecording() {
    this.$assistant.abortRecording();
  }

  handleStopAudioOutput() {
    this.$assistant.stopAudioOutput();
  }
}
</script>

<style scoped></style>


<template>

        {{ $t("main.csv.import_title") }}

        {{ $t("main.csv.required_fields") }}

            {{ column }}

        {{ $t("main.csv.select_file") }}

      <file-upload @fileselected="onFileSelected"></file-upload>

        {{ $t("main.csv.error_upload") }}

          {{ $t("main.confirmation") }}

        <router-link
          :to="cancelRoute"
          class="button is-link">
          {{ $t("main.cancel") }}
        </router-link>

</template>


Add component for displaying and selecting page links from the currently selected site in our page editor.

<template>
<el-card>

		Your pages

				{{ page.title }}
				{{ page.path }}

			<el-button @click="onClick({ text: page.title, url: page.path})" size="small" style="margin-left: auto;">
				Add to menu
			</el-button>

</el-card>
</template>


<template>

    <side-menu></side-menu>

      <router-view></router-view>

</template>

Move side-menu hiding to computed property


Add editor with codemirror with one-way binding, no styling

<template>

    <codemirror v-model="content" @changed="codeChange" >
    </codemirror>

{{content}}

</template>


Add widget: button that leads to a new route

<template>
<router-link
  class="button"
  :to="path"
>
  {{ text }}
</router-link>
</template>

<script>
export default {
  name: 'button-link',
  props: {
    text: {
      default: 'button',
      type: String
    },
    path: {
      default: '',
      type: String
    }
  }
}
</script>

<style scoped>
</style>


<template>

      <page-title
        :text="$t('tasks.create_tasks_shot')"
      >
      </page-title>

      <form v-on:submit.prevent>
        <combobox
          :label="$t('tasks.fields.task_type')"
          :options="getTaskTypeOptions"
          v-model="form.task_type_id"
        >
        </combobox>
      </form>

        {{ text }}

          {{ $t("main.confirmation") }}

        <router-link
          :to="cancelRoute"
          class="button is-link"
        >
          {{ $t("main.cancel") }}
        </router-link>

          {{ errorText }}

</template>


// *************************************
//
//   Byline
//   -> Article meta information
//
// -------------------------------------
//   Template (Haml)
// -------------------------------------
//
// .byline[.byline--modifier](.is-state)(.has-context)
//   .byline-main
//     .byline-author
//   .byline-secondary
//
// *************************************

.byline
  background: rgba($c-highlight, 0.8)
  color: $c-text-invert
  +respond-to($g-s)
    display: flex

// -------------------------------------
//   Scaffolding
// -------------------------------------

// ----- Author ----- //

.byline-author
  border-right: 2px solid $c-text-invert
  display: inline-block
  margin-right: $b-space-s
  padding-right: $b-space-s

// ----- Main ----- //

.byline-main
  background: $c-highlight
  box-sizing: border-box
  padding: $b-space-s

// ----- Secondary ----- //

.byline-secondary
  padding: $b-space-s
  +respond-to($g-s)
    flex-grow: 1
    text-align: right

Change Byline Structure to respond at `$g-m`

// *************************************
//
//   Byline
//   -> Article meta information
//
// -------------------------------------
//   Template (Haml)
// -------------------------------------
//
// .byline[.byline--modifier](.is-state)(.has-context)
//   .byline-main
//     .byline-author
//   .byline-secondary
//
// *************************************

.byline
  background: rgba($c-highlight, 0.8)
  color: $c-text-invert
  +respond-to($g-m)
    display: flex

// -------------------------------------
//   Scaffolding
// -------------------------------------

// ----- Author ----- //

.byline-author
  border-right: 2px solid $c-text-invert
  display: inline-block
  margin-right: $b-space-s
  padding-right: $b-space-s

// ----- Main ----- //

.byline-main
  background: $c-highlight
  box-sizing: border-box
  padding: $b-space-s

// ----- Secondary ----- //

.byline-secondary
  padding: $b-space-s
  +respond-to($g-m)
    flex-grow: 1
    text-align: right


$white: #c7c7c7
$gray: #909090
$bulletColor: $white
$primaryTextColor: $gray

Update bulletColor to be gray

$white: #c7c7c7
$gray: #909090
$bulletColor: $gray
$primaryTextColor: $gray


// -----------------------------------------------------------------------------
// Social Footer
// -----------------------------------------------------------------------------

.sharing
  @extend %clearfix
  border-top: 1px solid $body-background
  padding: 20px 0 0

// Ensure that social plugin flyouts remain at the top layer
.sharing__nav
  position: relative
  z-index: 10

.sharing__label
  +font-size(12)
  text-transform: uppercase
  font-weight: bold
  line-height: 22px

.sharing__icon
  @extend %inline-block
  color: $body-copy
  margin-left: 15px
  position: relative
  height: 24px
  text-align: left
  width: 20px
  &:hover
    text-decoration: none
  &:before
    top: -16px
  .no-js &, .no-background-size &
    text-indent: 0
    width: auto

  .tooltip
    color: white
    left: -63%
    text-indent: 0
    &:after
      color: $body-copy
      left: 53%

.facebook-like
  margin-left: 10px
  min-width: 90px

.tweet-button
  margin-left: 10px
  max-width: 103px

Fix positioning of new facebook like button

// -----------------------------------------------------------------------------
// Social Footer
// -----------------------------------------------------------------------------

.sharing
  @extend %clearfix
  border-top: 1px solid $body-background
  padding: 20px 0 0

// Ensure that social plugin flyouts remain at the top layer
.sharing__nav
  position: relative
  z-index: 10

.sharing__label
  +font-size(12)
  text-transform: uppercase
  font-weight: bold
  line-height: 22px

.sharing__icon
  @extend %inline-block
  color: $body-copy
  margin-left: 15px
  position: relative
  height: 24px
  text-align: left
  width: 20px
  &:hover
    text-decoration: none
  &:before
    top: -16px
  .no-js &, .no-background-size &
    text-indent: 0
    width: auto

  .tooltip
    color: white
    left: -63%
    text-indent: 0
    &:after
      color: $body-copy
      left: 53%

.facebook-like
  position: relative
  top: -4px
  margin-left: 10px
  min-width: 90px

.tweet-button
  margin-left: 3px
  max-width: 103px


@import "../../../styles/styles"

.featured-announcement
  display: block
  width: 100%
  text-align: center
  padding-top: +modular-scale(0)
  padding-bottom: +modular-scale(-2)
  text-decoration: none
  background-color: $color-red-lightest
  font-weight: 500
  border-bottom: 3px solid $color-red-light

Adjust padding on announcement mobile

@import "../../../styles/styles"

.featured-announcement
  display: block
  width: 100%
  text-align: center
  padding: +modular-scale(0)
  padding-bottom: +modular-scale(-2)
  text-decoration: none
  background-color: $color-red-lightest
  font-weight: 500
  border-bottom: 3px solid $color-red-light


.asciinema-terminal
  box-sizing: content-box
  -moz-box-sizing: content-box
  -webkit-box-sizing: content-box
  overflow: hidden
  padding: 0
  margin: 0px
  display: block
  white-space: pre
  border: 0
  word-wrap: normal
  word-break: normal
  border-radius: 0
  border-style: solid
  cursor: text

  +terminal-font

  .line
    display: block

  .bright
    font-weight: bold

  .underline
    text-decoration: underline

  .italic
    font-style: italic

  &.font-small
    +terminal-font-small
    border-width: 6px

  &.font-medium
    +terminal-font-medium
    border-width: 9px

  &.font-big
    +terminal-font-big
    border-width: 12px

  .font-sample
    display: block

    &.font-small
      +terminal-font-small

    &.font-medium
      +terminal-font-medium

    &.font-big
      +terminal-font-big

Fix terminal line width for some* obscure edge cases

.asciinema-terminal
  box-sizing: content-box
  -moz-box-sizing: content-box
  -webkit-box-sizing: content-box
  overflow: hidden
  padding: 0
  margin: 0px
  display: block
  white-space: pre
  border: 0
  word-wrap: normal
  word-break: normal
  border-radius: 0
  border-style: solid
  cursor: text

  +terminal-font

  .line
    display: block
    width: 101%

  .bright
    font-weight: bold

  .underline
    text-decoration: underline

  .italic
    font-style: italic

  &.font-small
    +terminal-font-small
    border-width: 6px

  &.font-medium
    +terminal-font-medium
    border-width: 9px

  &.font-big
    +terminal-font-big
    border-width: 12px

  .font-sample
    display: block

    &.font-small
      +terminal-font-small

    &.font-medium
      +terminal-font-medium

    &.font-big
      +terminal-font-big


// Links
//
//
// .link--back - Back
//
// Styleguide 1.6

.link--back
  @extend %left-icon
  @extend %inline-block
  +font-size(15)
  padding-left: 15px
  &:before
    width: 12px
    height: 12px
    top: 4px

.link--wrapper
  @extend %clearfix
  overflow: hidden
  display: block
  height: 100%
  color: $base-font-color
  &, &:hover
    text-decoration: none

Fix dodgy spacing on the back link

.link--back
  @extend %left-icon
  @extend %inline-block
  +font-size(15)
  padding-left: 15px
  &:before
    width: 12px
    height: 12px

.link--wrapper
  @extend %clearfix
  overflow: hidden
  display: block
  height: 100%
  color: $base-font-color
  &, &:hover
    text-decoration: none


.mod-navigation
	.content
		max-width: 14em
	.navball
		background: #444
		box-shadow: inset 0 .2em .7em #000, inset 0 1px 0 #000, 0 1px 0 #fff
		width: 1em
		height: 1em
		border-radius: 50%
		position: relative
		&::after
			content: ''
			display: block
			position: absolute
			width: 1em
			height: 1em
			top: 50%
			left: 50%
			transform: translate(-50%, -50%)
			border-radius: 50%
			border: 3px solid #f00

Add subtle gloss on navball

.mod-navigation
	.content
		max-width: 14em
	.navball
		background: #444
		box-shadow: inset 0 .2em .7em #000, inset 0 1px 0 #000, 0 1px 0 #fff
		width: 1em
		height: 1em
		border-radius: 50%
		position: relative
		&::before
			content: ''
			display: block
			position: absolute
			width: 100%
			height: 100%
			border-radius: 50%
			top: 0
			top: 0
			background: radial-gradient(ellipse 150% 100% at 50% 5%, rgba(#fff, 0), rgba(#fff, .2) 50%, rgba(#fff, .0) 50%, rgba(#fff, .2))
		&::after
			content: ''
			display: block
			position: absolute
			width: 1em
			height: 1em
			top: 50%
			left: 50%
			transform: translate(-50%, -50%)
			border-radius: 50%
			border: 3px solid #f00


// -----------------------------------------------------------------------------
// Alerts
// -----------------------------------------------------------------------------

.alert
  @extend %rounded-corners
  clear: both
  margin: 10px 0
  padding: 15px 15px 15px 45px
  position: relative

  &:before
    height: 18px
    left: 15px
    position: absolute
    top: 12px
    width: 20px

.alert--success
  background: lighten($green, 50%)

.alert--error
  background: lighten($red, 25%)

.alert--warning
  background: lighten($orange, 30%)

Decrease bottom padding of alerts.


.chart
  padding: $base-spacing

.key
  margin-bottom: $base-spacing
  padding-left: $base-spacing * 2
  position: relative

  &:before,
  &:after
    border-radius: 100px
    content: ""
    display: inline-block

  &:before
    +size(30px)
    +position(absolute, -2px null null 0)
    background: red
    margin-right: $small-spacing

  &:after
    +size(20px)
    +position(absolute, 3px null null 5px)
    +transition(opacity .1s ease-in-out)
    background: $white
    opacity: 0

  &:hover
    cursor: pointer
    &.inactive
      text-decoration: underline
      &:after
        opacity: 1
    &.active
      text-decoration: none
      &:after
        opacity: 0

  &.inactive
    &:after
      //opacity: 0

  &.active
    text-decoration: underline
    &:after
      opacity: 1

Remove default list styling on graph keys.

.chart
  padding: $base-spacing

.legend
  list-style: none
  padding-left: 0

.key
  margin-bottom: $base-spacing
  padding-left: $base-spacing * 2
  position: relative

  &:before,
  &:after
    border-radius: 100px
    content: ""
    display: inline-block

  &:before
    +size(30px)
    +position(absolute, -2px null null 0)
    background: red
    margin-right: $small-spacing

  &:after
    +size(20px)
    +position(absolute, 3px null null 5px)
    +transition(opacity .1s ease-in-out)
    background: $white
    opacity: 0

  &:hover
    cursor: pointer
    &.inactive
      text-decoration: underline
      &:after
        opacity: 1
    &.active
      text-decoration: none
      &:after
        opacity: 0

  &.inactive
    &:after
      //opacity: 0

  &.active
    text-decoration: underline
    &:after
      opacity: 1


@import 'app_colors'

.pagination
  margin-top: 0

  > .disabled > span
    &:hover
      cursor: not-allowed

.pagination-footer
  background-color: $app-color-white
  border-top: 1px solid $app-color-gray
  bottom: 0
  height: 40px
  padding: 5px 15px
  position: static

  .pagination-controls
    position: fixed
    right: 15px

Move pagination styles within pagination-footer

@import 'app_colors'

.pagination-footer
  background-color: $app-color-white
  border-top: 1px solid $app-color-gray
  bottom: 0
  height: 40px
  padding: 5px 15px
  position: static

  .pagination-controls
    position: fixed
    right: 15px

  .pagination
    margin-top: 0

    > .disabled > span
      &:hover
        cursor: not-allowed


.pagination-link
  +media(max-width 830px)
    +shift(0.5)
  +shift(3.03)
  font-family: CamptonBook
  background-color: white
  border: 1px solid #0060ff
  border-radius: 2px
  max-width:  17.4em
  padding:
    top: .5em
    bottom: .5em
  margin:
    bottom: ($large-margin + .2em)
  &:first-of-type
    float: left
  a
    padding:
      top: .5em
      bottom: .5em
      left: .8em
      right: .8em
    color: #0060ff
    font-size: 1.1em
    box-shadow: 0px 3px 0px rgba(#F6F6F6, .5)

Add breakpoint for pagination link

.pagination-link
  +media(max-width 830px)
    +shift(0.5)
  +media(max-width 1250px)
    +shift(1)
  +shift(3.03)
  font-family: CamptonBook
  background-color: white
  border: 1px solid #0060ff
  border-radius: 2px
  max-width:  17.4em
  padding:
    top: .5em
    bottom: .5em
  margin:
    bottom: ($large-margin + .2em)
  &:first-of-type
    float: left
  a
    padding:
      top: .5em
      bottom: .5em
      left: .8em
      right: .8em
    color: #0060ff
    font-size: 1.1em
    box-shadow: 0px 3px 0px rgba(#F6F6F6, .5)


// *************************************
//
//   Card
//   -> Individual style containers
//
// -------------------------------------
//   Template (Haml)
// -------------------------------------
//
// .card[.card--error|success|warning]
//
// *************************************

.card
  @extend .por
  @extend .ram
  background: $card-background
  box-shadow: $b-boxShadow
  padding: $b-whitespace

// -------------------------------------
//   Modifiers
// -------------------------------------

// ----- Types ----- //

.card--error
  box-shadow: none
  border: $card-borderWidth $b-borderStyle $c-error

.card--success
  box-shadow: none
  border: $card-borderWidth $b-borderStyle $c-success

.card--warning
  box-shadow: none
  border: $card-borderWidth $b-borderStyle $c-warning

Adjust the card responsive padding

// *************************************
//
//   Card
//   -> Individual style containers
//
// -------------------------------------
//   Template (Haml)
// -------------------------------------
//
// .card[.card--error|success|warning]
//
// *************************************

.card
  @extend .pas
  @extend .por
  @extend .ram
  background: $card-background
  box-shadow: $b-boxShadow
  +respond-to($grid-breakpoint-desk)
    padding: $b-whitespace

// -------------------------------------
//   Modifiers
// -------------------------------------

// ----- Types ----- //

.card--error
  box-shadow: none
  border: $card-borderWidth $b-borderStyle $c-error

.card--success
  box-shadow: none
  border: $card-borderWidth $b-borderStyle $c-success

.card--warning
  box-shadow: none
  border: $card-borderWidth $b-borderStyle $c-warning


@import 'compass/utilities/text/replacement'

=icon-text($ident, $size=16)
  .icon-#{$ident}-text
    +replace-text-with-dimensions("/#{$size}x#{$size}/#{$ident}.png")
    display: block
    float: left

=icon($ident, $size=16)
  background-image: url("/images/#{$size}x#{$size}/#{$ident}.png")

=icon-class($ident, $size=16)
  .icon-#{$ident}
    +icon($ident, $size)

.icon
  background-repeat: no-repeat
  padding-left: 20px
  text-decoration: none
  font-size: 16px
  color: $link_color
  &:hover
    color: $link_color_hover

+icon-class('add')
+icon-class('delete')
+icon-class('edit')
+icon-class('index')

+icon-text('add')
+icon-text('delete')
+icon-text('edit')
+icon-text('index')

Fix path for icon-text mixin urls.

@import 'compass/utilities/text/replacement'

=icon-text($ident, $size=16)
  .icon-#{$ident}-text
    +replace-text-with-dimensions("#{$size}x#{$size}/#{$ident}.png")
    display: block
    float: left

=icon($ident, $size=16)
  background-image: url("/images/#{$size}x#{$size}/#{$ident}.png")

=icon-class($ident, $size=16)
  .icon-#{$ident}
    +icon($ident, $size)

.icon
  background-repeat: no-repeat
  padding-left: 20px
  text-decoration: none
  font-size: 16px
  color: $link_color
  &:hover
    color: $link_color_hover

+icon-class('add')
+icon-class('delete')
+icon-class('edit')
+icon-class('index')

+icon-text('add')
+icon-text('delete')
+icon-text('edit')
+icon-text('index')


#main, .posts
  +outer-container

.soundcloud-player-small
  margin:
    top: $small-margin

.index-article
  margin:
    bottom: ($small-margin + $medium-margin)

.topic-list
  color: $medium-gray
  line-height: 1.8em

.posts, .article-detail
  p
    font-size: 1.05em
    line-height: 1.35em
    margin:
      bottom: $medium-margin

.detail-post-date, .post-date
  font-size: 1em

.post-date
  margin:
    left: em(-111px)
    right: em(12px)
  +media(max-width 830px)
    display: block
    margin:
      left: em(0px)
      right: em(0px)
      bottom: $small-margin

.recent-posts li:before, .article-detail li:before
  content: "• "
  color: $brand-color

Tweak spacing for post title on index page

#main, .posts
  +outer-container

.soundcloud-player-small
  margin:
    top: $small-margin

.index-article
  margin:
    bottom: ($small-margin + $medium-margin)

.topic-list
  color: $medium-gray
  line-height: 1.8em

.posts, .article-detail
  p
    font-size: 1.05em
    line-height: 1.35em
    margin:
      bottom: $medium-margin

.detail-post-date, .post-date
  font-size: 1em

.post-date
  margin:
    left: em(-111px)
    right: em(10px)
  +media(max-width 830px)
    display: block
    margin:
      left: em(0px)
      right: em(0px)
      bottom: $small-margin

.recent-posts li:before, .article-detail li:before
  content: "• "
  color: $brand-color


.current-spendings
  color: $color6
  >div
    display: inline-block

.spendings-currency
  font-size: 3rem !important
  line-height: 3rem

.spendings-value
  font-size: 5rem !important
  line-height: 5rem

.today-date-display
  >span
    color: $color3
    margin-right: 10px
    font-size: 1.4rem

.spendings-cont
  padding-right: 35px

Add css styles for isInPast warning message

.current-spendings
  color: $color6
  >div
    display: inline-block

.spendings-currency
  font-size: 3rem !important
  line-height: 3rem

.spendings-value
  font-size: 5rem !important
  line-height: 5rem

.today-date-display
  padding-top: 25px
  >span
    color: $color3
    margin-right: 10px
    font-size: 1.4rem

.spendings-cont
  padding-right: 35px

.isInPast-warning
  background: #fff9c4
  padding: 5px 15px
  border-radius: 5px
  strong
    display: block
  >p
    margin: 0
    text-align: center


.form-layout
  .form-group
    display: flex
    align-items: flex-start
    +render-to(xs, ms)
      display: block

    label
      min-width: rem(220)
      margin-top: rem(13)
      text-align: right
      +render-to(xs, ms)
        width: 100%
        min-width: auto
        text-align: left

    .form-control-wrapper
      margin-left: rem(15)
      margin-right: 25%
      flex-grow: 2
      +render-to(xs, ms, sm, md)
        margin-right: 0

      +render-to(xs, ms)
        margin-left: 0

      .form-control-wrapper
        margin-right: 0
        margin-left: 0

.box-footer
  text-align: right

  .for-horizontal-form
    padding-left: 0

Add hover on page list item

.form-layout
  .form-group
    display: flex
    align-items: flex-start
    +render-to(xs, ms)
      display: block

    label
      min-width: rem(220)
      margin-top: rem(13)
      text-align: right
      +render-to(xs, ms)
        width: 100%
        min-width: auto
        text-align: left

    .form-control-wrapper
      margin-left: rem(15)
      margin-right: 25%
      flex-grow: 2
      +render-to(xs, ms, sm, md)
        margin-right: 0

      +render-to(xs, ms)
        margin-left: 0

      .form-control-wrapper
        margin-right: 0
        margin-left: 0

.box-footer
  text-align: right

  .for-horizontal-form
    padding-left: 0

.pages-tree__row
  &:hover
    background-color: #F4F6FA


@import '../../../shared-sass/palette'
@import '../../../shared-sass/variables'

$height: 30px

.pagination
  color: $color-main-foreground
  list-style-position: inside
  list-style-type: none
  line-height: $height
  margin: 0 16px
  padding: 0

  .active
    a,
    span
      background-color: $color-theme-1
      color: $color-bright-primary

  a,
  span
    border-radius: 2px
    display: inline-block
    padding: 0 8px

  a
    text-decoration: none
    transition: color $animation-time-medium, background-color $animation-time-medium

    &:hover
      background-color: $color-bright-secondary

    &:active
      background-color: $color-theme-1
      color: $color-bright-primary

  li
    display: inline-block
    margin: 0 4px

  .directional-indicator,
  .spacer
    margin: 0 8px

Fix paddings and margins on pagination

@import '../../../shared-sass/palette'
@import '../../../shared-sass/variables'

$height: 30px

.pagination
  color: $color-main-foreground
  list-style-position: inside
  list-style-type: none
  line-height: $height
  margin: 16px
  padding: 0

  .active
    a,
    span
      background-color: $color-theme-1
      color: $color-bright-primary

  a,
  span
    border-radius: 2px
    display: inline-block
    padding: 0 8px

  a
    text-decoration: none
    transition: color $animation-time-medium, background-color $animation-time-medium

    &:hover
      background-color: $color-bright-secondary

    &:active
      background-color: $color-theme-1
      color: $color-bright-primary

  ul
    margin: 0
    padding: 0

    li
      display: inline-block
      margin: 0 4px

  .directional-indicator,
  .spacer
    margin: 0 8px


//-------------------------------------
//  Content
//-------------------------------------

// ----- Headings ----- //

h1, h2, h3,
h4, h5, h6
  font-family: $c-header-fontFamily
  font-weight: bold

h1, .c-h1, %c-h1
  font-size: em(40px)

h2, .c-h2, %c-h2
  font-size: em(35px)

h3, .c-h3, %c-h3
  font-size: em(30px)

h4, .c-h4, %c-h4
  font-size: em(25px)

h5, .c-h5, %c-h5
  font-size: em(20px)

h6, .c-h6, %c-h6
  font-size: em(16px)

// ----- Utilities ----- //

.c-center, %c-center
  text-align: center

.c-condensed, %c-condensed
  font-size: 85%

.c-lead, %c-lead
  font-size: 125%

.c-shout, %c-shout
  text-transform: uppercase

Adjust the order of placeholder selectors in the Content core

//-------------------------------------
//  Content
//-------------------------------------

// ----- Headings ----- //

h1, h2, h3,
h4, h5, h6
  font-family: $c-header-fontFamily
  font-weight: bold

h1, .c-h1, %c-h1
  font-size: em(40px)

h2, .c-h2, %c-h2
  font-size: em(35px)

h3, .c-h3, %c-h3
  font-size: em(30px)

h4, .c-h4, %c-h4
  font-size: em(25px)

h5, .c-h5, %c-h5
  font-size: em(20px)

h6, .c-h6, %c-h6
  font-size: em(16px)

// ----- Utilities ----- //

%c-center, .c-center
  text-align: center

%c-condensed, .c-condensed
  font-size: 85%

%c-lead, .c-lead
  font-size: 125%

%c-shout, .c-shout
  text-transform: uppercase


.hero-header
  padding: +emCalc(60px) 0
  min-height: +emCalc(200px)
  background-size: cover
  background-position: center
  text-align: center
  h2, h3
    color: white

Make some adjustments on hero header

.hero-header
  background-color: $secondary-color
  padding: +emCalc(60px) 0
  min-height: +emCalc(200px)
  background-size: cover
  background-position: center
  text-align: center
  h2, h3
    color: white
  h2
    font-weight: bold
  h3
    text-transform: uppercase
    font-weight: 300
    padding-top: +emCalc(8px)


#main, .posts
  +outer-container

.posts p,  article.article-detail, .index-article
  +shift(2)
  +span-columns(8)

.soundcloud-player-small
  margin:
    top: $small-margin

.index-article
  margin:
    bottom: ($small-margin + $medium-margin)

.topic-list
  color: $medium-gray
  line-height: 1.8em

.post-title
  a
    color: darken($medium-gray, 30%)
    font-size: 1.7em

.posts, .article-detail
  p
    color: darken($medium-gray, 30%)
    font-size: 1.05em
    line-height: 1.35em
    margin:
      bottom: $medium-margin

.detail-post-date, .post-date
  color: $light-gray
  font-size: 0.6em

.post-date
  margin:
    left: em(-111px)
    right: em(12px)

Add media query for date on index list

#main, .posts
  +outer-container

.posts p,  article.article-detail, .index-article
  +shift(2)
  +span-columns(8)

.soundcloud-player-small
  margin:
    top: $small-margin

.index-article
  margin:
    bottom: ($small-margin + $medium-margin)

.topic-list
  color: $medium-gray
  line-height: 1.8em

.post-title
  a
    color: darken($medium-gray, 30%)
    font-size: 1.7em

.posts, .article-detail
  p
    color: darken($medium-gray, 30%)
    font-size: 1.05em
    line-height: 1.35em
    margin:
      bottom: $medium-margin

.detail-post-date, .post-date
  color: $light-gray
  font-size: 0.6em

.post-date
  margin:
    left: em(-111px)
    right: em(12px)
  +media(max-width 780px)
    display: block
    margin:
      left: em(0px)
      right: em(0px)
      bottom: $small-margin


.border-none
  border: 0

.border-all
  border: 1px solid

.border-top
  border-top: 1px solid

.border-right
  border-right: 1px solid

.border-bottom
  border-bottom: 1px solid

.border-left
  border-left: 1px solid

.border-wide
  border-width: .125em

.border-extra
  border-width: .250em

.border-top-0
  border-top-width: 0

.border-right-0
  border-right-width: 0

.border-bottom-0
  border-bottom-width: 0

.border-left-0
  border-left-width: 0

.rad0
  border-radius: 0

.rad1
  border-radius: .125em

.rad2
  border-radius: .250em

.rad3
  border-radius: .5em

.rad4
  border-radius: 1em

.rounded-top
  border-bottom-left-radius: 0
  border-bottom-right-radius: 0

.rounded-right
  border-top-left-radius: 0
  border-bottom-left-radius: 0

.rounded-bottom
  border-top-left-radius: 0
  border-top-right-radius: 0

.rounded-left
  border-top-right-radius: 0
  border-bottom-right-radius: 0

.circle
  border-radius: 100%

Change border name class from .border- to .b-

.b-none
  border: 0

.b-all
  border: 1px solid

.b-top
  border-top: 1px solid

.b-right
  border-right: 1px solid

.b-bottom
  border-bottom: 1px solid

.b-left
  border-left: 1px solid

.b-wide
  border-width: .125em

.b-extra
  border-width: .250em

.b-top-0
  border-top-width: 0

.b-right-0
  border-right-width: 0

.b-bottom-0
  border-bottom-width: 0

.b-left-0
  border-left-width: 0

.rad0
  border-radius: 0

.rad1
  border-radius: .125em

.rad2
  border-radius: .250em

.rad3
  border-radius: .5em

.rad4
  border-radius: 1em

.rounded-top
  border-bottom-left-radius: 0
  border-bottom-right-radius: 0

.rounded-right
  border-top-left-radius: 0
  border-bottom-left-radius: 0

.rounded-bottom
  border-top-left-radius: 0
  border-top-right-radius: 0

.rounded-left
  border-top-right-radius: 0
  border-bottom-right-radius: 0

.circle
  border-radius: 100%


*
  @include box-sizing(border-box)

body
  font: 1em "Helvetica Neue", sans-serif
  margin: 0

#app
  max-width: 320px
  margin: 0 auto
  padding-bottom: 4.25em

Allow more space for the scrubber.

*
  @include box-sizing(border-box)

body
  font: 1em "Helvetica Neue", sans-serif
  margin: 0

#app
  max-width: 320px
  margin: 0 auto
  padding-bottom: 5.625em


@import 'bootstrap'

#zonks
  .zonk
    padding-top: 20px
    .name
      padding-top: 10px
      padding-bottom: 20px

#zonk_awards
  padding-top: 10px

  .award
    padding-bottom: 5px
    padding-top: 5px

#footer
  padding-top: 20px
  padding-bottom: 20px

Add a border around zonks

@import 'bootstrap'

#zonks
  .zonk
    img
      border: 1px solid gold
    padding-top: 20px
    .name
      padding-top: 10px
      padding-bottom: 20px

#zonk_awards
  padding-top: 10px

  .award
    img
      border: 1px solid gold
    padding-bottom: 5px
    padding-top: 5px

#footer
  padding-top: 20px
  padding-bottom: 20px


#devpost-footer
  background-color: $grey-2
  text-align: center
  font-size: 1rem
  text-align: left
  padding: 2em 0

  a
    +link-colors($dark)
    display: inline
    border-bottom: 1px solid transparent;
    transition: border-bottom-color 0.5s ease

    &:hover
      border-bottom: 1px solid $dark

  ul
    margin-bottom: 0
    list-style: none
    margin: 0

    li
      margin: 0 2.5em 0 0

      @media #{$small}
        display: inline-block

  .social-links
    float: right
    text-align: right

    li
      margin: 0 0 0 1em
      display: inline-block

    a
      +link-colors($grey-4)
      opacity: 0.6
      @include single-transition(opacity, 200ms)

      &:hover, &:focus
        opacity: 1

  a.ss-icon
    font-size: 2.25rem

    &:hover
      text-decoration: none

  .ss-heart
    color: $red-1

#site-footer-primary-nav
  margin-bottom: 0.7em

#site-footer-legal
  ul
    li
      margin-right: 2em

      a
        +link-colors($grey-4)
        border-bottom: 1px solid transparent;
        transition: border-bottom-color 0.5s ease

        &:hover
          border-bottom: 1px solid $grey-4

Remove semicolons because this isn't SCSS

#devpost-footer
  background-color: $grey-2
  text-align: center
  font-size: 1rem
  text-align: left
  padding: 2em 0

  a
    +link-colors($dark)
    display: inline
    border-bottom: 1px solid transparent
    transition: border-bottom-color 0.5s ease

    &:hover
      border-bottom: 1px solid $dark

  ul
    margin-bottom: 0
    list-style: none
    margin: 0

    li
      margin: 0 2.5em 0 0

      @media #{$small}
        display: inline-block

  .social-links
    float: right
    text-align: right

    li
      margin: 0 0 0 1em
      display: inline-block

    a
      +link-colors($grey-4)
      opacity: 0.6
      @include single-transition(opacity, 200ms)

      &:hover, &:focus
        opacity: 1

  a.ss-icon
    font-size: 2.25rem

    &:hover
      text-decoration: none

  .ss-heart
    color: $red-1

#site-footer-primary-nav
  margin-bottom: 0.7em

#site-footer-legal
  ul
    li
      margin-right: 2em

      a
        +link-colors($grey-4)
        border-bottom: 1px solid transparent
        transition: border-bottom-color 0.5s ease

        &:hover
          border-bottom: 1px solid $grey-4


.empty-state-wrapper
  padding: 0 0 10px
  text-align: center

  p.lead
    margin-bottom: 10px

Add styling for empty records message

.empty-state-wrapper
  padding: 0 0 10px
  text-align: center

  p.lead
    margin-bottom: 10px

.empty-records-message
  font-size: 1.15rem
  text-align: center


@import fonts
@import colors
@import animations

*
  margin: 0
  padding: 0
  outline: 0
  border: 0
  font-family: 'Montserrat', sans-serif
  list-style: none
  text-decoration: none
  box-sizing: border-box

body, html, .App
  width: 100vw
  height: 100vh
  color: $primaryTextColor
  scroll-behavior: smooth
  -webkit-font-smoothing: antialiased
  overflow: hidden

body
  background-image: url(../assets/images/background.png)
  background-size: cover
  background-position: center
  background-repeat: no-repeat
  background-color: black

.App
  display: flex
  align-items: center
  justify-content: center

a
  color: inherit

Remove tap highlight color on mobile

@import fonts
@import colors
@import animations

*
  margin: 0
  padding: 0
  outline: 0
  border: 0
  font-family: 'Montserrat', sans-serif
  list-style: none
  text-decoration: none
  box-sizing: border-box

body, html, .App
  width: 100vw
  height: 100vh
  color: $primaryTextColor
  scroll-behavior: smooth
  -webkit-font-smoothing: antialiased
  overflow: hidden

body
  background-image: url(../assets/images/background.png)
  background-size: cover
  background-position: center
  background-repeat: no-repeat
  background-color: black

.App
  display: flex
  align-items: center
  justify-content: center

a
  color: inherit
  -webkit-tap-highlight-color: transparent


.tabs
  border-bottom: 1px solid $border-color

  .tab-title
    a
      background-color: #efefef
      padding: 10px 20px
      transition: background-color 0.25s ease

      &:hover
        background-color: #e1e1e1

    &.active
      background-color: #fff

      a
        color: #222

        &:hover
          background-color: #fff

.tabs-content
  section
    outline: none

Improve the styling of the tabs

.tabs
  border-bottom: 1px solid $border-color

  .tab-title
    a
      background-color: #fff
      padding: 10px 20px
      transition: background-color 0.25s ease

      &:hover
        background-color: #f6f6f6

    &.active
      background-color: #efefef

      a
        background-color: #efefef
        color: #222

        &:hover
          background-color: #e1e1e1

.tabs-content
  section
    outline: none