inicios del FrontEnd

This commit is contained in:
2021-04-21 21:47:04 -05:00
parent 4a7fb24eb2
commit cf9505f26d
196 changed files with 28978 additions and 0 deletions

34
APP/components/Badge.vue Normal file
View File

@@ -0,0 +1,34 @@
<template>
<component :is="tag" class="badge" :class="`badge-${type}`">
<slot></slot>
</component>
</template>
<script>
export default {
name: 'badge',
props: {
tag: {
type: String,
default: 'span',
description: 'Badge tag'
},
type: {
type: String,
default: 'default',
validator: value => {
let acceptedValues = [
'primary',
'info',
'success',
'warning',
'danger',
'default'
];
return acceptedValues.indexOf(value) !== -1;
},
description: 'Badge type (primary|info|success|warning|danger|default)'
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,69 @@
<template>
<fade-transition>
<div
v-if="visible"
class="alert"
:class="[`alert-${type}`, { 'alert-with-icon': icon }]"
role="alert"
>
<slot v-if="!dismissible"></slot>
<template v-else>
<slot name="dismiss-icon">
<button
type="button"
class="close"
aria-label="Close"
@click="dismissAlert"
>
<i class="tim-icons icon-simple-remove"></i>
</button>
</slot>
<template v-if="icon || $slots.icon">
<slot name="icon">
<span data-notify="icon" :class="icon"></span>
</slot>
</template>
<span data-notify="message"> <slot></slot> </span>
</template>
</div>
</fade-transition>
</template>
<script>
import { FadeTransition } from 'vue2-transitions';
export default {
name: 'base-alert',
components: {
FadeTransition
},
props: {
type: {
type: String,
default: 'default',
description: 'Alert type'
},
dismissible: {
type: Boolean,
default: false,
description: 'Whether alert is dismissible (closeable)'
},
icon: {
type: String,
default: '',
description: 'Alert icon to display'
}
},
data() {
return {
visible: true
};
},
methods: {
dismissAlert() {
this.visible = false;
}
}
};
</script>

View File

@@ -0,0 +1,81 @@
<template>
<component
:is="tag"
:type="tag === 'button' ? nativeType : ''"
:disabled="disabled || loading"
@click="handleClick"
class="btn"
:class="[
{ 'btn-round': round },
{ 'btn-block': block },
{ 'btn-wd': wide },
{ 'btn-icon btn-fab': icon },
{ [`btn-${type}`]: type },
{ [`btn-${size}`]: size },
{ 'btn-simple': simple },
{ 'btn-link': link },
{ disabled: disabled && tag !== 'button' }
]"
>
<slot name="loading">
<i v-if="loading" class="fas fa-spinner fa-spin"></i>
</slot>
<slot></slot>
</component>
</template>
<script>
export default {
name: 'base-button',
props: {
tag: {
type: String,
default: 'button',
description: 'Button html tag'
},
round: Boolean,
icon: Boolean,
block: Boolean,
loading: Boolean,
wide: Boolean,
disabled: Boolean,
type: {
type: String,
default: 'default',
description: 'Button type (primary|secondary|danger etc)'
},
nativeType: {
type: String,
default: 'button',
description: 'Button native type (e.g button, input etc)'
},
size: {
type: String,
default: '',
description: 'Button size (sm|lg)'
},
simple: {
type: Boolean,
description: 'Whether button is simple (outlined)'
},
link: {
type: Boolean,
description: 'Whether button is a link (no borders or background)'
}
},
methods: {
handleClick(evt) {
this.$emit('click', evt);
}
}
};
</script>
<style scoped lang="scss">
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
/deep/ i {
padding: 0 3px;
}
}
</style>

View File

@@ -0,0 +1,97 @@
<template>
<component
:is="tag"
class="dropdown"
:class="[{ show: isOpen }, `drop${direction}`]"
@click="toggleDropDown"
v-click-outside="closeDropDown"
>
<slot name="title-container" :is-open="isOpen">
<component
:is="titleTag"
class="dropdown-toggle no-caret"
:class="titleClasses"
:aria-label="title || 'dropdown'"
:aria-expanded="isOpen"
data-toggle="dropdown"
>
<slot name="title" :is-open="isOpen">
<i :class="icon"></i> {{ title }}
</slot>
</component>
</slot>
<ul
class="dropdown-menu"
:class="[
{ show: isOpen },
{ 'dropdown-menu-right': menuOnRight },
menuClasses
]"
>
<slot></slot>
</ul>
</component>
</template>
<script>
export default {
name: 'base-dropdown',
props: {
tag: {
type: String,
default: 'div',
description: 'Dropdown html tag (e.g div, ul etc)'
},
titleTag: {
type: String,
default: 'button',
description: 'Dropdown title (toggle) html tag'
},
title: {
type: String,
description: 'Dropdown title'
},
direction: {
type: String,
default: 'down', // up | down
description: 'Dropdown menu direction (up|down)'
},
icon: {
type: String,
description: 'Dropdown icon'
},
titleClasses: {
type: [String, Object, Array],
description: 'Title css classes'
},
menuClasses: {
type: [String, Object],
description: 'Menu css classes'
},
menuOnRight: {
type: Boolean,
description: 'Whether menu should appear on the right'
}
},
data() {
return {
isOpen: false
};
},
methods: {
toggleDropDown() {
this.isOpen = !this.isOpen;
this.$emit('change', this.isOpen);
},
closeDropDown() {
this.isOpen = false;
this.$emit('change', false);
}
}
};
</script>
<style lang="scss" scoped>
.dropdown {
cursor: pointer;
user-select: none;
}
</style>

148
APP/components/BasePagination.vue Executable file
View File

@@ -0,0 +1,148 @@
<template>
<ul class="pagination" :class="paginationClass">
<li
class="page-item prev-page"
v-if="showArrows"
:class="{ disabled: value === 1 }"
>
<a class="page-link" aria-label="Previous" @click="prevPage">
<i class="tim-icons icon-double-left" aria-hidden="true"></i>
</a>
</li>
<li
class="page-item"
v-for="item in range(minPage, maxPage)"
:key="item"
:class="{ active: value === item }"
>
<a class="page-link" @click="changePage(item)">{{ item }}</a>
</li>
<li
v-if="showArrows"
class="page-item page-pre next-page"
:class="{ disabled: value === totalPages }"
>
<a class="page-link" aria-label="Next" @click="nextPage">
<i class="tim-icons icon-double-right" aria-hidden="true"></i>
</a>
</li>
</ul>
</template>
<script>
export default {
name: 'base-pagination',
props: {
type: {
type: String,
default: 'primary',
validator: value => {
return [
'default',
'primary',
'danger',
'success',
'warning',
'info'
].includes(value);
}
},
pageCount: {
type: Number,
default: 0
},
perPage: {
type: Number,
default: 10
},
showArrows: {
type: Boolean,
default: true
},
total: {
type: Number,
default: 0
},
value: {
type: Number,
default: 1
},
pagesToDisplay: {
type: Number,
default: 5
}
},
computed: {
paginationClass() {
return `pagination-${this.type}`;
},
totalPages() {
if (this.pageCount > 0) return this.pageCount;
if (this.total > 0) {
return Math.ceil(this.total / this.perPage);
}
return 1;
},
defaultPagesToDisplay() {
if (this.totalPages > 0 && this.totalPages < this.pagesToDisplay) {
return this.totalPages;
}
return this.pagesToDisplay;
},
minPage() {
if (this.value >= this.defaultPagesToDisplay) {
const pagesToAdd = Math.floor(this.defaultPagesToDisplay / 2);
const newMaxPage = pagesToAdd + this.value;
if (newMaxPage > this.totalPages) {
return this.totalPages - this.defaultPagesToDisplay + 1;
}
return this.value - pagesToAdd;
} else {
return 1;
}
},
maxPage() {
if (this.value >= this.defaultPagesToDisplay) {
const pagesToAdd = Math.floor(this.defaultPagesToDisplay / 2);
const newMaxPage = pagesToAdd + this.value;
if (newMaxPage < this.totalPages) {
return newMaxPage;
} else {
return this.totalPages;
}
} else {
return this.defaultPagesToDisplay;
}
}
},
methods: {
range(min, max) {
let arr = [];
for (let i = min; i <= max; i++) {
arr.push(i);
}
return arr;
},
changePage(item) {
this.$emit('input', item);
},
nextPage() {
if (this.value < this.totalPages) {
this.$emit('input', this.value + 1);
}
},
prevPage() {
if (this.value > 1) {
this.$emit('input', this.value - 1);
}
}
},
watch: {
perPage() {
this.$emit('input', 1);
},
total() {
this.$emit('input', 1);
}
}
};
</script>

79
APP/components/BaseProgress.vue Executable file
View File

@@ -0,0 +1,79 @@
<template>
<div
class="progress-container"
:class="{
[`progress-${type}`]: type,
[`progress-${size}`]: size
}"
>
<span class="progress-badge" v-if="label">{{ label }}</span>
<div class="progress">
<span class="progress-value" v-if="showValue && valuePosition === 'left'"
>{{ value }}%</span
>
<div
class="progress-bar"
:class="computedClasses"
role="progressbar"
:aria-valuenow="value"
aria-valuemin="0"
aria-valuemax="100"
:style="`width: ${value}%;`"
>
<slot>
<span
v-if="showValue && valuePosition === 'right'"
class="progress-value"
>{{ value }}%</span
>
</slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'base-progress',
props: {
striped: Boolean,
showValue: {
type: Boolean,
default: true
},
animated: Boolean,
label: String,
valuePosition: {
type: String,
default: 'left' // left | right
},
height: {
type: Number,
default: 1
},
type: {
type: String,
default: 'default'
},
size: {
type: String,
default: 'sm'
},
value: {
type: Number,
default: 0,
validator: value => {
return value >= 0 && value <= 100;
}
}
},
computed: {
computedClasses() {
return [
{ 'progress-bar-striped': this.striped },
{ 'progress-bar-animated': this.animated }
];
}
}
};
</script>
<style></style>

