@nixweb/nixloc-ui 0.0.292 → 0.0.293

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nixweb/nixloc-ui",
3
- "version": "0.0.292",
3
+ "version": "0.0.293",
4
4
  "description": "Componentes UI",
5
5
  "author": "Fábio Ávila <fabio@nixweb.com.br>",
6
6
  "private": false,
@@ -1,27 +1,17 @@
1
1
  <template>
2
2
  <div>
3
- <div
4
- v-show="!isLoading('panel')"
5
- class="bar side-by-side"
6
- :style="
7
- 'min-height:' + height + 'px; background-color:' + backgroundColor
8
- "
9
- :class="{
3
+ <div v-show="!isLoading('panel')" class="bar side-by-side" :style="'min-height:' + height + 'px; background-color:' + backgroundColor
4
+ " :class="{
10
5
  top: position == 'top',
11
6
  footer: position == 'footer',
12
7
  none: position == 'none',
13
- }"
14
- >
8
+ }">
15
9
  <div class="size">
16
10
  <div :class="{ 'side-by-side': showButtonClose }">
17
11
  <slot></slot>
18
12
  </div>
19
- <div
20
- :class="{ 'side-by-side': showButtonClose }"
21
- class="close-icon"
22
- v-if="position == 'top' && showButtonClose"
23
- @click="close"
24
- >
13
+ <div :class="{ 'side-by-side': showButtonClose }" class="close-icon" v-if="position == 'top' && showButtonClose"
14
+ @click="close">
25
15
  <i class="fa-regular fa-xmark"></i>
26
16
  </div>
27
17
  </div>
@@ -19,11 +19,12 @@ export default {
19
19
  .molded {
20
20
  border: 1px solid #e8eaed;
21
21
  background-color: white;
22
- border-radius: 8px !important;
22
+ border-radius: 10px !important;
23
23
  padding: 10px;
24
24
  padding-top: 15px;
25
25
  padding-left: 30px;
26
26
  padding-right: 30px;
27
27
  padding-bottom: 10px;
28
+ box-shadow: 0px 10px 100px -6px rgb(0 0 0 / 5%);
28
29
  }
29
30
  </style>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div>
3
3
  <div class="icon-logout" @click="execute">
4
- <i class="fa-solid fa-right-from-bracket"></i>
4
+ <i class="fa-duotone fa-solid fa-right-from-bracket"></i>
5
5
  </div>
6
6
  <div class="profile-container" v-if="hideShow">
7
7
  <div class="item-header text-center">
@@ -67,7 +67,7 @@ export default {
67
67
  width: 40px;
68
68
  height: 40px;
69
69
  border-radius: 12px;
70
- color: #3D4EAE;
70
+ color: #F0134D;
71
71
  font-size: 22px;
72
72
  }
73
73
 
@@ -1,63 +1,58 @@
1
1
  <template>
2
2
  <div>
3
- <div :class="['top', { collapsed: isSidebarCollapsed }]" :style="'background-color:' + backgroundColor">
3
+ <div :class="['top', { collapsed: menuCollapsed, notCollapsed: !menuCollapsed }]">
4
4
  <div class="side-by-side top-space">
5
5
  <slot></slot>
6
6
  </div>
7
+ <div class="side-by-side div-theme">
8
+ <ToggleTheme />
9
+ </div>
7
10
  </div>
8
- <br />
9
11
  </div>
10
12
  </template>
11
13
 
12
14
  <script>
13
15
 
14
- import { mapGetters } from "vuex";
16
+ import ToggleTheme from "@nixweb/nixloc-ui/src/component/shared/ToggleTheme.vue";
17
+
18
+ import { mapState } from "vuex";
15
19
 
16
20
  export default {
17
21
  name: "Top",
22
+ components: {
23
+ ToggleTheme
24
+ },
18
25
  props: {
19
26
  backgroundColor: {
20
27
  type: String,
21
28
  default: "#4680A5",
22
29
  },
23
30
  },
24
- data() {
25
- return {
26
- isSidebarCollapsed: false
27
- }
28
- },
29
31
  computed: {
30
- ...mapGetters("generic", ["event"]),
31
- },
32
- watch: {
33
- event: {
34
- handler(event) {
35
- if (event.name == "isSidebarCollapsed") {
36
- this.isSidebarCollapsed = event.data;
37
- }
38
- },
39
- deep: true,
40
- },
32
+ ...mapState("generic", ["menuCollapsed"]),
41
33
  },
42
34
  };
43
35
  </script>
44
36
 
45
37
  <style scoped>
46
38
  .top {
47
- padding-top: 4px;
48
- left: 298px;
49
39
  right: 10px;
50
40
  height: 55px;
51
41
  top: 5px;
52
- border-radius: 18px;
53
42
  border-bottom: 0px solid #eff0f1;
54
- box-shadow: 0px 10px 30px -6px rgb(0 0 0 / 10%);
55
- position: fixed;
43
+ position: relative;
56
44
  transition: all 0.3s ease;
57
- z-index: 100;
45
+ }
46
+
47
+ .top.notCollapsed {
48
+ left: 270px;
58
49
  }
59
50
 
60
51
  .top.collapsed {
61
- left: 110px;
52
+ left: 95px;
53
+ }
54
+
55
+ .div-theme {
56
+ margin-left: 15px;
62
57
  }
63
58
  </style>
@@ -2,10 +2,9 @@
2
2
  <div>
3
3
  <div v-for="icon in icons" class="molded-icon side-by-side" @click="executeEvent(icon.eventName)" v-b-tooltip.hover
4
4
  :title="icon.tooltip">
5
- <div class="icon-molded-icon" :class="{
6
- 'icon-active-top': menuActive == icon.module,
7
- 'icon-normal-top': menuActive != icon.module,
8
- }">
5
+ <div :class="{
6
+ 'icon-active-header': moduleActive === icon.module,
7
+ }" class="icon-molded-icon">
9
8
  <i :class="icon.icon"></i>
