old client structure
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
<template lang="pug">
|
||||
.form-check
|
||||
.custom-control.custom-checkbox
|
||||
input.custom-control-input(type="checkbox", v-model="isChecked", :id="id")
|
||||
label.custom-control-label(v-once, :for="id") {{ text }}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
checked: Boolean,
|
||||
id: String,
|
||||
text: String,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isChecked: this.checked,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
isChecked (after) {
|
||||
this.$emit('update:checked', after);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,34 @@
|
||||
<template lang="pug">
|
||||
span.badge.badge-pill.badge-item.badge-count(
|
||||
v-if="show && count > 0",
|
||||
) {{ count }}
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.badge-count {
|
||||
right: -9px;
|
||||
color: $white;
|
||||
background: $gray-200;
|
||||
padding: 4.5px 8.5px;
|
||||
min-width: 24px;
|
||||
height: 24px;
|
||||
box-shadow: 0 1px 1px 0 rgba($black, 0.12);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
},
|
||||
count: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,97 @@
|
||||
<!--
|
||||
A simplified dropdown component that doesn't rely on buttons as toggles like bootstrap-vue
|
||||
-->
|
||||
|
||||
<template lang="pug">
|
||||
.habitica-menu-dropdown.dropdown(@click="toggleDropdown()", @keypress.enter.space.stop.prevent="toggleDropdown()", role="button", tabindex="0", :class="{open: isOpen}", :aria-pressed="isPressed")
|
||||
.habitica-menu-dropdown-toggle
|
||||
slot(name="dropdown-toggle")
|
||||
.dropdown-menu(:class="{'dropdown-menu-right': right}")
|
||||
slot(name="dropdown-content")
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
.habitica-menu-dropdown {
|
||||
&:hover,
|
||||
&:focus { // NB focus styles match the hover styles for .svg-icon
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&.open {
|
||||
.habitica-menu-dropdown-toggle .svg-icon {
|
||||
color: $white !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang='scss' scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.dropdown {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
cursor: auto;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
max-height: calc(100vh - 100px);
|
||||
overflow: auto;
|
||||
left: inherit;
|
||||
right: 0px !important;
|
||||
|
||||
/deep/ .dropdown-separated {
|
||||
border-bottom: 1px solid $gray-500;
|
||||
}
|
||||
}
|
||||
|
||||
&.open {
|
||||
.dropdown-menu {
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
right: Boolean,
|
||||
openStatus: Number,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isDropdownOpen: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isOpen () {
|
||||
// Open status is a number so we can tell if the value was passed
|
||||
if (this.openStatus !== undefined) return this.openStatus === 1 ? true : false;
|
||||
return this.isDropdownOpen;
|
||||
},
|
||||
isPressed () {
|
||||
return this.isOpen ? 'true' : 'false';
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
document.documentElement.addEventListener('click', this._clickOutListener);
|
||||
},
|
||||
destroyed () {
|
||||
document.removeEventListener('click', this._clickOutListener);
|
||||
},
|
||||
methods: {
|
||||
_clickOutListener (e) {
|
||||
if (!this.$el.contains(e.target) && this.isOpen) {
|
||||
this.toggleDropdown();
|
||||
}
|
||||
},
|
||||
toggleDropdown () {
|
||||
this.isDropdownOpen = !this.isOpen;
|
||||
this.$emit('toggled', this.isDropdownOpen);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,191 @@
|
||||
<template lang="pug">
|
||||
.drawer-container
|
||||
.drawer-title(@click="toggle()")
|
||||
| {{title}}
|
||||
.drawer-toggle-icon.svg-icon.icon-10(v-html="isOpen ? icons.minimize : icons.expand", :class="{ closed: !isOpen }")
|
||||
transition(name="slide-up", @afterLeave="adjustPagePadding", @afterEnter="adjustPagePadding")
|
||||
.drawer-content(v-show="isOpen")
|
||||
slot(name="drawer-header")
|
||||
.drawer-slider
|
||||
slot(name="drawer-slider")
|
||||
div.message(v-if="errorMessage != null")
|
||||
.content {{ errorMessage }}
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.drawer-container {
|
||||
z-index: 19;
|
||||
position: fixed;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
bottom: 0;
|
||||
left: 19%;
|
||||
right: 3%;
|
||||
max-width: 80%;
|
||||
|
||||
@media screen and (min-width: 1241px) {
|
||||
max-width: 978px;
|
||||
// 236px is the width of the .standard-sidebar
|
||||
left: calc((100% + 236px - 978px) / 2);
|
||||
right: 0%;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-toggle-icon {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
|
||||
&.closed {
|
||||
top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-title {
|
||||
position: relative;
|
||||
background-color: $gray-10;
|
||||
box-shadow: 0 1px 2px 0 rgba($black, 0.2);
|
||||
cursor: pointer;
|
||||
border-top-right-radius: 8px;
|
||||
border-top-left-radius: 8px;
|
||||
text-align: center;
|
||||
line-height: 1.67;
|
||||
color: $white;
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.drawer-content {
|
||||
line-height: 1.33;
|
||||
max-height: 300px;
|
||||
background-color: $gray-50;
|
||||
color: $gray-500;
|
||||
box-shadow: 0 2px 16px 0 rgba($black, 0.3);
|
||||
padding-top: 6px;
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
.drawer-tab {
|
||||
&-container {
|
||||
display: flex;
|
||||
margin-left: 24px;
|
||||
|
||||
& > div {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&-text {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
line-height: 1.67;
|
||||
text-align: center;
|
||||
color: $white;
|
||||
border-bottom: 2px solid transparent;
|
||||
padding: 0px 8px 8px 8px;
|
||||
|
||||
&-active {
|
||||
border-color: $purple-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-help-text {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
|
||||
.svg-icon {
|
||||
position: relative;
|
||||
top: 4px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-slider {
|
||||
padding: 12px 0 0 8px;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
|
||||
& .message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
top: calc(50% - 30px);
|
||||
left: 24px;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
|
||||
& .content {
|
||||
background-color: rgba($gray-200, 0.5);
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slide-up-enter-active, .slide-up-leave-active {
|
||||
transition-property: all;
|
||||
transition-duration: 450ms;
|
||||
transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);
|
||||
}
|
||||
.slide-up-enter, .slide-up-leave-to {
|
||||
max-height: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import expandIcon from 'assets/svg/expand.svg';
|
||||
import minimizeIcon from 'assets/svg/minimize.svg';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
errorMessage: {
|
||||
type: String,
|
||||
},
|
||||
openStatus: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
open: true,
|
||||
icons: Object.freeze({
|
||||
expand: expandIcon,
|
||||
minimize: minimizeIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isOpen () {
|
||||
// Open status is a number so we can tell if the value was passed
|
||||
if (this.openStatus !== undefined) return this.openStatus === 1 ? true : false;
|
||||
return this.open;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
adjustPagePadding () {
|
||||
let minPaddingBottom = 20;
|
||||
let drawerHeight = this.$el.offsetHeight;
|
||||
let standardPage = document.getElementsByClassName('standard-page')[0];
|
||||
if (standardPage) {
|
||||
standardPage.style.paddingBottom = `${drawerHeight + minPaddingBottom}px`;
|
||||
}
|
||||
},
|
||||
toggle () {
|
||||
this.open = !this.isOpen;
|
||||
this.$emit('toggled', this.open);
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
// Make sure the page has enough space so the drawer does not overlap content
|
||||
this.adjustPagePadding();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,78 @@
|
||||
<template lang="pug">
|
||||
.header-tabs
|
||||
ul.drawer-tab-container
|
||||
li.drawer-tab(v-for="(tab, index) in tabs")
|
||||
a.drawer-tab-text(
|
||||
@click="changeTab(index)",
|
||||
:class="{'drawer-tab-text-active': selectedTabPosition === index}",
|
||||
:title="tab.label"
|
||||
) {{ tab.label }}
|
||||
|
||||
aside.help-item
|
||||
slot(name="right-item")
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.drawer-tab-text {
|
||||
display: block;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.drawer-tab {
|
||||
flex: inherit;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.drawer-tab-container {
|
||||
grid-column-start: 2;
|
||||
grid-column-end: 3;
|
||||
justify-self: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.help-item {
|
||||
grid-column-start: 3;
|
||||
position: relative;
|
||||
right: -11px;
|
||||
text-align: right;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.header-tabs {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
}
|
||||
|
||||
// MS Edge
|
||||
@supports (-ms-ime-align: auto) {
|
||||
.help-item {
|
||||
align-self: center;
|
||||
top: 1px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
tabs: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
selectedTabPosition: 0,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
changeTab (newIndex) {
|
||||
this.selectedTabPosition = newIndex;
|
||||
this.$emit('changedPosition', newIndex);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,189 @@
|
||||
<template lang="pug">
|
||||
div.slider-root
|
||||
div.slider-button-area.left-button(
|
||||
v-if="scrollButtonsVisible()",
|
||||
@mousedown.left="shiftRight"
|
||||
)
|
||||
a.slider-button
|
||||
.svg-icon(v-html="icons.previous")
|
||||
div.slider-button-area.right-button(
|
||||
v-if="scrollButtonsVisible()",
|
||||
@mousedown.left="shiftLeft"
|
||||
)
|
||||
a.slider-button
|
||||
.svg-icon(v-html="icons.next")
|
||||
|
||||
// 120 = width of the left/right buttons
|
||||
div.sliding-content(v-resize="500", @resized="currentWidth = $event.width - 120")
|
||||
.items.items-one-line
|
||||
template(v-for="item in showItems")
|
||||
div.vertical-divider(
|
||||
v-if="shouldAddVerticalLine(item)"
|
||||
v-bind:style="dividerMargins"
|
||||
)
|
||||
|
||||
slot(
|
||||
name="item",
|
||||
:item="item",
|
||||
)
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
$buttonAreaWidth: 60;
|
||||
|
||||
.slider-root {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.slider-button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
position: absolute;
|
||||
top: calc((100% - 40px) / 2);
|
||||
|
||||
.svg-icon {
|
||||
color: #a5a1ac;
|
||||
margin: auto 0;
|
||||
position: absolute;
|
||||
top: calc((100% - 12px) / 2);
|
||||
width: 8px;
|
||||
height: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.scrollButtonsVisible {
|
||||
|
||||
.sliding-content {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.slider-button-area {
|
||||
width: $buttonAreaWidth+px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
|
||||
&.left-button {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&.right-button {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sliding-content .items {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 10px;
|
||||
margin-left: $buttonAreaWidth+ px;
|
||||
margin-right: $buttonAreaWidth+ px;
|
||||
}
|
||||
|
||||
.vertical-divider {
|
||||
height: 92px;
|
||||
width: 1px;
|
||||
background: #34313a;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import previous from 'assets/svg/previous.svg';
|
||||
import next from 'assets/svg/next.svg';
|
||||
import ResizeDirective from 'client/directives/resize.directive';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
resize: ResizeDirective,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
previous,
|
||||
next,
|
||||
}),
|
||||
currentWidth: 0,
|
||||
pointer: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
showItems () {
|
||||
let items = this.items;
|
||||
let pointer = this.pointer;
|
||||
let itemsPerPage = this.itemsPerPage();
|
||||
let firstSlice = items.slice(pointer, pointer + itemsPerPage);
|
||||
|
||||
if (firstSlice.length === itemsPerPage || items.length < itemsPerPage) {
|
||||
return firstSlice;
|
||||
} else {
|
||||
let getRemainderItems = itemsPerPage - firstSlice.length;
|
||||
let secondSlice = items.slice(0, getRemainderItems);
|
||||
|
||||
return firstSlice.concat(secondSlice);
|
||||
}
|
||||
},
|
||||
dividerMargins () {
|
||||
return {
|
||||
marginLeft: `${-this.itemMargin / 2}px`,
|
||||
marginRight: `${this.itemMargin / 2}px`,
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
itemType () {
|
||||
this.pointer = 0;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
shiftLeft () {
|
||||
if (this.pointer < this.items.length - 1) {
|
||||
this.pointer++;
|
||||
} else {
|
||||
this.pointer = 0;
|
||||
}
|
||||
},
|
||||
shiftRight () {
|
||||
if (this.pointer > 0) {
|
||||
this.pointer--;
|
||||
} else {
|
||||
this.pointer = this.items.length - 1;
|
||||
}
|
||||
},
|
||||
itemsPerPage () {
|
||||
return Math.floor(this.currentWidth / (this.itemWidth + this.itemMargin));
|
||||
},
|
||||
shouldAddVerticalLine (item) {
|
||||
return this.items[this.itemsPerPage() - 1] === item && this.pointer !== 5;
|
||||
},
|
||||
scrollButtonsVisible () {
|
||||
return this.items.length > this.itemsPerPage();
|
||||
},
|
||||
},
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
},
|
||||
itemType: {
|
||||
type: Number,
|
||||
},
|
||||
itemWidth: {
|
||||
type: Number,
|
||||
},
|
||||
itemMargin: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,45 @@
|
||||
<template lang="pug">
|
||||
span
|
||||
span.dropdown-label {{ label }}
|
||||
b-dropdown(right=true)
|
||||
span(slot="text", :class="{'dropdown-icon-item': withIcon}")
|
||||
slot(name="item", :item="selectedItem")
|
||||
|
||||
b-dropdown-item(
|
||||
v-for="item in items",
|
||||
@click="selectItem(item)",
|
||||
:active="selectedItem.id === item.id",
|
||||
:key="item.id"
|
||||
)
|
||||
span(:class="{'dropdown-icon-item': withIcon}")
|
||||
slot(name="item", :item="item")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
label: String,
|
||||
items: Array,
|
||||
initialItem: Object,
|
||||
withIcon: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
selectedItem: this.initialItem,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
selectItem (item) {
|
||||
this.selectedItem = item;
|
||||
this.$emit('selected', item);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,102 @@
|
||||
<template lang="pug">
|
||||
.item-rows
|
||||
div.items(v-resize="500", @resized="setCurrentWidth($event)")
|
||||
template(v-for="item in itemsToShow(showAll)")
|
||||
slot(
|
||||
name="item",
|
||||
:item="item"
|
||||
)
|
||||
|
||||
div(v-if="items.length === 0")
|
||||
p(v-once) {{ noItemsLabel }}
|
||||
|
||||
.btn.btn-flat.btn-show-more(
|
||||
@click="toggleItemsToShow()",
|
||||
v-if="items.length > itemsPerRow"
|
||||
) {{ showAll ? $t('showLess') : $t('showMore') }}
|
||||
|
||||
div.fill-height(v-else)
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.fill-height {
|
||||
height: 38px; // button + margin + padding
|
||||
}
|
||||
|
||||
.item-rows {
|
||||
margin-right: -24px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import ResizeDirective from 'client/directives/resize.directive';
|
||||
import openedItemRowsMixin from 'client/mixins/openedItemRows';
|
||||
|
||||
import _take from 'lodash/take';
|
||||
|
||||
export default {
|
||||
mixins: [openedItemRowsMixin],
|
||||
directives: {
|
||||
resize: ResizeDirective,
|
||||
},
|
||||
computed: {
|
||||
itemsPerRow () {
|
||||
return Math.floor(this.currentWidth / (this.itemWidth + this.itemMargin));
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
currentWidth: 0,
|
||||
currentPage: 0,
|
||||
|
||||
showAll: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
toggleItemsToShow () {
|
||||
this.showAll = !this.showAll;
|
||||
|
||||
this.$_openedItemRows_toggleByType(this.type, this.showAll);
|
||||
},
|
||||
itemsToShow (showAll) {
|
||||
let itemsLength = this.items.length;
|
||||
|
||||
if (itemsLength === 0)
|
||||
return [];
|
||||
|
||||
let itemsPerRow = this.itemsPerRow;
|
||||
|
||||
if (showAll || itemsLength <= itemsPerRow) {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
return _take(this.items, itemsPerRow);
|
||||
},
|
||||
setCurrentWidth ($event) {
|
||||
if (this.currentWidth !== $event.width) {
|
||||
this.currentWidth = $event.width;
|
||||
}
|
||||
},
|
||||
},
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
},
|
||||
itemWidth: {
|
||||
type: Number,
|
||||
},
|
||||
itemMargin: {
|
||||
type: Number,
|
||||
},
|
||||
noItemsLabel: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
created () {
|
||||
this.showAll = this.$_openedItemRows_isToggled(this.type);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,33 @@
|
||||
<template lang="pug">
|
||||
div
|
||||
.clearfix
|
||||
h2.float-left.mb-3.filters-title {{ title }}
|
||||
|
||||
.filters.float-right
|
||||
slot(name="filters")
|
||||
|
||||
br
|
||||
|
||||
slot(name="content")
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
title: String,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@media only screen and (max-width: 768px) {
|
||||
.filters, .filters-title {
|
||||
float: none;
|
||||
button {
|
||||
margin-right: 4em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,25 @@
|
||||
<template lang="pug">
|
||||
.row
|
||||
.standard-sidebar.d-none.d-sm-block(v-if="showSidebar")
|
||||
slot(name="sidebar")
|
||||
.standard-page
|
||||
slot(name="page")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
showSidebar: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
.standard-page {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,48 @@
|
||||
<template lang="pug">
|
||||
span.badge.badge-pill.badge-item.badge-star(
|
||||
:class="{'item-selected-badge': selected === true}",
|
||||
@click.stop="click",
|
||||
v-if="show",
|
||||
) ★
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.badge-star {
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
left: -9px;
|
||||
color: $gray-400;
|
||||
background: $white;
|
||||
padding: 4.5px 6px;
|
||||
|
||||
&.item-selected-badge {
|
||||
display: block;
|
||||
background: $teal-50;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.item:hover > .badge-star {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
},
|
||||
selected: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
click () {
|
||||
this.$emit('click');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,126 @@
|
||||
<template lang="pug">
|
||||
.progress-container(ref="container", :id="elementId", :class="{condensed}")
|
||||
.svg-icon(v-html="icon")
|
||||
.progress
|
||||
.progress-bar(:class="progressClass", :style="{width: `${percent(value, maxValue)}%`}")
|
||||
span.small-text {{value | statFloor}} / {{maxValue}}
|
||||
b-tooltip.myClass(:target="() => $refs.container", :container="elementId", :title="tooltip", triggers="hover", placement="bottom")
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.progress-container {
|
||||
margin-left: 4px;
|
||||
margin-bottom: .5em;
|
||||
height: 24px;
|
||||
|
||||
/deep/ .bs-tooltip-bottom {
|
||||
top: -16px !important
|
||||
}
|
||||
}
|
||||
|
||||
.progress-container > span {
|
||||
color: $header-color;
|
||||
margin-left: 8px;
|
||||
font-style: normal;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.progress-container > .svg-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.progress-container > .progress {
|
||||
min-width: 200px;
|
||||
margin: 0px;
|
||||
border-radius: 1px;
|
||||
height: 12px;
|
||||
background-color: $header-dark-background;
|
||||
}
|
||||
|
||||
.progress-container > .progress > .progress-bar {
|
||||
border-radius: 1px;
|
||||
height: 12px;
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
.progress-container .svg-icon, .progress-container .progress, .progress-container .small-text {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.progress-container.condensed {
|
||||
> .svg-icon {
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
> .progress {
|
||||
width: 152px;
|
||||
border-radius: 1px;
|
||||
height: 10px;
|
||||
margin-top: 2px;
|
||||
background: $purple-100;
|
||||
}
|
||||
|
||||
> .progress > .progress-bar {
|
||||
border-radius: 1px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import percent from '../../../common/script/libs/percent';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
},
|
||||
value: {
|
||||
type: Number,
|
||||
},
|
||||
maxValue: {
|
||||
type: Number,
|
||||
},
|
||||
tooltip: {
|
||||
type: String,
|
||||
},
|
||||
progressClass: {
|
||||
type: String,
|
||||
},
|
||||
condensed: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
elementId: null,
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
statFloor (value) {
|
||||
if (value < 1 && value > 0) {
|
||||
return Math.ceil(value * 10) / 10;
|
||||
} else {
|
||||
return Math.floor(value);
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
percent,
|
||||
click () {
|
||||
this.$emit('click');
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.elementId = `container_${this._uid}`;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,153 @@
|
||||
<template lang="pug">
|
||||
.popover-box
|
||||
.clearfix(:id="containerId")
|
||||
.float-left.toggle-switch-description(v-if="label", :class="hoverText ? 'hasPopOver' : ''") {{ label }}
|
||||
.toggle-switch.float-left
|
||||
input.toggle-switch-checkbox(
|
||||
type='checkbox', :id="toggleId",
|
||||
@change="handleChange",
|
||||
:checked="isChecked",
|
||||
:value="value",
|
||||
)
|
||||
label.toggle-switch-label(:for="toggleId")
|
||||
span.toggle-switch-inner
|
||||
span.toggle-switch-switch
|
||||
|
||||
b-popover(
|
||||
v-if="hoverText"
|
||||
:target="containerId"
|
||||
triggers="hover",
|
||||
placement="top"
|
||||
)
|
||||
.popover-content-text {{ hoverText }}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.toggle-switch {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
user-select: none;
|
||||
margin-left: 9px;
|
||||
}
|
||||
|
||||
.toggle-switch-description {
|
||||
height: 20px;
|
||||
|
||||
&.hasPopOver {
|
||||
border-bottom: 1px dashed $gray-200;
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-switch-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle-switch-label {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
border-radius: 100px;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.toggle-switch-inner {
|
||||
display: block;
|
||||
width: 200%;
|
||||
margin-left: -100%;
|
||||
transition: margin 0.3s ease-in 0s;
|
||||
}
|
||||
|
||||
.toggle-switch-inner:before, .toggle-switch-inner:after {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 50%;
|
||||
height: 16px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.toggle-switch-inner:before {
|
||||
content: "";
|
||||
padding-left: 10px;
|
||||
background-color: $purple-400;
|
||||
}
|
||||
|
||||
.toggle-switch-inner:after {
|
||||
content: "";
|
||||
padding-right: 10px;
|
||||
background-color: $gray-200;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.toggle-switch-switch {
|
||||
box-shadow: 0 1px 2px 0 rgba($black, 0.32);
|
||||
display: block;
|
||||
width: 20px;
|
||||
margin: -2px;
|
||||
margin-top: 1px;
|
||||
height: 20px;
|
||||
background: $white;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 22px;
|
||||
border-radius: 100px;
|
||||
transition: all 0.3s ease-in 0s;
|
||||
}
|
||||
|
||||
.toggle-switch-checkbox:checked + .toggle-switch-label .toggle-switch-inner {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.toggle-switch-checkbox:checked + .toggle-switch-label .toggle-switch-switch {
|
||||
right: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
// The toggle requires a unique id to link it to the label
|
||||
toggleId: this.generateId(),
|
||||
// The container requires a unique id to link it to the pop-over
|
||||
containerId: this.generateId(),
|
||||
};
|
||||
},
|
||||
model: {
|
||||
prop: 'checked',
|
||||
event: 'change',
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
default: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
},
|
||||
checked: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
hoverText: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isChecked () {
|
||||
return this.checked === this.value;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleChange ({ target: { checked } }) {
|
||||
this.$emit('change', checked);
|
||||
},
|
||||
generateId () {
|
||||
return `id-${Math.random().toString(36).substr(2, 16)}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user