48
APP/components/BaseSwitch.vue Executable file
View File

@@ -0,0 +1,48 @@
<template>
<div
class="bootstrap-switch bootstrap-switch-wrapper bootstrap-switch-animate"
:class="switchClass"
>
<div class="bootstrap-switch-container" @click="triggerToggle()">
<span class="bootstrap-switch-handle-on ">
<slot name="on"> {{ onText }} </slot>
</span>
<span class="bootstrap-switch-label"></span>
<span class="bootstrap-switch-handle-off bootstrap-switch-default">
<slot name="off"> {{ offText }} </slot>
</span>
</div>
</div>
</template>
<script>
export default {
name: 'base-switch',
props: {
value: [Array, Boolean],
onText: String,
offText: String
},
computed: {
switchClass() {
let base = 'bootstrap-switch-';
let state = this.model ? 'on' : 'off';
let classes = base + state;
return classes;
},
model: {
get() {
return this.value;
},
set(value) {
this.$emit('input', value);
}
}
},
methods: {
triggerToggle() {
this.model = !this.model;
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,70 @@
<template>
<table class="table tablesorter" :class="tableClass">
<thead :class="theadClasses">
<tr>
<slot name="columns" :columns="columns">
<th v-for="column in columns" :key="column">{{ column }}</th>
</slot>
</tr>
</thead>
<tbody :class="tbodyClasses">
<tr v-for="(item, index) in data" :key="index">
<slot :row="item" :index="index">
<td
v-for="(column, index) in columns"
:key="index"
v-if="hasValue(item, column)"
>
{{ itemValue(item, column) }}
</td>
</slot>
</tr>
</tbody>
</table>
</template>
<script>
export default {
name: 'base-table',
props: {
columns: {
type: Array,
default: () => [],
description: 'Table columns'
},
data: {
type: Array,
default: () => [],
description: 'Table data'
},
type: {
type: String, // striped | hover
default: '',
description: 'Whether table is striped or hover type'
},
theadClasses: {
type: String,
default: '',
description: '<thead> css classes'
},
tbodyClasses: {
type: String,
default: '',
description: '<tbody> css classes'
}
},
computed: {
tableClass() {
return this.type && `table-${this.type}`;
}
},
methods: {
hasValue(item, column) {
return item[column.toLowerCase()] !== 'undefined';
},
itemValue(item, column) {
return item[column.toLowerCase()];
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,17 @@
<template>
<ul class="breadcrumb" :class="{ 'bg-transparent': transparent }">
<slot></slot>
</ul>
</template>
<script>
export default {
name: 'breadcrumb',
props: {
transparent: {
type: Boolean,
default: true
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,16 @@
<template>
<li class="breadcrumb-item" :class="{ active: active }"><slot></slot></li>
</template>
<script>
export default {
name: 'breadcrumb-item',
props: {
active: {
type: Boolean,
default: false,
description: 'Whether breadcrumb item is active'
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,48 @@
<template>
<bread-crumb>
<BreadCrumbItem
v-for="(route, index) in $route.matched.slice()"
:key="route.name"
style="display:inline-block"
>
<nuxt-link
:to="{ name: route.name }"
v-if="index < $route.matched.length - 1"
class="breadcrumb-link"
>
{{ routeName }}
</nuxt-link>
<span v-else class="breadcrumb-current">{{ routeName }}</span>
</BreadCrumbItem>
</bread-crumb>
</template>
<script>
import BreadCrumb from './Breadcrumb';
import BreadCrumbItem from './BreadcrumbItem';
export default {
name: 'route-breadcrumb',
components: {
BreadCrumb,
BreadCrumbItem
},
computed: {
routeName() {
const { path } = this.$route;
let parts = path.split('/')
return parts.map(p => this.capitalizeFirstLetter(p)).join(' ');
}
},
methods: {
capitalizeFirstLetter(string) {
if (!string || typeof string !== 'string') {
return ''
}
return string.charAt(0).toUpperCase() + string.slice(1);
}
}
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,62 @@
<template>
<div class="card" :class="[type && `card-${type}`]">
<div class="card-image" v-if="$slots.image"><slot name="image"></slot></div>
<div
class="card-header"
v-if="$slots.header || title"
:class="headerClasses"
>
<slot name="header">
<h4 class="card-title">{{ title }}</h4>
<p class="card-category" v-if="subTitle">{{ subTitle }}</p>
</slot>
</div>
<div class="card-body" v-if="$slots.default" :class="bodyClasses">
<slot></slot>
</div>
<div class="card-image" v-if="$slots['image-bottom']">
<slot name="image-bottom"></slot>
</div>
<slot name="raw-content"></slot>
<div class="card-footer" :class="footerClasses" v-if="$slots.footer">
<hr v-if="showFooterLine" />
<slot name="footer"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'card',
props: {
title: {
type: String,
description: 'Card title'
},
subTitle: {
type: String,
description: 'Card subtitle'
},
type: {
type: String,
description: 'Card type (e.g primary/danger etc)'
},
showFooterLine: {
type: Boolean,
default: false
},
headerClasses: {
type: [String, Object, Array],
description: 'Card header css classes'
},
bodyClasses: {
type: [String, Object, Array],
description: 'Card body css classes'
},
footerClasses: {
type: [String, Object, Array],
description: 'Card footer css classes'
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,63 @@
import { Bar, mixins } from 'vue-chartjs';
export default {
name: 'bar-chart',
extends: Bar,
mixins: [mixins.reactiveProp],
props: {
extraOptions: Object,
gradientColors: {
type: Array,
default: () => [
'rgba(72,72,176,0.2)',
'rgba(72,72,176,0.0)',
'rgba(119,52,169,0)'
],
validator: val => {
return val.length > 1;
}
},
gradientStops: {
type: Array,
default: () => [1, 0.4, 0],
validator: val => {
return val.length > 1;
}
}
},
data() {
return {
ctx: null
};
},
methods: {
updateGradients(chartData) {
if (!chartData) return;
const ctx =
this.ctx || document.getElementById(this.chartId).getContext('2d');
const gradientStroke = ctx.createLinearGradient(0, 230, 0, 50);
this.gradientStops.forEach((stop, index) => {
gradientStroke.addColorStop(stop, this.gradientColors[index]);
});
chartData.datasets.forEach(set => {
if (!set.backgroundColor) {
set.backgroundColor = gradientStroke;
}
});
}
},
mounted() {
this.$watch(
'chartData',
(newVal, oldVal) => {
this.updateGradients(newVal);
if (!oldVal) {
this.renderChart(this.chartData, this.extraOptions);
}
},
{ immediate: true }
);
}
};

View File

@@ -0,0 +1,62 @@
import { Line, mixins } from 'vue-chartjs';
export default {
name: 'line-chart',
extends: Line,
mixins: [mixins.reactiveProp],
props: {
extraOptions: Object,
gradientColors: {
type: Array,
default: () => [
'rgba(72,72,176,0.2)',
'rgba(72,72,176,0.0)',
'rgba(119,52,169,0)'
],
validator: val => {
return val.length > 1;
}
},
gradientStops: {
type: Array,
default: () => [1, 0.4, 0],
validator: val => {
return val.length > 1;
}
}
},
data() {
return {
ctx: null
};
},
methods: {
updateGradients(chartData) {
if (!chartData) return;
const ctx =
this.ctx || document.getElementById(this.chartId).getContext('2d');
const gradientStroke = ctx.createLinearGradient(0, 230, 0, 50);
this.gradientStops.forEach((stop, index) => {
gradientStroke.addColorStop(stop, this.gradientColors[index]);
});
chartData.datasets.forEach(set => {
if (!set.backgroundColor) {
set.backgroundColor = gradientStroke;
}
});
}
},
mounted() {
this.$watch(
'chartData',
(newVal, oldVal) => {
this.updateGradients(this.chartData);
if (!oldVal) {
this.renderChart(this.chartData, this.extraOptions);
}
},
{ immediate: true }
);
}
};

View File

@@ -0,0 +1,377 @@
export const basicOptions = {
maintainAspectRatio: false,
legend: {
display: false
},
responsive: true
};
export let blueChartOptions = {
...basicOptions,
tooltips: {
backgroundColor: '#f5f5f5',
titleFontColor: '#333',
bodyFontColor: '#666',
bodySpacing: 4,
xPadding: 12,
mode: 'nearest',
intersect: 0,
position: 'nearest'
},
scales: {
yAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.0)',
zeroLineColor: 'transparent'
},
ticks: {
suggestedMin: 60,
suggestedMax: 125,
padding: 20,
fontColor: '#2380f7'
}
}
],
xAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.1)',
zeroLineColor: 'transparent'
},
ticks: {
padding: 20,
fontColor: '#2380f7'
}
}
]
}
};
export let lineChartOptionsBlue = {
...basicOptions,
tooltips: {
backgroundColor: '#f5f5f5',
titleFontColor: '#333',
bodyFontColor: '#666',
bodySpacing: 4,
xPadding: 12,
mode: 'nearest',
intersect: 0,
position: 'nearest'
},
responsive: true,
scales: {
yAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.0)',
zeroLineColor: 'transparent'
},
ticks: {
suggestedMin: 60,
suggestedMax: 125,
padding: 20,
fontColor: '#9e9e9e'
}
}
],
xAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.1)',
zeroLineColor: 'transparent'
},
ticks: {
padding: 20,
fontColor: '#9e9e9e'
}
}
]
}
};
export let barChartOptionsGradient = {
...basicOptions,
tooltips: {
backgroundColor: '#f5f5f5',
titleFontColor: '#333',
bodyFontColor: '#666',
bodySpacing: 4,
xPadding: 12,
mode: 'nearest',
intersect: 0,
position: 'nearest'
},
responsive: true,
scales: {
yAxes: [
{
gridLines: {
drawBorder: false,
color: 'rgba(253,93,147,0.1)',
zeroLineColor: 'transparent'
},
ticks: {
suggestedMin: 60,
suggestedMax: 125,
padding: 20,
fontColor: '#9e9e9e'
}
}
],
xAxes: [
{
gridLines: {
drawBorder: false,
color: 'rgba(253,93,147,0.1)',
zeroLineColor: 'transparent'
},
ticks: {
padding: 20,
fontColor: '#9e9e9e'
}
}
]
}
};
export let pieChartOptions = {
...basicOptions,
cutoutPercentage: 70,
tooltips: {
backgroundColor: '#f5f5f5',
titleFontColor: '#333',
bodyFontColor: '#666',
bodySpacing: 4,
xPadding: 12,
mode: 'nearest',
intersect: 0,
position: 'nearest'
},
scales: {
yAxes: [
{
display: 0,
ticks: {
display: false
},
gridLines: {
drawBorder: false,
zeroLineColor: 'transparent',
color: 'rgba(255,255,255,0.05)'
}
}
],
xAxes: [
{
display: 0,
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: 'rgba(255,255,255,0.1)',
zeroLineColor: 'transparent'
},
ticks: {
display: false
}
}
]
}
};
export let purpleChartOptions = {
...basicOptions,
tooltips: {
backgroundColor: '#f5f5f5',
titleFontColor: '#333',
bodyFontColor: '#666',
bodySpacing: 4,
xPadding: 12,
mode: 'nearest',
intersect: 0,
position: 'nearest'
},
scales: {
yAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.0)',
zeroLineColor: 'transparent'
},
ticks: {
suggestedMin: 60,
suggestedMax: 125,
padding: 20,
fontColor: '#9a9a9a'
}
}
],
xAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: 'rgba(225,78,202,0.1)',
zeroLineColor: 'transparent'
},
ticks: {
padding: 20,
fontColor: '#9a9a9a'
}
}
]
}
};
export let orangeChartOptions = {
...basicOptions,
tooltips: {
backgroundColor: '#f5f5f5',
titleFontColor: '#333',
bodyFontColor: '#666',
bodySpacing: 4,
xPadding: 12,
mode: 'nearest',
intersect: 0,
position: 'nearest'
},
scales: {
yAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.0)',
zeroLineColor: 'transparent'
},
ticks: {
suggestedMin: 50,
suggestedMax: 110,
padding: 20,
fontColor: '#ff8a76'
}
}
],
xAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: 'rgba(220,53,69,0.1)',
zeroLineColor: 'transparent'
},
ticks: {
padding: 20,
fontColor: '#ff8a76'
}
}
]
}
};
export let greenChartOptions = {
...basicOptions,
tooltips: {
backgroundColor: '#f5f5f5',
titleFontColor: '#333',
bodyFontColor: '#666',
bodySpacing: 4,
xPadding: 12,
mode: 'nearest',
intersect: 0,
position: 'nearest'
},
scales: {
yAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.0)',
zeroLineColor: 'transparent'
},
ticks: {
suggestedMin: 50,
suggestedMax: 125,
padding: 20,
fontColor: '#9e9e9e'
}
}
],
xAxes: [
{
barPercentage: 1.6,
gridLines: {
drawBorder: false,
color: 'rgba(0,242,195,0.1)',
zeroLineColor: 'transparent'
},
ticks: {
padding: 20,
fontColor: '#9e9e9e'
}
}
]
}
};
export let barChartOptions = {
...basicOptions,
tooltips: {
backgroundColor: '#f5f5f5',
titleFontColor: '#333',
bodyFontColor: '#666',
bodySpacing: 4,
xPadding: 12,
mode: 'nearest',
intersect: 0,
position: 'nearest'
},
scales: {
yAxes: [
{
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.1)',
zeroLineColor: 'transparent'
},
ticks: {
suggestedMin: 60,
suggestedMax: 120,
padding: 20,
fontColor: '#9e9e9e'
}
}
],
xAxes: [
{
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.1)',
zeroLineColor: 'transparent'
},
ticks: {
padding: 20,
fontColor: '#9e9e9e'
}
}
]
}
};