10
9
  </div>
11
10
  </div>
@@ -21,7 +20,7 @@ export default {
21
20
  icons: Array,
22
21
  },
23
22
  data() {
24
- return { menuActive: "" };
23
+ return { moduleActive: "" };
25
24
  },
26
25
  methods: {
27
26
  ...mapMutations("generic", ["addEvent"]),
@@ -29,12 +28,15 @@ export default {
29
28
  this.addEvent({
30
29
  name: eventName,
31
30
  });
31
+ this.addEvent({
32
+ name: "cleanMenuSelected",
33
+ });
32
34
  },
33
35
  },
34
36
  watch: {
35
37
  $route: {
36
38
  handler: function (router) {
37
- this.menuActive = router.matched[0].props.default.module;
39
+ this.moduleActive = router.matched[0].props.default.module;
38
40
  },
39
41
  deep: true,
40
42
  },
@@ -49,12 +51,21 @@ export default {
49
51
  margin-left: 10px;
50
52
  margin-top: 4px;
51
53
  cursor: pointer;
52
-
53
54
  }
54
55
 
55
56
  .icon-molded-icon {
56
57
  font-size: 20px;
57
58
  margin-left: 10px;
58
- color: #2c3453 !important;
59
+ color: #2C3453;
60
+ }
61
+
62
+ .module-active {
63
+ border-radius: 50px;
64
+ background-color: #2C3453;
65
+ }
66
+
67
+ .icon-active-header {
68
+ color: #D98621;
69
+ font-size: 22px;
59
70
  }
60
71
  </style>
@@ -1,103 +1,160 @@
1
1
  <template>
2
2
  <div>
3
- <div :class="['sidebar', { collapsed: isSidebarCollapsed }]">
3
+ <div :class="['sidebar', { collapsed: menuCollapsed }]">
4
4
  <div class="sidebar-header">
5
- <span class="header-logo">
6
- <img src="https://espaco.blob.core.windows.net/nixloc-photo-user/E29W4HNYQG_10.png"
7
- alt="CodingNepal" />
5
+ <span class="header-logo" @click="editProfile">
6
+ <img class="photo" :src="urlPhoto" />
8
7
  </span>
9
- <button class="sidebar-toggler" @click="toggleSidebar">
10
- <span class="material-symbols-rounded icon-menu-arrow">
11
- <i class="fa-solid fa-angle-left"></i>
8
+ <Button class="sidebar-toggler" @click="toggleSidebar">
9
+ <span>
10
+ <i v-if="menuCollapsed" class="fa-solid fa-angle-right icon-menu-arrow"></i>
11
+ <i v-else class="fa-solid fa-angle-left icon-menu-arrow"></i>
12
12
  </span>
13
- </button>
13
+ </Button>
14
14
  </div>
15
-
16
- <div :class="{ sub: isSidebarCollapsed }">
17
- <div v-for="(item, index) in menuFilter(true)">
18
- <div>
19
- <div v-if="isSidebarCollapsed" class="molded-icon text-center"
20
- @mouseover="handleMouseOver(item.title, item.module)">
21
- <i :class="item.icon"></i>
22
- </div>
23
- <div class="molded-icon-open" v-else @click="toggleSubMenu(item.title, item.module)">
24
- <b-row>
25
- <b-col sm="1">
26
- <i :class="item.icon"></i>
27
- </b-col>
28
- <b-col sm="8">
29
- <span class="title-menu">{{ item.title }} </span>
30
- </b-col>
31
- <b-col sm="1">
32
- <div>
33
- <i v-if="titleSubMenu == item.title" class="fa-sharp fa-solid fa-angle-down"
34
- :class="{ 'rotate': titleSubMenu == item.title }"></i>
35
-
36
- <i v-else class="fa-sharp fa-solid fa-angle-down"
37
- :class="{ 'rotate-down': titleSubMenu != item.title }"></i>
38
- </div>
39
- </b-col>
40
- </b-row>
15
+ <div v-if="menuCollapsed">
16
+ <br><br>
17
+ </div>
18
+ <ScrollBar :minHeight="pageSize" :maxHeight="pageSize">
19
+ <div :class="{ 'sub': menuCollapsed }">
20
+ <div v-for="(item, index) in menuFilter(true)">
21
+ <div>
22
+ <div :ref="item.title" v-if="menuCollapsed" class="molded-icon text-center" :class="{
23
+ 'menu-active': moduleActive === item.module,
24
+ 'module-selected': module === item.module
25
+ }" @mouseover="handleMouseOver(item.title, item.module)">
26
+ <i :class="item.icon"></i>
27
+ </div>
28
+ <div class="molded-icon-open" :class="{
29
+ 'menu-active': moduleActive === item.module
30
+ }" v-else @click="toggleSubMenu(item.title, item.module)">
31
+ <b-row>
32
+ <b-col sm="1">
33
+ <i :class="item.icon"></i>
34
+ </b-col>
35
+ <b-col sm="8">
36
+ <span class="title-menu">{{ item.title }} </span>
37
+ </b-col>
38
+ <b-col sm="1">
39
+ <div>
40
+ <i v-if="titleSubMenu == item.title" class="fa-sharp fa-solid fa-angle-down"
41
+ :class="{ 'rotate': titleSubMenu == item.title }"></i>
42
+
43
+ <i v-else class="fa-sharp fa-solid fa-angle-down"
44
+ :class="{ 'rotate-down': titleSubMenu != item.title }"></i>
45
+ </div>
46
+ </b-col>
47
+ </b-row>
48
+ </div>
41
49
  </div>
42
- </div>
43
50
 
