@nixweb/nixloc-ui 0.0.291 → 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.291",
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>
@@ -0,0 +1,136 @@
1
+ <template>
2
+ <div>
3
+ <div class="icon-logout" @click="execute">
4
+ <i class="fa-duotone fa-solid fa-right-from-bracket"></i>
5
+ </div>
6
+ <div class="profile-container" v-if="hideShow">
7
+ <div class="item-header text-center">
8
+ <span>Conta</span>
9
+ </div>
10
+ <div class="profile-content" v-for="item in items" :key="item.title">
11
+ <div class="item-content" @click="navegateTo(item.routeName)">
12
+ <div class="title-container">
13
+ <span>
14
+ <i :class="item.classIcon"></i>
15
+ <span class="title-profile title-input">{{ item.title }}</span>
16
+ </span>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ <div class="profile-content" @click="execute">
21
+ <div class="item-content">
22
+ <div class="title-container">
23
+ <span>
24
+ <i class="fas fa-sign-in"></i>
25
+ <span class="title-profile title-input">Sair</span>
26
+ </span>
27
+ </div>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </template>
33
+ <script>
34
+ export default {
35
+ name: "Account",
36
+ props: {
37
+ items: [],
38
+ exited: Function,
39
+ },
40
+ data() {
41
+ return {
42
+ hideShow: false,
43
+ };
44
+ },
45
+ methods: {
46
+ navegateTo(routeName) {
47
+ this.$router.push({ name: routeName });
48
+ this.hideShow = false;
49
+ },
50
+ execute() {
51
+ if (this.exited) this.exited();
52
+ },
53
+ },
54
+ };
55
+ </script>
56
+ <style scoped>
57
+ .icon-logout {
58
+ padding-left: 12px;
59
+ padding-top: 2px;
60
+ margin-top: -43px;
61
+ margin-right: 28px;
62
+ cursor: pointer;
63
+ position: fixed;
64
+ float: right;
65
+ left: auto;
66
+ right: 0;
67
+ width: 40px;
68
+ height: 40px;
69
+ border-radius: 12px;
70
+ color: #F0134D;
71
+ font-size: 22px;
72
+ }
73
+
74
+ img {
75
+ border-radius: 50%;
76
+ height: 40px;
77
+ width: 40px;
78
+ }
79
+
80
+ .profile-container {
81
+ position: fixed;
82
+ float: right;
83
+ left: auto;
84
+ right: 0;
85
+ margin-right: 20px;
86
+ height: 100%;
87
+ z-index: 1000;
88
+ width: 190px;
89
+ margin-top: 26px;
90
+ background-color: white;
91
+ height: auto;
92
+ border-bottom: 1px solid #e9ebec;
93
+ }
94
+
95
+ .profile-content {
96
+ right: 0;
97
+ height: 100%;
98
+ z-index: 101;
99
+ width: 190px;
100
+ height: auto;
101
+ }
102
+
103
+ .item-header {
104
+ padding: 8px 20px;
105
+ background: #f8f8f8;
106
+ border-left: 1px solid #e9ebec;
107
+ border-right: 1px solid #e9ebec;
108
+ border-top: 1px solid #e9ebec;
109
+ }
110
+
111
+ .item-content {
112
+ padding-left: 15px;
113
+ height: 45px;
114
+ background: white;
115
+ border: 1px solid #e9ebec;
116
+ border-bottom: 0px solid #e9ebec;
117
+ cursor: pointer;
118
+ }
119
+
120
+ .item-content:hover {
121
+ background: #f8f8f8;
122
+ }
123
+
124
+ .title-container {
125
+ padding-top: 10px;
126
+ }
127
+
128
+ .title-container:hover {
129
+ padding-top: 10px;
130
+ color: #37597c;
131
+ }
132
+
133
+ .title-profile {
134
+ padding-left: 10px;
135
+ }
136
+ </style>
@@ -0,0 +1,58 @@
1
+ <template>
2
+ <div>
3
+ <div :class="['top', { collapsed: menuCollapsed, notCollapsed: !menuCollapsed }]">
4
+ <div class="side-by-side top-space">
5
+ <slot></slot>
6
+ </div>
7
+ <div class="side-by-side div-theme">
8
+ <ToggleTheme />
9
+ </div>
10
+ </div>
11
+ </div>
12
+ </template>
13
+
14
+ <script>
15
+
16
+ import ToggleTheme from "@nixweb/nixloc-ui/src/component/shared/ToggleTheme.vue";
17
+
18
+ import { mapState } from "vuex";
19
+
20
+ export default {
21
+ name: "Top",
22
+ components: {
23
+ ToggleTheme
24
+ },
25
+ props: {
26
+ backgroundColor: {
27
+ type: String,
28
+ default: "#4680A5",
29
+ },
30
+ },
31
+ computed: {
32
+ ...mapState("generic", ["menuCollapsed"]),
33
+ },
34
+ };
35
+ </script>
36
+
37
+ <style scoped>
38
+ .top {
39
+ right: 10px;
40
+ height: 55px;
41
+ top: 5px;
42
+ border-bottom: 0px solid #eff0f1;
43
+ position: relative;
44
+ transition: all 0.3s ease;
45
+ }
46
+
47
+ .top.notCollapsed {
48
+ left: 270px;
49
+ }
50
+
51
+ .top.collapsed {
52
+ left: 95px;
53
+ }
54
+
55
+ .div-theme {
56
+ margin-left: 15px;
57
+ }
58
+ </style>
@@ -0,0 +1,71 @@
1
+ <template>
2
+ <div>
3
+ <div v-for="icon in icons" class="molded-icon side-by-side" @click="executeEvent(icon.eventName)" v-b-tooltip.hover
4
+ :title="icon.tooltip">
5
+ <div :class="{
6
+ 'icon-active-header': moduleActive === icon.module,
7
+ }" class="icon-molded-icon">
8
+ <i :class="icon.icon"></i>
9
+ </div>
10
+ </div>
11
+ </div>
12
+ </template>
13
+
14
+ <script>
15
+ import { mapMutations } from "vuex";
16
+
17
+ export default {
18
+ name: "IconMolded",
19
+ props: {
20
+ icons: Array,
21
+ },
22
+ data() {
23
+ return { moduleActive: "" };
24
+ },
25
+ methods: {
26
+ ...mapMutations("generic", ["addEvent"]),
27
+ executeEvent(eventName) {
28
+ this.addEvent({
29
+ name: eventName,
30
+ });
31
+ this.addEvent({
32
+ name: "cleanMenuSelected",
33
+ });
34
+ },
35
+ },
36
+ watch: {
37
+ $route: {
38
+ handler: function (router) {
39
+ this.moduleActive = router.matched[0].props.default.module;
40
+ },
41
+ deep: true,
42
+ },
43
+ },
44
+ };
45
+ </script>
46
+
47
+ <style scoped>
48
+ .molded-icon {
49
+ height: 38px;
50
+ width: 38px;
51
+ margin-left: 10px;
52
+ margin-top: 4px;
53
+ cursor: pointer;
54
+ }
55
+
56
+ .icon-molded-icon {
57
+ font-size: 20px;
58
+ margin-left: 10px;
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;
70
+ }
71
+ </style>
@@ -0,0 +1,441 @@
1
+ <template>
2
+ <div>
3
+ <div :class="['sidebar', { collapsed: menuCollapsed }]">
4
+ <div class="sidebar-header">
5
+ <span class="header-logo" @click="editProfile">
6
+ <img class="photo" :src="urlPhoto" />
7
+ </span>
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
+ </span>
13
+ </Button>
14
+ </div>
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>
49
+ </div>
50
+
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>
61
+ </div>
62
+ </div>
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>
83
+ </div>
84
+ </div>
85
+ </transition>
86
+ </div>
87
+ <br>
88
+ <br>
89
+ <br>
90
+ </div>
91
+ </ScrollBar>
92
+
93
+ </div>
94
+ </div>
95
+ </template>
96
+
97
+ <script>
98
+
99
+ import ScrollBar from "@nixweb/nixloc-ui/src/component/layout/ScrollBar.vue";
100
+
101
+ import { mapState, mapMutations, mapGetters } from "vuex";
102
+
103
+ export default {
104
+ props: {
105
+ urlPhoto: String,
106
+ },
107
+ components: {
108
+ ScrollBar
109
+ },
110
+ data() {
111
+ return {
112
+ module: "",
113
+ moduleActive: "",
114
+ isSidebarCollapsed: true,
115
+ openDropdowns: {},
116
+ titleSubMenu: "",
117
+ titleSubMenuCollapsed: "",
118
+ pageSize: 0,
119
+ distanceFromBottom: 0,
120
+ };
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
+ },
143
+ computed: {
144
+ ...mapState("user", ["menu", "userLogged"]),
145
+ ...mapState("generic", ["menuCollapsed"]),
146
+ ...mapGetters("generic", ["event"]),
147
+ },
148
+ methods: {
149
+ ...mapMutations("generic", ["addEvent", "toggleMenu"]),
150
+ updatePageSize() {
151
+ const windowHeight = window.innerHeight;
152
+ this.pageSize = windowHeight;
153
+ },
154
+ toggleSidebar() {
155
+ this.isSidebarCollapsed = !this.isSidebarCollapsed;
156
+ this.toggleMenu(this.isSidebarCollapsed);
157
+ localStorage.setItem('menuCollapsed', this.isSidebarCollapsed ? "closed" : "open");
158
+ this.titleSubMenu = "";
159
+ this.titleSubMenuCollapsed = "";
160
+ },
161
+ toggleSubMenu(title, module) {
162
+ this.module = module;
163
+ if (this.titleSubMenu === title) {
164
+ this.titleSubMenu = "";
165
+ } else {
166
+ this.titleSubMenu = title;
167
+ }
168
+ },
169
+ handleMouseOver(title, module) {
170
+ this.module = module;
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
+ }
186
+ },
187
+ handleMouseLeave() {
188
+ this.titleSubMenuCollapsed = "";
189
+ if (this.menuCollapsed)
190
+ this.module = "";
191
+ },
192
+ menuFilter(isModule) {
193
+ let filter = [];
194
+ this.menu.items.forEach(function (obj) {
195
+ if (obj.isModule == isModule) filter.push(obj);
196
+ });
197
+ return filter.sort((a, b) => a.order - b.order);
198
+ },
199
+ subMenuFilter(isModule) {
200
+ let filter = [];
201
+ let self = this;
202
+ let userLogged = this.userLogged.user.userName;
203
+ this.menu.items.forEach(function (obj) {
204
+ if (obj.isModule == isModule && obj.module === self.module) {
205
+ if (obj.isVisible == "all") filter.push(obj);
206
+
207
+ if (obj.isVisible == "support" && userLogged == "UserTemp")
208
+ filter.push(obj);
209
+ }
210
+ });
211
+ return filter;
212
+ },
213
+ navegateTo(item, module) {
214
+ this.$router.push({
215
+ name: item.routeName,
216
+ });
217
+
218
+ this.moduleActive = module;
219
+ this.titleSubMenuCollapsed = "";
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
+ },
240
+ },
241
+ };
242
+ </script>
243
+
244
+ <style scoped>
245
+ .sidebar {
246
+ position: fixed;
247
+ top: 0;
248
+ left: 0;
249
+ width: 275px;
250
+ height: 100vh;
251
+ border-radius: 0px 20px 0px 0px;
252
+ background-color: #577696;
253
+ transition: all 0.4s ease;
254
+ z-index: 1000;
255
+ }
256
+
257
+ .sidebar.collapsed {
258
+ width: 85px;
259
+ }
260
+
261
+ .sidebar .sidebar-header {
262
+ display: flex;
263
+ position: relative;
264
+ padding: 10px 20px;
265
+ align-items: center;
266
+ justify-content: space-between;
267
+ }
268
+
269
+ .sidebar-header .header-logo img {
270
+ width: 46px;
271
+ height: 46px;
272
+ display: block;
273
+ object-fit: contain;
274
+ cursor: pointer;
275
+ border-radius: 50%;
276
+ }
277
+
278
+ .sidebar-header .sidebar-toggler,
279
+ .sidebar-menu-button {
280
+ position: absolute;
281
+ right: 23px;
282
+ height: 30px;
283
+ width: 30px;
284
+ color: #151A2D;
285
+ border: none;
286
+ cursor: pointer;
287
+ display: flex;
288
+ background: #EEF2FF;
289
+ align-items: center;
290
+ justify-content: center;
291
+ border-radius: 50px;
292
+ transition: 0.4s ease;
293
+ }
294
+
295
+ .sidebar.collapsed .sidebar-header .sidebar-toggler {
296
+ transform: translate(-4px, 65px);
297
+ }
298
+
299
+ .molded-icon-open {
300
+ padding-left: 10px;
301
+ cursor: pointer;
302
+ margin-top: 10px;
303
+ color: white;
304
+ font-size: 17px;
305
+ margin: 15px;
306
+ border-radius: 10px;
307
+ transition: all 0.3s ease;
308
+ }
309
+
310
+ .molded-icon-open:hover {
311
+ color: #2C3453;
312
+ background-color: white;
313
+ }
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
+
329
+ .molded-icon {
330
+ cursor: pointer;
331
+ padding: 1px;
332
+ color: white;
333
+ font-size: 18px;
334
+ margin: 10px;
335
+ border-radius: 10px;
336
+ transition: all 0.3s ease;
337
+ }
338
+
339
+ .molded-icon:hover {
340
+ background-color: white;
341
+ color: #2C3453;
342
+ margin: 10px;
343
+ border-radius: 10px;
344
+ transition: all 0.8s ease;
345
+ }
346
+
347
+ .sub {
348
+ cursor: pointer;
349
+ transition: all 0.3s ease;
350
+ }
351
+
352
+ .sub-menu {
353
+ margin: 15px;
354
+ padding: 10px;
355
+ border-radius: 15px;
356
+ color: white;
357
+ font-size: 14px;
358
+ background-color: #2C3453;
359
+ transition: all 0.5s ease;
360
+ }
361
+
362
+ .sub-menu-title {
363
+ cursor: pointer;
364
+ border-radius: 8px;
365
+ padding: 5px;
366
+ transition: all 1s ease;
367
+ }
368
+
369
+ .sub-menu-title:hover {
370
+ padding: 5px;
371
+ color: #2C3453;
372
+ background-color: white;
373
+ font-weight: bold;
374
+ transition: all 0.8s ease;
375
+ }
376
+
377
+ .sub-menu-collapsed {
378
+ width: 260px;
379
+ margin-top: -100px;
380
+ margin-left: 85px;
381
+ position: absolute;
382
+ border-radius: 0px 15px 15px 0px;
383
+ background-color: #2C3453;
384
+ }
385
+
386
+ .sub-menu-title-collapsed {
387
+ padding: 10px;
388
+ border-radius: 8px;
389
+ }
390
+
391
+ .sub-menu-title-collapsed:hover {
392
+ background-color: white;
393
+ color: #2C3453;
394
+ transition: all 0.8s ease;
395
+ }
396
+
397
+ .rotate {
398
+ transform: rotate(180deg);
399
+ transition: transform 0.5s ease;
400
+ }
401
+
402
+ .rotate-down {
403
+ transform: rotate(360deg);
404
+ transition: transform 0.5s ease;
405
+ }
406
+
407
+ .title-menu {
408
+ font-size: 14px;
409
+ padding: 20px;
410
+ }
411
+
412
+ .div-arrow {
413
+ margin-left: 50px;
414
+ }
415
+
416
+ .div-menu-bottom {
417
+ position: absolute;
418
+ bottom: 0;
419
+ left: 0;
420
+ width: 100%;
421
+ padding: 10px;
422
+ }
423
+
424
+ .div-icon-bottom {
425
+ cursor: pointer;
426
+ font-size: 17px;
427
+ color: white;
428
+ border-radius: 10px;
429
+ background-color: #2C3453;
430
+ }
431
+
432
+ .title-logout {
433
+ font-size: 16px;
434
+ margin-left: 10px;
435
+ }
436
+
437
+ .div-group {
438
+ margin-left: 10px;
439
+ padding: 5px;
440
+ }
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
  },