View File

@@ -0,0 +1,11 @@
export function hexToRGB(hex, alpha) {
const r = parseInt(hex.slice(1, 3), 16),
g = parseInt(hex.slice(3, 5), 16),
b = parseInt(hex.slice(5, 7), 16);
if (alpha) {
return `rgba(${r},${g},${b}, ${alpha})`;
} else {
return `rgb(${r},${g},${b})`;
}
}

35
APP/components/CloseButton.vue Executable file
View File

@@ -0,0 +1,35 @@
<template>
<button
type="button"
class="navbar-toggler"
data-toggle="collapse"
@click="handleClick"
:data-target="`#${target}`"
:aria-controls="target"
:aria-expanded="expanded"
aria-label="Toggle navigation"
>
<span></span> <span></span>
</button>
</template>
<script>
export default {
name: 'close-button',
props: {
target: {
type: [String, Number],
description: 'Close button target element'
},
expanded: {
type: Boolean,
description: 'Whether button is expanded (aria-expanded attribute)'
}
},
methods: {
handleClick(evt) {
this.$emit('click', evt);
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,72 @@
<template>
<base-table :data="tableData" thead-classes="text-primary">
<template slot-scope="{ row }">
<td><base-checkbox v-model="row.done"></base-checkbox></td>
<td>
<p class="title">{{ row.title }}</p>
<p class="text-muted">{{ row.description }}</p>
</td>
<td class="td-actions text-right">
<el-tooltip
content="Edit task"
effect="light"
:open-delay="300"
placement="top"
>
<base-button type="link">
<i class="tim-icons icon-pencil"></i>
</base-button>
</el-tooltip>
</td>
</template>
</base-table>
</template>
<script>
import { BaseTable } from '@/components';
export default {
components: {
BaseTable
},
data() {
return {
tableData: [
{
title: 'Update the Documentation',
description: 'Dwuamish Head, Seattle, WA 8:47 AM',
done: false
},
{
title: 'GDPR Compliance',
description:
'The GDPR is a regulation that requires businesses to protect the personal data and privacy of Europe citizens for transactions that occur within EU member states.',
done: true
},
{
title: 'Solve the issues',
description:
'Fifty percent of all respondents said they would be more likely to shop at a company',
done: false
},
{
title: 'Release v2.0.0',
description: 'Ra Ave SW, Seattle, WA 98116, SUA 11:19 AM',
done: false
},
{
title: 'Export the processed files',
description:
'The report also shows that consumers will not easily forgive a company once a breach exposing their personal data occurs.',
done: false
},
{
title: 'Arival at export process',
description: 'Capitol Hill, Seattle, WA 12:34 AM',
done: false
}
]
};
}
};
</script>
<style></style>

View File

@@ -0,0 +1,119 @@
<template>
<base-table :data="table" thead-classes="text-primary">
<template slot="columns" slot-scope="{ columns }">
<th>#</th>
<th>Name</th>
<th>Job Position</th>
<th>Salary</th>
<th class="text-right">Milestone</th>
<th class="text-right">Actions</th>
</template>
<template slot-scope="{ row, index }">
<td class="text-center">
<div class="photo"><img :src="row.img" alt="photo" /></div>
</td>
<td>{{ row.name }}</td>
<td>{{ row.job }}</td>
<td class="text-center"><base-progress :value="row.progress" /></td>
<td class="text-right"> 99,225</td>
<td class="text-right">
<el-tooltip
content="Refresh"
effect="light"
:open-delay="300"
placement="top"
>
<base-button
:type="index > 2 ? 'success' : 'neutral'"
icon
size="sm"
class="btn-link"
>
<i class="tim-icons icon-refresh-01"></i>
</base-button>
</el-tooltip>
<el-tooltip
content="Delete"
effect="light"
:open-delay="300"
placement="top"
>
<base-button
:type="index > 2 ? 'danger' : 'neutral'"
icon
size="sm"
class="btn-link"
>
<i class="tim-icons icon-simple-remove"></i>
</base-button>
</el-tooltip>
</td>
</template>
</base-table>
</template>
<script>
import { BaseTable, BaseProgress } from '@/components';
export default {
components: {
BaseTable,
BaseProgress
},
data() {
return {
table: [
{
id: 1,
img: 'img/tania.jpg',
name: 'Tania Mike',
job: 'Develop',
progress: 25,
salary: '€ 99,225'
},
{
id: 2,
img: 'img/robi.jpg',
name: 'John Doe',
job: 'CEO',
progress: 77,
salary: '€ 89,241'
},
{
id: 3,
img: 'img/lora.jpg',
name: 'Alexa Mike',
job: 'Design',
progress: 41,
salary: '€ 92,144'
},
{
id: 4,
img: 'img/jana.jpg',
name: 'Jana Monday',
job: 'Marketing',
progress: 50,
salary: '€ 49,990'
},
{
id: 5,
img: 'img/mike.jpg',
name: 'Paul Dickens',
job: 'Develop',
progress: 100,
salary: '€ 69,201'
},
{
id: 6,
img: 'img/emilyz.jpg',
name: 'Manuela Rico',
job: 'Manager',
progress: 15,
salary: '€ 99,201'
}
]
};
}
};
</script>
<style></style>

View File

@@ -0,0 +1,58 @@
<template>
<div class="form-check" :class="[{ disabled: disabled }, inlineClass]">
<label :for="cbId" class="form-check-label">
<input
:id="cbId"
class="form-check-input"
type="checkbox"
:disabled="disabled"
v-model="model"
/>
<span class="form-check-sign"></span>
<slot> <span v-if="inline">&nbsp;</span> </slot>
</label>
</div>
</template>
<script>
export default {
name: 'base-checkbox',
model: {
prop: 'checked'
},
props: {
checked: [Array, Boolean],
disabled: Boolean,
inline: Boolean,
hasError: Boolean
},
data() {
return {
cbId: '',
touched: false
};
},
computed: {
model: {
get() {
return this.checked;
},
set(check) {
if (!this.touched) {
this.touched = true;
}
this.$emit('input', check);
}
},
inlineClass() {
if (this.inline) {
return `form-check-inline`;
}
}
},
mounted() {
this.cbId = Math.random()
.toString(16)
.slice(2);
}
};
</script>

View File

@@ -0,0 +1,126 @@
<template>
<div
class="form-group"
:class="{
'input-group-focus': focused,
'has-danger': error,
'has-success': !error && touched,
'has-label': label,
'has-icon': hasIcon,
}"
>
<slot name="label">
<label v-if="label"> {{ label }} {{ required ? '*' : '' }} </label>
</slot>
<div class="mb-0" :class="{'input-group': hasIcon}">
<slot name="addonLeft">
<span v-if="addonLeftIcon" class="input-group-prepend">
<div class="input-group-text"><i :class="addonLeftIcon"></i></div>
</span>
</slot>
<slot>
<input
:value="value"
v-bind="$attrs"
v-on="listeners"
class="form-control"
aria-describedby="addon-right addon-left"
/>
</slot>
<slot name="addonRight">
<span v-if="addonRightIcon" class="input-group-append">
<div class="input-group-text"><i :class="addonRightIcon"></i></div>
</span>
</slot>
</div>
<slot name="error" v-if="error || $slots.error">
<label class="error">{{ error }}</label>
</slot>
<slot name="helperText"></slot>
</div>
</template>
<script>
export default {
inheritAttrs: false,
name: 'base-input',
props: {
required: Boolean,
label: {
type: String,
description: 'Input label'
},
error: {
type: String,
description: 'Input error',
default: ''
},
value: {
type: [String, Number],
description: 'Input value'
},
addonRightIcon: {
type: String,
description: 'Input icon on the right'
},
addonLeftIcon: {
type: String,
description: 'Input icon on the left'
}
},
model: {
prop: 'value',
event: 'input'
},
data() {
return {
focused: false,
touched: false
};
},
computed: {
hasIcon() {
return this.hasLeftAddon || this.hasRightAddon
},
hasLeftAddon() {
const { addonLeft } = this.$slots;
return (
addonLeft !== undefined ||
this.addonLeftIcon !== undefined
);
},
hasRightAddon() {
const { addonRight } = this.$slots;
return (
addonRight !== undefined ||
this.addonRightIcon !== undefined
);
},
listeners() {
return {
...this.$listeners,
input: this.onInput,
blur: this.onBlur,
focus: this.onFocus
};
}
},
methods: {
onInput(evt) {
if (!this.touched) {
this.touched = true;
}
this.$emit('input', evt.target.value);
},
onFocus(evt) {
this.focused = true;
this.$emit('focus', evt)
},
onBlur(evt) {
this.focused = false;
this.$emit('blur', evt)
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,67 @@
<template>
<div
class="form-check form-check-radio"
:class="[inlineClass, { disabled: disabled }]"
>
<label :for="cbId" class="form-check-label">
<input
:id="cbId"
class="form-check-input"
type="radio"
:disabled="disabled"
:value="name"
v-model="model"
/>
<slot></slot> <span class="form-check-sign"></span>
</label>
</div>
</template>
<script>
export default {
name: 'base-radio',
props: {
name: {
type: [String, Number],
description: 'Radio label'
},
disabled: {
type: Boolean,
description: 'Whether radio is disabled'
},
value: {
type: [String, Boolean],
description: 'Radio value'
},
inline: {
type: Boolean,
description: 'Whether radio is inline'
}
},
data() {
return {
cbId: ''
};
},
computed: {
model: {
get() {
return this.value;
},
set(value) {
this.$emit('input', value);
}
},
inlineClass() {
if (this.inline) {
return `form-check-inline`;
}
return '';
}
},
mounted() {
this.cbId = Math.random()
.toString(16)
.slice(2);
}
};
</script>

View File

@@ -0,0 +1,45 @@
<template>
<div
class="choice"
:class="{ active: checked }"
data-toggle="wizard-checkbox"
@click="updateValue"
>
<input
type="checkbox"
:name="name"
:disabled="disabled"
:checked="checked"
/>
<div class="icon">
<slot name="icon"> <i :class="icon"></i> </slot>
</div>
<slot name="title">
<h6>{{ title }}</h6>
</slot>
</div>
</template>
<script>
export default {
name: 'icon-checkbox',
model: {
prop: 'checked'
},
props: {
checked: {
type: Boolean,
default: false
},
name: String,
title: String,
icon: String,
disabled: Boolean
},
methods: {
updateValue() {
this.$emit('input', !this.checked);
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,17 @@
<template>
<div class="content">
<FadeTransition :duration="200" mode="out-in">
<!-- your content here -->
<nuxt></nuxt>
</FadeTransition>
</div>
</template>
<script>
import { FadeTransition } from 'vue2-transitions';
export default {
components: {
FadeTransition
}
};
</script>
<style></style>

View File

@@ -0,0 +1,40 @@
<template>
<footer class="footer">
<div class="container-fluid">
<ul class="nav">
<li class="nav-item">
<a
href="#"
target="_blank"
rel="noopener"
class="nav-link"
>
Blog
</a>
</li>
</ul>
<div class="copyright">
&copy; {{ year }}, hecho con <i class="tim-icons icon-heart-2"></i> por
<a
href="#"
target="_blank"
rel="noopener"
>mdchaparror</a
>
</div>
</div>
</footer>
</template>
<script>
export default {
data() {
return {
year: new Date().getFullYear()
};
}
};
</script>
<style></style>

View File

@@ -0,0 +1,293 @@
<template>
<div class="wrapper" :class="{ 'nav-open': $sidebar.showSidebar }">
<notifications></notifications>
<side-bar
:background-color="sidebarBackground"
:short-title="$t('sidebar.shortTitle')"
:title="$t('sidebar.title')"
>
<template slot-scope="props" slot="links">
<sidebar-item
:link="{
name: $t('sidebar.dashboard'),
icon: 'tim-icons icon-chart-pie-36',
path: '/dashboard'
}"
>
</sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.pages'), icon: 'tim-icons icon-image-02' }"
>
<sidebar-item
:link="{ name: $t('sidebar.pricing'), path: '/pricing' }"
></sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.rtl'), path: '/pages/rtl' }"
></sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.timeline'), path: '/pages/timeline' }"
></sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.login'), path: '/login' }"
></sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.register'), path: '/register' }"
></sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.lock'), path: '/lock' }"
></sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.userProfile'), path: '/pages/user' }"
></sidebar-item>
</sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.components'),
icon: 'tim-icons icon-molecule-40'
}"
>
<sidebar-item :link="{ name: $t('sidebar.multiLevelCollapse') }">
<sidebar-item
:link="{
name: $t('sidebar.example'),
isRoute: false,
path: 'https://google.com',
target: '_blank'
}"
></sidebar-item>
</sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.buttons'), path: '/components/buttons' }"
></sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.gridSystem'),
path: '/components/grid-system'
}"
></sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.panels'), path: '/components/panels' }"
></sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.sweetAlert'),
path: '/components/sweet-alert'
}"
></sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.notifications'),
path: '/components/notifications'
}"
></sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.icons'), path: '/components/icons' }"
></sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.typography'),
path: '/components/typography'
}"
></sidebar-item>
</sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.forms'), icon: 'tim-icons icon-notes' }"
>
<sidebar-item
:link="{ name: $t('sidebar.regularForms'), path: '/forms/regular' }"
></sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.extendedForms'),
path: '/forms/extended'
}"
></sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.validationForms'),
path: '/forms/validation'
}"
></sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.wizard'), path: '/forms/wizard' }"
></sidebar-item>
</sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.tables'),
icon: 'tim-icons icon-puzzle-10'
}"
>
<sidebar-item
:link="{
name: $t('sidebar.regularTables'),
path: '/table-list/regular'
}"
></sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.extendedTables'),
path: '/table-list/extended'
}"
></sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.paginatedTables'),
path: '/table-list/paginated'
}"
></sidebar-item>
</sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.maps'), icon: 'tim-icons icon-pin' }"
>
<sidebar-item
:link="{ name: $t('sidebar.googleMaps'), path: '/maps/google' }"
></sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.fullScreenMaps'),
path: '/maps/full-screen'
}"
></sidebar-item>
<sidebar-item
:link="{ name: $t('sidebar.vectorMaps'), path: '/maps/vector-map' }"
></sidebar-item>
</sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.widgets'),
icon: 'tim-icons icon-settings',
path: '/widgets'
}"
></sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.charts'),
icon: 'tim-icons icon-chart-bar-32',
path: '/charts'
}"
></sidebar-item>
<sidebar-item
:link="{
name: $t('sidebar.calendar'),
icon: 'tim-icons icon-time-alarm',
path: '/calendar'
}"
></sidebar-item>
</template>
</side-bar>
<!--Share plugin (for demo purposes). You can remove it if don't plan on using it-->
<sidebar-share :background-color.sync="sidebarBackground"> </sidebar-share>
<div class="main-panel" :data="sidebarBackground">
<dashboard-navbar></dashboard-navbar>
<router-view name="header"></router-view>
<div
:class="{ content: !$route.meta.hideContent }"
@click="toggleSidebar"
>
<zoom-center-transition :duration="200" mode="out-in">
<!-- your content here -->
<nuxt></nuxt>
</zoom-center-transition>
</div>
<content-footer v-if="!$route.meta.hideFooter"></content-footer>
</div>
</div>
</template>
<script>
/* eslint-disable no-new */
import PerfectScrollbar from 'perfect-scrollbar';
import 'perfect-scrollbar/css/perfect-scrollbar.css';
import SidebarShare from './SidebarSharePlugin';
function hasElement(className) {
return document.getElementsByClassName(className).length > 0;
}
function initScrollbar(className) {
if (hasElement(className)) {
new PerfectScrollbar(`.${className}`);
} else {
// try to init it later in case this component is loaded async
setTimeout(() => {
initScrollbar(className);
}, 100);
}
}
import DashboardNavbar from './DashboardNavbar.vue';
import ContentFooter from './ContentFooter.vue';
import DashboardContent from './Content.vue';
import { SlideYDownTransition, ZoomCenterTransition } from 'vue2-transitions';
export default {
components: {
DashboardNavbar,
ContentFooter,
DashboardContent,
SlideYDownTransition,
ZoomCenterTransition,
SidebarShare
},
data() {
return {
sidebarBackground: 'vue' //vue|blue|orange|green|red|primary
};
},
methods: {
toggleSidebar() {
if (this.$sidebar.showSidebar) {
this.$sidebar.displaySidebar(false);
}
},
initScrollbar() {
let docClasses = document.body.classList;
let isWindows = navigator.platform.startsWith('Win');
if (isWindows) {
// if we are on windows OS we activate the perfectScrollbar function
initScrollbar('sidebar');
initScrollbar('main-panel');
initScrollbar('sidebar-wrapper');
docClasses.add('perfect-scrollbar-on');
} else {
docClasses.add('perfect-scrollbar-off');
}
}
},
mounted() {
this.initScrollbar();
}
};
</script>
<style lang="scss">
$scaleSize: 0.95;
@keyframes zoomIn95 {
from {
opacity: 0;
transform: scale3d($scaleSize, $scaleSize, $scaleSize);
}
to {
opacity: 1;
}
}
.main-panel .zoomIn {
animation-name: zoomIn95;
}
@keyframes zoomOut95 {
from {
opacity: 1;
}
to {
opacity: 0;
transform: scale3d($scaleSize, $scaleSize, $scaleSize);
}
}
.main-panel .zoomOut {
animation-name: zoomOut95;
}
</style>

