Init project

This commit is contained in:
alirezakarari
2021-01-09 20:53:13 +03:30
commit 8d06c89a89
1005 changed files with 105625 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
<template>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 250 250" style="enable-background:new 0 0 250 250;" xml:space="preserve">
<g>
<polygon class="st0" points="124,12 90.4,46 109.9,65.3 125,49.9 125,13 "/>
<path class="st1" d="M184.1,71.4L125,13v36.9l0.1-0.1l36.3,35.8c21.9,19.8,19.8,39,19.8,39s1.3,18.1-20.4,38.2l-35.6,36.1l-0.2-0.2
v38.8l0.4,0.4l59.4-60.1c0,0,22.7-23.6,22.5-53.4C207.1,94.7,184.1,71.4,184.1,71.4z"/>
</g>
<path class="st2" d="M92.9,121.9l29.2,28.5c0,0,1.5-1.6,2.9-4.6c2.6-5.1,5.1-14.1,0-25.3c-2.4-5.3-6.6-11.1-13.4-17.2
c-0.1-0.1-0.1-0.1-0.2-0.2l-19.5-19l-0.4-0.4l-17.7,19.5C76.9,106.5,87.9,116.7,92.9,121.9z"/>
<path class="st0" d="M73.8,103.4L73.8,103.4C73.8,103.4,73.8,103.4,73.8,103.4C73.8,103.3,73.8,103.3,73.8,103.4l17.7-19.6l-8.6-8.5
L72.4,65.2L61.4,75.9c0,0,0,0,0,0c-1.2,1.4-18.6,21.2-19.2,49.6c0.1,29.8,23.2,53.1,23.2,53.1l59.7,58.9v-38.8l-37-34.3
c-21.9-19.8-19.8-39-19.8-39S67.1,115.9,73.8,103.4L73.8,103.4z"/>
<g class="st3">
<path class="st4" d="M91.9,84.2l-0.4-0.4l-17.7,19.5c1.7,1.8,6,5.8,10.3,9.9l7.9-29L91.9,84.2z"/>
</g>
</svg>
</template>
<style type="text/css">
.st0{fill:#488C51;}
.st1{fill:#26685D;}
.st2{fill:#28675C;}
.st3{opacity:0.5;}
.st4{fill:#333333;}
</style>
+36
View File
@@ -0,0 +1,36 @@
<!-- =========================================================================================
File Name: TheFooter.vue
Description: Footer component
Component Name: TheFooter
----------------------------------------------------------------------------------------
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template
Author: Pixinvent
Author URL: http://www.themeforest.net/user/pixinvent
========================================================================================== -->
<template functional>
<footer class="the-footer flex-wrap justify-between" :class="classes">
<p>
<span>COPYRIGHT &copy;</span>
<span>{{ new Date().getFullYear() }} </span>
<a href="https://1.envato.market/vuexy_admin" target="_blank" rel="nofollow">Pixinvent</a>
<span class="hidden sm:inline-block">, All rights Reserved</span>
</p>
<span class="md:flex hidden items-center">
<span>Hand-crafted & Made with</span>
<feather-icon icon="HeartIcon" svgClasses="stroke-current text-danger w-6 h-6" class="ml-2" />
</span>
</footer>
</template>
<script>
export default {
name: 'the-footer',
props: {
classes: {
type: String
}
}
}
</script>
+37
View File
@@ -0,0 +1,37 @@
<!-- =========================================================================================
File Name: VxBreadcrumb.vue
Description: Breadcrumb component
Component Name: VxBreadcrumb
----------------------------------------------------------------------------------------
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template
Author: Pixinvent
Author URL: http://www.themeforest.net/user/pixinvent
========================================================================================== -->
<template functional>
<div class="vx-breadcrumb" :class="data.staticClass">
<ul class="flex flex-wrap items-center">
<li class="inline-flex items-end">
<router-link to="/">
<feather-icon icon="HomeIcon" svgClasses="h-5 w-5 mb-1 stroke-current text-primary" />
</router-link>
<span class="breadcrumb-separator mx-2"><feather-icon :icon="props.isRTL ? 'ChevronsLeftIcon' : 'ChevronsRightIcon'" svgClasses="w-4 h-4" /></span>
</li>
<li v-for="(link, index) in props.route.meta.breadcrumb.slice(1,-1)" :key="index" class="inline-flex items-center">
<router-link :to="link.url" v-if="link.url">{{ link.title }}</router-link>
<span class="text-primary cursor-default" v-else>{{ link.title }}</span>
<span class="breadcrumb-separator mx-2 flex items-start"><feather-icon :icon="props.isRTL ? 'ChevronsLeftIcon' : 'ChevronsRightIcon'" svgClasses="w-4 h-4" /></span>
</li>
<li class="inline-flex">
<span v-if="props.route.meta.breadcrumb.slice(-1)[0].active" class="cursor-default">{{ props.route.meta.breadcrumb.slice(-1)[0].title }}</span>
</li>
</ul>
</div>
</template>
<script>
export default{
name: 'vx-breadcrumb'
}
</script>
@@ -0,0 +1,371 @@
<!-- =========================================================================================
File Name: TheCustomizer.vue
Description: Template Customizer
Component Name: TheCustomizer
----------------------------------------------------------------------------------------
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template
Author: Pixinvent
Author URL: http://www.themeforest.net/user/pixinvent
========================================================================================== -->
<template>
<div id="theme-customizer">
<!-- Open Customizer Button -->
<vs-button
@click.stop="active=!active"
color="primary"
type="filled"
class="customizer-btn"
icon-pack="feather"
icon="icon-settings" />
<!-- Customizer Content -->
<vs-sidebar
click-not-close
hidden-background
position-right
v-model="active"
class="items-no-padding">
<div class="h-full">
<div class="customizer-header mt-6 flex items-center justify-between px-6">
<div>
<h4>THEME CUSTOMIZER</h4>
<small>Customize & Preview in Real Time</small>
</div>
<feather-icon icon="XIcon" @click.stop="active = false" class="cursor-pointer"></feather-icon>
</div>
<vs-divider class="mb-0" />
<component :is="scrollbarTag" class="scroll-area--customizer pt-4 pb-6" :settings="settings" :key="$vs.rtl">
<div class="px-6">
<!-- Layout Type -->
<div class="mt-4">
<h5 class="mb-2">Layout Type</h5>
<div>
<vs-radio v-model="layoutType" vs-value="vertical" class="mr-4" vs-name="layout-type-vertical">Vertical</vs-radio>
<vs-radio v-model="layoutType" vs-value="horizontal" class="mr-4" vs-name="layout-type-horizontal">Horizontal</vs-radio>
</div>
</div>
<vs-divider />
<!-- THEME COLORS -->
<div>
<h5 class="mb-4">Theme Color</h5>
<ul class="clearfix">
<!-- Color Square -->
<li
v-for="color in themeColors"
:key="color"
:style="{backgroundColor: color}"
:class="{'shadow-outline': color == primaryColor}"
class="w-10 cursor-pointer h-10 rounded-lg m-2 float-left"
@click="updatePrimaryColor(color)" />
<!-- Custom Color Square -->
<li
:style="{backgroundColor: customPrimaryColor}"
:class="{'shadow-outline': customPrimaryColor == primaryColor}"
class="w-10 cursor-pointer h-10 rounded-lg m-2 float-left"
@click="updatePrimaryColor(customPrimaryColor)" />
<li class="float-left"><input class="w-10 cursor-pointer h-10 rounded-lg m-2" v-model="customPrimaryColor" type="color" /></li>
</ul>
</div>
<!-- /THEME COLORS -->
<vs-divider />
<!-- THEME -->
<div class="mt-4">
<h5 class="mb-2">Theme Mode</h5>
<div>
<vs-radio v-model="themeMode" vs-value="light" class="mr-4" vs-name="theme-mode-light">Light</vs-radio>
<vs-radio v-model="themeMode" vs-value="dark" class="mr-4" vs-name="theme-mode-dark">Dark</vs-radio>
<vs-radio
v-if="layoutType === 'vertical'"
v-model="themeMode"
vs-value="semi-dark"
vs-name="theme-mode-semi-dark">Semi Dark</vs-radio>
</div>
</div>
<vs-divider />
<template v-if="layoutType === 'vertical'">
<!-- COLLAPSE SIDEBAR -->
<div class="mt-4 flex justify-between">
<h5>Collapse Sidebar</h5>
<vs-switch v-model="reduced_sidebar" />
</div>
<vs-divider />
</template>
<!-- NAVBAR COLOR -->
<template v-if="layoutType === 'vertical'">
<div class="mt-4">
<h5>Navbar Color</h5>
<ul class="clearfix">
<!-- WHITE COLOR -->
<li
:style="{background: navbarColorInitial}"
class="w-10 m-2 h-10 rounded-lg float-left cursor-pointer border border-solid d-theme-border-grey-light"
:class="navbarColorOptionClasses(navbarColorInitial)"
@click="navbarColorLocal = navbarColorInitial " />
<!-- THEME COLORS -->
<li
v-for="color in themeColors"
:key="color"
:style="{backgroundColor: color}"
:class="navbarColorOptionClasses(color)"
class="w-10 cursor-pointer h-10 rounded-lg m-2 float-left"
@click="navbarColorLocal = color" />
<!-- CUSTOM COLOR -->
<li
:style="{backgroundColor: customNavbarColor}"
:class="navbarColorOptionClasses(navbarColorOptionClasses)"
class="w-10 cursor-pointer h-10 rounded-lg m-2 float-left"
@click="navbarColorLocal = customNavbarColor" />
<li class="float-left">
<input class="w-10 cursor-pointer h-10 rounded-lg m-2" v-model="customNavbarColor" type="color" />
</li>
</ul>
</div>
<!-- /NAVBAR COLOR -->
<vs-divider />
</template>
<!-- NAVBAR TYPE -->
<div class="mt-4">
<h5 class="mb-2">{{ (layoutType === 'vertical' || windowWidth &lt; 1200) ? "Navbar" : "Nav Menu" }} Type</h5>
<div>
<vs-radio
v-if="layoutType === 'vertical' || windowWidth < 1200"
v-model="navbarTypeLocal"
vs-value="hidden"
class="mr-4"
vs-name="navbar-type-hidden">Hidden</vs-radio>
<vs-radio v-model="navbarTypeLocal" vs-value="static" class="mr-4" vs-name="navbar-type-static">Static</vs-radio>
<vs-radio v-model="navbarTypeLocal" vs-value="sticky" vs-name="navbar-type-sticky" class="mr-4">Sticky</vs-radio>
<vs-radio v-model="navbarTypeLocal" vs-value="floating" vs-name="navbar-type-floating">Floating</vs-radio>
</div>
</div>
<vs-divider />
<!-- FOOTER TYPE -->
<div class="mt-4">
<h5 class="mb-2">Footer Type</h5>
<div>
<vs-radio v-model="footerTypeLocal" vs-value="hidden" class="mr-4" vs-name="footer-type-hidden">Hidden</vs-radio>
<vs-radio v-model="footerTypeLocal" vs-value="static" class="mr-4" vs-name="footer-type-static">Static</vs-radio>
<vs-radio v-model="footerTypeLocal" vs-value="sticky" vs-name="footer-type-sticky">Sticky</vs-radio>
</div>
</div>
<vs-divider />
<!-- RTL -->
<div class="mt-4 flex justify-between">
<h5 class="mb-2">RTL</h5>
<vs-switch v-model="rtl" />
</div>
<vs-divider />
<!-- SHOW SCROLL TO TOP -->
<div class="mt-4 flex justify-between">
<h5 class="mb-2">Hide Scroll To Top</h5>
<vs-switch v-model="hideScrollToTopLocal" />
</div>
<vs-divider />
<!-- ROUTER ANIMATION -->
<div class="mt-4">
<h5 class="mb-2">Router Animation {{ routerTransitionLocal }}</h5>
<vs-select v-model="routerTransitionLocal">
<vs-select-item
v-for="(item,index) in routerTransitionsList"
:key="index"
:value="item.value"
:text="item.text" />
</vs-select>
</div>
</div>
</component>
</div>
</vs-sidebar>
</div>
</template>
<script>
import VuePerfectScrollbar from 'vue-perfect-scrollbar'
export default {
props: {
footerType : { type: String, required: true },
hideScrollToTop : { type: Boolean, required: true },
navbarType : { type: String, required: true },
navbarColor : { type: String, required: true, default: '#fff' },
routerTransition : { type: String, required: true }
},
data () {
return {
active : false,
customPrimaryColor : '#3DC9B3',
customNavbarColor : '#3DC9B3',
routerTransitionsList: [
{ text: 'Zoom Fade', value: 'zoom-fade' },
{ text: 'Slide Fade', value: 'slide-fade' },
{ text: 'Fade Bottom', value: 'fade-bottom' },
{ text: 'Fade', value: 'fade' },
{ text: 'Zoom Out', value: 'zoom-out' },
{ text: 'None', value: 'none' }
],
settings: {
maxScrollbarLength : 60,
wheelSpeed : .60
},
themeColors: ['#7367F0', '#28C76F', '#EA5455', '#FF9F43', '#1E1E1E']
}
},
watch: {
layoutType (val) {
// Reset unsupported options
if (val === 'horizontal') {
if (this.themeMode === 'semi-dark') this.themeMode = 'light'
if (this.navbarType === 'hidden') this.navbarTypeLocal = 'floating'
this.$emit('updateNavbarColor', '#fff')
}
}
},
computed: {
footerTypeLocal: {
get () { return this.footerType },
set (val) { this.$emit('updateFooter', val) }
},
hideScrollToTopLocal: {
get () { return this.hideScrollToTop },
set (val) { this.$emit('toggleHideScrollToTop', val) }
},
navbarColorInitial () {
return this.$store.state.theme === 'dark' ? '#10163a' : '#fff'
},
navbarColorOptionClasses () {
return (color) => {
const classes = {}
if (color === this.navbarColorLocal) classes['shadow-outline'] = true
if (this.navbarTypeLocal === 'static') classes['cursor-not-allowed'] = true
return classes
}
},
navbarColorLocal: {
get () { return this.navbarColor },
set (val) {
if (this.navbarType === 'static') return
this.$emit('updateNavbarColor', val)
}
},
navbarTypeLocal: {
get () { return this.navbarType },
set (val) { this.$emit('updateNavbar', val) }
},
layoutType: {
get () { return this.$store.state.mainLayoutType },
set (val) { this.$store.commit('UPDATE_MAIN_LAYOUT_TYPE', val) }
},
primaryColor: {
get () { return this.$store.state.themePrimaryColor },
set (val) { this.$store.commit('UPDATE_PRIMARY_COLOR', val) }
},
reduced_sidebar: {
get () { return this.$store.state.reduceButton },
set (val) { this.$store.commit('TOGGLE_REDUCE_BUTTON', val) }
},
routerTransitionLocal: {
get () { return this.routerTransition },
set (val) { this.$emit('updateRouterTransition', val) }
},
rtl: {
get () { return this.$vs.rtl },
set (val) { this.$vs.rtl = val }
},
themeMode: {
get () { return this.$store.state.theme },
set (val) { this.$store.dispatch('updateTheme', val) }
},
scrollbarTag () { return this.$store.state.is_touch_device ? 'div' : 'VuePerfectScrollbar' },
windowWidth () {
return this.$store.state.windowWidth
}
},
methods: {
updatePrimaryColor (color) {
this.primaryColor = color
this.$vs.theme({ primary: color })
}
},
components: {
VuePerfectScrollbar
}
}
</script>
<style lang="scss">
#theme-customizer {
.vs-sidebar {
position: fixed;
z-index: 52000;
width: 400px;
max-width: 90vw;
// @apply shadow-lg;
box-shadow: 0 15px 30px 0 rgba(0,0,0,0.11), 0 5px 15px 0 rgba(0,0,0,0.08);
}
}
.customizer-btn {
position: fixed;
top: 50%;
right: 0;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
z-index: 50000;
.vs-icon {
animation: spin 1.5s linear infinite;
}
}
.scroll-area--customizer {
height: calc(100% - 5rem);
&:not(.ps) {
overflow-y: auto;
}
}
</style>
@@ -0,0 +1,96 @@
<template>
<div class="relative">
<div class="vx-navbar-wrapper nav-menu-wrapper">
<vs-navbar class="vx-navbar navbar-custom navbar-skelton" :color="navbarColor">
<ul class="menu-items flex flex-wrap w-full items-center">
<li
class = "menu-item"
v-for = "(item, index) in navMenuItems"
:key = "index"
:class = "{'mr-2': !(navMenuItems.length === index+1)}">
<!-- If header -->
<template v-if="item.header">
<h-nav-menu-header :header="item" class="menu-header relative" />
</template>
<!-- If it's group -->
<template v-else-if="item.submenu">
<h-nav-menu-group
class="menu-group relative py-4"
bottom
:key ="`group-${index}`"
:group ="item"
:groupIndex ="index"
:open ="checkGrpChildrenActive(item)" />
</template>
<!-- If it's link -->
<div v-else-if="item.url" class="menu-link">
<h-nav-menu-item
class = "relative py-4 cursor-pointer"
:to = "item.slug !== 'external' ? item.url : null"
:href = "item.slug === 'external' ? item.url : null"
:icon = "item.icon"
:target = "item.target"
:isDisabled = "item.isDisabled"
:slug = "item.slug">
<span class="truncate">{{ $t(item.i18n) || item.name }}</span>
<vs-chip :color="item.tagColor" v-if="item.tag">{{ item.tag }}</vs-chip>
</h-nav-menu-item>
</div>
</li>
</ul>
</vs-navbar>
</div>
</div>
</template>
<script>
import HNavMenuGroup from './HorizontalNavMenuGroup.vue'
import HNavMenuHeader from './HorizontalNavMenuHeader.vue'
import HNavMenuItem from './HorizontalNavMenuItem.vue'
export default {
props: {
// navbarColor : { type: String, default: "#fff", },
navMenuItems : { type: Array, required: true }
},
components: {
HNavMenuGroup,
HNavMenuHeader,
HNavMenuItem
},
computed: {
navbarColor () {
return this.$store.state.theme === 'dark' ? '#10163a' : '#fff'
}
},
methods: {
checkGrpChildrenActive (group) {
const path = this.$route.fullPath
let active = false
const routeParent = this.$route.meta ? this.$route.meta.parent : undefined
if (group.submenu) {
group.submenu.forEach((item) => {
if (active) return true
if ((path === item.url || routeParent === item.slug) && item.url) { active = true } else if (item.submenu) { this.checkGrpChildrenActive(item) }
})
}
return active
}
}
}
</script>
<style lang="scss">
@import "@/assets/scss/vuexy/components/horizontalNavMenu.scss";
.v-nav-menu .vs-sidebar--item .router-link-active span {
color: #fff;
padding-right: 0.5em;
}
</style>
@@ -0,0 +1,194 @@
<template>
<div
class = "h-nav-group relative"
:class = "[
{'h-nav-group-open' : openItems },
{'h-nav-group-active' : open },
{'disabled-item pointer-events-none': group.isDisabled }
]"
@mouseover = "mouseover"
@mouseleave = "mouseout">
<!-- Group Label -->
<div class="group-header w-full flex items-center">
<span class="flex items-center w-full">
<!-- Group Icon -->
<feather-icon
v-if = "group.icon || (this.groupIndex > Math.floor(this.groupIndex))"
:icon = "group.icon || 'CircleIcon'"
:svgClasses = "iconClasses" />
<!-- Group Name -->
<span class="truncate mr-3 select-none">{{ $t(group.i18n) || group.name }}</span>
</span>
<!-- Group Collapse Icon -->
<feather-icon
:class = "[{'rotate90' : openItems}, 'feather-grp-header-arrow']"
:icon = "bottom ? 'ChevronDownIcon' : $vs.rtl ? 'ChevronLeftIcon' : 'ChevronRightIcon'"
svg-classes= "w-4 h-4" />
</div>
<!-- /Group Label -->
<!-- Group Items -->
<transition name="fade-bottom-2x">
<ul :style="styleItems" class="h-nav-group-items h-nav-menu-dd absolute shadow-drop py-2" v-show="openItems" ref="childDropdown">
<li v-for="(groupItem, index) in group.submenu" :key="index">
<h-nav-menu-group
v-if = "groupItem.submenu"
:group = "groupItem"
:groupIndex = "Number(`${groupIndex}.${index+1}`)"
:open = "isGroupActive(groupItem)"
:openHover = "openHover" />
<h-nav-menu-item
v-else
icon-small
:index = "groupIndex + '.' + index"
:to = "groupItem.slug !== 'external' ? groupItem.url : null"
:href = "groupItem.slug === 'external' ? groupItem.url : null"
:icon = "itemIcon"
:slug = "groupItem.slug"
:target = "groupItem.target">
<span class="truncate">{{ $t(groupItem.i18n) || groupItem.name }}</span>
<vs-chip class="ml-auto" :color="groupItem.tagColor" v-if="groupItem.tag">{{ groupItem.tag }}</vs-chip>
</h-nav-menu-item>
</li>
</ul>
</transition>
<!-- /Group Items -->
</div>
</template>
<script>
// import VNavMenuItem from './VerticalNavMenuItem.vue'
import HNavMenuItem from './HorizontalNavMenuItem.vue'
export default {
name : 'h-nav-menu-group',
props : {
openHover : { type: Boolean, default: true },
open : { type: Boolean, default: false },
group : { type: Object },
groupIndex : { type: Number },
bottom : { type: Boolean, default: false }
},
components: {
HNavMenuItem
},
data: () => ({
openItems : false,
hovered: false,
dropLeft: false
}),
computed: {
iconClasses () {
let classes = 'mr-3 '
classes += this.groupIndex % 1 !== 0 ? 'w-3 h-3' : 'w-5 h-5'
return classes
},
styleItems () {
const style = {}
if (this.bottom) {
style.top = '100%'
style.left = '0'
} else {
style.top = '12px'
style.left = '100%'
}
if (this.dropLeft) {
style.left = null
style.right = '100%'
}
if (this.$vs.rtl) {
const temp = style.left
style.left = style.right
style.right = temp
}
return style
},
itemIcon () {
// return (index) => {
// // if (!((index.match(/\./g) || []).length > 1)) return "CircleIcon"
// }
return 'CircleIcon'
},
isGroupActive () {
return (item) => {
const path = this.$route.fullPath
let open = false
const routeParent = this.$route.meta ? this.$route.meta.parent : undefined
const func = (item) => {
if (item.submenu) {
item.submenu.forEach((item) => {
if ((path === item.url || routeParent === item.slug) && item.url) { open = true } else if (item.submenu) { func(item) }
})
}
}
func(item)
return open
}
}
},
watch: {
hovered (val) {
this.$nextTick(() => {
if (val) {
const dd = this.$refs.childDropdown
if (window.innerHeight - dd.getBoundingClientRect().top - dd.getBoundingClientRect().height - 28 < 1) {
const maxHeight = window.innerHeight - dd.getBoundingClientRect().top - 70
dd.style.maxHeight = `${maxHeight}px`
dd.style.overflowY = 'auto'
dd.style.overflowX = 'hidden'
}
if (dd.getBoundingClientRect().left + dd.offsetWidth - (window.innerWidth - 16) >= 0 || this.$parent.dropLeft) {
this.dropLeft = true
}
if (this.$vs.rtl) {
if (dd.getBoundingClientRect().right - dd.offsetWidth - 16 < 0) {
this.dropLeft = true
}
}
} else {
this.dropLeft = false
}
})
}
},
methods: {
mouseover () {
this.hovered = true
if (this.openHover) {
this.showChildren()
}
},
mouseout () {
this.hovered = false
if (this.openHover) {
this.showChildren(false)
}
},
showChildren (val = true) {
this.openItems = val
}
}
}
</script>
<style lang="scss">
@import "@/assets/scss/vuexy/components/horizontalNavMenuGroup.scss"
</style>
@@ -0,0 +1,134 @@
<template>
<div
class="nav-header py-4"
@mouseover = "hovered"
@mouseleave = "hovered(false)"
@click = "showChildren = !showChildren">
<!-- header -->
<div
class="header-label flex items-center cursor-pointer relative px-5 py-2"
:class="[
{'text-white bg-primary-gradient header-active': isHeaderActive},
{'header-open': isHovered || showChildren}
]">
<feather-icon :icon="header.icon" svgClasses="h-5 w-5" class="mr-3" />
<span class="whitespace-no-wrap">{{ $t(header.i18n) || header.header }}</span>
<feather-icon icon="ChevronDownIcon" svgClasses="h-4 w-4" class="ml-1" />
</div>
<!-- Children -->
<transition name="fade-top-2x">
<ul class="header-children h-nav-menu-dd shadow-drop text-intial absolute shadow-lg py-2" :class="{'dd-right': dropRight}" v-show="showChildren" ref="headerDropdown">
<li v-for="(item, index) in header.items" :key="item.name">
<template v-if="!item.submenu">
<h-nav-menu-item
:to="item.slug != 'external' ? item.url : ''"
:href="item.slug == 'external' ? item.url : ''"
:icon="item.icon" :target="item.target"
:isDisabled="item.isDisabled"
:slug="item.slug">
<span class="truncate">{{ $t(item.i18n) || item.name }}</span>
<vs-chip :color="item.tagColor" v-if="item.tag">{{ item.tag }}</vs-chip>
</h-nav-menu-item>
</template>
<template v-else>
<h-nav-menu-group
openHover
:key="`group-${index}`"
:group="item"
:groupIndex="index"
:open="checkGrpChildrenActive(item)" />
</template>
</li>
</ul>
</transition>
</div>
</template>
<script>
import HNavMenuGroup from './HorizontalNavMenuGroup.vue'
import HNavMenuItem from './HorizontalNavMenuItem.vue'
export default {
props: {
header: {
type: Object,
requried: true
},
openOnHover: {
type: Boolean,
default: true
}
},
components: {
HNavMenuGroup,
HNavMenuItem
},
data () {
return {
showChildren: false,
isHovered: false,
dropRight: false
}
},
computed: {
isHeaderActive () {
const path = this.$route.fullPath
let active = false
const routeParent = this.$route.meta ? this.$route.meta.parent : undefined
this.header.items.forEach((item) => {
// If item is group
if (item.submenu) {
if (this.checkGrpChildrenActive(item)) { active = true }
} else if (item.url) {
if (path === item.url || routeParent === item.slug) { active = true }
}
})
return active
}
},
watch: {
showChildren () {
this.$nextTick(() => {
if (this.showChildren) {
const dd = this.$refs.headerDropdown
if (dd.getBoundingClientRect().left + dd.offsetWidth - (window.innerWidth - 16) >= 0) {
this.dropRight = true
}
}
})
}
},
methods: {
checkGrpChildrenActive (group) {
const path = this.$route.fullPath
let active = false
const routeParent = this.$route.meta ? this.$route.meta.parent : undefined
if (group.submenu) {
group.submenu.forEach((item) => {
if ((path === item.url || routeParent === item.slug) && item.slug) active = true
else if (item.submenu) { if (this.checkGrpChildrenActive(item)) active = true }
})
}
return active
},
hovered (val = true) {
this.isHovered = val
if (this.openOnHover) {
val ? this.showChildren = true : this.showChildren = false
}
}
}
}
</script>
<style lang="scss">
@import "@/assets/scss/vuexy/components/horizontalNavMenuHeader.scss";
</style>
@@ -0,0 +1,72 @@
<!-- =========================================================================================
File Name: VerticalNavMenuItem.vue
Description: Vertical NavMenu item component. Extends vuesax framework's 'vs-sidebar-item' component
Component Name: VerticalNavMenuItem
----------------------------------------------------------------------------------------
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template
Author: Pixinvent
Author URL: http://www.themeforest.net/user/pixinvent
========================================================================================== -->
<template>
<div
v-if="canSee"
class="h-nav-menu-item"
:class="[
{'h-nav-active-item text-primary font-medium' : activeLink},
{'disabled-item pointer-events-none' : isDisabled},
]" >
<router-link
v-if="to"
exact
:class="[{'router-link-active': activeLink}, 'nav-link flex items-center']"
:to="to"
:target="target" >
<vs-icon v-if="!featherIcon" :icon-pack="iconPack" :icon="icon" />
<feather-icon v-else :class="iconClasses" :icon="icon" />
<slot />
</router-link>
<a v-else :target="target" :href="href" class="nav-link flex items-center">
<vs-icon v-if="!featherIcon" :icon-pack="iconPack" :icon="icon" />
<feather-icon v-else :class="iconClasses" :icon="icon" />
<slot />
</a>
</div>
</template>
<script>
export default {
name: 'v-nav-menu-item',
props: {
icon : { type: String, default: '' },
iconSmall : { type: Boolean, default: false },
iconPack : { type: String, default: 'material-icons' },
href : { type: [String, null], default: '#' },
to : { type: [String, Object, null], default: null },
slug : { type: String, default: null },
index : { type: [String, Number], default: null },
featherIcon : { type: Boolean, default: true },
target : { type: String, default: '_self' },
isDisabled : { type: Boolean, default: false }
},
computed: {
iconClasses () {
return this.iconSmall ? 'w-3 h-3 mr-3' : 'w-5 h-5 mr-3'
},
canSee () {
this.$acl.check(this.$store.state.AppActiveUser.userRole)
return this.to ? this.$acl.check(this.$router.match(this.to).meta.rule) : true
},
activeLink () {
return !!((this.to === this.$route.path || this.$route.meta.parent === this.slug) && this.to)
}
}
}
</script>
<style lang="scss">
@import "@/assets/scss/vuexy/components/horizontalNavMenuItem.scss";
</style>
@@ -0,0 +1,90 @@
<!-- =========================================================================================
File Name: TheNavbar.vue
Description: Navbar component
Component Name: TheNavbar
----------------------------------------------------------------------------------------
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template
Author: Pixinvent
Author URL: http://www.themeforest.net/user/pixinvent
========================================================================================== -->
<template>
<div class="relative">
<div class="vx-navbar-wrapper navbar-full p-0">
<vs-navbar class="navbar-custom navbar-skelton" :class="navbarClasses" :style="navbarStyle" :color="navbarColor">
<bookmarks :navbarColor="navbarColor" v-if="windowWidth >= 992" />
<router-link tag="div" to="/" class="vx-logo cursor-pointer mx-auto flex items-center">
<logo class="w-10 mr-4 fill-current text-primary" />
<span class="vx-logo-text text-primary">کنسولی</span>
</router-link>
<search-bar />
<profile-drop-down />
</vs-navbar>
</div>
</div>
</template>
<script>
import Bookmarks from './components/Bookmarks.vue'
import I18n from './components/I18n.vue'
import SearchBar from './components/SearchBar.vue'
import CartDropDown from './components/CartDropDown.vue'
import NotificationDropDown from './components/NotificationDropDown.vue'
import ProfileDropDown from './components/ProfileDropDown.vue'
import Logo from '../Logo.vue'
export default {
name: 'the-navbar-horizontal',
props: {
logo: { type: String },
navbarType: {
type: String,
required: true
}
},
components: {
Logo,
Bookmarks,
I18n,
SearchBar,
CartDropDown,
NotificationDropDown,
ProfileDropDown
},
computed: {
navbarColor () {
let color = '#fff'
if (this.navbarType === 'sticky') color = '#f7f7f7'
else if (this.navbarType === 'static') {
if (this.scrollY < 50) {
color = '#f7f7f7'
}
}
if (this.isThemedark === 'dark') {
if (color === '#fff') {
color = '#10163a'
} else {
color = '#262c49'
}
}
return color
},
isThemedark () { return this.$store.state.theme },
navbarStyle () { return this.navbarType === 'static' ? {transition: 'all .25s ease-in-out'} : {} },
navbarClasses () { return this.scrollY > 5 && this.navbarType === 'static' ? null : 'd-theme-dark-light-bg shadow-none' },
scrollY () { return this.$store.state.scrollY },
verticalNavMenuWidth () { return this.$store.state.verticalNavMenuWidth },
windowWidth () { return this.$store.state.windowWidth }
}
}
</script>
@@ -0,0 +1,87 @@
<!-- =========================================================================================
File Name: TheNavbar.vue
Description: Navbar component
Component Name: TheNavbar
----------------------------------------------------------------------------------------
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template
Author: Pixinvent
Author URL: http://www.themeforest.net/user/pixinvent
========================================================================================== -->
<template>
<div class="relative">
<div class="vx-navbar-wrapper" :class="classObj">
<vs-navbar class="vx-navbar navbar-custom navbar-skelton" :color="navbarColorLocal" :class="textColor">
<!-- SM - OPEN SIDEBAR BUTTON -->
<feather-icon class="sm:inline-flex xl:hidden cursor-pointer p-2" icon="MenuIcon" @click.stop="showSidebar" />
<!-- <search-bar />-->
<vs-spacer />
<profile-drop-down />
</vs-navbar>
</div>
</div>
</template>
<script>
import Bookmarks from './components/Bookmarks.vue'
import I18n from './components/I18n.vue'
import SearchBar from './components/SearchBar.vue'
import CartDropDown from './components/CartDropDown.vue'
import NotificationDropDown from './components/NotificationDropDown.vue'
import ProfileDropDown from './components/ProfileDropDown.vue'
export default {
name: 'the-navbar-vertical',
props: {
navbarColor: {
type: String,
default: '#fff'
}
},
components: {
Bookmarks,
I18n,
SearchBar,
CartDropDown,
NotificationDropDown,
ProfileDropDown
},
computed: {
navbarColorLocal () {
return this.$store.state.theme === 'dark' && this.navbarColor === '#fff' ? '#10163a' : this.navbarColor
},
verticalNavMenuWidth () {
return this.$store.state.verticalNavMenuWidth
},
textColor () {
return {'text-white': (this.navbarColor !== '#10163a' && this.$store.state.theme === 'dark') || (this.navbarColor !== '#fff' && this.$store.state.theme !== 'dark')}
},
windowWidth () {
return this.$store.state.windowWidth
},
// NAVBAR STYLE
classObj () {
if (this.verticalNavMenuWidth === 'default') return 'navbar-default'
else if (this.verticalNavMenuWidth === 'reduced') return 'navbar-reduced'
else if (this.verticalNavMenuWidth) return 'navbar-full'
}
},
methods: {
showSidebar () {
this.$store.commit('TOGGLE_IS_VERTICAL_NAV_MENU_ACTIVE', true)
}
}
}
</script>
@@ -0,0 +1,163 @@
<template>
<div class="navbar-bookmarks flex items-center">
<!-- STARRED PAGES - FIRST 10 -->
<ul class="vx-navbar__starred-pages">
<draggable v-model="starredPagesLimited" :group="{name: 'pinList'}" class="flex cursor-move">
<li class="starred-page" v-for="page in starredPagesLimited" :key="page.url">
<vx-tooltip :text="page.title" position="bottom" delay=".3s">
<feather-icon :svgClasses="['h-6 w-6 stroke-current', textColor]" class="p-2 cursor-pointer" :icon="page.icon" @click="$router.push(page.url).catch(() => {})" />
</vx-tooltip>
</li>
</draggable>
</ul>
<!-- STARRED PAGES MORE -->
<div class="vx-navbar__starred-pages--more-dropdown" v-if="starredPagesMore.length">
<vs-dropdown vs-custom-content vs-trigger-click class="cursor-pointer">
<feather-icon icon="ChevronDownIcon" svgClasses="h-4 w-4" class="cursor-pointer p-2"></feather-icon>
<vs-dropdown-menu>
<ul class="vx-navbar__starred-pages-more--list">
<draggable v-model="starredPagesMore" :group="{name: 'pinList'}" class="cursor-move">
<li class="starred-page--more flex items-center cursor-pointer" v-for="page in starredPagesMore" :key="page.url" @click="$router.push(page.url).catch(() => {})">
<feather-icon class="ml-2 mr-1" :icon="page.icon" :svgClasses="['h-5 w-5 stroke-current', textColor]"></feather-icon>
<span class="px-2 pt-2 pb-1">{{ page.title }}</span>
</li>
</draggable>
</ul>
</vs-dropdown-menu>
</vs-dropdown>
</div>
<div class="bookmark-container">
<feather-icon icon="StarIcon" :svgClasses="['stoke-current text-warning', textColor]" class="cursor-pointer p-2" @click.stop="showBookmarkPagesDropdown = !showBookmarkPagesDropdown" />
<div v-click-outside="outside" class="absolute bookmark-list w-1/3 xl:w-1/4 mt-4" v-if="showBookmarkPagesDropdown">
<vx-auto-suggest
ref="bookmarkAutoSuggest"
:autoFocus="true"
:data="navbarSearchAndPinList"
:initalData="{pages: starredPagesLimited.concat(starredPagesMore)}"
:searchLimit="5"
placeholder="Explore Vuexy..."
inputClassses="w-full"
show-action
show-pinned
hideGroupTitle
background-overlay
@input="hnd_search_query_update"
@selected="selected">
<!-- Pages Suggestion -->
<template v-slot:pages="{ suggestion }">
<div class="flex items-center justify-between">
<div class="flex items-end leading-none py-1">
<feather-icon :icon="suggestion.icon" svgClasses="h-5 w-5" class="mr-4" />
<span class="mt-1">{{ suggestion.title }}</span>
</div>
<feather-icon
icon="StarIcon"
:svgClasses="[{'text-warning': suggestion.is_bookmarked}, 'h-5 w-5 stroke-current mt-1']"
@click.stop="actionClicked(suggestion)" />
</div>
</template>
</vx-auto-suggest>
</div>
</div>
</div>
</template>
<script>
import draggable from 'vuedraggable'
import VxAutoSuggest from '@/components/vx-auto-suggest/VxAutoSuggest.vue'
export default {
props: {
navbarColor: {
type: String,
default: '#fff'
}
},
components: {
draggable,
VxAutoSuggest
},
data () {
return {
showBookmarkPagesDropdown : false
}
},
watch: {
'$route' () {
if (this.showBookmarkPagesDropdown) this.showBookmarkPagesDropdown = false
}
},
computed: {
navbarSearchAndPinList () {
return {pages: this.$store.state.navbarSearchAndPinList['pages']}
},
starredPages () {
return this.$store.state.starredPages
},
starredPagesLimited: {
get () {
return this.starredPages.slice(0, 10)
},
set (list) {
this.$store.dispatch('arrangeStarredPagesLimited', list)
}
},
starredPagesMore: {
get () {
return this.starredPages.slice(10)
},
set (list) {
this.$store.dispatch('arrangeStarredPagesMore', list)
}
},
textColor () {
return {'text-white': this.$store.state.mainLayoutType === 'vertical' && this.navbarColor !== (this.$store.state.theme === 'dark' ? '#10163a' : '#fff') }
}
},
methods: {
selected (obj) {
this.$store.commit('TOGGLE_CONTENT_OVERLAY', false)
this.showBookmarkPagesDropdown = false
this.$router.push(obj.pages.url).catch(() => {})
},
actionClicked (item) {
this.$store.dispatch('updateStarredPage', { url: item.url, val: !item.is_bookmarked })
// this.$refs.bookmarkAutoSuggest.filterData()
},
outside () {
this.showBookmarkPagesDropdown = false
},
hnd_search_query_update (query) {
// Show overlay if any character is entered
this.$store.commit('TOGGLE_CONTENT_OVERLAY', !!query)
}
},
directives: {
'click-outside': {
bind (el, binding) {
const bubble = binding.modifiers.bubble
const handler = (e) => {
/* eslint-disable no-mixed-operators */
if (bubble || !el.contains(e.target) && el !== e.target) {
/* eslint-enable no-mixed-operators */
binding.value(e)
}
}
el.__vueClickOutside__ = handler
document.addEventListener('click', handler)
},
unbind (el) {
document.removeEventListener('click', el.__vueClickOutside__)
el.__vueClickOutside__ = null
}
}
}
}
</script>
@@ -0,0 +1,91 @@
<template>
<!-- CART DROPDOWN -->
<vs-dropdown vs-custom-content vs-trigger-click class="cursor-pointer">
<feather-icon icon="ShoppingCartIcon" class="cursor-pointer ml-4 mr-6 mt-1" :badge="cartItems.length" />
<vs-dropdown-menu class="cart-dropdown vx-navbar-dropdown" :class="{'dropdown-custom': cartItems.length}">
<!-- IF CART HAVE ITEMS: HEADER -->
<template v-if="cartItems.length">
<div class="notification-header text-center p-5 bg-primary text-white">
<h3 class="text-white">{{ cartItems.length }} Item<span v-show="cartItems.length > 1">s</span></h3>
<p class="opacity-75">In Your Cart</p>
</div>
<!-- CART ITEMS -->
<component :is="scrollbarTag" ref="mainSidebarPs" class="scroll-area--cart-items-dropdowm p-0 mb-10" :settings="settings" :key="$vs.rtl">
<ul class="bordered-items">
<li
v-for="item in cartItems"
:key="item.objectID"
class="vx-row no-gutter cart-item cursor-pointer"
@click="$router.push({name: 'ecommerce-item-detail-view', params: {item_id: item.objectID }}).catch(() => {})">
<!-- IMG COL -->
<div class="vx-col w-1/5 item-img-container bg-white flex items-center justify-center">
<img :src="item.image" alt="item" class="cart-dropdown-item-img p-4">
</div>
<!-- INFO COL -->
<div class="vx-col w-4/5 pr-4 pl-2 py-4 flex flex-col justify-center">
<span class="font-medium block cart-item-title truncate">{{ item.name }}</span>
<small class="truncate mb-2">{{ item.description }}</small>
<div class="flex items-center justify-between">
<span class="text-sm font-medium">{{ item.quantity }} <small>x</small> ${{ item.price }}</span>
<feather-icon icon="XIcon" svgClasses="h-4 w-4 cursor-pointer text-danger" class="hover:text-danger" @click.stop="removeItemFromCart(item)" />
</div>
</div>
</li>
</ul>
</component>
<div
class=" checkout-footer fixed bottom-0 rounded-b-lg text-primary font-semibold w-full p-2 text-center border border-b-0 border-l-0 border-r-0 border-solid d-theme-border-grey-light cursor-pointer"
@click="$router.push('/apps/eCommerce/checkout').catch(() => {})">
<span class="flex items-center justify-center">
<feather-icon icon="ShoppingCartIcon" svgClasses="h-4 w-4" />
<span class="ml-2">Checkout</span>
</span>
</div>
</template>
<!-- IF CART IS EMPTY -->
<template v-else>
<p class="p-4">Your Cart Is Empty.</p>
</template>
</vs-dropdown-menu>
</vs-dropdown>
</template>
<script>
import VuePerfectScrollbar from 'vue-perfect-scrollbar'
export default {
components: {
VuePerfectScrollbar
},
data () {
return {
settings: { // perfectscrollbar settings
maxScrollbarLength: 60,
wheelSpeed: .60
}
}
},
computed: {
// CART DROPDOWN
cartItems () {
return this.$store.state.eCommerce.cartItems.slice().reverse()
},
scrollbarTag () {
return this.$store.getters.scrollbarTag
}
},
methods: {
removeItemFromCart (item) {
this.$store.dispatch('eCommerce/toggleItemInCart', item)
}
}
}
</script>
@@ -0,0 +1,36 @@
<template>
<vs-dropdown vs-custom-content vs-trigger-click class="cursor-pointer">
<span class="cursor-pointer flex items-center i18n-locale">
<img class="h-4 w-5" :src="i18n_locale_img" :alt="$i18n.locale" />
<span class="hidden sm:block ml-2">{{ getCurrentLocaleData.lang }}</span>
</span>
<vs-dropdown-menu class="w-48 i18n-dropdown vx-navbar-dropdown">
<vs-dropdown-item @click="updateLocale('en')"><img class="h-4 w-5 mr-1" src="@/assets/images/flags/en.png" alt="en" /> &nbsp;English</vs-dropdown-item>
<vs-dropdown-item @click="updateLocale('fr')"><img class="h-4 w-5 mr-1" src="@/assets/images/flags/fr.png" alt="fr" /> &nbsp;French</vs-dropdown-item>
<vs-dropdown-item @click="updateLocale('de')"><img class="h-4 w-5 mr-1" src="@/assets/images/flags/de.png" alt="de" /> &nbsp;German</vs-dropdown-item>
<vs-dropdown-item @click="updateLocale('pt')"><img class="h-4 w-5 mr-1" src="@/assets/images/flags/pt.png" alt="pt" /> &nbsp;Portuguese</vs-dropdown-item>
</vs-dropdown-menu>
</vs-dropdown>
</template>
<script>
export default {
computed: {
i18n_locale_img () {
return require(`@/assets/images/flags/${this.$i18n.locale}.png`)
},
getCurrentLocaleData () {
const locale = this.$i18n.locale
if (locale === 'en') return { flag: 'us', lang: 'English' }
else if (locale === 'pt') return { flag: 'br', lang: 'Portuguese' }
else if (locale === 'fr') return { flag: 'fr', lang: 'French' }
else if (locale === 'de') return { flag: 'de', lang: 'German' }
}
},
methods: {
updateLocale (locale) {
this.$i18n.locale = locale
}
}
}
</script>
@@ -0,0 +1,146 @@
<template>
<!-- NOTIFICATIONS -->
<vs-dropdown vs-custom-content vs-trigger-click class="cursor-pointer">
<feather-icon icon="BellIcon" class="cursor-pointer mt-1 sm:mr-6 mr-2" :badge="unreadNotifications.length" />
<vs-dropdown-menu class="notification-dropdown dropdown-custom vx-navbar-dropdown">
<div class="notification-top text-center p-5 bg-primary text-white">
<h3 class="text-white">{{ unreadNotifications.length }} پیام جدید</h3>
<p class="opacity-75">رویداد ها</p>
</div>
<component :is="scrollbarTag" ref="mainSidebarPs" class="scroll-area--nofications-dropdown p-0 mb-10" :settings="settings" :key="$vs.rtl">
<ul class="bordered-items">
<li v-for="ntf in unreadNotifications" :key="ntf.index" class="flex justify-between px-4 py-4 notification cursor-pointer">
<div class="flex items-start">
<feather-icon :icon="ntf.icon" :svgClasses="[`text-${ntf.category}`, 'stroke-current mr-1 h-6 w-6']"></feather-icon>
<div class="mx-2">
<span class="font-medium block notification-title" :class="[`text-${ntf.category}`]">{{ ntf.title }}</span>
<small>{{ ntf.msg }}</small>
</div>
</div>
<small class="mt-1 whitespace-no-wrap">{{ elapsedTime(ntf.time) }}</small>
</li>
</ul>
</component>
<div class="
checkout-footer
fixed
bottom-0
rounded-b-lg
text-primary
w-full
p-2
font-semibold
text-center
border
border-b-0
border-l-0
border-r-0
border-solid
d-theme-border-grey-light
cursor-pointer">
<span>نمایش تمامی اعلان ها</span>
</div>
</vs-dropdown-menu>
</vs-dropdown>
</template>
<script>
import VuePerfectScrollbar from 'vue-perfect-scrollbar'
export default {
components: {
VuePerfectScrollbar
},
data () {
return {
unreadNotifications: [
{
index : 0,
title : 'تحویل سفارش',
msg : 'سفارش #25550 به محمد محسنی تحویل داده شد',
icon : 'MessageSquareIcon',
time : this.randomDate({sec: 10}),
category : 'primary'
},
{ index : 1,
title : 'سفارش جدید',
msg : 'سفارش #45550 برای محمد شایسته ',
icon : 'PackageIcon',
time : this.randomDate({sec: 40}),
category : 'success'
},
{ index : 2,
title : 'لغو سفارش',
msg : 'سفارش #45550 برای محمد شایسته ',
icon : 'AlertOctagonIcon',
time : this.randomDate({min: 1}),
category : 'danger'
}
],
settings: {
maxScrollbarLength: 60,
wheelSpeed: .60
}
}
},
computed: {
scrollbarTag () { return this.$store.getters.scrollbarTag }
},
methods: {
elapsedTime (startTime) {
const x = new Date(startTime)
const now = new Date()
let timeDiff = now - x
timeDiff /= 1000
const seconds = Math.round(timeDiff)
timeDiff = Math.floor(timeDiff / 60)
const minutes = Math.round(timeDiff % 60)
timeDiff = Math.floor(timeDiff / 60)
const hours = Math.round(timeDiff % 24)
timeDiff = Math.floor(timeDiff / 24)
const days = Math.round(timeDiff % 365)
timeDiff = Math.floor(timeDiff / 365)
const years = timeDiff
if (years > 0) {
return `${years + (years > 1 ? ' سال ' : ' سال ')}پیش`
} else if (days > 0) {
return `${days + (days > 1 ? ' روز ' : ' روز ')}پیش`
} else if (hours > 0) {
return `${hours + (hours > 1 ? ' ساعت ' : ' ساعت ')}پیش`
} else if (minutes > 0) {
return `${minutes + (minutes > 1 ? ' دقیقه ' : ' دقیقه ')}پیش`
} else if (seconds > 0) {
return seconds + (seconds > 1 ? 'چند ثانیه پیش' : 'همین الان')
}
return 'همین الان'
},
// Method for creating dummy notification time
randomDate ({ hr, min, sec }) {
const date = new Date()
if (hr) date.setHours(date.getHours() - hr)
if (min) date.setMinutes(date.getMinutes() - min)
if (sec) date.setSeconds(date.getSeconds() - sec)
return date
}
}
}
</script>
@@ -0,0 +1,64 @@
<template>
<div class="the-navbar__user-meta flex items-center">
<ADropdown :trigger="['click']" style="z-index: 250000">
<div class="flex items-center">
<div class="flex justify-start">
<p class="font-semibold mb-0">
{{ username }}
</p>
</div>
<div class="con-img ml-3">
<feather-icon icon="UserIcon" class="cursor-pointer" svg-classes="text-primary"/>
</div>
</div>
<ACard slot="overlay">
<ul style="min-width: 9rem;z-index: 25000">
<li
@click="logout"
class="flex py-2 px-4 cursor-pointer hover:bg-primary hover:text-white">
<feather-icon icon="LogOutIcon" svgClasses="w-4 h-4"/>
<span class="ml-2">خروج از حساب کاربری</span>
</li>
</ul>
</ACard>
</ADropdown>
</div>
</template>
<script>
import 'firebase/auth';
export default {
data() {
return {};
},
computed: {
activeUserInfo() {
const j = localStorage.getItem('user');
if (!j || j == 'undefined') {
return {};
}
const s = JSON.parse(j || '{}');
return s;
},
// username() {
// return this.activeUserInfo.name;
// },
username(){
const data = localStorage.getItem('user')
console.log(data,'dayaaaaaaa');
}
},
methods: {
logout() {
if (localStorage.getItem('accessToken')) {
localStorage.removeItem('user');
localStorage.removeItem('accessToken');
}
this.$router.push('/auth/login').catch(() => {
});
}
}
};
</script>
@@ -0,0 +1,106 @@
<template>
<div class="flex">
<div class="search-full-container w-full h-full absolute left-0 top-0" :class="{'flex': showFullSearch}" v-show="showFullSearch">
<vx-auto-suggest
ref="navbarSearch"
:autoFocus="showFullSearch"
:data="navbarSearchAndPinList"
search_key="title"
background-overlay
class="w-full"
inputClassses="w-full vs-input-no-border vs-input-no-shdow-focus"
icon="SearchIcon"
placeholder="جستجو کنید..."
@input="hnd_search_query_update"
@selected="selected"
@closeSearchbar="showFullSearch = false">
<template v-slot:group="{ group_name }">
<p class="font-semibold text-primary">{{ group_name | title }}</p>
</template>
<!-- Pages Suggestion -->
<template v-slot:pages="{ suggestion }">
<div class="flex items-end leading-none py-1">
<feather-icon :icon="suggestion.icon" svgClasses="h-5 w-5" class="mr-4" />
<span class="mt-1">{{ suggestion.title }}</span>
</div>
</template>
<!-- &lt;!&ndash; Files Suggestion &ndash;&gt;-->
<!-- <template v-slot:files="{ suggestion }">-->
<!-- <div class="flex items-center justify-between">-->
<!-- <div class="flex items-center">-->
<!-- <div class="img-container w-8 mr-3 flex">-->
<!-- <img :src="require(`@/assets/images/file-icons/${suggestion.file_ext}.png`)" :alt="suggestion.file_name" class="responsive">-->
<!-- </div>-->
<!-- <div class="leading-none mt-1">-->
<!-- <p class="mb-1">{{ suggestion.file_name }}</p>-->
<!-- <small>by {{ suggestion.from }}</small>-->
<!-- </div>-->
<!-- </div>-->
<!-- <small>{{ suggestion.size }}</small>-->
<!-- </div>-->
<!-- </template>-->
<!-- &lt;!&ndash; Contacts Suggestion &ndash;&gt;-->
<!-- <template v-slot:contacts="{ suggestion }">-->
<!-- <div class="flex items-center justify-between">-->
<!-- <div class="flex items-center">-->
<!-- <img :src="suggestion.img" :alt="suggestion.name" class="w-8 h-8 mr-3 rounded-full">-->
<!-- <div class="leading-none mt-1">-->
<!-- <p>{{ suggestion.name }}</p>-->
<!-- <small>{{ suggestion.email }}</small>-->
<!-- </div>-->
<!-- </div>-->
<!-- <small>{{ suggestion.time }}</small>-->
<!-- </div>-->
<!-- </template>-->
<!-- No Items Slot -->
<template v-slot:noResult="{ group_name }">
<div class="flex items-center">
<feather-icon icon="InfoIcon" svgClasses="h-5 w-5" class="mr-4" />
<span>No results found.</span>
</div>
</template>
</vx-auto-suggest>
<div class="absolute right-0 h-full z-50">
<feather-icon
icon="XIcon"
class="px-4 cursor-pointer h-full close-search-icon"
@click="showFullSearch = false" />
</div>
</div>
<feather-icon icon="SearchIcon" @click="showFullSearch = true" class="cursor-pointer navbar-fuzzy-search mr-8" />
</div>
</template>
<script>
import VxAutoSuggest from '@/components/vx-auto-suggest/VxAutoSuggest.vue'
export default {
components: {
VxAutoSuggest
},
data () {
return {
navbarSearchAndPinList: this.$store.state.navbarSearchAndPinList,
showFullSearch: false
}
},
methods: {
selected (item) {
if (item.pages) this.$router.push(item.pages.url).catch(() => {})
this.showFullSearch = false
},
hnd_search_query_update (query) {
// Show overlay if any character is entered
this.$store.commit('TOGGLE_CONTENT_OVERLAY', !!query)
}
}
}
</script>
@@ -0,0 +1,152 @@
/* eslint-disable */
export default {
pages: {
key: "title",
data: [
// DASHBOARDS
{title: "Analytics Dashboard", url: "/dashboard/analytics", icon: "HomeIcon", is_bookmarked: false},
{title: "eCommerce Dashboard", url: "/dashboard/ecommerce", icon: "HomeIcon", is_bookmarked: false},
// APPS
{title: "Todo", url: "/apps/todo", icon: "CheckSquareIcon", is_bookmarked: true},
{title: "Chat", url: "/apps/chat", icon: "MessageSquareIcon", is_bookmarked: true},
{title: "Email", url: "/apps/email", icon: "MailIcon", is_bookmarked: true},
{title: "Calendar", url: "/apps/calendar/vue-simple-calendar", icon: "CalendarIcon", is_bookmarked: true},
{title: "E-Commerce Shop", url: "/apps/eCommerce/shop", icon: "ShoppingCartIcon", is_bookmarked: true},
{title: "E-Commerce Item Detail", url: "/apps/eCommerce/item", icon: "SmartphoneIcon", is_bookmarked: false},
{title: "E-Commerce Wish List", url: "/apps/eCommerce/wish-list", icon: "HeartIcon", is_bookmarked: false},
{title: "E-Commerce Checkout", url: "/apps/eCommerce/checkout", icon: "CreditCardIcon", is_bookmarked: false},
{title: "User List", url: "/apps/user/user-list", icon: "ListIcon", is_bookmarked: false},
{title: "User View", url: "/apps/user/user-view/268", icon: "UserIcon", is_bookmarked: false},
{title: "User Edit", url: "/apps/user/user-edit/268", icon: "EditIcon", is_bookmarked: false},
// UI ELEMENTS
{title: "Data List - List View", url: "/ui-elements/data-list/list-view", icon: "ListIcon", is_bookmarked: false},
{title: "Data List - Thumb View", url: "/ui-elements/data-list/thumb-view", icon: "ImageIcon", is_bookmarked: false},
{title: "Vuesax Grid", url: "/ui-elements/grid/vuesax", icon: "LayoutIcon", is_bookmarked: false},
{title: "Tailwind Grid", url: "/ui-elements/grid/tailwind", icon: "LayoutIcon", is_bookmarked: false},
{title: "Colors", url: "/ui-elements/colors", icon: "DropletIcon", is_bookmarked: false},
{title: "Basic Cards", url: "/ui-elements/card/basic", icon: "CreditCardIcon", is_bookmarked: false},
{title: "Statistics Card", url: "/ui-elements/card/statistics", icon: "CreditCardIcon", is_bookmarked: false},
{title: "Analytics Cards", url: "/ui-elements/card/analytics", icon: "CreditCardIcon", is_bookmarked: false},
{title: "Card Actions", url: "/ui-elements/card/card-actions", icon: "CreditCardIcon", is_bookmarked: false},
{title: "Card Colors", url: "/ui-elements/card/card-colors", icon: "FeatherIcon", is_bookmarked: false},
{title: "Table", url: "/ui-elements/table", icon: "GridIcon", is_bookmarked: false},
{title: "agGrid Table", url: "/ui-elements/ag-grid-table", icon: "GridIcon", is_bookmarked: false},
{title: "Alert Component", url: "/components/alert", icon: "AlertTriangleIcon", is_bookmarked: false},
{title: "Avatar Component", url: "/components/avatar", icon: "UserIcon", is_bookmarked: false},
{title: "Breadcrumb Component", url: "/components/breadcrumb", icon: "NavigationIcon", is_bookmarked: false},
{title: "Button Component", url: "/components/button", icon: "BoldIcon", is_bookmarked: false},
{title: "Button Group Component", url: "/components/button-group", icon: "BoldIcon", is_bookmarked: false},
{title: "Chip Component", url: "/components/chip", icon: "TagIcon", is_bookmarked: false},
{title: "Collapse Component", url: "/components/collapse", icon: "PlusIcon", is_bookmarked: false},
{title: "Dialogs Component", url: "/components/dialogs", icon: "CopyIcon", is_bookmarked: false},
{title: "Divider Component", url: "/components/divider", icon: "MinusIcon", is_bookmarked: false},
{title: "DropDown Component", url: "/components/dropdown", icon: "MoreHorizontalIcon", is_bookmarked: false},
{title: "List Component", url: "/components/list", icon: "ListIcon", is_bookmarked: false},
{title: "Loading Component", url: "/components/loading", icon: "LoaderIcon", is_bookmarked: false},
{title: "Navbar Component", url: "/components/navbar", icon: "CreditCardIcon", is_bookmarked: false},
{title: "Notifications Component", url: "/components/notifications", icon: "BellIcon", is_bookmarked: false},
{title: "Pagination Component", url: "/components/pagination", icon: "ChevronsRightIcon", is_bookmarked: false},
{title: "Popup Component", url: "/components/popup", icon: "CopyIcon", is_bookmarked: false},
{title: "Progress Component", url: "/components/progress", icon: "SlidersIcon", is_bookmarked: false},
{title: "Sidebar Component", url: "/components/sidebar", icon: "SidebarIcon", is_bookmarked: false},
{title: "Slider Component", url: "/components/slider", icon: "SlidersIcon", is_bookmarked: false},
{title: "Tabs Component", url: "/components/tabs", icon: "CreditCardIcon", is_bookmarked: false},
{title: "Tooltip Component", url: "/components/tooltip", icon: "AlertCircleIcon", is_bookmarked: false},
{title: "Upload Component", url: "/components/upload", icon: "UploadIcon", is_bookmarked: false},
// FORMS
// {title: "Select Form Element", url: "/forms/form-elements/select", icon: "CheckIcon", is_bookmarked: false},
{title: "Switch Form Element", url: "/forms/form-elements/switch", icon: "ToggleLeftIcon", is_bookmarked: false},
{title: "Checkbox Form Element", url: "/forms/form-elements/checkbox", icon: "CheckSquareIcon", is_bookmarked: false},
{title: "Radio Form Element", url: "/forms/form-elements/radio", icon: "DiscIcon", is_bookmarked: false},
{title: "Input Form Element", url: "/forms/form-elements/input", icon: "TypeIcon", is_bookmarked: false},
{title: "Number Input Form Element", url: "/forms/form-elements/number-input", icon: "TypeIcon", is_bookmarked: false},
{title: "Textarea Form Element", url: "/forms/form-elements/textarea", icon: "TypeIcon", is_bookmarked: false},
{title: "Form Layouts", url: "/forms/form-layouts", icon: "LayoutIcon", is_bookmarked: false},
{title: "Form Wizard", url: "/forms/form-wizard", icon: "GitCommitIcon", is_bookmarked: false},
{title: "Form Validation", url: "/forms/form-validation", icon: "CheckSquareIcon", is_bookmarked: false},
{title: "Form Input Group", url: "/forms/form-input-group", icon: "MenuIcon", is_bookmarked: false},
// PAGES
{title: "Login Page", url: "/pages/login", icon: "LockIcon", is_bookmarked: false},
{title: "Register Page", url: "/pages/register", icon: "UserPlusIcon", is_bookmarked: false},
{title: "Forgot Password Page", url: "/pages/forgot-password", icon: "HelpCircleIcon", is_bookmarked: false},
{title: "Reset Password Page", url: "/pages/reset-password", icon: "UnlockIcon", is_bookmarked: false},
{title: "Lock Screen Page", url: "/pages/lock-screen", icon: "LockIcon", is_bookmarked: false},
{title: "Coming Soon Page", url: "/pages/comingsoon", icon: "ClockIcon", is_bookmarked: false},
{title: "404 Page", url: "/pages/error-404", icon: "MonitorIcon", is_bookmarked: false},
{title: "500 Page", url: "/pages/error-500", icon: "MonitorIcon", is_bookmarked: false},
{title: "Not Authorized Page", url: "/pages/not-authorized", icon: "XCircleIcon", is_bookmarked: false},
{title: "Maintenance Page", url: "/pages/maintenance", icon: "MonitorIcon", is_bookmarked: false},
{title: "Profile Page", url: "/pages/profile", icon: "UserIcon", is_bookmarked: false},
{title: "User Settings", url: "/pages/user-settings", icon: "SettingsIcon", is_bookmarked: false},
{title: "FAQ Page", url: "/pages/faq", icon: "HelpCircleIcon", is_bookmarked: false},
{title: "KnowledgeBase Page", url: "/pages/knowledge-base", icon: "BookIcon", is_bookmarked: false},
{title: "Search Page", url: "/pages/search", icon: "SearchIcon", is_bookmarked: false},
{title: "Invoice Page", url: "/pages/invoice", icon: "FileIcon", is_bookmarked: false},
// CHARTS & MAPS
{title: "Apex Charts", url: "/charts-and-maps/charts/apex-charts", icon: "PieChartIcon", is_bookmarked: false},
{title: "chartjs", url: "/charts-and-maps/charts/chartjs", icon: "PieChartIcon", is_bookmarked: false},
{title: "echarts", url: "/charts-and-maps/charts/echarts", icon: "PieChartIcon", is_bookmarked: false},
{title: "Google Map", url: "/charts-and-maps/maps/google-map", icon: "MapIcon", is_bookmarked: false},
// EXTENSIONS
{title: "Select Extension", url: "/extensions/select", icon: "CheckIcon", is_bookmarked: false},
{title: "Quill Editor", url: "/extensions/quill-editor", icon: "EditIcon", is_bookmarked: false},
{title: "Drag & Drop", url: "/extensions/drag-and-drop", icon: "CopyIcon", is_bookmarked: false},
{title: "Datepicker", url: "/extensions/datepicker", icon: "CalendarIcon", is_bookmarked: false},
{title: "Datetime Picker", url: "/extensions/datetime-picker", icon: "ClockIcon", is_bookmarked: false},
{title: "Access Control", url: "/extensions/access-control", icon: "LockIcon", is_bookmarked: false},
{title: "I18n", url: "/extensions/i18n", icon: "GlobeIcon", is_bookmarked: false},
{title: "Carousel", url: "/extensions/carousel", icon: "LayersIcon", is_bookmarked: false},
{title: "Clipboard", url: "/extensions/clipboard", icon: "CopyIcon", is_bookmarked: false},
{title: "Context Menu", url: "/extensions/context-menu", icon: "MoreHorizontalIcon", is_bookmarked: false},
{title: "Star Rating", url: "/extensions/star-ratings", icon: "StarIcon", is_bookmarked: false},
{title: "Autocomplete", url: "/extensions/autocomplete", icon: "Edit3Icon", is_bookmarked: false},
{title: "Tree", url: "/extensions/tree", icon: "GitPullRequestIcon", is_bookmarked: false},
{title: "Import", url: "/import-export/import", icon: "FileTextIcon", is_bookmarked: false},
{title: "Export", url: "/import-export/export", icon: "ExternalLinkIcon", is_bookmarked: false},
{title: "Export Selected", url: "/import-export/export-selected", icon: "ExternalLinkIcon", is_bookmarked: false},
]
},
files: {
key:"file_name",
data: [
{ file_name: "Joe's CV", from:"Stacy Watson", file_ext:"doc", size:"1.7 mb" },
{ file_name: "Passport Image", from:"Ben Sinitiere", file_ext:"jpg", size:" 52 kb" },
{ file_name: "Questions", from:"Charleen Patti", file_ext:"doc", size:"1.5 gb" },
{ file_name: "Parenting Guide", from:"Doyle Blatteau", file_ext:"doc", size:"2.3 mb" },
{ file_name: "Class Notes", from:"Gwen Greenlow", file_ext:"doc", size:" 30 kb" },
{ file_name: "Class Attendance", from:"Tom Alred", file_ext:"xls", size:"52 mb" },
{ file_name: "Company Salary", from:"Nellie Dezan", file_ext:"xls", size:"29 mb" },
{ file_name: "Company Logo", from:"Steve Sheldon", file_ext:"jpg", size:"1.3 mb" },
{ file_name: "Crime Rates", from:"Sherlock Holmes", file_ext:"xls", size:"37 kb" },
{ file_name: "Ulysses", from:"Theresia Wrenne", file_ext:"pdf", size:"7.2 mb" },
{ file_name: "War and Peace", from:"Goldie Highnote", file_ext:"pdf", size:"10.5 mb" },
{ file_name: "Vedas", from:"Ajay Patel", file_ext:"pdf", size:"8.3 mb" },
{ file_name: "The Trial", from:"Sirena Linkert", file_ext:"pdf", size:"1.5 mb" },
]
},
contacts: {
key:"name",
data: [
{ img: require("@/assets/images/portrait/small/avatar-s-4.jpg"), name: "Rena Brant", email: "nephrod@preany.co.uk", time: "21/05/2019" },
{ img: require("@/assets/images/portrait/small/avatar-s-2.jpg"), name: "Mariano Packard", email: "seek@sparaxis.org", time: "14/01/2018" },
{ img: require("@/assets/images/portrait/small/avatar-s-24.jpg"), name: "Risa Montufar", email: "vagary@unblist.org", time: "10/08/2019" },
{ img: require("@/assets/images/portrait/small/avatar-s-15.jpg"), name: "Maragaret Cimo", email: "designed@insanely.net", time: "01/12/2019" },
{ img: require("@/assets/images/portrait/small/avatar-s-7.jpg"), name: "Jona Prattis", email: "unwieldable@unblist.org", time: "21/05/2019" },
{ img: require("@/assets/images/portrait/small/avatar-s-5.jpg"), name: "Edmond Chicon", email: "museist@anaphyte.co.uk", time: "15/11/2019" },
{ img: require("@/assets/images/portrait/small/avatar-s-25.jpg"), name: "Abbey Darden", email: "astema@defectively.co.uk", time: "07/05/2019" },
{ img: require("@/assets/images/portrait/small/avatar-s-10.jpg"), name: "Seema Moallankamp", email: "fernando@storkish.co.uk", time: "13/08/2017" },
{ img: require("@/assets/images/portrait/small/avatar-s-2.jpg"), name: "Charleen Warmington", email: "furphy@cannibal.net", time: "11/08/1891" },
{ img: require("@/assets/images/portrait/small/avatar-s-25.jpg"), name: "Geri Linch", email: "insignia@markab.org", time: "18/01/2015" },
{ img: require("@/assets/images/portrait/small/avatar-s-23.jpg"), name: "Shellie Muster", email: "maxillary@equalize.co.uk", time: "26/07/2019" },
{ img: require("@/assets/images/portrait/small/avatar-s-20.jpg"), name: "Jesenia Vanbramer", email: "hypotony@phonetist.net", time: "12/09/2017" },
{ img: require("@/assets/images/portrait/small/avatar-s-23.jpg"), name: "Mardell Channey", email: "peseta@myrica.com", time: "11/11/2019" },
]
},
}
/* eslint-enable */
@@ -0,0 +1,355 @@
<!-- =========================================================================================
File Name: VerticalNavMenu.vue
Description: Vertical NavMenu Component
Component Name: VerticalNavMenu
----------------------------------------------------------------------------------------
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template
Author: Pixinvent
Author URL: http://www.themeforest.net/user/pixinvent
========================================================================================== -->
<template>
<div class="parentx">
<vs-sidebar
class="v-nav-menu items-no-padding"
v-model="isVerticalNavMenuActive"
ref="verticalNavMenu"
default-index="-1"
:click-not-close="clickNotClose"
:reduce-not-rebound="reduceNotRebound"
:parent="parent"
:hiddenBackground="clickNotClose"
:reduce="reduce"
v-hammer:swipe="onMenuSwipe">
<div @mouseenter="mouseEnter" @mouseleave="mouseLeave">
<!-- Header -->
<div class="header-sidebar flex items-end justify-between" slot="header">
<!-- Logo -->
<router-link tag="div" class="vx-logo cursor-pointer flex items-center" to="/">
<img src="../../../../public/logo.svg" width="75px"/>
<span class="vx-logo-text text-primary" v-show="isMouseEnter || !reduce" v-if="title">{{ title }}</span>
</router-link>
<!-- /Logo -->
<!-- Menu Buttons -->
<div>
<!-- Close Button -->
<template v-if="showCloseButton">
<feather-icon icon="XIcon" class="m-0 cursor-pointer" @click="$store.commit('TOGGLE_IS_VERTICAL_NAV_MENU_ACTIVE', false)" />
</template>
<!-- Toggle Buttons -->
<template v-else-if="!showCloseButton && !verticalNavMenuItemsMin">
<!-- <feather-icon-->
<!-- id="btnVNavMenuMinToggler"-->
<!-- class="mr-0 cursor-pointer"-->
<!-- :icon="reduce ? 'CircleIcon' : 'DiscIcon'"-->
<!-- svg-classes="stroke-current text-primary"-->
<!-- @click="toggleReduce(!reduce)" />-->
</template>
</div>
<!-- /Menu Toggle Buttons -->
</div>
<!-- /Header -->
<!-- Header Shadow -->
<div class="shadow-bottom" v-show="showShadowBottom" />
<!-- Menu Items -->
<component :is="scrollbarTag" ref="verticalNavMenuPs" class="scroll-area-v-nav-menu pt-2" :settings="settings" @ps-scroll-y="psSectionScroll" @scroll="psSectionScroll" :key="$vs.rtl">
<template v-for="(item, index) in menuItemsUpdated">
<!-- Group Header -->
<span v-if="item.header && !verticalNavMenuItemsMin" class="navigation-header truncate" :key="`header-${index}`">
{{ $t(item.i18n) || item.header }}
</span>
<!-- /Group Header -->
<template v-else-if="!item.header">
<!-- Nav-Item -->
<v-nav-menu-item
v-if="!item.submenu"
:key="`item-${index}`"
:index="index"
:to="item.slug !== 'external' ? item.url : null"
:href="item.slug === 'external' ? item.url : null"
:icon="item.icon" :target="item.target"
:isDisabled="item.isDisabled"
:slug="item.slug">
<span v-show="!verticalNavMenuItemsMin" class="truncate">{{ $t(item.i18n) || item.name }}</span>
<vs-chip class="ml-auto" :color="item.tagColor" v-if="item.tag && (isMouseEnter || !reduce)">{{ item.tag }}</vs-chip>
</v-nav-menu-item>
<!-- Nav-Group -->
<template v-else>
<v-nav-menu-group
:key="`group-${index}`"
:openHover="openGroupHover"
:group="item"
:groupIndex="index"
:open="isGroupActive(item)" />
</template>
<!-- /Nav-Group -->
</template>
</template>
</component>
<!-- /Menu Items -->
</div>
</vs-sidebar>
<!-- Swipe Gesture -->
<div
v-if="!isVerticalNavMenuActive"
class="v-nav-menu-swipe-area"
v-hammer:swipe="onSwipeAreaSwipe" />
<!-- /Swipe Gesture -->
</div>
</template>
<script>
import VuePerfectScrollbar from 'vue-perfect-scrollbar'
import VNavMenuGroup from './VerticalNavMenuGroup.vue'
import VNavMenuItem from './VerticalNavMenuItem.vue'
import Logo from '../Logo.vue'
export default {
name: 'v-nav-menu',
components: {
VNavMenuGroup,
VNavMenuItem,
VuePerfectScrollbar,
Logo
},
props: {
logo: { type: String },
openGroupHover: { type: Boolean, default: false },
parent: { type: String },
reduceNotRebound: { type: Boolean, default: true },
navMenuItems: { type: Array, required: true },
title: { type: String }
},
data: () => ({
clickNotClose : false, // disable close navMenu on outside click
isMouseEnter : false,
reduce : false, // determines if navMenu is reduce - component property
showCloseButton : false, // show close button in smaller devices
settings : { // perfectScrollbar settings
maxScrollbarLength: 60,
wheelSpeed : 1,
swipeEasing : true
},
showShadowBottom : false
}),
computed: {
isGroupActive () {
return (item) => {
const path = this.$route.fullPath
const routeParent = this.$route.meta ? this.$route.meta.parent : undefined
let open = false
const func = (item) => {
if (item.submenu) {
item.submenu.forEach((item) => {
if (item.url && (path === item.url || routeParent === item.slug)) { open = true } else if (item.submenu) { func(item) }
})
}
}
func(item)
return open
}
},
menuItemsUpdated () {
const clone = this.navMenuItems.slice()
for (const [index, item] of this.navMenuItems.entries()) {
if (item.header && item.items.length && (index || 1)) {
const i = clone.findIndex(ix => ix.header === item.header)
for (const [subIndex, subItem] of item.items.entries()) {
clone.splice(i + 1 + subIndex, 0, subItem)
}
}
}
console.log(clone
)
return clone
},
isVerticalNavMenuActive: {
get () { return this.$store.state.isVerticalNavMenuActive },
set (val) { this.$store.commit('TOGGLE_IS_VERTICAL_NAV_MENU_ACTIVE', val) }
},
layoutType () { return this.$store.state.mainLayoutType },
reduceButton: {
get () { return this.$store.state.reduceButton },
set (val) { this.$store.commit('TOGGLE_REDUCE_BUTTON', val) }
},
isVerticalNavMenuReduced () { return Boolean(this.reduce && this.reduceButton) },
verticalNavMenuItemsMin () { return this.$store.state.verticalNavMenuItemsMin },
scrollbarTag () { return this.$store.getters.scrollbarTag },
windowWidth () { return this.$store.state.windowWidth }
},
watch: {
'$route' () {
if (this.isVerticalNavMenuActive && this.showCloseButton) this.$store.commit('TOGGLE_IS_VERTICAL_NAV_MENU_ACTIVE', false)
},
reduce (val) {
const verticalNavMenuWidth = val ? 'reduced' : this.$store.state.windowWidth < 1200 ? 'no-nav-menu' : 'default'
this.$store.dispatch('updateVerticalNavMenuWidth', verticalNavMenuWidth)
setTimeout(function () {
window.dispatchEvent(new Event('resize'))
}, 100)
},
layoutType () { this.setVerticalNavMenuWidth() },
reduceButton () { this.setVerticalNavMenuWidth() },
windowWidth () { this.setVerticalNavMenuWidth() }
},
methods: {
onMenuSwipe (event) {
if (event.direction === 4 && this.$vs.rtl) {
// Swipe Right
if (this.isVerticalNavMenuActive && this.showCloseButton) this.isVerticalNavMenuActive = false
} else if (event.direction === 2 && !this.$vs.rtl) {
// Swipe Left
if (this.isVerticalNavMenuActive && this.showCloseButton) this.isVerticalNavMenuActive = false
}
},
onSwipeAreaSwipe (event) {
if (event.direction === 4 && !this.$vs.rtl) {
// Swipe Right
if (!this.isVerticalNavMenuActive && this.showCloseButton) this.isVerticalNavMenuActive = true
} else if (event.direction === 2 && this.$vs.rtl) {
// Swipe Left
if (!this.isVerticalNavMenuActive && this.showCloseButton) this.isVerticalNavMenuActive = true
}
},
psSectionScroll () {
const scroll_el = this.$refs.verticalNavMenuPs.$el || this.$refs.verticalNavMenuPs
this.showShadowBottom = scroll_el.scrollTop > 0
},
mouseEnter () {
if (this.reduce) this.$store.commit('UPDATE_VERTICAL_NAV_MENU_ITEMS_MIN', false)
this.isMouseEnter = true
},
mouseLeave () {
if (this.reduce) this.$store.commit('UPDATE_VERTICAL_NAV_MENU_ITEMS_MIN', true)
this.isMouseEnter = false
},
setVerticalNavMenuWidth () {
if (this.windowWidth > 1200) {
if (this.layoutType === 'vertical') {
// Set reduce
this.reduce = !!this.reduceButton
// Open NavMenu
this.$store.commit('TOGGLE_IS_VERTICAL_NAV_MENU_ACTIVE', true)
// Set Menu Items Only Icon Mode
const verticalNavMenuItemsMin = !!(this.reduceButton && !this.isMouseEnter)
this.$store.commit('UPDATE_VERTICAL_NAV_MENU_ITEMS_MIN', verticalNavMenuItemsMin)
// Menu Action buttons
this.clickNotClose = true
this.showCloseButton = false
const verticalNavMenuWidth = this.isVerticalNavMenuReduced ? 'reduced' : 'default'
this.$store.dispatch('updateVerticalNavMenuWidth', verticalNavMenuWidth)
return
}
}
// Close NavMenu
this.$store.commit('TOGGLE_IS_VERTICAL_NAV_MENU_ACTIVE', false)
// Reduce button
if (this.reduceButton) this.reduce = false
// Menu Action buttons
this.showCloseButton = true
this.clickNotClose = false
// Update NavMenu Width
this.$store.dispatch('updateVerticalNavMenuWidth', 'no-nav-menu')
// Remove Only Icon in Menu
this.$store.commit('UPDATE_VERTICAL_NAV_MENU_ITEMS_MIN', false)
// if(this.layoutType === 'vertical' || (this.layoutType === 'horizontal' && this.windowWidth < 1200))
// if (this.windowWidth < 1200) {
// // Close NavMenu
// this.$store.commit('TOGGLE_IS_VERTICAL_NAV_MENU_ACTIVE', false)
// // Reduce button
// if (this.reduceButton) this.reduce = false
// // Menu Action buttons
// this.showCloseButton = true
// this.clickNotClose = false
// // Update NavMenu Width
// this.$store.dispatch('updateVerticalNavMenuWidth', 'no-nav-menu')
// // Remove Only Icon in Menu
// this.$store.commit('UPDATE_VERTICAL_NAV_MENU_ITEMS_MIN', false)
// } else {
// // Set reduce
// this.reduce = this.reduceButton ? true : false
// // Open NavMenu
// this.$store.commit('TOGGLE_IS_VERTICAL_NAV_MENU_ACTIVE', true)
// // Set Menu Items Only Icon Mode
// const verticalNavMenuItemsMin = (this.reduceButton && !this.isMouseEnter) ? true : false
// this.$store.commit('UPDATE_VERTICAL_NAV_MENU_ITEMS_MIN', verticalNavMenuItemsMin)
// // Menu Action buttons
// this.clickNotClose = true
// this.showCloseButton = false
// const verticalNavMenuWidth = this.isVerticalNavMenuReduced ? "reduced" : "default"
// this.$store.dispatch('updateVerticalNavMenuWidth', verticalNavMenuWidth)
// }
},
toggleReduce (val) {
this.reduceButton = val
this.setVerticalNavMenuWidth()
}
},
mounted () {
this.setVerticalNavMenuWidth()
}
}
</script>
<style lang="scss">
@import "@/assets/scss/vuexy/components/verticalNavMenu.scss";
.cursor-pointer.navbar-fuzzy-search.mr-8.feather-icon.select-none.relative{
display: none !important;
}
</style>
@@ -0,0 +1,239 @@
<!-- =========================================================================================
File Name: VerticalNavMenuGroup.vue
Description: Vertical NavMenu Group Component. Extends vuesax framework's 'vs-sidebar-group' component
Component Name: VerticalNavMenuGroup
----------------------------------------------------------------------------------------
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template
Author: Pixinvent
Author URL: http://www.themeforest.net/user/pixinvent
========================================================================================== -->
<template>
<div
class = "vs-sidebar-group"
:class = "[
{'vs-sidebar-group-open' : openItems },
{'vs-sidebar-group-active' : open },
{'disabled-item pointer-events-none': group.isDisabled }
]"
@mouseover = "mouseover"
@mouseout = "mouseout">
<!-- Group Label -->
<div @click="clickGroup" class="group-header w-full">
<span class="flex items-center w-full">
<!-- Group Icon -->
<feather-icon
v-if = "group.icon || (this.groupIndex > Math.floor(this.groupIndex))"
:icon = "group.icon || 'CircleIcon'"
:svgClasses = "{ 'w-3 h-3' : this.groupIndex % 1 != 0 }" />
<!-- Group Name -->
<span v-show="!verticalNavMenuItemsMin" class="truncate mr-3 select-none">{{ $t(group.i18n) || group.name }}</span>
<!-- Group Tag -->
<vs-chip class="ml-auto mr-4" :color="group.tagColor" v-if="group.tag && !verticalNavMenuItemsMin">{{ group.tag }}</vs-chip>
</span>
<!-- Group Collapse Icon -->
<feather-icon
v-show = "!verticalNavMenuItemsMin"
:class = "[{'rotate90' : openItems}, 'feather-grp-header-arrow']"
:icon = "$vs.rtl ? 'ChevronLeftIcon' : 'ChevronRightIcon'"
svg-classes= "w-4 h-4" />
<!-- Group Tooltip -->
<span class="vs-sidebar--tooltip">{{ $t(group.i18n) || group.name }}</span>
</div>
<!-- /Group Label -->
<!-- Group Items -->
<ul ref="items" :style="styleItems" class="vs-sidebar-group-items">
<li v-for="(groupItem, index) in group.submenu" :key="index">
<!-- If item is group -->
<v-nav-menu-group
v-if = "groupItem.submenu"
:group = "groupItem"
:groupIndex = "Number(`${groupIndex}.${index+1}`)"
:open = "isGroupActive(groupItem)"
:openHover = "openHover" />
<!-- Else: Item -->
<v-nav-menu-item
v-else
icon-small
:index = "groupIndex + '.' + index"
:to="groupItem.slug !== 'external' ? groupItem.url : null"
:href="groupItem.slug === 'external' ? groupItem.url : null"
:icon = "itemIcon(groupIndex + '.' + index)"
:slug = "groupItem.slug"
:target = "groupItem.target">
<span class="truncate">{{ $t(groupItem.i18n) || groupItem.name }}</span>
<vs-chip class="ml-auto" :color="groupItem.tagColor" v-if="groupItem.tag">{{ groupItem.tag }}</vs-chip>
</v-nav-menu-item>
</li>
</ul>
<!-- /Group Items -->
</div>
</template>
<script>
import VNavMenuItem from './VerticalNavMenuItem.vue'
export default {
name : 'v-nav-menu-group',
props : {
openHover : { type: Boolean, default: false },
open : { type: Boolean, default: false },
group : { type: Object },
groupIndex : { type: Number }
},
components: {
VNavMenuItem
},
data: () => ({
maxHeight : '0px',
openItems : false
}),
computed: {
verticalNavMenuItemsMin () { return this.$store.state.verticalNavMenuItemsMin },
styleItems () {
return { maxHeight: this.maxHeight }
},
itemIcon () {
return (index) => {
if (!((index.match(/\./g) || []).length > 1)) return 'CircleIcon'
}
},
isGroupActive () {
return (item) => {
const path = this.$route.fullPath
let open = false
const routeParent = this.$route.meta ? this.$route.meta.parent : undefined
const func = (item) => {
if (item.submenu) {
item.submenu.forEach((item) => {
if ((path === item.url || routeParent === item.slug) && item.url) { open = true } else if (item.submenu) { func(item) }
})
}
}
func(item)
return open
}
}
},
watch: {
// OPEN & CLOSES DROPDOWN ON ROUTE CHANGE
'$route' () {
if (this.verticalNavMenuItemsMin) return
const scrollHeight = this.scrollHeight
// Collapse Group
if (this.openItems && !this.open) {
this.maxHeight = `${scrollHeight}px`
setTimeout(() => {
this.maxHeight = `${0}px`
}, 50)
// Expand Group
} else if (this.open) {
this.maxHeight = `${scrollHeight}px`
setTimeout(() => {
this.maxHeight = 'none'
}, 300)
}
},
maxHeight () {
this.openItems = this.maxHeight !== '0px'
},
// OPEN AND CLOSES DROPDOWN MENU ON NavMenu COLLAPSE AND DEFAULT VIEW
'$store.state.verticalNavMenuItemsMin' (val) {
const scrollHeight = this.$refs.items.scrollHeight
if (!val && this.open) {
this.maxHeight = `${scrollHeight}px`
setTimeout(() => {
this.maxHeight = 'none'
}, 300)
} else {
this.maxHeight = `${scrollHeight}px`
setTimeout(() => {
this.maxHeight = '0px'
}, 50)
}
if (val && this.open) {
this.maxHeight = `${scrollHeight}px`
setTimeout(() => {
this.maxHeight = '0px'
}, 250)
}
}
},
methods: {
clickGroup () {
if (!this.openHover) {
const thisScrollHeight = this.$refs.items.scrollHeight
if (this.maxHeight === '0px') {
this.maxHeight = `${thisScrollHeight}px`
setTimeout(() => {
this.maxHeight = 'none'
}, 300)
} else {
this.maxHeight = `${thisScrollHeight}px`
setTimeout(() => {
this.maxHeight = `${0}px`
}, 50)
}
this.$parent.$children.map((child) => {
if (child.isGroupActive) {
if (child !== this && !child.open && child.maxHeight !== '0px') {
setTimeout(() => {
child.maxHeight = `${0}px`
}, 50)
}
}
})
}
},
mouseover () {
if (this.openHover) {
const scrollHeight = this.$refs.items.scrollHeight
this.maxHeight = `${scrollHeight}px`
}
},
mouseout () {
if (this.openHover) {
const scrollHeight = 0
this.maxHeight = `${scrollHeight}px`
}
}
},
mounted () {
this.openItems = this.open
if (this.open) { this.maxHeight = 'none' }
}
}
</script>
<style lang="scss">
@import "@/assets/scss/vuexy/components/verticalNavMenuGroup.scss"
</style>
@@ -0,0 +1,67 @@
<!-- =========================================================================================
File Name: VerticalNavMenuItem.vue
Description: Vertical NavMenu item component. Extends vuesax framework's 'vs-sidebar-item' component
Component Name: VerticalNavMenuItem
----------------------------------------------------------------------------------------
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template
Author: Pixinvent
Author URL: http://www.themeforest.net/user/pixinvent
========================================================================================== -->
<template>
<div
v-if="canSee"
class="vs-sidebar--item"
:class="[
{'vs-sidebar-item-active' : activeLink},
{'disabled-item pointer-events-none' : isDisabled}
]" >
<router-link
tabindex="-1"
v-if="to"
exact
:class="[{'router-link-active': activeLink}]"
:to="to"
:target="target" >
<vs-icon v-if="!featherIcon" :icon-pack="iconPack" :icon="icon" />
<feather-icon v-else :class="{'w-3 h-3': iconSmall}" :icon="icon" />
<slot />
</router-link>
<a v-else :target="target" :href="href" tabindex="-1">
<vs-icon v-if="!featherIcon" :icon-pack="iconPack" :icon="icon" />
<feather-icon v-else :class="{'w-3 h-3': iconSmall}" :icon="icon" />
<slot />
</a>
</div>
</template>
<script>
export default {
name: 'v-nav-menu-item',
props: {
icon : { type: String, default: '' },
iconSmall : { type: Boolean, default: false },
iconPack : { type: String, default: 'material-icons' },
href : { type: [String, null], default: '#' },
to : { type: [String, Object, null], default: null },
slug : { type: String, default: null },
index : { type: [String, Number], default: null },
featherIcon : { type: Boolean, default: true },
target : { type: String, default: '_self' },
isDisabled : { type: Boolean, default: false }
},
computed: {
canSee () {
this.$acl.check(this.$store.state.AppActiveUser.userRole)
return this.to ? this.$acl.check(this.$router.match(this.to).meta.rule) : true
},
activeLink () {
return !!((this.to === this.$route.path || this.$route.meta.parent === this.slug) && this.to)
}
}
}
</script>
@@ -0,0 +1,33 @@
export default [
{
url: '/dashboard',
name: 'داشبرد',
icon: 'HomeIcon',
i18n: 'داشبرد',
slug: "config",
},
{
url: '/config',
icon: 'LayersIcon',
i18n: 'پیکر بندی',
slug: 'config',
},
{
url: "/proposal",
name: "proposal",
slug: "proposal",
icon: "AlignJustifyIcon",
i18n: "درخواست ها",
},
{
url: "/personel",
name: "personel",
slug: "personel",
icon: "AlignJustifyIcon",
i18n: "اطلاعات پرسنلی",
},
]
@@ -0,0 +1,124 @@
<template>
<div
ref="convstooltip"
class="con-vs-tooltip"
@mouseleave="mouseleavex"
@mouseenter="mouseenterx"
@mouseup="destroy" >
<transition name="tooltip-fade">
<div
v-show="active"
ref="vstooltip"
:class="[`vs-tooltip-${positionx || position}`,`vs-tooltip-${color}`, {'after-none': noneAfter}]"
:style="style"
class="vs-tooltip">
<h4 v-if="title">{{ title }}</h4>
{{ text }}
</div>
</transition>
<slot></slot>
</div>
</template>
<script>
import utils from '@/assets/utils'
import _color from '@/assets/utils/color.js'
export default {
name:'vx-tooltip',
props:{
title:{
default:null,
type:[String, Number]
},
text:{
default:null,
type:[String, Number]
},
color:{
default:null,
type:String
},
position:{
default:'top',
type:String
},
delay:{
default:'0s',
type:[Number, String]
}
},
data:() => ({
cords:{},
active:false,
widthx: 'auto',
positionx: null,
noneAfter: false
}),
computed:{
style () {
return {
left:this.cords.left,
top:this.cords.top,
transitionDelay: this.active ? this.delay : '0s',
background:_color.getColor(this.color, 1),
width: this.widthx
}
}
},
methods:{
mouseenterx () {
this.active = true
this.$nextTick(() => {
utils.insertBody(this.$refs.vstooltip)
this.changePosition(this.$refs.convstooltip, this.$refs.vstooltip)
})
},
mouseleavex () {
this.active = false
},
changePosition (elxEvent, tooltip) {
this.noneAfter = false
this.positionx = null
const elx = elxEvent.closest('.con-vs-tooltip')
const scrollTopx = window.pageYOffset || document.documentElement.scrollTop
let topx = elx.getBoundingClientRect().top + scrollTopx - tooltip.clientHeight - 4
let leftx = elx.getBoundingClientRect().left - tooltip.clientWidth / 2 + elx.clientWidth / 2
const widthx = elx.clientWidth
if (this.position == 'bottom') {
topx = elx.getBoundingClientRect().top + scrollTopx + elx.clientHeight + 4
} else if (this.position == 'left') {
leftx = elx.getBoundingClientRect().left - tooltip.clientWidth - 4
topx = elx.getBoundingClientRect().top + scrollTopx + elx.clientHeight / 2 - tooltip.clientHeight / 2
if (Math.sign(leftx) == -1) {
leftx = elx.getBoundingClientRect().left
topx = elx.getBoundingClientRect().top + scrollTopx + elx.clientHeight + 4
this.positionx = 'bottom'
this.noneAfter = true
}
} else if (this.position == 'right') {
leftx = elx.getBoundingClientRect().left + elx.clientWidth + 4
topx = elx.getBoundingClientRect().top + scrollTopx + elx.clientHeight / 2 - tooltip.clientHeight / 2
if (window.innerWidth - (leftx + tooltip.clientWidth) <= 20) {
leftx = elx.getBoundingClientRect().left - tooltip.clientWidth / 2 - 10
topx = elx.getBoundingClientRect().top + scrollTopx + elx.clientHeight + 4
this.positionx = 'bottom'
this.noneAfter = true
}
}
this.cords = {
left: `${leftx}px`,
top: `${topx}px`,
width: `${widthx}px`
}
},
destroy () {
this.active = false
this.$nextTick(() => {
if (this.active) {
utils.removeBody(this.$refs.vstooltip)
}
})
}
}
}
</script>
+15
View File
@@ -0,0 +1,15 @@
<!-- =========================================================================================
File Name: FullPage.vue
Description: Full page layout
----------------------------------------------------------------------------------------
Item Name: Vuexy - Vuejs, HTML & Laravel Admin Dashboard Template
Author: Pixinvent
Author URL: http://www.themeforest.net/user/pixinvent
========================================================================================== -->
<template>
<div class="layout--full-page">
<router-view></router-view>
</div>
</template>
+265
View File
@@ -0,0 +1,265 @@
<template>
<div class="layout--main" :class="[layoutTypeClass, navbarClasses, footerClasses, {'no-scroll': isAppPage}]">
<vx-tour :steps="steps" v-if="!disableThemeTour && (windowWidth >= 1200 && mainLayoutType === 'vertical' && verticalNavMenuWidth == 'default')" />
<v-nav-menu
:navMenuItems = "navMenuItems"
title = ""
parent = ".layout--main" />
<div id="content-area" :class="[contentAreaClass, {'show-overlay': bodyOverlay}]">
<div id="content-overlay" />
<!-- Navbar -->
<template v-if="mainLayoutType === 'horizontal' && windowWidth >= 1200">
<the-navbar-horizontal
:navbarType= "navbarType"
:class="[
{'text-white' : isNavbarDark && !isThemeDark},
{'text-base' : !isNavbarDark && isThemeDark}
]" />
<div style="height: 62px" v-if="navbarType === 'static'"></div>
<h-nav-menu
:class="[
{'text-white' : isNavbarDark && !isThemeDark},
{'text-base' : !isNavbarDark && isThemeDark}
]"
:navMenuItems="navMenuItems" />
</template>
<template v-else>
<the-navbar-vertical
:navbarColor="navbarColor"
:class="[
{'text-white' : isNavbarDark && !isThemeDark},
{'text-base' : !isNavbarDark && isThemeDark}
]" />
</template>
<!-- /Navbar -->
<div class="content-wrapper">
<div class="router-view">
<div class="router-content">
<transition :name="routerTransition">
<div v-if="$route.meta.breadcrumb || $route.meta.pageTitle" class="router-header flex flex-wrap items-center mb-6">
<div
class="content-area__heading"
:class="{'pr-4 border-0 md:border-r border-solid border-grey-light' : $route.meta.breadcrumb}">
<h2 class="mb-1">{{ routeTitle }}</h2>
</div>
<!-- BREADCRUMB -->
<vx-breadcrumb class="ml-4 md:block hidden" v-if="$route.meta.breadcrumb" :route="$route" :isRTL="$vs.rtl" />
</div>
</transition>
<div class="content-area__content">
<back-to-top bottom="5%" :right="$vs.rtl ? 'calc(100% - 2.2rem - 38px)' : '30px'" visibleoffset="500" v-if="!hideScrollToTop">
<vs-button icon-pack="feather" icon="icon-arrow-up" class="shadow-lg btn-back-to-top" />
</back-to-top>
<transition :name="routerTransition" mode="out-in">
<router-view @changeRouteTitle="changeRouteTitle" @setAppClasses="(classesStr) => $emit('setAppClasses', classesStr)" />
</transition>
</div>
</div>
</div>
</div>
<the-footer />
</div>
</div>
</template>
<script>
import BackToTop from 'vue-backtotop'
import HNavMenu from '@/layouts/components/horizontal-nav-menu/HorizontalNavMenu.vue'
import navMenuItems from '@/layouts/components/vertical-nav-menu/navMenuItems.js'
import TheCustomizer from '@/layouts/components/customizer/TheCustomizer.vue'
import TheNavbarHorizontal from '@/layouts/components/navbar/TheNavbarHorizontal.vue'
import TheNavbarVertical from '@/layouts/components/navbar/TheNavbarVertical.vue'
import TheFooter from '@/layouts/components/TheFooter.vue'
import themeConfig from '@/../themeConfig.js'
import VNavMenu from '@/layouts/components/vertical-nav-menu/VerticalNavMenu.vue'
const VxTour = () => import('@/components/VxTour.vue')
export default {
components: {
BackToTop,
HNavMenu,
TheCustomizer,
TheFooter,
TheNavbarHorizontal,
TheNavbarVertical,
VNavMenu,
VxTour
},
data () {
return {
disableCustomizer : themeConfig.disableCustomizer,
disableThemeTour : themeConfig.disableThemeTour,
dynamicWatchers : {},
footerType : themeConfig.footerType || 'static',
hideScrollToTop : themeConfig.hideScrollToTop,
isNavbarDark : false,
navbarColor : themeConfig.navbarColor || '#fff',
navbarType : themeConfig.navbarType || 'floating',
navMenuItems,
routerTransition : themeConfig.routerTransition || 'none',
routeTitle : this.$route.meta.pageTitle,
steps: [
{
target : '#btnVNavMenuMinToggler',
content : 'Toggle Collapse Sidebar.'
},
{
target : '.vx-navbar__starred-pages',
content : 'Create your own bookmarks. You can also re-arrange them using drag & drop.'
},
{
target : '.i18n-locale',
content : 'You can change language from here.'
},
{
target : '.navbar-fuzzy-search',
content : 'Try fuzzy search to visit pages in flash.'
},
{
target : '.customizer-btn',
content : 'Customize template based on your preference',
params : {
placement: 'left'
}
},
{
target : '.vs-button.buy-now',
content : 'Buy this awesomeness at affordable price!',
params : {
placement: 'top'
}
}
]
}
},
watch: {
'$route' () {
this.routeTitle = this.$route.meta.pageTitle
},
isThemeDark (val) {
const color = this.navbarColor === '#fff' && val ? '#10163a' : '#fff'
this.updateNavbarColor(color)
},
'$store.state.mainLayoutType' (val) {
this.setNavMenuVisibility(val)
this.disableThemeTour = true
}
},
computed: {
bodyOverlay () { return this.$store.state.bodyOverlay },
contentAreaClass () {
if (this.mainLayoutType === 'vertical') {
if (this.verticalNavMenuWidth === 'default') return 'content-area-reduced'
else if (this.verticalNavMenuWidth === 'reduced') return 'content-area-lg'
else return 'content-area-full'
} else return 'content-area-full'
},
footerClasses () {
return {
'footer-hidden': this.footerType === 'hidden',
'footer-sticky': this.footerType === 'sticky',
'footer-static': this.footerType === 'static'
}
},
isAppPage () {
return this.$route.meta.no_scroll
},
isThemeDark () { return this.$store.state.theme === 'dark' },
layoutTypeClass () { return `main-${this.mainLayoutType}` },
mainLayoutType () { return this.$store.state.mainLayoutType },
navbarClasses () {
return {
'navbar-hidden' : this.navbarType === 'hidden',
'navbar-sticky' : this.navbarType === 'sticky',
'navbar-static' : this.navbarType === 'static',
'navbar-floating' : this.navbarType === 'floating'
}
},
verticalNavMenuWidth () { return this.$store.state.verticalNavMenuWidth },
windowWidth () { return this.$store.state.windowWidth }
},
methods: {
changeRouteTitle (title) {
this.routeTitle = title
},
updateNavbar (val) {
if (val === 'static') this.updateNavbarColor(this.isThemeDark ? '#10163a' : '#fff')
this.navbarType = val
},
updateNavbarColor (val) {
this.navbarColor = val
if (val === '#fff') this.isNavbarDark = false
else this.isNavbarDark = true
},
updateFooter (val) {
this.footerType = val
},
updateRouterTransition (val) {
this.routerTransition = val
},
setNavMenuVisibility (layoutType) {
if ((layoutType === 'horizontal' && this.windowWidth >= 1200) || (layoutType === 'vertical' && this.windowWidth < 1200)) {
this.$store.commit('TOGGLE_IS_VERTICAL_NAV_MENU_ACTIVE', false)
this.$store.dispatch('updateVerticalNavMenuWidth', 'no-nav-menu')
} else {
this.$store.commit('TOGGLE_IS_VERTICAL_NAV_MENU_ACTIVE', true)
}
},
toggleHideScrollToTop (val) {
this.hideScrollToTop = val
}
},
created () {
const color = this.navbarColor === '#fff' && this.isThemeDark ? '#10163a' : this.navbarColor
this.updateNavbarColor(color)
this.setNavMenuVisibility(this.$store.state.mainLayoutType)
// Dynamic Watchers for tour
// Reason: Once tour is disabled it is not required to enable it.
// So, watcher is required for just disabling it.
this.dynamicWatchers.windowWidth = this.$watch('$store.state.windowWidth', (val) => {
if (val < 1200) {
this.disableThemeTour = true
this.dynamicWatchers.windowWidth()
}
})
this.dynamicWatchers.verticalNavMenuWidth = this.$watch('$store.state.verticalNavMenuWidth', () => {
this.disableThemeTour = true
this.dynamicWatchers.verticalNavMenuWidth()
})
this.dynamicWatchers.rtl = this.$watch('$vs.rtl', () => {
this.disableThemeTour = true
this.dynamicWatchers.rtl()
})
},
beforeDestroy () {
Object.keys(this.dynamicWatchers).map(i => {
this.dynamicWatchers[i]()
delete this.dynamicWatchers[i]
})
}
}
</script>