44
-
45
- <transition name="slide-fade">
46
- <div class="sub-menu" v-if="!isSidebarCollapsed && titleSubMenu == item.title">
47
- <div v-for="(item, index) in subMenuFilter(false)" :key="index">
48
- <div v-if="item.title" class="sub-menu-title" @click.prevent="navegateTo(item)">
49
- <b-row>
50
- <b-col sm="3"> <i :class="item.icon"></i></b-col>
51
- <span> {{ item.title }}</span>
52
- </b-row>
51
+ <transition name="slide-fade">
52
+ <div class="sub-menu" v-if="!menuCollapsed && titleSubMenu == item.title">
53
+ <div v-for="(item, index) in subMenuFilter(false)" :key="index">
54
+ <div v-if="item.title" class="sub-menu-title"
55
+ @click.prevent="navegateTo(item, item.module)">
56
+ <b-row>
57
+ <b-col sm="3"> <i :class="item.icon"></i></b-col>
58
+ <span> {{ item.title }}</span>
59
+ </b-row>
60
+ </div>
53
61
  </div>
54
62
  </div>
55
- </div>
56
- </transition>
57
-
58
- <transition name="slide-fade">
59
- <div class="sub-menu-collapsed sub-menu" @mouseleave="handleMouseLeave"
60
- v-if="isSidebarCollapsed && titleSubMenuCollapsed == item.title">
61
- <div v-for="(item, index) in subMenuFilter(false)" :key="index">
62
- <div v-if="item.title" class="sub-menu-title-collapsed"
63
- @click.prevent="navegateTo(item)">
64
- <b-row>
65
- <b-col sm="3"> <i :class="item.icon"></i></b-col>
66
- <span> {{ item.title }}</span>
67
- </b-row>
63
+ </transition>
64
+
65
+ <transition name="slide-fade">
66
+ <div :ref="item.title + 'sub'" class="sub-menu-collapsed sub-menu"
67
+ v-if="menuCollapsed && titleSubMenuCollapsed == item.title">
68
+ <div v-for="(item, index) in subMenuFilter(false)" :key="index">
69
+ <div :class="{ 'sub-menu-title-collapsed': item.title }"
70
+ @click.prevent="navegateTo(item, item.module)">
71
+ <b-row>
72
+ <b-col sm="2" v-if="item.title">
73
+ <i :class="item.icon"></i>
74
+ </b-col>
75
+ <b-col sm="9">
76
+ <div v-if="item.groupName" class="div-group">
77
+ {{ item.groupName }}
78
+ </div>
79
+ <span> {{ item.title }}</span>
80
+ </b-col>
81
+ </b-row>
82
+ </div>
68
83
  </div>
69
84
  </div>
70
- </div>
71
- </transition>
85
+ </transition>
86
+ </div>
87
+ <br>
88
+ <br>
89
+ <br>
72
90
  </div>
73
- </div>
91
+ </ScrollBar>
92
+
74
93
  </div>
75
94
  </div>
76
95
  </template>
77
96
 
78
97
  <script>
79
98
 
99
+ import ScrollBar from "@nixweb/nixloc-ui/src/component/layout/ScrollBar.vue";
100
+
80
101
  import { mapState, mapMutations, mapGetters } from "vuex";
81
102
 