View File

@@ -0,0 +1,133 @@
<template>
<base-nav
v-model="showMenu"
class="navbar-absolute top-navbar"
type="white"
:transparent="true"
>
<div slot="brand" class="navbar-wrapper">
<div
class="navbar-toggle d-inline"
:class="{ toggled: $sidebar.showSidebar }"
>
<button type="button" class="navbar-toggler" @click="toggleSidebar">
<span class="navbar-toggler-bar bar1"></span>
<span class="navbar-toggler-bar bar2"></span>
<span class="navbar-toggler-bar bar3"></span>
</button>
</div>
<a class="navbar-brand ml-xl-3 ml-5" href="#pablo">{{ routeName }}</a>
</div>
<ul class="navbar-nav" :class="$rtl.isRTL ? 'mr-auto' : 'ml-auto'">
<div class="search-bar input-group" @click="searchModalVisible = true">
<button
class="btn btn-link"
id="search-button"
data-toggle="modal"
data-target="#searchModal"
>
<i class="tim-icons icon-zoom-split"></i>
</button>
<!-- You can choose types of search input -->
</div>
<modal
:show.sync="searchModalVisible"
class="modal-search"
id="searchModal"
:centered="false"
:show-close="true"
>
<input
slot="header"
v-model="searchQuery"
type="text"
class="form-control"
id="inlineFormInputGroup"
placeholder="SEARCH"
/>
</modal>
<base-dropdown
tag="li"
:menu-on-right="!$rtl.isRTL"
title-tag="a"
title-classes="nav-link"
class="nav-item"
>
<template
slot="title"
>
<div class="photo"><img src="img/mdchaparror.png" /></div>
<b class="caret d-none d-lg-block d-xl-block"></b>
<p class="d-lg-none">Log out</p>
</template>
<li class="nav-link">
<a href="#" class="nav-item dropdown-item">Profile</a>
</li>
<li class="nav-link">
<a href="#" class="nav-item dropdown-item">Settings</a>
</li>
<div class="dropdown-divider"></div>
<li class="nav-link">
<a href="#" class="nav-item dropdown-item">Log out</a>
</li>
</base-dropdown>
</ul>
</base-nav>
</template>
<script>
import { CollapseTransition } from 'vue2-transitions';
import { BaseNav, Modal } from '@/components';
export default {
components: {
CollapseTransition,
BaseNav,
Modal
},
computed: {
routeName() {
const { path } = this.$route;
let parts = path.split('/')
if(parts == ','){
return 'Dashboard';
}
return parts.map(p => this.capitalizeFirstLetter(p)).join(' ');
},
isRTL() {
return this.$rtl.isRTL;
}
},
data() {
return {
activeNotifications: false,
showMenu: false,
searchModalVisible: false,
searchQuery: ''
};
},
methods: {
capitalizeFirstLetter(string) {
if (!string || typeof string !== 'string') {
return ''
}
return string.charAt(0).toUpperCase() + string.slice(1);
},
closeDropDown() {
this.activeNotifications = false;
},
toggleSidebar() {
this.$sidebar.displaySidebar(!this.$sidebar.showSidebar);
},
toggleMenu() {
this.showMenu = !this.showMenu;
}
}
};
</script>
<style scoped>
.top-navbar {
top: 0px;
}
</style>

