devextreme-cli 1.3.0-beta.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/index.js +1 -1
  2. package/package.json +32 -9
  3. package/src/application.js +1 -1
  4. package/src/applications/application.angular.js +46 -10
  5. package/src/applications/application.react.js +6 -4
  6. package/src/applications/application.vue.js +102 -35
  7. package/src/commands.json +34 -25
  8. package/src/templates/react/application/src/App.js +3 -3
  9. package/src/templates/react/application/src/Content.js +1 -1
  10. package/src/templates/react/application/src/{NotAuthenticatedContent.js → UnauthenticatedContent.js} +1 -1
  11. package/src/templates/react/application/src/api/auth.js +1 -1
  12. package/src/templates/react/application/src/app-info.js +4 -2
  13. package/src/templates/react/application/src/components/change-password-form/change-password-form.js +1 -1
  14. package/src/templates/react/application/src/components/create-account-form/create-account-form.js +1 -1
  15. package/src/templates/react/application/src/components/footer/footer.js +2 -2
  16. package/src/templates/react/application/src/components/header/header.js +37 -37
  17. package/src/templates/react/application/src/components/login-form/login-form.js +1 -1
  18. package/src/templates/react/application/src/components/reset-password-form/reset-password-form.js +2 -2
  19. package/src/templates/react/application/src/components/side-navigation-menu/side-navigation-menu.js +5 -5
  20. package/src/templates/react/application/src/components/user-panel/user-panel.js +8 -2
  21. package/src/templates/react/application/src/dx-styles.scss +6 -1
  22. package/src/templates/react/application/src/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.js +1 -1
  23. package/src/templates/react/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.js +1 -1
  24. package/src/templates/react/application/src/layouts/single-card/single-card.js +11 -10
  25. package/src/templates/react/application/src/utils/media-query.js +1 -1
  26. package/src/templates/react/application/src/utils/patches.scss +1 -1
  27. package/src/templates/react/sample-pages/home/home.js +47 -46
  28. package/src/templates/react/sample-pages/profile/profile.js +3 -3
  29. package/src/templates/react/sample-pages/tasks/tasks.js +70 -68
  30. package/src/templates/vue-v2/application/devextreme.json +38 -0
  31. package/src/templates/{vue → vue-v2}/application/src/App.vue +3 -3
  32. package/src/templates/{vue → vue-v2}/application/src/app-info.js +0 -0
  33. package/src/templates/{vue → vue-v2}/application/src/app-navigation.js +0 -0
  34. package/src/templates/{vue → vue-v2}/application/src/auth.js +0 -0
  35. package/src/templates/{vue/application/src/components/the-footer.vue → vue-v2/application/src/components/app-footer.vue} +0 -0
  36. package/src/templates/{vue → vue-v2}/application/src/components/header-toolbar.vue +8 -1
  37. package/src/templates/{vue → vue-v2}/application/src/components/side-nav-menu.vue +0 -0
  38. package/src/templates/{vue → vue-v2}/application/src/components/user-panel.vue +0 -0
  39. package/src/templates/{vue → vue-v2}/application/src/dx-styles.scss +4 -0
  40. package/src/templates/{vue → vue-v2}/application/src/layouts/side-nav-inner-toolbar.vue +0 -0
  41. package/src/templates/{vue → vue-v2}/application/src/layouts/side-nav-outer-toolbar.vue +0 -0
  42. package/src/templates/{vue → vue-v2}/application/src/layouts/single-card.vue +0 -0
  43. package/src/templates/{vue → vue-v2}/application/src/main.js +0 -0
  44. package/src/templates/{vue → vue-v2}/application/src/router.js +3 -3
  45. package/src/templates/{vue → vue-v2}/application/src/themes/metadata.additional.json +0 -0
  46. package/src/templates/{vue → vue-v2}/application/src/themes/metadata.base.json +0 -0
  47. package/src/templates/{vue → vue-v2}/application/src/utils/media-query.js +0 -0
  48. package/src/templates/{vue → vue-v2}/application/src/views/change-password-form.vue +2 -3
  49. package/src/templates/{vue → vue-v2}/application/src/views/create-account-form.vue +2 -3
  50. package/src/templates/{vue → vue-v2}/application/src/views/login-form.vue +2 -3
  51. package/src/templates/{vue → vue-v2}/application/src/views/reset-password-form.vue +2 -3
  52. package/src/templates/{vue → vue-v2}/application/vue.config.js +0 -0
  53. package/src/templates/{vue → vue-v2}/page/page.vue +0 -0
  54. package/src/templates/{vue/sample-pages/home.vue → vue-v2/sample-pages/home-page.vue} +5 -5
  55. package/src/templates/{vue/sample-pages/profile.vue → vue-v2/sample-pages/profile-page.vue} +1 -1
  56. package/src/templates/{vue/sample-pages/tasks.vue → vue-v2/sample-pages/tasks-page.vue} +1 -0
  57. package/src/templates/{vue → vue-v3}/application/devextreme.json +3 -0
  58. package/src/templates/vue-v3/application/src/App.vue +101 -0
  59. package/src/templates/vue-v3/application/src/app-info.js +3 -0
  60. package/src/templates/vue-v3/application/src/app-navigation.js +21 -0
  61. package/src/templates/vue-v3/application/src/auth.js +101 -0
  62. package/src/templates/vue-v3/application/src/components/app-footer.vue +21 -0
  63. package/src/templates/vue-v3/application/src/components/header-toolbar.vue +161 -0
  64. package/src/templates/vue-v3/application/src/components/side-nav-menu.vue +204 -0
  65. package/src/templates/vue-v3/application/src/components/user-panel.vue +114 -0
  66. package/src/templates/vue-v3/application/src/dx-styles.scss +57 -0
  67. package/src/templates/vue-v3/application/src/layouts/side-nav-inner-toolbar.vue +192 -0
  68. package/src/templates/vue-v3/application/src/layouts/side-nav-outer-toolbar.vue +144 -0
  69. package/src/templates/vue-v3/application/src/layouts/single-card.vue +83 -0
  70. package/src/templates/vue-v3/application/src/main.js +10 -0
  71. package/src/templates/vue-v3/application/src/router.js +130 -0
  72. package/src/templates/vue-v3/application/src/themes/metadata.additional.json +12 -0
  73. package/src/templates/vue-v3/application/src/themes/metadata.base.json +7 -0
  74. package/src/templates/vue-v3/application/src/utils/media-query.js +33 -0
  75. package/src/templates/vue-v3/application/src/views/change-password-form.vue +115 -0
  76. package/src/templates/vue-v3/application/src/views/create-account-form.vue +155 -0
  77. package/src/templates/vue-v3/application/src/views/login-form.vue +146 -0
  78. package/src/templates/vue-v3/application/src/views/reset-password-form.vue +117 -0
  79. package/src/templates/vue-v3/application/vue.config.js +3 -0
  80. package/src/templates/vue-v3/page/page.vue +13 -0
  81. package/src/templates/vue-v3/sample-pages/home-page.vue +173 -0
  82. package/src/templates/vue-v3/sample-pages/profile-page.vue +88 -0
  83. package/src/templates/vue-v3/sample-pages/tasks-page.vue +133 -0
  84. package/src/themebuider.js +42 -63
  85. package/src/utility/latest-versions.js +3 -3
  86. package/src/utility/package-manager.js +8 -2
  87. package/src/{layout.js → utility/prompts/layout.js} +4 -4
  88. package/src/utility/prompts/prompts.js +16 -0
  89. package/src/utility/prompts/vue-version.js +29 -0
  90. package/src/utility/run-command.js +8 -6
  91. package/src/utility/prompts.js +0 -11
