Merge branch 'feat/sidebar-v2' into wip2
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 454 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 873 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 978 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 946 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 779 B |
@ -2,7 +2,7 @@
|
|||||||
<header class="header-component">
|
<header class="header-component">
|
||||||
<dx-toolbar class="header-toolbar" style="background-image: url('images/bg-header.jpg');">
|
<dx-toolbar class="header-toolbar" style="background-image: url('images/bg-header.jpg');">
|
||||||
<dx-item
|
<dx-item
|
||||||
:visible="menuToggleEnabled"
|
:visible="false"
|
||||||
location="before"
|
location="before"
|
||||||
css-class="menu-button"
|
css-class="menu-button"
|
||||||
>
|
>
|
||||||
@ -142,7 +142,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.header-title .dx-item-content {
|
.header-title .dx-item-content {
|
||||||
padding: 0;
|
padding: 0 24px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,26 +1,31 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="dx-swatch-additional side-navigation-menu"
|
class="side-navigation-menu"
|
||||||
@click="forwardClick"
|
@click="forwardClick"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
<div class="menu-container">
|
<div v-for="item in menus" :key="item.id" class="relative-view">
|
||||||
<dx-tree-view
|
<img :src="item.icon" alt="icon" @click="handleIconClick(item.text)" :class="selectedMenus === item.text ? 'active-icons' : 'icons'">
|
||||||
ref="treeViewRef"
|
|
||||||
:items="menus"
|
<div ref="expandRef" v-if="item.text === selectedMenus" class="absolute-view">
|
||||||
key-expr="path"
|
<div class="expand-title">
|
||||||
selection-mode="single"
|
<p>{{item.text}}</p>
|
||||||
:focus-state-enabled="false"
|
</div>
|
||||||
expand-event="click"
|
|
||||||
@item-click="handleItemClick"
|
<dx-scroll-view ref="scrollViewRef" :class="checkLength(item.items) ? 'expand-menu-height' : 'expand-menu'">
|
||||||
width="100%"
|
<div v-for="it in item.items" :key="it.id" class="no-wrap">
|
||||||
/>
|
<p :class="route.path === it.path ? 'pointer-active' : 'pointer'" @click="handleItemClick(item.text,it.path)">
|
||||||
|
{{it.text}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</dx-scroll-view>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DxTreeView from "devextreme-vue/ui/tree-view";
|
import DxScrollView from "devextreme-vue/scroll-view";
|
||||||
import { sizes } from '../utils/media-query';
|
import { sizes } from '../utils/media-query';
|
||||||
import navigation from '../app-navigation';
|
import navigation from '../app-navigation';
|
||||||
import { onMounted, ref, watch } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
@ -36,7 +41,12 @@ export default {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const menus = ref("");
|
const menus = ref("");
|
||||||
auth.getUser().then((e) => menus.value = e.data.menus);
|
const selectedMenus = ref("")
|
||||||
|
|
||||||
|
auth.getUser().then((e) => {
|
||||||
|
const listMenu = e.data.menus.filter((it) => it.text !== "Home")
|
||||||
|
menus.value = listMenu
|
||||||
|
});
|
||||||
//console.log(navigation);
|
//console.log(navigation);
|
||||||
console.log(menus);
|
console.log(menus);
|
||||||
|
|
||||||
@ -48,29 +58,39 @@ export default {
|
|||||||
return {...item, expanded: isLargeScreen}
|
return {...item, expanded: isLargeScreen}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const expandRef = ref(null)
|
||||||
const treeViewRef = ref(null);
|
const treeViewRef = ref(null);
|
||||||
|
const scrollViewRef = ref(null);
|
||||||
|
|
||||||
function forwardClick (...args) {
|
function forwardClick (...args) {
|
||||||
context.emit("click", args);
|
context.emit("click", args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleItemClick(e) {
|
function handleItemClick(text, path) {
|
||||||
if (!e.itemData.path || props.compactMode) {
|
if (!path) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
router.push(e.itemData.path);
|
router.push(path);
|
||||||
|
selectedMenus.value = text
|
||||||
|
}
|
||||||
|
|
||||||
const pointerEvent = e.event;
|
function handleIconClick(text) {
|
||||||
pointerEvent.stopPropagation();
|
if(text === selectedMenus.value) {
|
||||||
|
selectedMenus.value = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
selectedMenus.value = text
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSelection () {
|
function updateSelection () {
|
||||||
if (!treeViewRef.value || !treeViewRef.value.instance) {
|
if(route.path === "/home") {
|
||||||
return;
|
selectedMenus.value = "Home"
|
||||||
|
selectedMenus.value = ""
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
treeViewRef.value.instance.selectItem(route.path);
|
function checkLength(it) {
|
||||||
treeViewRef.value.instance.expandItem(route.path);
|
return it.length > 4
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -105,11 +125,16 @@ export default {
|
|||||||
forwardClick,
|
forwardClick,
|
||||||
handleItemClick,
|
handleItemClick,
|
||||||
updateSelection,
|
updateSelection,
|
||||||
menus
|
menus,
|
||||||
|
route,
|
||||||
|
selectedMenus,
|
||||||
|
handleIconClick,
|
||||||
|
scrollViewRef,
|
||||||
|
checkLength,
|
||||||
|
expandRef
|
||||||
};
|
};
|
||||||
},
|
},components: {
|
||||||
components: {
|
DxScrollView
|
||||||
DxTreeView
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@ -117,95 +142,95 @@ export default {
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../dx-styles.scss";
|
@import "../dx-styles.scss";
|
||||||
@import "../themes/generated/variables.additional.scss";
|
@import "../themes/generated/variables.additional.scss";
|
||||||
|
@import "../themes/generated/variables.base.scss";
|
||||||
|
|
||||||
.side-navigation-menu {
|
.side-navigation-menu {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 250px !important;
|
width: $side-bar-width !important;
|
||||||
|
box-shadow: $base-shadow-color 4px 100px 10px 0px !important;
|
||||||
|
padding-top: 25px !important;
|
||||||
|
background-color: white;
|
||||||
|
padding-left: 9px;
|
||||||
|
|
||||||
.menu-container {
|
.relative-view {
|
||||||
min-height: 100%;
|
position: relative;
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
.dx-treeview {
|
.icons {
|
||||||
// ## Long text positioning
|
border-radius: 4px !important;
|
||||||
white-space: nowrap;
|
width: $side-bar-icon-size !important;
|
||||||
// ##
|
height: $side-bar-icon-size !important;
|
||||||
|
border: 1px solid $base-border-color !important;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
// ## Icon width customization
|
.active-icons {
|
||||||
.dx-treeview-item {
|
border-radius: 4px !important;
|
||||||
padding-left: 0;
|
width: $side-bar-icon-size !important;
|
||||||
padding-right: 0;
|
height: $side-bar-icon-size !important;
|
||||||
|
border: 1px solid $datagrid-columnchooser-item-color !important;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.dx-icon {
|
.absolute-view {
|
||||||
width: $side-panel-min-width !important;
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
|
background: transparent;
|
||||||
|
left: $side-bar-expand-left;
|
||||||
|
width: $side-bar-expand-width;
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
background: white;
|
||||||
|
padding: 4px 38px;
|
||||||
|
color: $base-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer-active {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
background: white;
|
||||||
|
padding: 4px 38px;
|
||||||
|
color: $datagrid-columnchooser-item-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-title {
|
||||||
|
border-radius: 0px 8px 0px 0px !important;
|
||||||
|
background: $datagrid-columnchooser-item-color;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
}
|
color: white;
|
||||||
}
|
padding: 1px 22px;
|
||||||
// ##
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
// ## Arrow customization
|
|
||||||
.dx-treeview-node {
|
|
||||||
padding: 0 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dx-treeview-toggle-item-visibility {
|
|
||||||
right: 10px;
|
|
||||||
left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dx-rtl .dx-treeview-toggle-item-visibility {
|
|
||||||
left: 10px;
|
|
||||||
right: auto;
|
|
||||||
}
|
|
||||||
// ##
|
|
||||||
|
|
||||||
// ## Item levels customization
|
|
||||||
.dx-treeview-node {
|
|
||||||
&[aria-level="1"] {
|
|
||||||
font-weight: bold;
|
|
||||||
border-bottom: 1px solid $base-border-color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&[aria-level="2"] .dx-treeview-item-content {
|
.expand-menu {
|
||||||
font-weight: normal;
|
background: white;
|
||||||
padding: 0 $side-panel-min-width;
|
margin-top: 0px !important;
|
||||||
|
padding: 8px 0px;
|
||||||
|
border-radius: 0px 0px 8px 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-menu-height {
|
||||||
|
background: white;
|
||||||
|
margin-top: 0px !important;
|
||||||
|
padding: 8px 0px;
|
||||||
|
border-radius: 0px 0px 8px 0px !important;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-wrap {
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ##
|
|
||||||
}
|
|
||||||
|
|
||||||
// ## Selected & Focuced items customization
|
|
||||||
.dx-treeview {
|
|
||||||
.dx-treeview-node-container {
|
|
||||||
.dx-treeview-node {
|
|
||||||
&.dx-state-selected:not(.dx-state-focused) > .dx-treeview-item {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.dx-state-selected > .dx-treeview-item * {
|
|
||||||
color: $base-accent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.dx-state-focused) > .dx-treeview-item.dx-state-hover {
|
|
||||||
background-color: lighten($base-bg, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dx-theme-generic .dx-treeview {
|
|
||||||
.dx-treeview-node-container
|
|
||||||
.dx-treeview-node.dx-state-selected.dx-state-focused
|
|
||||||
> .dx-treeview-item
|
|
||||||
* {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// ##
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -67,3 +67,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$side-panel-min-width: 60px;
|
$side-panel-min-width: 60px;
|
||||||
|
$side-bar-width: 76px;
|
||||||
|
$side-bar-expand-left: 70px;
|
||||||
|
$side-bar-icon-size: 56px;
|
||||||
|
$side-bar-expand-width: 239px;
|
||||||
|
$base-shadow-color: #3333331A;
|
@ -9,7 +9,6 @@
|
|||||||
<dx-drawer
|
<dx-drawer
|
||||||
class="layout-body"
|
class="layout-body"
|
||||||
position="before"
|
position="before"
|
||||||
template="menuTemplate"
|
|
||||||
v-model:opened="menuOpened"
|
v-model:opened="menuOpened"
|
||||||
:opened-state-mode="drawerOptions.menuMode"
|
:opened-state-mode="drawerOptions.menuMode"
|
||||||
:reveal-mode="drawerOptions.menuRevealMode"
|
:reveal-mode="drawerOptions.menuRevealMode"
|
||||||
@ -18,16 +17,18 @@
|
|||||||
:shading="drawerOptions.shaderEnabled"
|
:shading="drawerOptions.shaderEnabled"
|
||||||
:close-on-outside-click="drawerOptions.closeOnOutsideClick"
|
:close-on-outside-click="drawerOptions.closeOnOutsideClick"
|
||||||
>
|
>
|
||||||
<dx-scroll-view ref="scrollViewRef" class="with-footer">
|
<div class="flex">
|
||||||
<slot />
|
<div class="sidebar">
|
||||||
<slot name="footer" />
|
<side-nav-menu
|
||||||
</dx-scroll-view>
|
:compact-mode="!menuOpened"
|
||||||
<template #menuTemplate>
|
@click="handleSideBarClick"
|
||||||
<side-nav-menu
|
/>
|
||||||
:compact-mode="!menuOpened"
|
</div>
|
||||||
@click="handleSideBarClick"
|
<dx-scroll-view ref="scrollViewRef" class="with-footer">
|
||||||
/>
|
<slot />
|
||||||
</template>
|
<slot name="footer" />
|
||||||
|
</dx-scroll-view>
|
||||||
|
</div>
|
||||||
</dx-drawer>
|
</dx-drawer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -122,6 +123,8 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@import "../dx-styles.scss";
|
||||||
|
|
||||||
.side-nav-outer-toolbar {
|
.side-nav-outer-toolbar {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -132,4 +135,14 @@ export default {
|
|||||||
.layout-header {
|
.layout-header {
|
||||||
z-index: 1501;
|
z-index: 1501;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: $side-bar-width;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|