View File

@@ -0,0 +1,25 @@
<template>
<div class="row" v-loading="true" id="loading"></div>
</template>
<script>
import Vue from 'vue';
import { Loading } from 'element-ui';
Vue.use(Loading.directive);
export default {};
</script>
<style>
#loading {
min-height: 200px;
display: flex;
align-items: center;
}
.el-loading-spinner .path {
stroke: #66615b !important;
}
.el-loading-mask {
background: transparent !important;
}
</style>

View File

@@ -0,0 +1,106 @@
<template>
<div class="fixed-plugin" v-click-outside="closeDropDown">
<div class="dropdown show-dropdown" :class="{ show: isOpen }">
<a data-toggle="dropdown" class="settings-icon">
<i class="fa fa-cog fa-2x" @click="toggleDropDown"> </i>
</a>
<ul class="dropdown-menu" :class="{ show: isOpen }">
<li class="header-title">Sidebar Background</li>
<li class="adjustments-line">
<a class="switch-trigger background-color">
<div class="badge-colors text-center">
<span
v-for="item in sidebarColors"
:key="item.color"
class="badge filter"
:class="[`badge-${item.color}`, { active: item.active }]"
:data-color="item.color"
@click="changeSidebarBackground(item);"
></span>
</div>
<div class="clearfix"></div>
</a>
</li>
<li class="header-title">Sidebar Mini</li>
<li class="adjustments-line">
<div class="togglebutton switch-change-color mt-3">
<span class="label-switch">LIGHT MODE</span>
<base-switch v-model="darkMode" @input="toggleMode"></base-switch>
<span class="label-switch label-right">DARK MODE</span>
</div>
</li>
<li>
</li>
</ul>
</div>
</div>
</template>
<script>
import { BaseSwitch } from '@/components';
export default {
name: 'sidebar-share',
components: {
BaseSwitch
},
props: {
backgroundColor: String
},
data() {
return {
sidebarMini: true,
darkMode: false,
isOpen: false,
sidebarColors: [
{ color: 'primary', active: false, value: 'primary' },
{ color: 'vue', active: true, value: 'vue' },
{ color: 'info', active: false, value: 'blue' },
{ color: 'success', active: false, value: 'green' }
]
};
},
methods: {
toggleDropDown() {
this.isOpen = !this.isOpen;
},
closeDropDown() {
this.isOpen = false;
},
toggleList(list, itemToActivate) {
list.forEach(listItem => {
listItem.active = false;
});
itemToActivate.active = true;
},
changeSidebarBackground(item) {
this.$emit('update:backgroundColor', item.value);
this.toggleList(this.sidebarColors, item);
},
toggleMode(type) {
let docClasses = document.body.classList;
if (type) {
docClasses.remove('white-content');
} else {
docClasses.add('white-content');
}
},
minimizeSidebar() {
this.$sidebar.toggleMinimize();
}
}
};
</script>
<style scoped lang="scss">
@import '~@/assets/sass/dashboard/custom/variables';
.settings-icon {
cursor: pointer;
}
.badge-vue {
background-color: $vue;
}
</style>

View File

@@ -0,0 +1,49 @@
<template>
<footer class="footer">
<div class="container-fluid">
<ul class="nav">
<li class="nav-item">
<a
href="https://example.com"
target="_blank"
rel="noopener"
class="nav-link"
>
Link
</a>
</li>
<li class="nav-item">
<a
href="https://example.com"
target="_blank"
rel="noopener"
class="nav-link"
>
Another Link
</a>
</li>
</ul>
<div class="copyright">
&copy; {{ year }}, made with <i class="tim-icons icon-heart-2"></i> by
<a
href="https://www.creative-tim.com/?ref=pdf-vuejs"
target="_blank"
rel="noopener"
>Creative Tim</a
>
for a better web.
</div>
</div>
</footer>
</template>
<script>
export default {
data() {
return {
year: new Date().getFullYear()
};
}
};
</script>
<style></style>