82
103
  export default {
104
+ props: {
105
+ urlPhoto: String,
106
+ },
107
+ components: {
108
+ ScrollBar
109
+ },
83
110
  data() {
84
111
  return {
85
112
  module: "",
86
- isSidebarCollapsed: false,
113
+ moduleActive: "",
114
+ isSidebarCollapsed: true,
87
115
  openDropdowns: {},
88
116
  titleSubMenu: "",
89
117
  titleSubMenuCollapsed: "",
118
+ pageSize: 0,
119
+ distanceFromBottom: 0,
90
120
  };
91
121
  },
122
+ mounted() {
123
+ this.updatePageSize();
124
+ window.addEventListener('resize', this.updatePageSize);
125
+
126
+ if (!localStorage.getItem('menuCollapsed')) {
127
+ localStorage.setItem('menuCollapsed', this.isSidebarCollapsed ? "closed" : "open");
128
+ }
129
+
130
+ if (localStorage.getItem('menuCollapsed') === 'open') {
131
+ this.toggleMenu(false);
132
+ } else {
133
+ this.toggleMenu(true);
134
+ }
135
+
136
+ if (this.$route.matched[0])
137
+ this.moduleActive = this.$route.matched[0].props.default.module;
138
+
139
+ },
140
+ beforeDestroy() {
141
+ window.removeEventListener('resize', this.updatePageSize);
142
+ },
92
143
  computed: {
93
144
  ...mapState("user", ["menu", "userLogged"]),
145
+ ...mapState("generic", ["menuCollapsed"]),
94
146
  ...mapGetters("generic", ["event"]),
95
147
  },
96
148
  methods: {
97
- ...mapMutations("generic", ["addEvent"]),
149
+ ...mapMutations("generic", ["addEvent", "toggleMenu"]),
150
+ updatePageSize() {
151
+ const windowHeight = window.innerHeight;
152
+ this.pageSize = windowHeight;
153
+ },
98
154
  toggleSidebar() {
99
155
  this.isSidebarCollapsed = !this.isSidebarCollapsed;
100
- this.addEvent({ name: "isSidebarCollapsed", data: this.isSidebarCollapsed });
156
+ this.toggleMenu(this.isSidebarCollapsed);
157
+ localStorage.setItem('menuCollapsed', this.isSidebarCollapsed ? "closed" : "open");
101
158
  this.titleSubMenu = "";
102
159
  this.titleSubMenuCollapsed = "";
103
160
  },
@@ -112,9 +169,25 @@ export default {
112
169
  handleMouseOver(title, module) {
113
170
  this.module = module;
114
171
  this.titleSubMenuCollapsed = title;
172
+
173
+ var divSub = this.$refs[title + 'sub'];
174
+
175
+ if (divSub) {
176
+ let self = this;
177
+ setTimeout(function () {
178
+ const heightSubMenu = divSub[0].getBoundingClientRect();
179
+
180
+ if (heightSubMenu.top < 0 || heightSubMenu.left < 0 || heightSubMenu.bottom > window.innerHeight || heightSubMenu.right > window.innerWidth) {
181
+ divSub[0].style.bottom = '0px';
182
+ }
183
+
184
+ }, 100);
185
+ }
115
186
  },
116
187
  handleMouseLeave() {
117
188
  this.titleSubMenuCollapsed = "";
189
+ if (this.menuCollapsed)
190
+ this.module = "";
118
191
  },
119
192
  menuFilter(isModule) {
120
193
  let filter = [];
@@ -137,13 +210,33 @@ export default {
137
210
  });
138
211
  return filter;
139
212
  },
140
- navegateTo(item) {
213
+ navegateTo(item, module) {
141
214
  this.$router.push({
142
215
  name: item.routeName,
143
216
  });
144
- this.titleSubMenu = "";
217
+
218
+ this.moduleActive = module;
145
219
  this.titleSubMenuCollapsed = "";
146
220
  },
221
+ editProfile() {
222
+ this.addEvent({ name: "clickedProfile" });
223
+ },
224
+ },
225
+ watch: {
226
+ event: {
227
+ handler: function (event) {
228
+ if (event.name == "handleMouseOver") {
229
+ this.handleMouseLeave();
230
+ }
231
+ },
232
+ deep: true,
233
+ },
234
+ $route: {
235
+ handler: function (router) {
236
+ this.moduleActive = router.matched[0].props.default.module;
237
+ },
238
+ deep: true,
239
+ },
147
240
  },
148
241
  };
149
242
  </script>
@@ -153,11 +246,12 @@ export default {
153
246
  position: fixed;
154
247
  top: 0;
155
248
  left: 0;
156
- z-index: 10;
157
- width: 270px;
249
+ width: 275px;
158
250
  height: 100vh;
159
- background: #577696;
251
+ border-radius: 0px 20px 0px 0px;
252
+ background-color: #577696;
160
253
  transition: all 0.4s ease;
254
+ z-index: 1000;
161
255
  }
162
256
 
163
257
  .sidebar.collapsed {
@@ -177,15 +271,16 @@ export default {
177
271
  height: 46px;
178
272
  display: block;
179
273
  object-fit: contain;
274
+ cursor: pointer;
180
275
  border-radius: 50%;
181
276
  }
182
277
 
183
278
  .sidebar-header .sidebar-toggler,
184
279
  .sidebar-menu-button {
185
280
  position: absolute;
186
- right: 20px;
187
- height: 35px;
188
- width: 35px;
281
+ right: 23px;
282
+ height: 30px;
283
+ width: 30px;
189
284
  color: #151A2D;
190
285
  border: none;
191
286
  cursor: pointer;
@@ -193,7 +288,7 @@ export default {
193
288
  background: #EEF2FF;
194
289
  align-items: center;
195
290
  justify-content: center;
196
- border-radius: 8px;
291
+ border-radius: 50px;
197
292
  transition: 0.4s ease;
198
293
  }
199
294
 
@@ -201,96 +296,6 @@ export default {
201
296
  transform: translate(-4px, 65px);
202
297
  }
203
298
 
204
- .sidebar-header .sidebar-toggler span,
205
- .sidebar-menu-button span {
206
- font-size: 1.75rem;
207
- transition: 0.4s ease;
208
- }
209
-
210
- .sidebar.collapsed .sidebar-header .sidebar-toggler span {
211
- transform: rotate(180deg);
212
- }
213
-
214
- .sidebar-header .sidebar-toggler:hover {
215
- background: #d9e1fd;
216
- }
217
-
218
- .sidebar-nav .nav-list {
219
- list-style: none;
220
- display: flex;
221
- gap: 4px;
222
- padding: 0 15px;
223
- flex-direction: column;
224
- transform: translateY(15px);
225
- transition: 0.4s ease;
226
- }
227
-
228
- .sidebar .sidebar-nav .primary-nav {
229
- overflow-y: auto;
230
- scrollbar-width: thin;
231
- padding-bottom: 20px;
232
- height: calc(100vh - 227px);
233
- scrollbar-color: transparent transparent;
234
- }
235
-
236
- .sidebar .sidebar-nav .primary-nav:hover {
237
- scrollbar-color: #EEF2FF transparent;
238
- }
239
-
240
- .sidebar.collapsed .sidebar-nav .primary-nav {
241
- overflow: unset;
242
- transform: translateY(65px);
243
- }
244
-
245
- .sidebar-nav .nav-item .nav-link {
246
- color: #fff;
247
- display: flex;
248
- gap: 12px;
249
- white-space: nowrap;
250
- border-radius: 8px;
251
- padding: 11px 15px;
252
- align-items: center;
253
- text-decoration: none;
254
- border: 1px solid #151A2D;
255
- transition: 0.4s ease;
256
- }
257
-
258
- .sidebar-nav .nav-item:is(:hover, .open)>.nav-link:not(.dropdown-title) {
259
- color: #151A2D;
260
- background: #EEF2FF;
261
- }
262
-
263
- .sidebar .nav-link .nav-label {
264
- transition: opacity 0.3s ease;
265
- color: white;
266
- }
267
-
268
- .sidebar.collapsed .nav-link :where(.nav-label, .dropdown-icon) {
269
- opacity: 0;
270
- pointer-events: none;
271
- }
272
-
273
- .sidebar.collapsed .nav-link .dropdown-icon {
274
- transition: opacity 0.3s 0s ease;
275
- }
276
-
277
- .sidebar-nav .secondary-nav {
278
- position: absolute;
279
- bottom: 35px;
280
- width: 100%;
281
- background: #151A2D;
282
- }
283
-
284
- .sidebar-nav .nav-item {
285
- position: relative;
286
- }
287
-
288
-
289
- .icon-menu-arrow {
290
- font-size: 18px !important;
291
- margin-top: 1px !important;
292
- }
293
-
294
299
  .molded-icon-open {
295
300
  padding-left: 10px;
296
301
  cursor: pointer;
@@ -307,12 +312,26 @@ export default {
307
312
  background-color: white;
308
313
  }
309
314
 
315
+ .menu-active {
316
+ background-color: #D98621;
317
+ }
318
+
319
+ .module-selected {
320
+ color: #2C3453 !important;
321
+ background-color: white !important;
322
+ }
323
+
324
+ .icon-menu-arrow {
325
+ font-size: 17px;
326
+ margin-top: 7px;
327
+ }
328
+
310
329
  .molded-icon {
311
330
  cursor: pointer;
312
- margin-top: 10px;
331
+ padding: 1px;
313
332
  color: white;
314
333
  font-size: 18px;
315
- margin: 15px;
334
+ margin: 10px;
316
335
  border-radius: 10px;
317
336
  transition: all 0.3s ease;
318
337
  }
@@ -320,13 +339,12 @@ export default {
320
339
  .molded-icon:hover {
321
340
  background-color: white;
322
341
  color: #2C3453;
323
- margin: 15px;
324
- border-radius: 8px;
342
+ margin: 10px;
343
+ border-radius: 10px;
325
344
  transition: all 0.8s ease;
326
345
  }
327
346
 
328
347
  .sub {
329
- margin-top: 70px;
330
348
  cursor: pointer;
331
349
  transition: all 0.3s ease;
332
350
  }
@@ -358,9 +376,9 @@ export default {
358
376
 
359
377
  .sub-menu-collapsed {
360
378
  width: 260px;
361
- margin-top: -50px;
379
+ margin-top: -100px;
362
380
  margin-left: 85px;
363
- position: fixed;
381
+ position: absolute;
364
382
  border-radius: 0px 15px 15px 0px;
365
383
  background-color: #2C3453;
366
384
  }
@@ -415,5 +433,9 @@ export default {
415
433
  font-size: 16px;
416
434
  margin-left: 10px;
417
435
  }
418
-
436
+
437
+ .div-group {
438
+ margin-left: 10px;
439
+ padding: 5px;
440
+ }
419
441
  </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="panel">
2
+ <div :class="['panel', { collapsed: menuCollapsed }]">
3
3
  <Toast />
4
4
  <Loading v-show="isLoading('panel')" />
5
5
  <div v-show="!isLoading('panel')">
@@ -93,8 +93,8 @@ export default {
93
93
  this.currentRoute = this.$route.name;
94
94
  },
95
95
  computed: {
96
- ...mapGetters("generic", ["isLoading"]),
97
- ...mapState("generic", ["modal"]),
96
+ ...mapGetters("generic", ["isLoading", "event"]),
97
+ ...mapState("generic", ["modal", "menuCollapsed"]),
98
98
  },
99
99
  methods: {
100
100
  ...mapMutations("generic", ["addLoading"]),
@@ -105,10 +105,6 @@ export default {
105
105
  };
106
106
  </script>
107
107
  <style scoped>
108
- .layout-small {
109
- max-width: 1500px;
110
- }
111
-
112
108
  .local-container {
113
109
  margin: auto;
114
110
  padding-left: 100px;
@@ -147,9 +143,13 @@ export default {
147
143
  }
148
144
 
149
145
  .panel {
150
- margin-top: 30px;
151
146
  padding-right: 30px;
152
- padding-left: 20px;
147
+ margin-left: 190px;
148
+ }
149
+
150
+ .panel.collapsed {
151
+ margin-left: 10px;
152
+ transition: all 0.3s ease;
153
153
  }
154
154
 
155
155
  .div-back {
@@ -1,5 +1,9 @@
1
1
  <template>
2
2
  <div>
3
+ <div class="div-download title" @click="download">
4
+ <i class="fa-solid fa-download icon-download"></i>
5
+ <span class="title-download">Baixar</span>
6
+ </div>
3
7
  <AceEditor v-model="code" lang="html" @init="editorInit" theme="monokai" width="100%" height="400px" :options="{
4
8
  enableBasicAutocompletion: true,
5
9
  enableLiveAutocompletion: true,
@@ -11,10 +15,11 @@
11
15
  showPrintMargin: false,
12
16
  showGutter: true,
13
17
  }" />
14
- <div class="apply">
18
+ <div v-if="!editMode" class="apply">
15
19
  <b-row>
16
20
  <b-col class="text-right">
17
- <Button key="applyCode" type="primary" title="Aplicar" classIcon="far fa-code" size="small" :clicked="apply" />
21
+ <Button key="applyCode" type="primary" title="Aplicar" classIcon="far fa-code" size="small"
22
+ :clicked="apply" />
18
23
  </b-col>
19
24
  </b-row>
20
25
  </div>
@@ -25,10 +30,13 @@
25
30
  import AceEditor from "vuejs-ace-editor";
26
31
  import Button from "@nixweb/nixloc-ui/src/component/forms/Button";
27
32
 
28
- import { mapMutations } from "vuex";
33
+ import { mapMutations, mapState } from "vuex";
29
34
 
30
35
  export default {
31
36
  name: "CodeEditor",
37
+ props: {
38
+ editMode: Boolean
39
+ },
32
40
  components: {
33
41
  AceEditor,
34
42
  Button,
@@ -38,22 +46,16 @@ export default {
38
46
  code: "",
39
47
  };
40
48
  },
41
- computed: {
42
- documentHtml: {
43
- get() {
44
- return this.$store.state.generic.documentHtml;
45
- },
46
- set(value) {
47
- this.updateDocumentHtml(value);
48
- },
49
- },
50
- },
51
49
  mounted() {
52
- this.code = this.documentHtml;
50
+ this.code = this.editMode ? this.documentHtmlFinal : this.documentHtml;
51
+ },
52
+ computed: {
53
+ ...mapState("generic", ["documentHtml", "documentHtmlFinal"]),
53
54
  },
54
55
  methods: {
55
56
  ...mapMutations("generic", [
56
57
  "updateDocumentHtml",
58
+ "updateDocumentHtmlFinal",
57
59
  "hideModal",
58
60
  "removeLoading",
59
61
  ]),
@@ -70,6 +72,34 @@ export default {
70
72
  require("brace/theme/monokai");
71
73
  require("brace/snippets/javascript"); //snippet
72
74
  },
75
+ download() {
76
+ const blob = new Blob([this.code], { type: 'text/plain' });
77
+ const link = document.createElement('a');
78
+ link.href = URL.createObjectURL(blob);
79
+ link.download = 'arquivo.txt';
80
+ link.click();
81
+ URL.revokeObjectURL(link.href);
82
+ }
83
+ },
84
+ watch: {
85
+ code: {
86
+ handler(code) {
87
+ this.updateDocumentHtmlFinal(this.code);
88
+ },
89
+ deep: true,
90
+ },
91
+ documentHtml: {
92
+ handler(documentHtml) {
93
+ this.code = documentHtml;
94
+ },
95
+ deep: true,
96
+ },
97
+ documentHtmlFinal: {
98
+ handler(documentHtmlFinal) {
99
+ this.code = documentHtmlFinal;
100
+ },
101
+ deep: true,
102
+ },
73
103
  },
74
104
  };
75
105
  </script>
@@ -77,4 +107,22 @@ export default {
77
107
  .apply {
78
108
  margin-top: 10px;
79
109
  }
110
+
111
+ .div-download {
112
+ cursor: pointer;
113
+ margin-bottom: 5px;
114
+ }
115
+
116
+ .title-download {
117
+ margin-left: 6px;
118
+ font-size: 14px;
119
+ }
120
+
121
+ .title-download:hover {
122
+ text-decoration: underline;
123
+ }
124
+
125
+ .icon-download {
126
+ font-size: 18px;
127
+ }
80
128
  </style>
@@ -5,12 +5,7 @@
5
5
  <div class="document-editor__toolbar"></div>
6
6
  <div class="document-editor__editable-container">
7
7
  <div id="template-dev">
8
- <ckeditor
9
- :editor="editor"
10
- v-model="documentHtml"
11
- @ready="onReady"
12
- @focus="changed"
13
- ></ckeditor>
8
+ <ckeditor :editor="editor" v-model="computedDocumentHtml" @ready="onReady" @focus="changed"></ckeditor>
14
9
  </div>
15
10
  </div>
16
11
  </div>
@@ -21,11 +16,11 @@
21
16
 
22
17
  <script>
23
18
  import CKEditor from "ckeditor5-custom-build/build/ckeditor";
24
-
25
19
  import { mapState, mapMutations } from "vuex";
26
20
 
27
21
  export default {
28
22
  name: "DocumentEditor",
23
+ props: ["editMode"],
29
24
  components: {
30
25
  CKEditor,
31
26
  },
@@ -35,22 +30,29 @@ export default {
35
30
  };
36
31
  },
37
32
  computed: {
38
- ...mapState("generic", ["documentHtml"]),
39
- documentHtml: {
33
+ ...mapState("generic", ["documentHtml", "documentHtmlFinal"]),
34
+ computedDocumentHtml: {
40
35
  get() {
41
- return this.$store.state.generic.documentHtml;
36
+ if (this.editMode) {
37
+ return this.documentHtmlFinal
38
+ } else {
39
+ return this.documentHtml;
40
+ }
42
41
  },
43
- set(value) {
44
- this.updateDocumentHtml(value);
42
+ set(newValue) {
43
+ console.log(newValue);
44
+ if (this.editMode) {
45
+ this.updateDocumentHtmlFinal(newValue);
46
+ } else {
47
+ this.updateDocumentHtml(newValue);
48
+ }
45
49
  },
46
50
  },
47
51
  },
48
52
  methods: {
49
- ...mapMutations("generic", ["updateDocumentHtml", "addEvent"]),
53
+ ...mapMutations("generic", ["updateDocumentHtmlFinal", "updateDocumentHtml", "addEvent"]),
50
54
  onReady(editor) {
51
- const toolbarContainer = document.querySelector(
52
- ".document-editor__toolbar"
53
- );
55
+ const toolbarContainer = document.querySelector(".document-editor__toolbar");
54
56
  toolbarContainer.appendChild(editor.ui.view.toolbar.element);
55
57
  },
56
58
  changed() {
@@ -61,6 +63,7 @@ export default {
61
63
  </script>
62
64
 
63
65
  <style scoped>
66
+ /* Estilos do seu componente */
64
67
  .document-editor {
65
68
  border-radius: var(--ck-border-radius);
66
69
  max-height: 700px;
@@ -74,10 +77,6 @@ export default {
74
77
  min-width: 1100px;
75
78
  }
76
79
 
77
- .document-editor__toolbar .ck-toolbar {
78
- border-radius: 0;
79
- }
80
-
81
80
  .document-editor__editable-container {
82
81
  padding: 10px;
83
82
  border: 1px solid #e4e6ec;
@@ -95,56 +94,7 @@ export default {
95
94
  margin: 0 auto;
96
95
  }
97
96
 
98
- .document-editor .ck-content,
99
- .document-editor .ck-heading-dropdown .ck-list .ck-button__label {
97
+ .document-editor .ck-content {
100
98
  font: 16px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
101
99
  }
102
-
103
- .document-editor .ck-heading-dropdown .ck-list .ck-button__label {
104
- line-height: calc(
105
- 1.7 * var(--ck-line-height-base) * var(--ck-font-size-base)
106
- );
107
- min-width: 6em;
108
- }
109
-
110
- .document-editor
111
- .ck-heading-dropdown
112
- .ck-list
113
- .ck-button:not(.ck-heading_paragraph)
114
- .ck-button__label {
115
- transform: scale(0.8);
116
- transform-origin: left;
117
- }
118
-
119
- .document-editor .ck-content h2,
120
- .document-editor .ck-heading-dropdown .ck-heading_heading1 .ck-button__label {
121
- font-size: 2.18em;
122
- font-weight: normal;
123
- }
124
-
125
- .document-editor .ck-content h2 {
126
- line-height: 1.37em;
127
- padding-top: 0.342em;
128
- margin-bottom: 0.142em;
129
- }
130
-
131
- .document-editor .ck-content h3,
132
- .document-editor .ck-heading-dropdown .ck-heading_heading2 .ck-button__label {
133
- font-size: 1.75em;
134
- font-weight: normal;
135
- color: hsl(203, 100%, 50%);
136
- }
137
-
138
- .document-editor
139
- .ck-heading-dropdown
140
- .ck-heading_heading2.ck-on
141
- .ck-button__label {
142
- color: var(--ck-color-list-button-on-text);
143
- }
144
-
145
- .document-editor .ck-content h3 {
146
- line-height: 1.86em;
147
- padding-top: 0.171em;
148
- margin-bottom: 0.357em;
149
- }
150
100
  </style>
@@ -1,11 +1,15 @@
1
1
  <template>
2
- <v-runtime-template :template="`<div>${template}</div>`" />
2
+ <div>
3
+ <div ref='preview'>
4
+ <v-runtime-template :template="`<div>${template}</div>`" />
5
+ </div>
6
+ </div>
3
7
  </template>
4
8
 
5
9
  <script>
6
10
  import VRuntimeTemplate from "v-runtime-template";
7
11
 
8
- import { mapGetters } from "vuex";
12
+ import { mapGetters, mapMutations } from "vuex";
9
13
 
10
14
  export default {
11
15
  name: "DocumentPreview",
@@ -17,6 +21,7 @@ export default {
17
21
  d: Object,
18
22
  },
19
23
  methods: {
24
+ ...mapMutations("generic", ["updateDocumentHtmlFinal"]),
20
25
  periodo(grupo, campo) {
21
26
  var item = this.d.itensLocacao.find(item => item.grupo == grupo);
22
27
  const campoMap = {
@@ -48,14 +53,29 @@ export default {
48
53
  convertToNumber(value) {
49
54
  return parseFloat(value.replace("R$", "").replace(",", "."));
50
55
  },
56
+ getPreviewContent() {
57
+ const previewDiv = this.$refs.preview;
58
+ this.updateDocumentHtmlFinal(previewDiv.innerHTML);
59
+ }
51
60
  },
52
61
  computed: {
53
- ...mapGetters("generic", ["groupBy"]),
62
+ ...mapGetters("generic", ["groupBy", "event"]),
54
63
  produtoAgrupado() {
55
64
  var group = this.groupBy({ array: this.d.itensLocacao, key: "grupo" });
56
65
  return group;
57
66
  },
58
-
59
67
  },
68
+ watch: {
69
+ event: {
70
+ handler(event) {
71
+ if (event.name == "updateDocumentHtml") {
72
+ this.getPreviewContent();
73
+ }
74
+ },
75
+ deep: true,
76
+ },
77
+ },
78
+
79
+
60
80
  };
61
81
  </script>
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <div class="loading-skeleton" :style="'height:' + height + 'px'">
3
+ <div v-for="index in totalLine" :key="index" class="line"
4
+ :style="{ height: getRandomHeight() + 'px', width: '100%' }"></div>
5
+ </div>
6
+ </template>
7
+
8
+ <script>
9
+ export default {
10
+ name: "LoadingCard",
11
+ props: {
12
+ totalLine: {
13
+ type: Number,
14
+ default: 3,
15
+ validator(value) {
16
+ return value >= 1 && value <= 10;
17
+ }
18
+ },
19
+ height: {
20
+ type: Number,
21
+ default: 200,
22
+ validator(value) {
23
+ return value > 0;
24
+ }
25
+ }
26
+ },
27
+ methods: {
28
+ getRandomHeight() {
29
+ const minHeight = 10;
30
+ const maxHeight = 30;
31
+ return Math.floor(Math.random() * (maxHeight - minHeight + 1)) + minHeight;
32
+ }
33
+ }
34
+ };
35
+ </script>
36
+
37
+ <style scoped>
38
+ .loading-skeleton {
39
+ display: flex;
40
+ flex-direction: column;
41
+ gap: 12px;
42
+ max-width: 400px;
43
+ margin: 0 auto;
44
+ overflow: hidden;
45
+ }
46
+
47
+ .line {
48
+ width: 100%;
49
+ background: linear-gradient(90deg, #f0f0f0 25%, #d8d8d8 50%, #f0f0f0 75%);
50
+ background-size: 200% 100%;
51
+ animation: shimmer 1.5s infinite linear;
52
+ border-radius: 4px;
53
+ opacity: 0.4;
54
+ }
55
+
56
+ @keyframes shimmer {
57
+ 0% {
58
+ background-position: -200% 0;
59
+ }
60
+
61
+ 100% {
62
+ background-position: 200% 0;
63
+ }
64
+ }
65
+ </style>
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <div>
3
- <progress-bar :size="size" :text="text" :val="value" :max="max"></progress-bar>
3
+ <progress-bar :bg-color="bColor" :bar-color="bgColor" :size="size" :text="text" :val="value" :max="max"
4
+ bar-border-radius="10"></progress-bar>
4
5
  </div>
5
6
  </template>
6
7
  <script>
@@ -13,6 +14,8 @@ export default {
13
14
  ProgressBar,
14
15
  },
15
16
  props: {
17
+ bgColor: String,
18
+ bColor: String,
16
19
  text: String,
17
20
  value: Number,
18
21
  max: Number,
@@ -0,0 +1,128 @@
1
+ <template>
2
+ <div class="toggle-container">
3
+ <label class="switch">
4
+ <input type="checkbox" v-model="isDarkMode" @change="toggleTheme">
5
+ <span class="slider round">
6
+ <div class="icon-theme-light" v-if="themeLabel == 'Dark'">
7
+ <i class="fa-solid fa-sun"></i>
8
+ </div>
9
+ <div class="icon-theme-dark" v-if="themeLabel == 'Light'">
10
+ <i class="fa-solid fa-moon"></i>
11
+ </div>
12
+ </span>
13
+ </label>
14
+ </div>
15
+ </template>
16
+
17
+ <script>
18
+ export default {
19
+ data() {
20
+ return {
21
+ isDarkMode: false,
22
+ };
23
+ },
24
+ computed: {
25
+ themeLabel() {
26
+ return this.isDarkMode ? 'Dark' : 'Light';
27
+ }
28
+ },
29
+ methods: {
30
+ toggleTheme() {
31
+ if (this.isDarkMode) {
32
+ document.body.classList.add('dark-theme');
33
+ document.body.classList.remove('light-theme');
34
+ } else {
35
+ document.body.classList.add('light-theme');
36
+ document.body.classList.remove('dark-theme');
37
+ }
38
+ },
39
+ },
40
+ mounted() {
41
+ if (localStorage.getItem('theme') === 'dark') {
42
+ this.isDarkMode = true;
43
+ document.body.classList.add('dark-theme');
44
+ document.body.classList.remove('light-theme');
45
+ } else {
46
+ this.isDarkMode = false;
47
+ document.body.classList.add('light-theme');
48
+ document.body.classList.remove('dark-theme');
49
+ }
50
+ },
51
+ watch: {
52
+ isDarkMode(newVal) {
53
+ localStorage.setItem('theme', newVal ? 'dark' : 'light');
54
+ }
55
+ }
56
+ };
57
+ </script>
58
+
59
+ <style scoped>
60
+ .icon-theme-dark {
61
+ margin-left: 26px;
62
+ margin-top: -2px;
63
+ }
64
+
65
+ .icon-theme-light {
66
+ margin-left: 6px;
67
+ margin-top: -3px;
68
+ color: white;
69
+ }
70
+
71
+
72
+ .toggle-container {
73
+ display: flex;
74
+ align-items: center;
75
+ gap: 10px;
76
+ }
77
+
78
+ .switch {
79
+ position: relative;
80
+ display: inline-block;
81
+ width: 45px;
82
+ height: 22px;
83
+ }
84
+
85
+ .switch input {
86
+ opacity: 0;
87
+ width: 0;
88
+ height: 0;
89
+ }
90
+
91
+ .slider {
92
+ position: absolute;
93
+ cursor: pointer;
94
+ top: 0;
95
+ left: 0;
96
+ right: 0;
97
+ bottom: 0;
98
+ background-color: #ccc;
99
+ transition: 0.4s;
100
+ border-radius: 34px;
101
+ }
102
+
103
+ .slider:before {
104
+ position: absolute;
105
+ content: "";
106
+ height: 14px;
107
+ width: 14px;
108
+ border-radius: 50%;
109
+ left: 4px;
110
+ bottom: 4px;
111
+ background-color: white;
112
+ transition: 0.4s;
113
+ }
114
+
115
+ input:checked+.slider {
116
+ background-color: #ccc;
117
+ }
118
+
119
+ input:checked+.slider:before {
120
+ transform: translateX(20px);
121
+ }
122
+
123
+ .theme-indicator {
124
+ font-size: 12px;
125
+ font-weight: bold;
126
+ color: #333;
127
+ }
128
+ </style>
@@ -17,6 +17,7 @@ export default {
17
17
  name: undefined,
18
18
  open: false
19
19
  },
20
+ menuCollapsed: true,
20
21
  notifications: [],
21
22
  pagination: [],
22
23
  paginations: { currentPage: 1, totalPerPage: 10 },
@@ -35,6 +36,7 @@ export default {
35
36
  ids: undefined,
36
37
  search: { content: "", filter: { content: "Contém", id: "contains" } },
37
38
  documentHtml: "",
39
+ documentHtmlFinal: "",
38
40
  selectStatic: { dateTime: undefined, tag: undefined, fieldTarget: undefined, value: undefined },
39
41
  tags: [],
40
42
  executedSearch: false,
@@ -258,6 +260,9 @@ export default {
258
260
  state.modal.name = name;
259
261
  state.modal.open = true;
260
262
  },
263
+ toggleMenu: (state, data) => {
264
+ state.menuCollapsed = data;
265
+ },
261
266
  hideModal: (state) => {
262
267
  state.modal.open = false;
263
268
  },
@@ -292,6 +297,9 @@ export default {
292
297
  updateTotalPerPage: (state, value) => {
293
298
  state.paginations.totalPerPage = value.id;
294
299
  },
300
+ updateDocumentHtmlFinal: (state, html) => {
301
+ state.documentHtmlFinal = html;
302
+ },
295
303
  addSelected: (state, selected) => {
296
304
  state.selected = selected;
297
305
  },