@processmaker/screen-builder 2.83.11 → 2.84.0
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/dist/vue-form-builder.css +1 -1
- package/dist/vue-form-builder.es.js +4502 -4042
- package/dist/vue-form-builder.es.js.map +1 -1
- package/dist/vue-form-builder.umd.js +52 -52
- package/dist/vue-form-builder.umd.js.map +1 -1
- package/package.json +18 -2
- package/src/App.vue +33 -56
- package/src/assets/css/custom.css +11 -0
- package/src/bootstrap.js +111 -0
- package/src/components/ScreenToolbar.vue +100 -0
- package/src/components/TabsBar.vue +354 -0
- package/src/components/editor/pagesDropdown.vue +125 -0
- package/src/components/inspector/color-select.vue +18 -1
- package/src/components/sortable/Sortable.vue +80 -0
- package/src/components/sortable/sortable.scss +25 -0
- package/src/components/sortable/sortableList/SortableList.vue +140 -0
- package/src/components/sortable/sortableList/sortableList.scss +73 -0
- package/src/components/vue-form-builder.vue +339 -253
- package/src/main.js +1 -2
- package/src/mixins/canOpenJsonFile.js +1 -1
- package/src/stories/ColorSelect.stories.js +79 -0
- package/src/stories/Configure.mdx +78 -0
- package/src/stories/DropdownAndPages.stories.js +112 -0
- package/src/stories/PageTabs.stories.js +338 -0
- package/src/stories/PagesDropdown.stories.js +132 -0
- package/src/stories/ScreenToolbar.stories.js +188 -0
- package/src/stories/Sortable.stories.js +225 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<b-tabs
|
|
3
|
+
ref="tabs"
|
|
4
|
+
v-model="activeTab"
|
|
5
|
+
class="h-100 w-100 flat-tabs"
|
|
6
|
+
content-class="h-tab"
|
|
7
|
+
lazy
|
|
8
|
+
@changed="tabsUpdated"
|
|
9
|
+
@input="tabOpened"
|
|
10
|
+
>
|
|
11
|
+
<template #tabs-start>
|
|
12
|
+
<div class="tabs-sticky d-flex flex-row tabs-start">
|
|
13
|
+
<div
|
|
14
|
+
v-show="tabsListOverflow"
|
|
15
|
+
class="position-relative overflow-visible"
|
|
16
|
+
>
|
|
17
|
+
<div
|
|
18
|
+
role="link"
|
|
19
|
+
class="nav-scroll nav-scroll-left"
|
|
20
|
+
data-test="scroll-left"
|
|
21
|
+
@click="scrollTabsLeft"
|
|
22
|
+
>
|
|
23
|
+
<i class="fas fa-chevron-left" />
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div :class="{'dd-ml': tabsListOverflow}">
|
|
29
|
+
<slot name="tabs-start" />
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
<b-tab
|
|
33
|
+
v-for="(index, n) in validLocalOpenedPages"
|
|
34
|
+
:key="`tab-${n}`"
|
|
35
|
+
class="h-100 w-100"
|
|
36
|
+
>
|
|
37
|
+
<template #title>
|
|
38
|
+
<b-badge variant="primary" class="mr-1">
|
|
39
|
+
{{ pageNumber(index) }}
|
|
40
|
+
</b-badge>
|
|
41
|
+
<span :data-test="`tab-${n}`">
|
|
42
|
+
{{ pages[index]?.name }}
|
|
43
|
+
</span>
|
|
44
|
+
<span
|
|
45
|
+
:data-test="`close-tab-${n}`"
|
|
46
|
+
class="close-tab"
|
|
47
|
+
role="link"
|
|
48
|
+
@click.stop="closeTab(n)"
|
|
49
|
+
>
|
|
50
|
+
<i class="fas fa-times" />
|
|
51
|
+
</span>
|
|
52
|
+
</template>
|
|
53
|
+
<template #default>
|
|
54
|
+
<div class="h-100 w-100" data-test="tab-content">
|
|
55
|
+
<slot :current-page="index" />
|
|
56
|
+
</div>
|
|
57
|
+
</template>
|
|
58
|
+
</b-tab>
|
|
59
|
+
<template #tabs-end>
|
|
60
|
+
<div
|
|
61
|
+
v-if="tabsListOverflow"
|
|
62
|
+
class="tabs-sticky overflow-visible"
|
|
63
|
+
>
|
|
64
|
+
<div
|
|
65
|
+
role="link"
|
|
66
|
+
class="nav-scroll nav-scroll-right"
|
|
67
|
+
data-test="scroll-right"
|
|
68
|
+
@click="scrollTabsRight"
|
|
69
|
+
>
|
|
70
|
+
<i class="fas fa-chevron-right" />
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</template>
|
|
74
|
+
<template #empty>
|
|
75
|
+
<p class="text-center m-5 text-secondary" data-test="tab-content">
|
|
76
|
+
{{ $t("There are no open pages.") }}<br />
|
|
77
|
+
{{ $t("Open a new page above using the button") }}
|
|
78
|
+
<i :class="buttonIcon" />
|
|
79
|
+
</p>
|
|
80
|
+
</template>
|
|
81
|
+
</b-tabs>
|
|
82
|
+
</template>
|
|
83
|
+
|
|
84
|
+
<script>
|
|
85
|
+
const SCROLL_STEP = 200;
|
|
86
|
+
|
|
87
|
+
export default {
|
|
88
|
+
props: {
|
|
89
|
+
/**
|
|
90
|
+
* The configuration of all the pages
|
|
91
|
+
*/
|
|
92
|
+
pages: {
|
|
93
|
+
type: Array,
|
|
94
|
+
required: true
|
|
95
|
+
},
|
|
96
|
+
/**
|
|
97
|
+
* The array of initial opened pages indexes
|
|
98
|
+
*/
|
|
99
|
+
initialOpenedPages: {
|
|
100
|
+
type: Array,
|
|
101
|
+
default: () => [0]
|
|
102
|
+
},
|
|
103
|
+
/**
|
|
104
|
+
* Icon to open a new tab, displayed when there are no pages opened.
|
|
105
|
+
*/
|
|
106
|
+
buttonIcon: {
|
|
107
|
+
type: String,
|
|
108
|
+
default: () => "fa fa-file"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
data() {
|
|
112
|
+
return {
|
|
113
|
+
tabsListOverflow: false,
|
|
114
|
+
showLeftScroll: true,
|
|
115
|
+
showRightScroll: true,
|
|
116
|
+
updates: 0,
|
|
117
|
+
activeTab: 0,
|
|
118
|
+
localOpenedPages: this.initialOpenedPages
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
computed: {
|
|
122
|
+
validLocalOpenedPages() {
|
|
123
|
+
return this.localOpenedPages.filter((page) => this.pages[page]);
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
watch: {
|
|
127
|
+
openedPages: {
|
|
128
|
+
handler(newVal) {
|
|
129
|
+
this.localOpenedPages = newVal;
|
|
130
|
+
},
|
|
131
|
+
deep: true
|
|
132
|
+
},
|
|
133
|
+
pages: {
|
|
134
|
+
handler() {
|
|
135
|
+
this.localOpenedPages = this.localOpenedPages.filter(
|
|
136
|
+
(page) => this.pages[page]
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
deep: true
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
mounted() {
|
|
143
|
+
this.$nextTick(() => {
|
|
144
|
+
// check resize of tabs list
|
|
145
|
+
window.addEventListener("resize", this.checkTabsOverflow);
|
|
146
|
+
// listen to scroll event
|
|
147
|
+
const tablist = this.$refs.tabs.$el.querySelector(".nav-tabs");
|
|
148
|
+
tablist.addEventListener("scroll", this.checkScrollPosition);
|
|
149
|
+
|
|
150
|
+
Promise.resolve().then(() => {
|
|
151
|
+
this.checkTabsOverflow();
|
|
152
|
+
this.checkScrollPosition();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
},
|
|
157
|
+
beforeDestroy() {
|
|
158
|
+
window.removeEventListener("resize", this.checkTabsOverflow);
|
|
159
|
+
},
|
|
160
|
+
updated() {
|
|
161
|
+
this.checkTabsOverflow();
|
|
162
|
+
},
|
|
163
|
+
methods: {
|
|
164
|
+
tabOpened() {
|
|
165
|
+
const pageIndex = this.localOpenedPages[this.activeTab];
|
|
166
|
+
this.$emit("tab-opened", pageIndex);
|
|
167
|
+
},
|
|
168
|
+
pageNumber(index) {
|
|
169
|
+
return index + 1;
|
|
170
|
+
},
|
|
171
|
+
checkScrollPosition() {
|
|
172
|
+
const tablist = this.$refs.tabs.$el.querySelector(".nav-tabs");
|
|
173
|
+
this.showLeftScroll = tablist.scrollLeft > 0;
|
|
174
|
+
this.showRightScroll =
|
|
175
|
+
tablist.scrollWidth - tablist.clientWidth > tablist.scrollLeft;
|
|
176
|
+
},
|
|
177
|
+
scrollTabsLeft() {
|
|
178
|
+
const tablist = this.$refs.tabs.$el.querySelector(".nav-tabs");
|
|
179
|
+
tablist.scrollLeft -= SCROLL_STEP;
|
|
180
|
+
},
|
|
181
|
+
scrollTabsRight() {
|
|
182
|
+
const tablist = this.$refs.tabs.$el.querySelector(".nav-tabs");
|
|
183
|
+
tablist.scrollLeft += SCROLL_STEP;
|
|
184
|
+
},
|
|
185
|
+
tabsUpdated() {
|
|
186
|
+
this.updates++;
|
|
187
|
+
},
|
|
188
|
+
waitUpdates(n, timeout, visualThreshold = 80) {
|
|
189
|
+
return new Promise((resolve) => {
|
|
190
|
+
const start = Date.now();
|
|
191
|
+
const interval = setInterval(() => {
|
|
192
|
+
if (this.updates >= n || Date.now() - start > timeout) {
|
|
193
|
+
clearInterval(interval);
|
|
194
|
+
resolve();
|
|
195
|
+
}
|
|
196
|
+
}, visualThreshold);
|
|
197
|
+
});
|
|
198
|
+
},
|
|
199
|
+
closeTab(pageId) {
|
|
200
|
+
this.localOpenedPages.splice(this.localOpenedPages.indexOf(pageId), 1);
|
|
201
|
+
this.$emit("tab-closed", this.pages[pageId], this.localOpenedPages);
|
|
202
|
+
},
|
|
203
|
+
updateTabsReferences(pageDelete) {
|
|
204
|
+
this.localOpenedPages = this.localOpenedPages.map((page) =>
|
|
205
|
+
page > pageDelete ? page - 1 : page
|
|
206
|
+
);
|
|
207
|
+
},
|
|
208
|
+
async openPageByIndex(index) {
|
|
209
|
+
if (index === -1) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const n = this.localOpenedPages.indexOf(index * 1);
|
|
213
|
+
if (n === -1) {
|
|
214
|
+
this.localOpenedPages.push(index);
|
|
215
|
+
await this.waitUpdates(this.updates + 2, 1000);
|
|
216
|
+
this.activeTab = this.localOpenedPages.length - 1;
|
|
217
|
+
} else {
|
|
218
|
+
this.activeTab = n;
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
closePageByIndex(index) {
|
|
222
|
+
const n = this.localOpenedPages.indexOf(index);
|
|
223
|
+
if (n !== -1) {
|
|
224
|
+
this.localOpenedPages.splice(n, 1);
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
checkTabsOverflow() {
|
|
228
|
+
const tablist = this.$refs.tabs.$el.querySelector(".nav-tabs");
|
|
229
|
+
this.tabsListOverflow = tablist.scrollWidth > tablist.clientWidth;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
</script>
|
|
234
|
+
|
|
235
|
+
<style>
|
|
236
|
+
/* Setup some colors */
|
|
237
|
+
:root {
|
|
238
|
+
--tabs-blue: #1572c2;
|
|
239
|
+
--tabs-light: #c3c9cf;
|
|
240
|
+
--tabs-grey: #6a7888;
|
|
241
|
+
--tabs-border: #cdddee;
|
|
242
|
+
--tabs-scroll-bg: #ebeef2;
|
|
243
|
+
--tabs-white: #ffffff;
|
|
244
|
+
}
|
|
245
|
+
/* Override Bootstrap default tab styles */
|
|
246
|
+
.nav-tabs {
|
|
247
|
+
border-bottom: 1px solid var(--tabs-border) !important;
|
|
248
|
+
flex-wrap: nowrap !important;
|
|
249
|
+
overflow: hidden !important;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.nav-tabs .nav-item .nav-link {
|
|
253
|
+
display: flex;
|
|
254
|
+
align-items: center;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* Style for individual tabs */
|
|
258
|
+
.nav-tabs .nav-item.show .nav-link,
|
|
259
|
+
.nav-tabs .nav-link.active {
|
|
260
|
+
border: none;
|
|
261
|
+
box-shadow: inset 0 -3px 0 0 var(--tabs-blue) !important; /* This sets the blue bottom border for the active tab */
|
|
262
|
+
background-color: var(
|
|
263
|
+
--tabs-white
|
|
264
|
+
); /* This sets the background color for the active tab */
|
|
265
|
+
border-radius: 0 !important; /* This removes the border-radius */
|
|
266
|
+
color: var(--tabs-blue) !important;
|
|
267
|
+
position: relative;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/* Style for non-active tabs */
|
|
271
|
+
.nav-tabs .nav-link {
|
|
272
|
+
border: 1px solid var(--tabs-border) !important;
|
|
273
|
+
color: var(--tabs-grey); /* This sets the text color for the inactive tabs */
|
|
274
|
+
border-radius: 0 !important; /* This ensures no border radius for a flat design */
|
|
275
|
+
padding: 0.5rem 1rem;
|
|
276
|
+
margin-right: -1px;
|
|
277
|
+
text-wrap: nowrap !important;
|
|
278
|
+
flex-wrap: nowrap !important;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.nav-tabs .nav-item .nav-link:not(.active) {
|
|
282
|
+
.badge {
|
|
283
|
+
background-color: #6A7888 !important;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
span:not(.badge, .close-tab) {
|
|
287
|
+
color: #556271 !important;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* Style for the hover effect */
|
|
292
|
+
.nav-tabs .nav-link:hover {
|
|
293
|
+
border: none;
|
|
294
|
+
background-color: var(
|
|
295
|
+
--tabs-white
|
|
296
|
+
); /* This changes the background color when hovering */
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* Adding the 'x' button to the tab */
|
|
300
|
+
.nav-tabs .nav-link .close-tab {
|
|
301
|
+
font-size: 0.8rem;
|
|
302
|
+
color: var(--tabs-light);
|
|
303
|
+
margin-left: 0.5rem;
|
|
304
|
+
display: inline !important;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* Style adjustments for the 'x' button */
|
|
308
|
+
.nav-tabs .nav-link .close-tab:hover {
|
|
309
|
+
color: var(--tabs-grey);
|
|
310
|
+
cursor: pointer;
|
|
311
|
+
}
|
|
312
|
+
.nav-tabs .nav-scroll {
|
|
313
|
+
position: absolute;
|
|
314
|
+
top: calc(50% - 0.75rem);
|
|
315
|
+
width: 1.5rem;
|
|
316
|
+
height: 1.5rem;
|
|
317
|
+
font-size: 0.75rem;
|
|
318
|
+
display: flex;
|
|
319
|
+
align-items: center;
|
|
320
|
+
justify-content: center;
|
|
321
|
+
background-color: var(--tabs-scroll-bg);
|
|
322
|
+
color: var(--tabs-grey);
|
|
323
|
+
cursor: pointer;
|
|
324
|
+
border: 1px solid var(--tabs-border);
|
|
325
|
+
border-radius: 100%;
|
|
326
|
+
z-index: 1;
|
|
327
|
+
}
|
|
328
|
+
.nav-tabs .nav-scroll-right {
|
|
329
|
+
right: 5px;
|
|
330
|
+
}
|
|
331
|
+
.nav-tabs .nav-scroll-left {
|
|
332
|
+
margin-left: 5px;
|
|
333
|
+
}
|
|
334
|
+
.nav-tabs .tabs-sticky {
|
|
335
|
+
position: sticky;
|
|
336
|
+
-webkit-position: sticky;
|
|
337
|
+
left: 0;
|
|
338
|
+
right: 0;
|
|
339
|
+
z-index: 2;
|
|
340
|
+
}
|
|
341
|
+
.nav-tabs .tabs-start {
|
|
342
|
+
background-color: var(--tabs-white);
|
|
343
|
+
}
|
|
344
|
+
/* add margin right to the last li element to hide safely the right scroll button */
|
|
345
|
+
.nav-tabs .nav-item:last-of-type {
|
|
346
|
+
margin-right: 2rem;
|
|
347
|
+
}
|
|
348
|
+
.flat-tabs .h-tab {
|
|
349
|
+
height: calc(100% - 42px) !important;
|
|
350
|
+
}
|
|
351
|
+
.dd-ml {
|
|
352
|
+
margin-left: 2rem;
|
|
353
|
+
}
|
|
354
|
+
</style>
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!--
|
|
3
|
+
Dropdown component to display options related to pages.
|
|
4
|
+
Provides options to add a new page, see all pages, and select individual pages.
|
|
5
|
+
-->
|
|
6
|
+
<b-dropdown
|
|
7
|
+
ref="pageDropdown"
|
|
8
|
+
data-test="page-dropdown"
|
|
9
|
+
variant="platform"
|
|
10
|
+
:boundary="boundary"
|
|
11
|
+
menu-class="page-dropdown-menu"
|
|
12
|
+
>
|
|
13
|
+
<!-- Dropdown button content -->
|
|
14
|
+
<template #button-content>
|
|
15
|
+
<!-- Icon representing a file -->
|
|
16
|
+
<i class="fa fa-file"></i>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<!-- Option to add a new page -->
|
|
20
|
+
<b-dropdown-item data-test="add-page" @click="onAddPage">
|
|
21
|
+
<!-- Icon for adding a new page -->
|
|
22
|
+
<i class="fa fa-plus platform-dropdown-item-icon"></i>
|
|
23
|
+
<!-- Text for adding a new page -->
|
|
24
|
+
{{ $t("Create Page") }}
|
|
25
|
+
</b-dropdown-item>
|
|
26
|
+
|
|
27
|
+
<!-- Option to see all pages -->
|
|
28
|
+
<b-dropdown-item data-test="see-all-pages" @click="onSeeAllPages">
|
|
29
|
+
<!-- Icon for seeing all pages -->
|
|
30
|
+
<i class="fa fa-eye platform-dropdown-item-icon"></i>
|
|
31
|
+
<!-- Text for seeing all pages -->
|
|
32
|
+
{{ $t("See all pages") }}
|
|
33
|
+
</b-dropdown-item>
|
|
34
|
+
|
|
35
|
+
<!-- Divider between adding and viewing options -->
|
|
36
|
+
<b-dropdown-divider></b-dropdown-divider>
|
|
37
|
+
|
|
38
|
+
<!-- Dropdown items for selecting individual pages -->
|
|
39
|
+
<b-dropdown-item
|
|
40
|
+
v-for="(item, page) in data"
|
|
41
|
+
:key="page"
|
|
42
|
+
:data-test="'page-' + item.name"
|
|
43
|
+
:data-cy="'page-' + page"
|
|
44
|
+
@click="onClickPage(page)"
|
|
45
|
+
>
|
|
46
|
+
<!-- Display the name of the page -->
|
|
47
|
+
{{ item.name }}
|
|
48
|
+
</b-dropdown-item>
|
|
49
|
+
</b-dropdown>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script>
|
|
53
|
+
/**
|
|
54
|
+
* Vue component for managing pages through a dropdown menu.
|
|
55
|
+
* @component
|
|
56
|
+
* @prop {Props} props - The component's props object.
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
export default {
|
|
60
|
+
/**
|
|
61
|
+
* The name of the component.
|
|
62
|
+
* @type {string}
|
|
63
|
+
*/
|
|
64
|
+
name: "PagesDropdown",
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The props that the component accepts.
|
|
68
|
+
* @type {Object}
|
|
69
|
+
* @property {PageItem[]} data - The array of page items to be displayed in the dropdown.
|
|
70
|
+
* Defaults to null.
|
|
71
|
+
*/
|
|
72
|
+
props: {
|
|
73
|
+
data: {
|
|
74
|
+
type: Array,
|
|
75
|
+
default: null
|
|
76
|
+
},
|
|
77
|
+
boundary: {
|
|
78
|
+
type: String,
|
|
79
|
+
default: "viewport"
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The methods available within the component.
|
|
85
|
+
*/
|
|
86
|
+
methods: {
|
|
87
|
+
/**
|
|
88
|
+
* Handler for when the "Add Page" option is clicked.
|
|
89
|
+
* Emits the "addPage" event.
|
|
90
|
+
*/
|
|
91
|
+
onAddPage() {
|
|
92
|
+
this.$emit("addPage");
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Handler for when the "See All Pages" option is clicked.
|
|
97
|
+
* Emits the "seeAllPages" event.
|
|
98
|
+
*/
|
|
99
|
+
onSeeAllPages() {
|
|
100
|
+
this.$emit("seeAllPages");
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Handler for when a specific page is clicked.
|
|
105
|
+
* Emits the "clickPage" event with the selected page.
|
|
106
|
+
* @param {PageItem} page - The selected page item.
|
|
107
|
+
*/
|
|
108
|
+
onClickPage(page) {
|
|
109
|
+
this.$emit("clickPage", page);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<style lang="scss" scoped>
|
|
116
|
+
// Platform btn style
|
|
117
|
+
.btn-platform {
|
|
118
|
+
background-color: #ffff;
|
|
119
|
+
color: #6a7888;
|
|
120
|
+
}
|
|
121
|
+
.platform-dropdown-item-icon {
|
|
122
|
+
// Style for the icons in dropdown items.
|
|
123
|
+
color: #1572c2;
|
|
124
|
+
}
|
|
125
|
+
</style>
|
|
@@ -36,7 +36,24 @@
|
|
|
36
36
|
<script>
|
|
37
37
|
export default {
|
|
38
38
|
components: {},
|
|
39
|
-
props:
|
|
39
|
+
props: {
|
|
40
|
+
/**
|
|
41
|
+
* The label for the color select
|
|
42
|
+
*/
|
|
43
|
+
label: {},
|
|
44
|
+
/**
|
|
45
|
+
* The value of the color select. eg. `alert alert-success`
|
|
46
|
+
*/
|
|
47
|
+
value: {},
|
|
48
|
+
/**
|
|
49
|
+
* The helper text for the color select (not visible yet)
|
|
50
|
+
*/
|
|
51
|
+
helper: {},
|
|
52
|
+
/**
|
|
53
|
+
* The options for the color select
|
|
54
|
+
*/
|
|
55
|
+
options: {},
|
|
56
|
+
},
|
|
40
57
|
data() {
|
|
41
58
|
return {
|
|
42
59
|
newColor: ""
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="container sortable-box">
|
|
3
|
+
<div class="row">
|
|
4
|
+
<div class="col-sm border rounded-lg p-0 mr-3 sortable-search-box">
|
|
5
|
+
<i class="fa fa-search sortable-search-icon"></i>
|
|
6
|
+
<input
|
|
7
|
+
id="search"
|
|
8
|
+
v-model="search"
|
|
9
|
+
class="form-control border-0 shadow-none px-0"
|
|
10
|
+
:placeholder="$t('Search here')"
|
|
11
|
+
data-test="search"
|
|
12
|
+
/>
|
|
13
|
+
</div>
|
|
14
|
+
<div>
|
|
15
|
+
<button
|
|
16
|
+
type="button"
|
|
17
|
+
class="btn sortable-btn-new"
|
|
18
|
+
@click="$emit('add-page', $event)"
|
|
19
|
+
>
|
|
20
|
+
<i class="fa fa-plus"></i>
|
|
21
|
+
</button>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<SortableList
|
|
26
|
+
:items="items"
|
|
27
|
+
:filtered-items="filteredItems"
|
|
28
|
+
@ordered="$emit('ordered', $event)"
|
|
29
|
+
@item-edit="$emit('item-edit', $event)"
|
|
30
|
+
@item-delete="$emit('item-delete', $event)"
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script>
|
|
36
|
+
import SortableList from './sortableList/SortableList.vue'
|
|
37
|
+
|
|
38
|
+
export default {
|
|
39
|
+
name: 'Sortable',
|
|
40
|
+
components: {
|
|
41
|
+
SortableList
|
|
42
|
+
},
|
|
43
|
+
props: {
|
|
44
|
+
items: { type: Array, required: true },
|
|
45
|
+
filterKey: { type: String, required: true },
|
|
46
|
+
},
|
|
47
|
+
data() {
|
|
48
|
+
return {
|
|
49
|
+
search: "",
|
|
50
|
+
filteredItems: [...this.items],
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
watch: {
|
|
54
|
+
search(value) {
|
|
55
|
+
this.filteredItems = this.filterItems(value, this.items);
|
|
56
|
+
},
|
|
57
|
+
items: {
|
|
58
|
+
handler(newItems) {
|
|
59
|
+
this.filteredItems = [...newItems];
|
|
60
|
+
|
|
61
|
+
if (this.search.length > 0) {
|
|
62
|
+
this.filteredItems = this.filterItems(this.search, newItems);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
deep: true,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
methods: {
|
|
69
|
+
clearSearch(value) {
|
|
70
|
+
return value.trim().toLowerCase();
|
|
71
|
+
},
|
|
72
|
+
filterItems(searchValue, items) {
|
|
73
|
+
const cleanSearch = this.clearSearch(searchValue);
|
|
74
|
+
return items.filter((item) => item[this.filterKey].toLowerCase().includes(cleanSearch));
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<style lang="scss" scoped src="./sortable.scss"></style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
.sortable {
|
|
2
|
+
&-box {
|
|
3
|
+
font-family: "Open Sans", sans-serif !important;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
&-search-box {
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
border-color: #cdddee !important;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
&-search-icon {
|
|
13
|
+
margin: {
|
|
14
|
+
left: 16px;
|
|
15
|
+
right: 8px;
|
|
16
|
+
}
|
|
17
|
+
color: #6A7888;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&-btn-new {
|
|
21
|
+
background: #1572C2;
|
|
22
|
+
color: #ffffff;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|