View File

@@ -0,0 +1,137 @@
<template>
<base-nav
v-model="showMenu"
class="navbar-absolute top-navbar"
type="white"
:transparent="true"
>
<div slot="brand" class="navbar-wrapper">
<div
class="navbar-toggle d-inline"
:class="{ toggled: $sidebar.showSidebar }"
>
<button type="button" class="navbar-toggler" @click="toggleSidebar">
<span class="navbar-toggler-bar bar1"></span>
<span class="navbar-toggler-bar bar2"></span>
<span class="navbar-toggler-bar bar3"></span>
</button>
</div>
<a class="navbar-brand" href="#pablo">{{ routeName }}</a>
</div>
<ul class="navbar-nav" :class="$rtl.isRTL ? 'mr-auto' : 'ml-auto'">
<div class="search-bar input-group" @click="searchModalVisible = true">
<!--
<input type="text" class="form-control" placeholder="Search...">
<div class="input-group-addon"><i class="tim-icons icon-zoom-split"></i></div>
-->
<button
class="btn btn-link"
id="search-button"
data-toggle="modal"
data-target="#searchModal"
>
<i class="tim-icons icon-zoom-split"></i>
</button>
<!-- You can choose types of search input -->
</div>
<modal
:show.sync="searchModalVisible"
class="modal-search"
id="searchModal"
:centered="false"
:show-close="true"
>
<input
slot="header"
v-model="searchQuery"
type="text"
class="form-control"
id="inlineFormInputGroup"
placeholder="SEARCH"
/>
</modal>
<base-dropdown
tag="li"
:menu-on-right="!$rtl.isRTL"
title-tag="a"
class="nav-item"
title-classes="nav-link"
menu-classes="dropdown-navbar"
>
<template
slot="title"
>
<div class="photo"><img src="img/mike.jpg" /></div>
<b class="caret d-none d-lg-block d-xl-block"></b>
<p class="d-lg-none">Log out</p>
</template>
<li class="nav-link">
<a href="#" class="nav-item dropdown-item">Profile</a>
</li>
<li class="nav-link">
<a href="#" class="nav-item dropdown-item">Settings</a>
</li>
<div class="dropdown-divider"></div>
<li class="nav-link">
<a href="#" class="nav-item dropdown-item">Log out</a>
</li>
</base-dropdown>
</ul>
</base-nav>
</template>
<script>
import { CollapseTransition } from 'vue2-transitions';
import { BaseNav, Modal } from '@/components';
export default {
components: {
CollapseTransition,
BaseNav,
Modal
},
computed: {
routeName() {
const { path } = this.$route;
let parts = path.split('/')
return parts.map(p => this.capitalizeFirstLetter(p)).join(' ');
},
isRTL() {
return this.$rtl.isRTL;
}
},
data() {
return {
activeNotifications: false,
showMenu: false,
searchModalVisible: false,
searchQuery: ''
};
},
methods: {
capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
},
toggleNotificationDropDown() {
this.activeNotifications = !this.activeNotifications;
},
closeDropDown() {
this.activeNotifications = false;
},
toggleSidebar() {
this.$sidebar.displaySidebar(!this.$sidebar.showSidebar);
},
hideSidebar() {
this.$sidebar.displaySidebar(false);
},
toggleMenu() {
this.showMenu = !this.showMenu;
}
}
};
</script>
<style scoped>
.top-navbar {
top: 0px;
}
</style>

25
APP/components/LoadingPanel.vue Executable file
View File

@@ -0,0 +1,25 @@
<template>
<div class="row" v-loading="true" id="loading"></div>
</template>
<script>
import Vue from 'vue';
import { Loading } from 'element-ui';
Vue.use(Loading.directive);
export default {};
</script>
<style>
#loading {
min-height: 200px;
display: flex;
align-items: center;
}
.el-loading-spinner .path {
stroke: #66615b !important;
}
.el-loading-mask {
background: transparent !important;
}
</style>

170
APP/components/Modal.vue Normal file
View File

@@ -0,0 +1,170 @@
<template>
<SlideYUpTransition :duration="animationDuration">
<div
ref="modal"
class="modal fade"
@click.self="closeModal"
:class="[
{ 'show d-block': show },
{ 'd-none': !show },
{ 'modal-mini': type === 'mini' }
]"
v-show="show"
tabindex="-1"
role="dialog"
:aria-hidden="!show"
>
<div
class="modal-dialog"
role="document"
:class="[
{ 'modal-notice': type === 'notice' },
{ 'modal-dialog-centered': centered },
modalClasses
]"
>
<div
class="modal-content"
:class="[
gradient ? `bg-gradient-${gradient}` : '',
modalContentClasses
]"
>
<div
class="modal-header"
:class="[headerClasses]"
v-if="$slots.header"
>
<slot name="header"></slot>
<slot name="close-button">
<button
type="button"
class="close"
v-if="showClose"
@click="closeModal"
data-dismiss="modal"
aria-label="Close"
>
<i class="tim-icons icon-simple-remove"></i>
</button>
</slot>
</div>
<div v-if="$slots.default" class="modal-body" :class="bodyClasses">
<slot></slot>
</div>
<div class="modal-footer" :class="footerClasses" v-if="$slots.footer">
<slot name="footer"></slot>
</div>
</div>
</div>
</div>
</SlideYUpTransition>
</template>
<script>
import { SlideYUpTransition } from 'vue2-transitions';
export default {
name: 'modal',
components: {
SlideYUpTransition
},
props: {
show: Boolean,
showClose: {
type: Boolean,
default: true
},
centered: {
type: Boolean,
default: false
},
appendToBody: {
type: Boolean,
default: true,
description: 'Whether modal should be appended to document body'
},
scrollToBottom: {
type: Boolean,
default: true,
description: "Whether modal should scroll to it's bottom automatically"
},
type: {
type: String,
default: '',
validator(value) {
let acceptedValues = ['', 'notice', 'mini'];
return acceptedValues.indexOf(value) !== -1;
},
description: 'Modal type (notice|mini|"") '
},
modalClasses: {
type: [Object, String],
description: 'Modal dialog css classes'
},
modalContentClasses: {
type: [Object, String],
description: 'Modal dialog content css classes'
},
gradient: {
type: String,
description: 'Modal gradient type (danger, primary etc)'
},
headerClasses: {
type: [Object, String],
description: 'Modal Header css classes'
},
bodyClasses: {
type: [Object, String],
description: 'Modal Body css classes'
},
footerClasses: {
type: [Object, String],
description: 'Modal Footer css classes'
},
animationDuration: {
type: Number,
default: 500,
description: 'Modal transition duration'
}
},
methods: {
closeModal() {
this.$emit('update:show', false);
this.$emit('close');
},
scrollModalToBottom() {
if (!this.scrollToBottom) return;
let elm = this.$refs.modal;
elm.scrollTop = elm.scrollHeight - elm.clientHeight;
}
},
mounted() {
if (this.appendToBody) {
document.body.appendChild(this.$el);
}
},
destroyed() {
if (this.appendToBody && this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el);
}
},
watch: {
show(val) {
let documentClasses = document.body.classList;
if (val) {
documentClasses.add('modal-open');
this.$nextTick(this.scrollModalToBottom);
} else {
documentClasses.remove('modal-open');
}
}
}
};
</script>
<style>
.modal.show {
background-color: rgba(0, 0, 0, 0.3);
}
</style>

View File