@@ -0,0 +1,204 @@
1
+ <template>
2
+ <div
3
+ class="dx-swatch-additional side-navigation-menu"
4
+ @click="forwardClick"
5
+ >
6
+ <slot />
7
+ <div class="menu-container">
8
+ <dx-tree-view
9
+ ref="treeViewRef"
10
+ :items="items"
11
+ key-expr="path"
12
+ selection-mode="single"
13
+ :focus-state-enabled="false"
14
+ expand-event="click"
15
+ @item-click="handleItemClick"
16
+ width="100%"
17
+ />
18
+ </div>
19
+ </div>
20
+ </template>
21
+
22
+ <script>
23
+ import DxTreeView from "devextreme-vue/ui/tree-view";
24
+ import { sizes } from '../utils/media-query';
25
+ import navigation from '../app-navigation';
26
+ import { onMounted, ref, watch } from 'vue';
27
+ import { useRoute, useRouter } from 'vue-router';
28
+
29
+ export default {
30
+ props: {
31
+ compactMode: Boolean
32
+ },
33
+ setup(props, context) {
34
+ const route = useRoute();
35
+ const router = useRouter();
36
+
37
+ const isLargeScreen = sizes()['screen-large'];
38
+ const items = navigation.map((item) => {
39
+ if(item.path && !(/^\//.test(item.path))){
40
+ item.path = `/${item.path}`;
41
+ }
42
+ return {...item, expanded: isLargeScreen}
43
+ });
44
+
45
+ const treeViewRef = ref(null);
46
+
47
+ function forwardClick (...args) {
48
+ context.emit("click", args);
49
+ }
50
+
51
+ function handleItemClick(e) {
52
+ if (!e.itemData.path || props.compactMode) {
53
+ return;
54
+ }
55
+ router.push(e.itemData.path);
56
+
57
+ const pointerEvent = e.event;
58
+ pointerEvent.stopPropagation();
59
+ }
60
+
61
+ function updateSelection () {
62
+ if (!treeViewRef.value || !treeViewRef.value.instance) {
63
+ return;
64
+ }
65
+
66
+ treeViewRef.value.instance.selectItem(route.path);
67
+ treeViewRef.value.instance.expandItem(route.path);
68
+ }
69
+
70
+ onMounted(() => {
71
+ updateSelection();
72
+ if (props.compactMode) {
73
+ treeViewRef.value.instance.collapseAll();
74
+ }
75
+ });
76
+
77
+
78
+ watch(
79
+ () => route.path,
80
+ () => {
81
+ updateSelection();
82
+ }
83
+ );
84
+
85
+ watch(
86
+ () => props.compactMode,
87
+ () => {
88
+ if (props.compactMode) {
89
+ treeViewRef.value.instance.collapseAll();
90
+ } else {
91
+ updateSelection();
92
+ }
93
+ }
94
+ );
95
+
96
+ return {
97
+ treeViewRef,
98
+ items,
99
+ forwardClick,
100
+ handleItemClick,
101
+ updateSelection
102
+ };
103
+ },
104
+ components: {
105
+ DxTreeView
106
+ }
107
+ };
108
+ </script>
109
+
110
+ <style lang="scss">
111
+ @import "../dx-styles.scss";
112
+ @import "../themes/generated/variables.additional.scss";
113
+
114
+ .side-navigation-menu {
115
+ display: flex;
116
+ flex-direction: column;
117
+ min-height: 100%;
118
+ height: 100%;
119
+ width: 250px !important;
120
+
121
+ .menu-container {
122
+ min-height: 100%;
123
+ display: flex;
124
+ flex: 1;
125
+
126
+ .dx-treeview {
127
+ // ## Long text positioning
128
+ white-space: nowrap;
129
+ // ##
130
+
131
+ // ## Icon width customization
132
+ .dx-treeview-item {
133
+ padding-left: 0;
134
+ padding-right: 0;
135
+
136
+ .dx-icon {
137
+ width: $side-panel-min-width !important;
138
+ margin: 0 !important;
139
+ }
140
+ }
141
+ // ##
142
+
143
+ // ## Arrow customization
144
+ .dx-treeview-node {
145
+ padding: 0 0 !important;
146
+ }
147
+
148
+ .dx-treeview-toggle-item-visibility {
149
+ right: 10px;
150
+ left: auto;
151
+ }
152
+
153
+ .dx-rtl .dx-treeview-toggle-item-visibility {
154
+ left: 10px;
155
+ right: auto;
156
+ }
157
+ // ##
158
+
159
+ // ## Item levels customization
160
+ .dx-treeview-node {
161
+ &[aria-level="1"] {
162
+ font-weight: bold;
163
+ border-bottom: 1px solid $base-border-color;
164
+ }
165
+
166
+ &[aria-level="2"] .dx-treeview-item-content {
167
+ font-weight: normal;
168
+ padding: 0 $side-panel-min-width;
169
+ }
170
+ }
171
+ // ##
172
+ }
173
+
174
+ // ## Selected & Focuced items customization
175
+ .dx-treeview {
176
+ .dx-treeview-node-container {
177
+ .dx-treeview-node {
178
+ &.dx-state-selected:not(.dx-state-focused) > .dx-treeview-item {
179
+ background: transparent;
180
+ }
181
+
182
+ &.dx-state-selected > .dx-treeview-item * {
183
+ color: $base-accent;
184
+ }
185
+
186
+ &:not(.dx-state-focused) > .dx-treeview-item.dx-state-hover {
187
+ background-color: lighten($base-bg, 4);
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ .dx-theme-generic .dx-treeview {
194
+ .dx-treeview-node-container
195
+ .dx-treeview-node.dx-state-selected.dx-state-focused
196
+ > .dx-treeview-item
197
+ * {
198
+ color: inherit;
199
+ }
200
+ }
201
+ // ##
202
+ }
203
+ }
204
+ </style>
@@ -0,0 +1,114 @@
1
+ <template>
2
+ <div class="user-panel">
3
+ <div class="user-info">
4
+ <div class="image-container">
5
+ <div class="user-image" />
6
+ </div>
7
+ <div class="user-name">{{email}}</div>
8
+ </div>
9
+
10
+ <dx-context-menu
11
+ v-if="menuMode === 'context'"
12
+ target=".user-button"
13
+ :items="menuItems"
14
+ :width="210"
15
+ show-event="dxclick"
16
+ css-class="user-menu"
17
+ >
18
+ <dx-position my="top center" at="bottom center" />
19
+ </dx-context-menu>
20
+
21
+ <dx-list
22
+ v-if="menuMode === 'list'"
23
+ class="dx-toolbar-menu-action"
24
+ :items="menuItems"
25
+ />
26
+ </div>
27
+ </template>
28
+
29
+ <script>
30
+ import DxContextMenu, { DxPosition } from "devextreme-vue/context-menu";
31
+ import DxList from "devextreme-vue/list";
32
+
33
+ export default {
34
+ props: {
35
+ menuMode: String,
36
+ menuItems: Array,
37
+ email: String
38
+ },
39
+ components: {
40
+ DxContextMenu,
41
+ DxPosition,
42
+ DxList
43
+ }
44
+ };
45
+ </script>
46
+
47
+ <style lang="scss">
48
+ @import "../themes/generated/variables.base.scss";
49
+
50
+ .user-info {
51
+ display: flex;
52
+ align-items: center;
53
+
54
+ .dx-toolbar-menu-section & {
55
+ padding: 10px 6px;
56
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
57
+ }
58
+
59
+ .image-container {
60
+ overflow: hidden;
61
+ border-radius: 50%;
62
+ height: 30px;
63
+ width: 30px;
64
+ margin: 0 4px;
65
+ border: 1px solid rgba(0, 0, 0, 0.1);
66
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
67
+
68
+ .user-image {
69
+ width: 100%;
70
+ height: 100%;
71
+ background: url("https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png")
72
+ no-repeat #fff;
73
+ background-size: cover;
74
+ }
75
+ }
76
+
77
+ .user-name {
78
+ font-size: 14px;
79
+ color: $base-text-color;
80
+ margin: 0 9px;
81
+ }
82
+ }
83
+
84
+ .user-panel {
85
+ .dx-list-item .dx-icon {
86
+ vertical-align: middle;
87
+ color: $base-text-color;
88
+ margin-right: 16px;
89
+ }
90
+ .dx-rtl .dx-list-item .dx-icon {
91
+ margin-right: 0;
92
+ margin-left: 16px;
93
+ }
94
+ }
95
+
96
+ .dx-context-menu.user-menu.dx-menu-base {
97
+ &.dx-rtl {
98
+ .dx-submenu .dx-menu-items-container .dx-icon {
99
+ margin-left: 16px;
100
+ }
101
+ }
102
+ .dx-submenu .dx-menu-items-container .dx-icon {
103
+ margin-right: 16px;
104
+ }
105
+ .dx-menu-item .dx-menu-item-content {
106
+ padding: 3px 15px 4px;
107
+ }
108
+ }
109
+
110
+ .dx-theme-generic .user-menu .dx-menu-item-content .dx-menu-item-text {
111
+ padding-left: 4px;
112
+ padding-right: 4px;
113
+ }
114
+ </style>
@@ -0,0 +1,57 @@
1
+ .content {
2
+ line-height: 1.5;
3
+
4
+ h2 {
5
+ font-size: 30px;
6
+ margin-top: 20px;
7
+ margin-bottom: 20px;
8
+ }
9
+ }
10
+
11
+ .side-nav-outer-toolbar .dx-drawer {
12
+ height: calc(100% - 56px)
13
+ }
14
+
15
+ .content-block {
16
+ margin-left: 40px;
17
+ margin-right: 40px;
18
+ margin-top: 20px;
19
+
20
+ .screen-x-small & {
21
+ margin-left: 20px;
22
+ margin-right: 20px;
23
+ }
24
+ }
25
+
26
+ .responsive-paddings {
27
+ padding: 20px;
28
+
29
+ .screen-large & {
30
+ padding: 40px;
31
+ }
32
+ }
33
+
34
+ .dx-card.wide-card {
35
+ border-radius: 0;
36
+ margin-left: 0;
37
+ margin-right: 0;
38
+ border-right: 0;
39
+ border-left: 0;
40
+ }
41
+
42
+ .with-footer > .dx-scrollable-wrapper >
43
+ .dx-scrollable-container > .dx-scrollable-content {
44
+ height: 100%;
45
+
46
+ & > .dx-scrollview-content {
47
+ display: flex;
48
+ flex-direction: column;
49
+ min-height: 100%;
50
+ }
51
+ }
52
+
53
+ #app {
54
+ height: 100%;
55
+ }
56
+
57
+ $side-panel-min-width: 60px;
@@ -0,0 +1,192 @@
1
+ <template>
2
+ <div class="side-nav-inner-toolbar">
3
+ <dx-drawer
4
+ class="drawer"
5
+ position="before"
6
+ template="menuTemplate"
7
+ v-model:opened="menuOpened"
8
+ :opened-state-mode="drawerOptions.menuMode"
9
+ :reveal-mode="drawerOptions.menuRevealMode"
10
+ :min-size="drawerOptions.minMenuSize"
11
+ :max-size="drawerOptions.maxMenuSize"
12
+ :shading="drawerOptions.shaderEnabled"
13
+ :close-on-outside-click="drawerOptions.closeOnOutsideClick"
14
+ >
15
+ <div class="container">
16
+ <header-toolbar
17
+ :menu-toggle-enabled="headerMenuTogglerEnabled"
18
+ :toggle-menu-func="toggleMenu"
19
+ />
20
+ <dx-scroll-view ref="scrollViewRef" class="layout-body with-footer">
21
+ <slot />
22
+ <slot name="footer" />
23
+ </dx-scroll-view>
24
+ </div>
25
+ <template #menuTemplate>
26
+ <side-nav-menu
27
+ :compact-mode="!menuOpened"
28
+ @click="handleSideBarClick"
29
+ >
30
+ <dx-toolbar id="navigation-header">
31
+ <dx-item v-if="!isXSmall" location="before" css-class="menu-button">
32
+ <template #default>
33
+ <dx-button
34
+ icon="menu"
35
+ styling-mode="text"
36
+ @click="toggleMenu"
37
+ />
38
+ </template>
39
+ </dx-item>
40
+ <dx-item location="before" css-class="header-title dx-toolbar-label">
41
+ <template #default>
42
+ <div>{{ title }}</div>
43
+ </template>
44
+ </dx-item>
45
+ </dx-toolbar>
46
+ </side-nav-menu>
47
+ </template>
48
+ </dx-drawer>
49
+ </div>
50
+ </template>
51
+
52
+ <script>
53
+ import DxButton from "devextreme-vue/button";
54
+ import DxDrawer from "devextreme-vue/drawer";
55
+ import DxScrollView from "devextreme-vue/scroll-view";
56
+ import DxToolbar, { DxItem } from "devextreme-vue/toolbar";
57
+
58
+ import HeaderToolbar from "../components/header-toolbar";
59
+ import SideNavMenu from "../components/side-nav-menu";
60
+ import menuItems from "../app-navigation";
61
+ import { ref, watch, computed } from 'vue';
62
+ import { useRoute } from 'vue-router';
63
+
64
+ export default {
65
+ props: {
66
+ title: String,
67
+ isXSmall: Boolean,
68
+ isLarge: Boolean
69
+ },
70
+ setup(props) {
71
+ const route = useRoute();
72
+
73
+ const scrollViewRef = ref(null);
74
+ const menuOpened = ref(props.isLarge);
75
+ const menuTemporaryOpened = ref(false);
76
+
77
+ function toggleMenu (e) {
78
+ const pointerEvent = e.event;
79
+ pointerEvent.stopPropagation();
80
+ if (menuOpened.value) {
81
+ menuTemporaryOpened.value = false;
82
+ }
83
+
84
+ menuOpened.value = !menuOpened.value;
85
+ }
86
+
87
+ function handleSideBarClick () {
88
+ if (menuOpened.value === false) {
89
+ menuTemporaryOpened.value = true;
90
+ }
91
+
92
+ menuOpened.value = true;
93
+ }
94
+
95
+ const drawerOptions = computed(() => {
96
+ const shaderEnabled = !props.isLarge;
97
+
98
+ return {
99
+ menuMode: props.isLarge ? "shrink" : "overlap",
100
+ menuRevealMode: props.isXSmall ? "slide" : "expand",
101
+ minMenuSize: props.isXSmall ? 0 : 60,
102
+ maxMenuSize: props.isXSmall ? 250 : undefined,
103
+ closeOnOutsideClick: shaderEnabled,
104
+ shaderEnabled
105
+ };
106
+ });
107
+
108
+ const headerMenuTogglerEnabled = computed(() => {
109
+ return props.isXSmall;
110
+ });
111
+
112
+ watch(
113
+ () => props.isLarge,
114
+ () => {
115
+ if (!menuTemporaryOpened.value) {
116
+ menuOpened.value = props.isLarge;
117
+ }
118
+ }
119
+ );
120
+
121
+ watch(
122
+ () => route.path,
123
+ () => {
124
+ if (menuTemporaryOpened.value || !props.isLarge) {
125
+ menuOpened.value = false;
126
+ menuTemporaryOpened.value = false;
127
+ }
128
+ scrollViewRef.value.instance.scrollTo(0);
129
+ }
130
+ );
131
+
132
+ return {
133
+ scrollViewRef,
134
+ menuOpened,
135
+ drawerOptions,
136
+ menuItems,
137
+ headerMenuTogglerEnabled,
138
+ toggleMenu,
139
+ handleSideBarClick
140
+ };
141
+ },
142
+ components: {
143
+ DxButton,
144
+ DxDrawer,
145
+ DxScrollView,
146
+ DxToolbar,
147
+ DxItem,
148
+ HeaderToolbar,
149
+ SideNavMenu
150
+ }
151
+ };
152
+ </script>
153
+
154
+ <style lang="scss">
155
+ .side-nav-inner-toolbar {
156
+ width: 100%;
157
+ }
158
+
159
+ .container {
160
+ height: 100%;
161
+ flex-direction: column;
162
+ display: flex;
163
+ }
164
+
165
+ .layout-body {
166
+ flex: 1;
167
+ min-height: 0;
168
+ }
169
+
170
+ .content {
171
+ flex-grow: 1;
172
+ }
173
+
174
+ #navigation-header {
175
+ @import "../themes/generated/variables.additional.scss";
176
+ background-color: $base-accent;
177
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
178
+
179
+ .menu-button .dx-icon {
180
+ color: $base-text-color;
181
+ }
182
+
183
+ .screen-x-small & {
184
+ padding-left: 20px;
185
+ }
186
+
187
+ .dx-theme-generic & {
188
+ padding-top: 10px;
189
+ padding-bottom: 10px;
190
+ }
191
+ }
192
+ </style>
@@ -0,0 +1,144 @@
1
+ <template>
2
+ <div class="side-nav-outer-toolbar">
3
+ <header-toolbar
4
+ class="layout-header"
5
+ :menu-toggle-enabled="true"
6
+ :toggle-menu-func="toggleMenu"
7
+ :title="title"
8
+ />
9
+ <dx-drawer
10
+ class="layout-body"
11
+ position="before"
12
+ template="menuTemplate"
13
+ v-model:opened="menuOpened"
14
+ :opened-state-mode="drawerOptions.menuMode"
15
+ :reveal-mode="drawerOptions.menuRevealMode"
16
+ :min-size="drawerOptions.minMenuSize"
17
+ :max-size="drawerOptions.maxMenuSize"
18
+ :shading="drawerOptions.shaderEnabled"
19
+ :close-on-outside-click="drawerOptions.closeOnOutsideClick"
20
+ >
21
+ <dx-scroll-view ref="scrollViewRef" class="with-footer">
22
+ <slot />
23
+ <slot name="footer" />
24
+ </dx-scroll-view>
25
+ <template #menuTemplate>
26
+ <side-nav-menu
27
+ :compact-mode="!menuOpened"
28
+ @click="handleSideBarClick"
29
+ />
30
+ </template>
31
+ </dx-drawer>
32
+ </div>
33
+ </template>
34
+
35
+ <script>
36
+ import DxDrawer from "devextreme-vue/drawer";
37
+ import DxScrollView from "devextreme-vue/scroll-view";
38
+
39
+ import menuItems from "../app-navigation";
40
+ import HeaderToolbar from "../components/header-toolbar";
41
+ import SideNavMenu from "../components/side-nav-menu";
42
+ import { computed, ref, watch} from 'vue';
43
+ import { useRoute } from 'vue-router';
44
+
45
+ export default {
46
+ props: {
47
+ title: String,
48
+ isXSmall: Boolean,
49
+ isLarge: Boolean
50
+ },
51
+ setup(props) {
52
+ const route = useRoute();
53
+
54
+ const scrollViewRef = ref(null);
55
+ const menuOpened = ref(props.isLarge);
56
+ const menuTemporaryOpened = ref(false);
57
+
58
+ function toggleMenu(e) {
59
+ const pointerEvent = e.event;
60
+ pointerEvent.stopPropagation();
61
+ if (menuOpened.value) {
62
+ menuTemporaryOpened.value = false;
63
+ }
64
+ menuOpened.value = !menuOpened.value;
65
+ }
66
+
67
+ function handleSideBarClick() {
68
+ if (menuOpened.value === false) {
69
+ menuTemporaryOpened.value = true;
70
+ }
71
+ menuOpened.value = true;
72
+ }
73
+
74
+ const drawerOptions = computed(() => {
75
+ const shaderEnabled = !props.isLarge;
76
+
77
+ return {
78
+ menuMode: props.isLarge ? "shrink" : "overlap",
79
+ menuRevealMode: props.isXSmall ? "slide" : "expand",
80
+ minMenuSize: props.isXSmall ? 0 : 60,
81
+ maxMenuSize: props.isXSmall ? 250 : undefined,
82
+ closeOnOutsideClick: shaderEnabled,
83
+ shaderEnabled
84
+ };
85
+ });
86
+
87
+ watch(
88
+ () => props.isLarge,
89
+ () => {
90
+ if (!menuTemporaryOpened.value) {
91
+ menuOpened.value = props.isLarge;
92
+ }
93
+ });
94
+
95
+ watch(
96
+ () => route.path,
97
+ () => {
98
+ if (menuTemporaryOpened.value || !props.isLarge) {
99
+ menuOpened.value = false;
100
+ menuTemporaryOpened.value = false;
101
+ }
102
+ scrollViewRef.value.instance.scrollTo(0);
103
+ }
104
+ );
105
+
106
+ return {
107
+ menuOpened,
108
+ menuItems,
109
+ toggleMenu,
110
+ handleSideBarClick,
111
+ drawerOptions,
112
+ scrollViewRef
113
+ };
114
+ },
115
+ components: {
116
+ DxDrawer,
117
+ DxScrollView,
118
+ HeaderToolbar,
119
+ SideNavMenu
120
+ }
121
+ };
122
+ </script>
123
+
124
+ <style lang="scss">
125
+ .side-nav-outer-toolbar {
126
+ flex-direction: column;
127
+ display: flex;
128
+ height: 100%;
129
+ width: 100%;
130
+ }
131
+
132
+ .layout-header {
133
+ z-index: 1501;
134
+ }
135
+
136
+ .layout-body {
137
+ flex: 1;
138
+ min-height: 0;
139
+ }
140
+
141
+ .content {
142
+ flex-grow: 1;
143
+ }
144
+ </style>