@@ -0,0 +1,136 @@
<template>
<nav :class="classes" class="navbar">
<div :class="containerClasses">
<slot name="brand"></slot>
<slot name="toggle-button">
<button
class="navbar-toggler collapsed"
v-if="hasMenu"
type="button"
@click="toggleMenu"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-bar navbar-kebab"></span>
<span class="navbar-toggler-bar navbar-kebab"></span>
<span class="navbar-toggler-bar navbar-kebab"></span>
</button>
</slot>
<CollapseTransition
@after-leave="onTransitionEnd"
@before-enter="onTransitionStart"
>
<div
class="collapse navbar-collapse show"
:class="menuClasses"
v-show="show"
>
<slot></slot>
</div>
</CollapseTransition>
</div>
</nav>
</template>
<script>
import { CollapseTransition } from 'vue2-transitions';
export default {
name: 'base-nav',
props: {
show: {
type: Boolean,
default: false,
description:
'Whether navbar menu is shown (valid for viewports < specified by `expand` prop)'
},
transparent: {
type: Boolean,
default: false,
description: 'Whether navbar is transparent'
},
expand: {
type: String,
default: 'lg',
description: 'Breakpoint where nav should expand'
},
menuClasses: {
type: [String, Object, Array],
default: '',
description:
'Navbar menu (items) classes. Can be used to align menu items to the right/left'
},
containerClasses: {
type: [String, Object, Array],
default: 'container-fluid',
description:
'Container classes. Can be used to control container classes (contains both navbar brand and menu items)'
},
type: {
type: String,
default: 'white',
validator(value) {
return [
'dark',
'success',
'danger',
'warning',
'white',
'primary',
'info',
'vue'
].includes(value);
},
description: 'Navbar color type'
}
},
model: {
prop: 'show',
event: 'change'
},
components: {
CollapseTransition
},
data() {
return {
transitionFinished: true
};
},
computed: {
classes() {
let color = `bg-${this.type}`;
let classes = [
{ 'navbar-transparent': !this.show && this.transparent },
{ [`navbar-expand-${this.expand}`]: this.expand }
];
if (this.position) {
classes.push(`navbar-${this.position}`);
}
if (
!this.transparent ||
(this.show && !this.transitionFinished) ||
(!this.show && !this.transitionFinished)
) {
classes.push(color);
}
return classes;
},
hasMenu() {
return this.$slots.default;
}
},
methods: {
toggleMenu() {
this.$emit('change', !this.show);
},
onTransitionStart() {
this.transitionFinished = false;
},
onTransitionEnd() {
this.transitionFinished = true;
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,21 @@
<template>
<button
type="button"
class="navbar-toggler collapsed"
data-toggle="collapse"
data-target="#navbar"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-bar bar1"></span>
<span class="navbar-toggler-bar bar2"></span>
<span class="navbar-toggler-bar bar3"></span>
</button>
</template>
<script>
export default {
name: 'navbar-toggle-button'
};
</script>
<style></style>

View File

@@ -0,0 +1,186 @@
<template>
<div
@click="tryClose"
data-notify="container"
class="alert open"
:class="[
{ 'alert-with-icon': icon },
verticalAlign,
horizontalAlign,
alertType
]"
role="alert"
:style="customPosition"
data-notify-position="top-center"
>
<button
v-if="showClose"
type="button"
aria-hidden="true"
class="close col-xs-1"
data-notify="dismiss"
@click="close"
>
<i class="tim-icons icon-simple-remove"></i>
</button>
<span v-if="icon" data-notify="icon" :class="['alert-icon', icon]"></span>
<span data-notify="message">
<span v-if="title" class="title"
><b>{{ title }}<br /></b
></span>
<span v-if="message" v-html="message"></span>
<content-render
v-if="!message && component"
:component="component"
></content-render>
</span>
</div>
</template>
<script>
export default {
name: 'notification',
components: {
contentRender: {
props: ['component'],
render: h => h(this.component)
}
},
props: {
message: String,
title: String,
icon: String,
verticalAlign: {
type: String,
default: 'top',
validator: value => {
let acceptedValues = ['top', 'bottom'];
return acceptedValues.indexOf(value) !== -1;
}
},
horizontalAlign: {
type: String,
default: 'right',
validator: value => {
let acceptedValues = ['left', 'center', 'right'];
return acceptedValues.indexOf(value) !== -1;
}
},
type: {
type: String,
default: 'info',
validator: value => {
let acceptedValues = [
'info',
'primary',
'danger',
'warning',
'success'
];
return acceptedValues.indexOf(value) !== -1;
}
},
timeout: {
type: Number,
default: 5000,
validator: value => {
return value >= 0;
}
},
timestamp: {
type: Date,
default: () => new Date()
},
component: {
type: [Object, Function]
},
showClose: {
type: Boolean,
default: true
},
closeOnClick: {
type: Boolean,
default: true
},
clickHandler: Function
},
data() {
return {
elmHeight: 0
};
},
computed: {
hasIcon() {
return this.icon && this.icon.length > 0;
},
alertType() {
return `alert-${this.type}`;
},
customPosition() {
let initialMargin = 20;
let alertHeight = this.elmHeight + 10;
let sameAlerts = this.$notifications.state.filter(alert => {
return (
alert.horizontalAlign === this.horizontalAlign &&
alert.verticalAlign === this.verticalAlign
);
});
let sameAlertsCount = 1
let currentIndex = sameAlerts.findIndex(n => n.timestamp === this.timestamp)
if (this.$notifications.settings.overlap) {
sameAlertsCount = 1;
}
if (currentIndex !== -1) {
sameAlertsCount = currentIndex + 1
}
let pixels = (sameAlertsCount - 1) * alertHeight + initialMargin;
let styles = {};
if (this.verticalAlign === 'top') {
styles.top = `${pixels}px`;
} else {
styles.bottom = `${pixels}px`;
}
return styles;
}
},
methods: {
close() {
this.$emit('close', this.timestamp);
},
tryClose(evt) {
if (this.clickHandler) {
this.clickHandler(evt, this);
}
if (this.closeOnClick) {
this.close();
}
}
},
mounted() {
this.elmHeight = this.$el.clientHeight;
if (this.timeout) {
setTimeout(this.close, this.timeout);
}
}
};
</script>
<style lang="scss">
.notifications .alert {
position: fixed;
z-index: 10000;
&[data-notify='container'] {
width: 400px;
}
&.center {
margin: 0 auto;
}
&.left {
left: 20px;
}
&.right {
right: 20px;
}
}
</style>

View File

@@ -0,0 +1,80 @@
<template>
<div class="notifications">
<transition-group :name="transitionName" :mode="transitionMode">
<notification
v-for="notification in notifications"
v-bind="notification"
:clickHandler="notification.onClick"
:key="notification.timestamp.getTime()"
@close="removeNotification"
>
</notification>
</transition-group>
</div>
</template>
<script>
import Notification from './Notification.vue';
export default {
components: {
Notification
},
props: {
transitionName: {
type: String,
default: 'list'
},
transitionMode: {
type: String,
default: 'in-out'
},
overlap: {
type: Boolean,
default: false
}
},
data() {
return {
notifications: this.$notifications.state
};
},
methods: {
removeNotification(timestamp) {
this.$notifications.removeNotification(timestamp);
}
},
created() {
this.$notifications.settings.overlap = this.overlap;
},
watch: {
overlap: function(newVal) {
this.$notifications.settings.overlap = newVal;
}
}
};
</script>
<style lang="scss">
.notifications {
.list-move {
transition: transform 0.3s, opacity 0.4s;
}
.list-item {
display: inline-block;
}
.list-enter-active {
transition: transform 0.2s ease-in, opacity 0.4s ease-in;
}
.list-leave-active {
transition: transform 1s ease-out, opacity 0.4s ease-out;
}
.list-enter {
opacity: 0;
transform: scale(1.1);
}
.list-leave-to {
opacity: 0;
transform: scale(1.2, 0.7);
}
}
</style>

View File

@@ -0,0 +1,71 @@
import Notifications from './Notifications.vue';
const NotificationStore = {
state: [], // here the notifications will be added
settings: {
overlap: false,
verticalAlign: 'top',
horizontalAlign: 'right',
type: 'info',
timeout: 5000,
closeOnClick: true,
showClose: true,
order: 'normal' // normal | reverse (When reverse, each notification will be added on top)
},
setOptions(options) {
this.settings = Object.assign(this.settings, options);
},
removeNotification(timestamp) {
const indexToDelete = this.state.findIndex(n => n.timestamp === timestamp);
if (indexToDelete !== -1) {
this.state.splice(indexToDelete, 1);
}
},
addNotification(notification) {
if (typeof notification === 'string' || notification instanceof String) {
notification = { message: notification };
}
notification.timestamp = new Date();
notification.timestamp.setMilliseconds(
notification.timestamp.getMilliseconds() + this.state.length
);
notification = Object.assign({}, this.settings, notification);
if (this.settings.order === 'reverse') {
this.state.unshift(notification)
} else {
this.state.push(notification)
}
},
notify(notification) {
if (Array.isArray(notification)) {
notification.forEach(notificationInstance => {
this.addNotification(notificationInstance);
});
} else {
this.addNotification(notification);
}
}
};
const NotificationsPlugin = {
install(Vue, options) {
let app = new Vue({
data: {
notificationStore: NotificationStore
},
methods: {
notify(notification) {
this.notificationStore.notify(notification);
}
}
});
Vue.prototype.$notify = app.notify;
Vue.prototype.$notifications = app.notificationStore;
Vue.component('Notifications', Notifications);
if (options) {
NotificationStore.setOptions(options);
}
}
};
export default NotificationsPlugin;

7
APP/components/README.md Normal file
View File

@@ -0,0 +1,7 @@
# COMPONENTS
**This directory is not required, you can delete it if you don't want to use it.**
The components directory contains your Vue.js Components.
_Nuxt.js doesn't supercharge these components._

View File

@@ -0,0 +1,90 @@
<template>
<div class="sidebar" :data="backgroundColor">
<div class="sidebar-wrapper" ref="sidebarScrollArea">
<div class="logo">
<span class="simple-text logo-normal">
{{ title }}
</span>
</div>
<slot></slot>
<ul class="nav">
<slot name="links">
<sidebar-item
v-for="(link, index) in sidebarLinks"
:key="link.name + index"
:link="link"
>
</sidebar-item>
</slot>
</ul>
</div>
</div>
</template>
<script>
export default {
name: 'sidebar',
props: {
title: {
type: String,
default: 'Creative Tim',
description: 'Sidebar title'
},
shortTitle: {
type: String,
default: 'CT',
description: 'Sidebar short title'
},
logo: {
type: String,
default: 'http://demos.creative-tim.com/nuxt-black-dashboard-pro/img/icon-nuxt.svg',
description: 'Sidebar app logo'
},
backgroundColor: {
type: String,
default: 'vue',
validator: value => {
let acceptedValues = [
'',
'vue',
'blue',
'green',
'primary'
];
return acceptedValues.indexOf(value) !== -1;
},
description:
'Sidebar background color (vue|blue|green|orange|red|primary)'
},
sidebarLinks: {
type: Array,
default: () => [],
description:
"List of sidebar links as an array if you don't want to use components for these."
},
autoClose: {
type: Boolean,
default: true,
description:
'Whether sidebar should autoclose on mobile when clicking an item'
}
},
provide() {
return {
autoClose: this.autoClose
};
},
beforeDestroy() {
if (this.$sidebar.showSidebar) {
this.$sidebar.showSidebar = false;
}
}
};
</script>
<style>
@media (min-width: 992px) {
.navbar-search-form-mobile,
.nav-mobile-menu {
display: none;
}
}
</style>

View File

@@ -0,0 +1,178 @@
<template>
<component
:is="baseComponent"
:to="link.path ? link.path : '/'"
:class="{ active: isActive }"
tag="li"
>
<a
v-if="isMenu"
class="sidebar-menu-item"
:aria-expanded="!collapsed"
data-toggle="collapse"
@click.prevent="collapseMenu"
>
</a>
<slot
name="title"
v-if="children.length === 0 && !$slots.default && link.path"
>
<component
:to="link.path"
@click.native="linkClick"
:is="elementType(link, false)"
:class="{ active: link.active }"
:target="link.target"
:href="link.path"
>
<template v-if="addLink">
<span class="sidebar-normal">{{ link.name }}</span>
</template>
<template v-else>
<i :class="link.icon"></i>
<p>{{ link.name }}</p>
</template>
</component>
</slot>
</component>
</template>
<script>
import { CollapseTransition } from 'vue2-transitions';
export default {
name: 'sidebar-item',
components: {
CollapseTransition
},
props: {
menu: {
type: Boolean,
default: false,
description:
"Whether the item is a menu. Most of the item it's not used and should be used only if you want to override the default behavior."
},
link: {
type: Object,
default: () => {
return {
name: '',
path: '',
children: []
};
},
description:
'Sidebar link. Can contain name, path, icon and other attributes. See examples for more info'
}
},
provide() {
return {
addLink: this.addChild,
removeLink: this.removeChild
};
},
inject: {
addLink: { default: null },
removeLink: { default: null },
autoClose: {
default: true
}
},
data() {
return {
children: [],
collapsed: true
};
},
computed: {
baseComponent() {
return this.isMenu || this.link.isRoute ? 'li' : 'nuxt-link';
},
linkPrefix() {
if (this.link.name) {
let words = this.link.name.split(' ');
return words.map(word => word.substring(0, 1)).join('');
}
},
isMenu() {
if (!this.$slots.default) {
return false
}
return this.$slots.default.some(item => item.tag.endsWith('sidebar-item'))
},
isActive() {
if (this.$route && this.$route.path) {
let matchingRoute = this.children.find(c =>
this.$route.path.startsWith(c.link.path)
);
if (matchingRoute !== undefined) {
return true;
}
}
return false;
}
},
methods: {
addChild(item) {
const index = this.$slots.default.indexOf(item.$vnode);
this.children.splice(index, 0, item);
},
removeChild(item) {
const tabs = this.children;
const index = tabs.indexOf(item);
tabs.splice(index, 1);
},
elementType(link, isParent = true) {
if (link.isRoute === false) {
return isParent ? 'li' : 'a';
} else {
return 'nuxt-link';
}
},
linkAbbreviation(name) {
const matches = name.match(/\b(\w)/g);
return matches.join('');
},
linkClick() {
if (
this.autoClose &&
this.$sidebar &&
this.$sidebar.showSidebar === true
) {
this.$sidebar.displaySidebar(false);
}
},
collapseMenu() {
this.collapsed = !this.collapsed;
},
collapseSubMenu(link) {
link.collapsed = !link.collapsed;
}
},
mounted() {
if (this.addLink) {
this.addLink(this);
}
if (this.link.collapsed !== undefined) {
this.collapsed = this.link.collapsed;
}
if (this.isActive && this.isMenu) {
this.collapsed = false;
}
},
destroyed() {
if (this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el);
}
if (this.removeLink) {
this.removeLink(this);
}
}
};
</script>
<style>
.sidebar-menu-item {
cursor: pointer;
}
</style>

View File

@@ -0,0 +1,28 @@
import Sidebar from './SideBar.vue';
import SidebarItem from './SidebarItem.vue';
const SidebarStore = {
showSidebar: false,
sidebarLinks: [],
displaySidebar(value) {
this.showSidebar = value;
},
};
const SidebarPlugin = {
install(Vue, options) {
if (options && options.sidebarLinks) {
SidebarStore.sidebarLinks = options.sidebarLinks;
}
let app = new Vue({
data: {
sidebarStore: SidebarStore
}
});
Vue.prototype.$sidebar = app.sidebarStore;
Vue.component('side-bar', Sidebar);
Vue.component('sidebar-item', SidebarItem);
}
};
export default SidebarPlugin;

View File

@@ -0,0 +1,142 @@
<template>
<card>
<h5 slot="header" class="title">Edit Profile</h5>
<form @submit.prevent="updateProfile">
<div class="row">
<div class="col-md-5">
<base-input
type="text"
label="Company"
:disabled="true"
placeholder="Company"
v-model="user.company"
>
</base-input>
</div>
<div class="col-md-3">
<base-input
type="text"
label="Username"
placeholder="Username"
v-model="user.username"
>
</base-input>
</div>
<div class="col-md-4">
<base-input
type="email"
label="Email address"
placeholder="mike@email.com"
v-model="user.email"
>
</base-input>
</div>
</div>
<div class="row">
<div class="col-md-6">
<base-input
type="text"
label="First Name"
placeholder="First Name"
v-model="user.firstName"
>
</base-input>
</div>
<div class="col-md-6">
<base-input
type="text"
label="Last Name"
placeholder="Last Name"
v-model="user.lastName"
>
</base-input>
</div>
</div>
<div class="row">
<div class="col-md-12">
<base-input
type="text"
label="Address"
placeholder="Home Address"
v-model="user.address"
>
</base-input>
</div>
</div>
<div class="row">
<div class="col-md-4">
<base-input
type="text"
label="City"
placeholder="City"
v-model="user.city"
>
</base-input>
</div>
<div class="col-md-4">
<base-input
type="text"
label="Country"
placeholder="Country"
v-model="user.country"
>
</base-input>
</div>
<div class="col-md-4">
<base-input
label="Postal Code"
placeholder="ZIP Code"
v-model="user.postalCode"
>
</base-input>
</div>
</div>
<div class="row">
<div class="col-md-12">
<base-input label="About Me">
<textarea
class="form-control"
placeholder="ZIP Code"
v-model="user.aboutMe"
>
</textarea>
</base-input>
</div>
</div>
<base-button native-type="submit" type="primary" class="btn-fill">
Save
</base-button>
</form>
</card>
</template>
<script>
export default {
data() {
return {
user: {
company: 'Creative Code Inc.',
username: 'michael23',
email: '',
firstName: 'Mike',
lastName: 'Andrew',
address: 'Bld Mihail Kogalniceanu, nr. 8 Bl 1, Sc 1, Ap 09',
city: 'New York',
country: 'USA',
postalCode: '',
aboutMe: `Lamborghini Mercy, Your chick she so thirsty, I'm in that two seat Lambo.`
}
};
},
methods: {
updateProfile() {
alert('Your data: ' + JSON.stringify(this.user));
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,38 @@
<template>
<card class="card-user">
<p class="card-text"></p>
<div class="author">
<div class="block block-one"></div>
<div class="block block-two"></div>
<div class="block block-three"></div>
<div class="block block-four"></div>
<a href="javascript:void(0)">
<img class="avatar" src="img/emilyz.jpg" alt="..." />
<h5 class="title">Mike Andrew</h5>
</a>
<p class="description">Ceo/Co-Founder</p>
</div>
<p></p>
<div class="card-description">
Do not be scared of the truth because we need to restart the human
foundation in truth And I love you like Kanye loves Kanye I love Rick
Owens bed design but the back is...
</div>
<div slot="footer" class="button-container">
<base-button class="btn-facebook" icon round>
<i class="fab fa-facebook"></i>
</base-button>
<base-button class="btn-twitter" icon round>
<i class="fab fa-twitter"></i>
</base-button>
<base-button class="btn-google" icon round>
<i class="fab fa-google-plus"></i>
</base-button>
</div>
</card>
</template>
<script>
export default {};
</script>
<style></style>

51
APP/components/index.js Executable file
View File

@@ -0,0 +1,51 @@
import BaseCheckbox from './Inputs/BaseCheckbox.vue';
import BaseAlert from './BaseAlert.vue';
import IconCheckbox from './Inputs/IconCheckbox.vue';
import BaseRadio from './Inputs/BaseRadio.vue';
import BaseInput from './Inputs/BaseInput.vue';
import BaseSwitch from './BaseSwitch.vue';
import Badge from './Badge';
import BaseProgress from './BaseProgress.vue';
import BaseButton from './BaseButton.vue';
import BaseDropdown from './BaseDropdown.vue';
import BaseTable from './BaseTable.vue';
import Card from './Cards/Card.vue';
import BaseNav from './Navbar/BaseNav';
import NavbarToggleButton from './Navbar/NavbarToggleButton';
import Breadcrumb from './Breadcrumb/Breadcrumb.vue';
import BreadcrumbItem from './Breadcrumb/BreadcrumbItem.vue';
import RouteBreadCrumb from './Breadcrumb/RouteBreadcrumb.vue';
import Modal from './Modal.vue';
import LoadingPanel from './LoadingPanel.vue';
import BasePagination from './BasePagination.vue';
import SidebarPlugin from './SidebarPlugin';
export {
BaseCheckbox,
IconCheckbox,
BaseSwitch,
Badge,
BaseAlert,
BaseProgress,
BasePagination,
BaseRadio,
BaseInput,
Card,
BaseTable,
BaseDropdown,
SidebarPlugin,
BaseNav,
NavbarToggleButton,
Breadcrumb,
BreadcrumbItem,
RouteBreadCrumb,
Modal,
BaseButton,
LoadingPanel
};