@vcmap/module-selector 2.0.0 → 2.0.2

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.
@@ -0,0 +1,747 @@
1
+ <template>
2
+ <AbstractConfigEditor
3
+ @submit="apply"
4
+ v-if="localConfig"
5
+ v-bind="{ ...$attrs, ...$props }"
6
+ >
7
+ <v-container v-if="currentGroup === undefined" class="py-0 px-0">
8
+ <VcsFormSection heading="moduleSelector.configEditor.general">
9
+ <v-container class="py-0 px-1">
10
+ <v-row no-gutters>
11
+ <v-col cols="6">
12
+ <VcsLabel html-for="moduleselector-window-title">
13
+ {{ $st('moduleSelector.configEditor.windowTitle') }}
14
+ </VcsLabel>
15
+ </v-col>
16
+ <v-col>
17
+ <VcsTextField
18
+ id="moduleselector-window-title"
19
+ :placeholder="$st('moduleSelector.title')"
20
+ v-model="localConfig.windowTitle"
21
+ />
22
+ </v-col>
23
+ </v-row>
24
+ <v-row no-gutters>
25
+ <v-col>
26
+ <VcsCheckbox
27
+ v-model="localConfig.isActiveOnStart"
28
+ label="moduleSelector.configEditor.isActiveOnStart"
29
+ />
30
+ </v-col>
31
+ </v-row>
32
+ <v-row no-gutters>
33
+ <v-col>
34
+ <VcsCheckbox
35
+ v-model="localConfig.requireModuleSelection"
36
+ label="moduleSelector.configEditor.requireModuleSelection"
37
+ />
38
+ </v-col>
39
+ </v-row>
40
+ </v-container>
41
+ </VcsFormSection>
42
+ <VcsFormSection
43
+ heading="moduleSelector.configEditor.windowPosition"
44
+ :expandable="true"
45
+ >
46
+ <WindowPositionSettings
47
+ v-model="localConfig.position!"
48
+ :position-keys="[
49
+ 'top',
50
+ 'right',
51
+ 'bottom',
52
+ 'left',
53
+ 'width',
54
+ 'maxWidth',
55
+ 'height',
56
+ 'maxHeight',
57
+ ]"
58
+ />
59
+ </VcsFormSection>
60
+ <VcsFormSection heading="moduleSelector.configEditor.baseModule">
61
+ <v-container class="py-0 px-1">
62
+ <v-row no-gutters>
63
+ <v-col>
64
+ <VcsCheckbox
65
+ id="BaseModuleCheckbox"
66
+ v-model="basisModuleExists"
67
+ label="moduleSelector.configEditor.baseModuleCheckbox"
68
+ >
69
+ </VcsCheckbox>
70
+ </v-col>
71
+ </v-row>
72
+ <v-row v-if="basisModuleExists" no-gutters>
73
+ <v-col cols="6">
74
+ <VcsLabel required html-for="basisModuleName">
75
+ {{ $st('moduleSelector.configEditor.title') }}
76
+ </VcsLabel>
77
+ </v-col>
78
+ <v-col>
79
+ <VcsTextField
80
+ id="basisModuleName"
81
+ placeholder="Base Module"
82
+ :rules="[
83
+ basisModuleExists &&
84
+ (!basisModule.title || basisModule.title === '')
85
+ ? () => 'moduleSelector.configEditor.error'
86
+ : () => true,
87
+ ]"
88
+ v-model="basisModule.title"
89
+ />
90
+ </v-col>
91
+ </v-row>
92
+ <v-row v-if="basisModuleExists" no-gutters>
93
+ <v-col cols="6">
94
+ <VcsLabel required html-for="basisModuleIcon">
95
+ {{ $st('components.style.icon') }}
96
+ </VcsLabel>
97
+ </v-col>
98
+ <v-col>
99
+ <VcsTextField
100
+ id="basisModuleIcon"
101
+ placeholder="mdi-home-city"
102
+ :rules="[
103
+ basisModuleExists &&
104
+ (!basisModule.icon || basisModule.icon === '')
105
+ ? () => 'moduleSelector.configEditor.error'
106
+ : () => true,
107
+ ]"
108
+ v-model="basisModule.icon"
109
+ />
110
+ </v-col>
111
+ </v-row>
112
+ </v-container>
113
+ </VcsFormSection>
114
+ </v-container>
115
+ <v-container v-else class="py-0 px-1">
116
+ <v-breadcrumbs :items="breadcrumbItems" divider="/">
117
+ <template #item="{ item }">
118
+ <v-breadcrumbs-item
119
+ :key="item.title"
120
+ :disabled="item.disabled"
121
+ :href="item.href"
122
+ @click="item.disabled ? null : returnLevel()"
123
+ >
124
+ {{ item.title }}
125
+ </v-breadcrumbs-item>
126
+ </template>
127
+ </v-breadcrumbs>
128
+
129
+ <v-row no-gutters>
130
+ <v-col cols="6">
131
+ <VcsLabel required html-for="groupModuleName">
132
+ {{ $st('moduleSelector.configEditor.groupName') }}
133
+ </VcsLabel>
134
+ </v-col>
135
+ <v-col>
136
+ <VcsTextField
137
+ id="groupModuleName"
138
+ placeholder="Module Name"
139
+ v-model="currentGroup!.title"
140
+ :rules="[(v: string) => !!v || 'moduleSelector.configEditor.error']"
141
+ />
142
+ </v-col>
143
+ </v-row>
144
+ <v-row no-gutters>
145
+ <v-col cols="6">
146
+ <VcsLabel required html-for="groupModuleIcon">
147
+ {{ $st('moduleSelector.configEditor.moduleIcon') }}
148
+ </VcsLabel>
149
+ </v-col>
150
+ <v-col>
151
+ <VcsTextField
152
+ id="groupModuleIcon"
153
+ placeholder="Module Icon"
154
+ v-model="currentGroup!.icon"
155
+ :rules="[
156
+ (v: string) => !!v || 'moduleSelector.configEditor.editorError',
157
+ ]"
158
+ />
159
+ </v-col>
160
+ </v-row>
161
+ </v-container>
162
+ <VcsFormSection
163
+ heading="moduleSelector.configEditor.heading"
164
+ :start-open="true"
165
+ :header-actions="headerActions"
166
+ >
167
+ <VcsList
168
+ v-if="currentGroup === undefined"
169
+ :items="listItemArray"
170
+ :draggable="true"
171
+ @item-moved="move"
172
+ />
173
+ <VcsList
174
+ v-else
175
+ :items="currentGroup.cards"
176
+ :draggable="true"
177
+ @item-moved="move"
178
+ />
179
+ <v-dialog
180
+ v-model="editingItemDialogVisible"
181
+ width="400"
182
+ :persistent="true"
183
+ >
184
+ <ModuleEditor
185
+ :model-value="editingItem"
186
+ @close="editingItemDialogVisible = false"
187
+ @submit="updateItem()"
188
+ />
189
+ </v-dialog>
190
+ <v-dialog
191
+ v-model="selectCloudItemDialogVisible"
192
+ width="1000"
193
+ :persistent="true"
194
+ >
195
+ <VcsModuleTable
196
+ :model-value="selectCloudItem"
197
+ @close="selectCloudItemDialogVisible = false"
198
+ @submit="updateCloudItem()"
199
+ />
200
+ </v-dialog>
201
+ </VcsFormSection>
202
+ </AbstractConfigEditor>
203
+ </template>
204
+
205
+ <script lang="ts">
206
+ import {
207
+ AbstractConfigEditor,
208
+ VcsAction,
209
+ VcsCheckbox,
210
+ VcsFormSection,
211
+ VcsLabel,
212
+ VcsList,
213
+ VcsListItem,
214
+ VcsTextField,
215
+ VcsUiApp,
216
+ } from '@vcmap/ui';
217
+ import {
218
+ computed,
219
+ defineComponent,
220
+ inject,
221
+ PropType,
222
+ reactive,
223
+ Ref,
224
+ ref,
225
+ watch,
226
+ } from 'vue';
227
+ import {
228
+ VBreadcrumbs,
229
+ VBreadcrumbsItem,
230
+ VCol,
231
+ VContainer,
232
+ VDialog,
233
+ VRow,
234
+ } from 'vuetify/components';
235
+ import ModuleEditor from './ModuleEditor.vue';
236
+ import { Module, ModuleSelectorConfig, ModuleType } from '../index';
237
+ import getDefaultOptions from '../defaultOptions.js';
238
+ import WindowPositionSettings from './WindowPositionSettings.vue';
239
+ import CloudModuleSelector from './CloudModuleSelector.vue';
240
+
241
+ interface VcsListItemWithLabel extends VcsListItem {
242
+ id: string;
243
+ title: string;
244
+ icon: string;
245
+ type: string;
246
+ moduleUrl?: string;
247
+ cards?: VcsListItemWithLabel[];
248
+ }
249
+
250
+ export const windowIdConfigEditor = 'configEditor_window_id';
251
+ export default defineComponent({
252
+ name: 'ModuleSelectorConfigEditor',
253
+ components: {
254
+ VcsCheckbox,
255
+ VDialog,
256
+ VcsList,
257
+ VcsFormSection,
258
+ VRow,
259
+ VcsLabel,
260
+ AbstractConfigEditor,
261
+ VcsTextField,
262
+ VCol,
263
+ VContainer,
264
+ ModuleEditor,
265
+ VBreadcrumbs,
266
+ VBreadcrumbsItem,
267
+ WindowPositionSettings,
268
+ VcsModuleTable: CloudModuleSelector,
269
+ },
270
+ props: {
271
+ getConfig: {
272
+ type: Function as PropType<() => ModuleSelectorConfig>,
273
+ required: true,
274
+ },
275
+ setConfig: {
276
+ type: Function as PropType<(c?: ModuleSelectorConfig) => void>,
277
+ required: true,
278
+ },
279
+ },
280
+ setup(props) {
281
+ const app = inject('vcsApp') as VcsUiApp;
282
+ const level = ref<number>(0);
283
+ const localConfig = ref<ModuleSelectorConfig | undefined>(undefined);
284
+ const listItemArray: Ref<VcsListItemWithLabel[]> = ref([]);
285
+ const currentGroup: Ref<VcsListItemWithLabel | undefined> =
286
+ ref(undefined);
287
+ const editingItem: Ref<{
288
+ id: string;
289
+ title: string;
290
+ icon: string;
291
+ moduleUrl: string;
292
+ }> = ref({ id: '', title: '', icon: '', moduleUrl: '' });
293
+ const selectCloudItem: Ref<{
294
+ id: string;
295
+ title: string;
296
+ icon: string;
297
+ moduleUrl: string;
298
+ }> = ref({ id: '', title: '', icon: '', moduleUrl: '' });
299
+ const selectCloudItemDialogVisible: Ref<boolean> = ref(false);
300
+ const editingItemDialogVisible: Ref<boolean> = ref(false);
301
+ const groupItemDialogVisible: Ref<boolean> = ref(false);
302
+ const listItems: Ref<VcsListItemWithLabel[] | undefined> = ref(undefined);
303
+
304
+ localConfig.value = {
305
+ ...getDefaultOptions(),
306
+ ...props.getConfig(),
307
+ } as ModuleSelectorConfig;
308
+
309
+ const basisModule = ref();
310
+
311
+ if (localConfig.value?.basisModule) {
312
+ basisModule.value = localConfig.value?.basisModule;
313
+ }
314
+
315
+ const basisModuleExists = computed({
316
+ get() {
317
+ return !!basisModule.value;
318
+ },
319
+ set(value: boolean) {
320
+ if (value) {
321
+ basisModule.value = localConfig.value?.basisModule || { title: '' };
322
+ } else {
323
+ basisModule.value = null;
324
+ }
325
+ },
326
+ });
327
+ const headerActions = reactive<VcsAction[]>([]);
328
+
329
+ function createListItem(
330
+ moduleInfo: Module<ModuleType>,
331
+ index: number,
332
+ ): VcsListItemWithLabel {
333
+ const listItemObject: VcsListItemWithLabel = {
334
+ id: `${moduleInfo.title || 'undefined'}-${index}`,
335
+ name: moduleInfo.title,
336
+ title: moduleInfo.title,
337
+ icon: moduleInfo.icon,
338
+ type: moduleInfo.type,
339
+ actions: [],
340
+ };
341
+ if (moduleInfo.type === 'url') {
342
+ listItemObject.moduleUrl = moduleInfo.moduleUrl;
343
+ listItemObject.actions?.push({
344
+ name: 'edit',
345
+ title: 'moduleSelector.configEditor.TooltipEditModule',
346
+ icon: '$vcsEdit',
347
+ callback(): void {
348
+ if (
349
+ currentGroup.value === undefined &&
350
+ listItemArray.value.length > 0
351
+ ) {
352
+ const item = listItemArray.value.find(
353
+ (i) => i.id === listItemObject.id,
354
+ );
355
+
356
+ if (item) {
357
+ editingItem.value = {
358
+ id: item.id,
359
+ title: item.title,
360
+ icon: item.icon,
361
+ moduleUrl: item.moduleUrl!,
362
+ };
363
+ }
364
+ } else {
365
+ const item = currentGroup.value!.cards!.find(
366
+ (i) => i.id === listItemObject.id,
367
+ );
368
+
369
+ if (item) {
370
+ editingItem.value = {
371
+ id: item.id,
372
+ title: item.title,
373
+ icon: item.icon,
374
+ moduleUrl: item.moduleUrl!,
375
+ };
376
+ }
377
+ }
378
+ editingItemDialogVisible.value = true;
379
+ },
380
+ });
381
+ }
382
+ if (moduleInfo.type === 'group') {
383
+ listItemObject.actions?.push({
384
+ name: 'editGroup',
385
+ title: 'moduleSelector.configEditor.TooltipEditGroup',
386
+ icon: 'mdi-playlist-edit',
387
+ callback(): void {
388
+ if (listItemArray.value.length > 0) {
389
+ const item = listItemArray.value.find(
390
+ (i) => i.id === listItemObject.id,
391
+ );
392
+ if (item) {
393
+ currentGroup.value = item;
394
+ headerActions.splice(2, 1);
395
+ if (headerActions.length > 1) {
396
+ headerActions[1].icon = '$vcsPlus';
397
+ headerActions[1].title =
398
+ 'moduleSelector.configEditor.TooltipAddModule';
399
+ }
400
+ }
401
+ }
402
+ },
403
+ });
404
+ if (moduleInfo.cards) {
405
+ listItemObject.cards = moduleInfo.cards.map(createListItem);
406
+ }
407
+ }
408
+ listItemObject.actions?.push({
409
+ name: 'linkButton.editor.remove',
410
+ title: 'moduleSelector.configEditor.TooltipDeleteMG',
411
+ icon: '$vcsTrashCan',
412
+ callback(): void {
413
+ if (currentGroup.value) {
414
+ currentGroup.value.cards = currentGroup.value?.cards?.filter(
415
+ (item) => item.id !== listItemObject.id,
416
+ );
417
+ } else {
418
+ listItemArray.value = listItemArray.value?.filter(
419
+ (item) => item.id !== listItemObject.id,
420
+ );
421
+ }
422
+ },
423
+ });
424
+ return listItemObject;
425
+ }
426
+
427
+ headerActions.push({
428
+ name: 'moduleSelector.configEditor.addFromCloud',
429
+ icon: '$vcsImport',
430
+ callback(): void {
431
+ selectCloudItem.value = {
432
+ id: '',
433
+ title: '',
434
+ icon: '',
435
+ moduleUrl: '',
436
+ };
437
+ selectCloudItemDialogVisible.value = true;
438
+ },
439
+ });
440
+
441
+ function removeIdAndActions(
442
+ item: VcsListItemWithLabel,
443
+ ): Module<ModuleType> {
444
+ if (item.type === 'url') {
445
+ const { actions, id, name, ...configItem } = item;
446
+ return {
447
+ ...configItem,
448
+ moduleUrl: item.moduleUrl || '',
449
+ } as Module<'url'>;
450
+ } else {
451
+ const updatedCards =
452
+ item.cards?.map((card) => {
453
+ const { actions, id, name, ...configItem } = card;
454
+ return {
455
+ ...configItem,
456
+ } as Module<'url'>;
457
+ }) || [];
458
+ const { actions, id, name, ...configItem } = item;
459
+ return {
460
+ ...configItem,
461
+ ...(updatedCards.length ? { cards: updatedCards } : {}),
462
+ } as Module<'group'>;
463
+ }
464
+ }
465
+
466
+ const headerGroupAction = {
467
+ name: 'moduleSelector.configEditor.addGroup',
468
+ callback(): void {
469
+ const newGroup = {
470
+ type: 'group',
471
+ title: '',
472
+ icon: '',
473
+ cards: [],
474
+ };
475
+
476
+ groupItemDialogVisible.value = true;
477
+ const indexItem = listItemArray.value?.push(
478
+ createListItem(
479
+ newGroup as Module<'group'>,
480
+ listItemArray.value.length,
481
+ ),
482
+ );
483
+
484
+ currentGroup.value = listItemArray.value[indexItem - 1];
485
+
486
+ headerActions.splice(2, 1);
487
+ if (headerActions.length > 1) {
488
+ headerActions[1].icon = '$vcsPlus';
489
+ headerActions[1].title =
490
+ 'moduleSelector.configEditor.TooltipAddModule';
491
+ }
492
+ },
493
+ };
494
+
495
+ function removeIdAndActionsFromArray(
496
+ items: VcsListItemWithLabel[],
497
+ ): Module<ModuleType>[] {
498
+ return items.map(removeIdAndActions);
499
+ }
500
+
501
+ if (localConfig.value?.modules) {
502
+ listItemArray.value = localConfig.value.modules.map(createListItem);
503
+ }
504
+
505
+ headerActions.push(
506
+ {
507
+ name: 'moduleSelector.configEditor.add',
508
+ callback(): void {
509
+ editingItem.value = {
510
+ id: '',
511
+ title: '',
512
+ icon: '',
513
+ moduleUrl: '',
514
+ };
515
+ editingItemDialogVisible.value = true;
516
+ },
517
+ },
518
+ headerGroupAction,
519
+ );
520
+ watch(localConfig, (config) => {
521
+ if (config?.modules) {
522
+ listItems.value = config.modules.map((moduleInfo, index) =>
523
+ createListItem(moduleInfo, index),
524
+ );
525
+ } else {
526
+ listItems.value = [];
527
+ }
528
+ });
529
+
530
+ const apply = (): void => {
531
+ props.setConfig({
532
+ ...localConfig.value,
533
+ modules: removeIdAndActionsFromArray(listItemArray.value),
534
+ basisModule: basisModule.value,
535
+ });
536
+ };
537
+
538
+ const updateItem = (): void => {
539
+ if (currentGroup.value === undefined) {
540
+ if (editingItem.value) {
541
+ if (editingItem.value?.id !== '') {
542
+ const item = listItemArray.value.find(
543
+ (i) => i.id === editingItem.value?.id,
544
+ );
545
+ if (item) {
546
+ Object.assign(item, {
547
+ ...editingItem.value,
548
+ });
549
+ }
550
+ } else {
551
+ listItemArray.value.push(
552
+ createListItem(
553
+ {
554
+ ...editingItem.value,
555
+ type: 'url',
556
+ },
557
+ listItemArray.value.length,
558
+ ),
559
+ );
560
+ }
561
+ }
562
+ } else if (editingItem.value && editingItem.value?.id !== '') {
563
+ const item = currentGroup.value.cards!.find(
564
+ (i) => i.id === editingItem.value.id,
565
+ );
566
+ if (item) {
567
+ Object.assign(item, {
568
+ ...editingItem.value,
569
+ });
570
+ }
571
+
572
+ let groupId;
573
+ if (currentGroup.value?.id || currentGroup.value?.id !== '') {
574
+ groupId = currentGroup.value.id;
575
+ } else {
576
+ groupId = `${currentGroup.value.title}-${listItemArray.value.length - 1}`;
577
+ }
578
+ currentGroup.value = listItemArray.value.find(
579
+ (i) => i.id === groupId,
580
+ );
581
+ } else {
582
+ currentGroup.value.cards!.push(
583
+ createListItem(
584
+ {
585
+ ...editingItem.value,
586
+ type: 'url',
587
+ },
588
+ currentGroup.value.cards!.length,
589
+ ),
590
+ );
591
+
592
+ let groupId;
593
+ if (currentGroup.value?.id || currentGroup.value?.id !== '') {
594
+ groupId = currentGroup.value.id;
595
+ } else {
596
+ groupId = `${currentGroup.value?.title}-${listItemArray.value.length - 1}`;
597
+ }
598
+ currentGroup.value = listItemArray.value?.find(
599
+ (item) => item.id === groupId,
600
+ );
601
+ }
602
+
603
+ editingItem.value = {
604
+ id: '',
605
+ title: '',
606
+ icon: '',
607
+ moduleUrl: '',
608
+ };
609
+ editingItemDialogVisible.value = false;
610
+ };
611
+
612
+ const updateCloudItem = (): void => {
613
+ if (currentGroup.value === undefined) {
614
+ if (selectCloudItem.value) {
615
+ listItemArray.value.push(
616
+ createListItem(
617
+ {
618
+ title: selectCloudItem.value.title,
619
+ icon: selectCloudItem.value.icon,
620
+ moduleUrl: selectCloudItem.value.moduleUrl,
621
+ type: 'url',
622
+ },
623
+ listItemArray.value.length,
624
+ ),
625
+ );
626
+ }
627
+ } else {
628
+ currentGroup.value.cards!.push(
629
+ createListItem(
630
+ {
631
+ ...selectCloudItem.value,
632
+ type: 'url',
633
+ },
634
+ currentGroup.value.cards!.length,
635
+ ),
636
+ );
637
+
638
+ let groupId;
639
+ if (currentGroup.value?.id || currentGroup.value?.id !== '') {
640
+ groupId = currentGroup.value.id;
641
+ } else {
642
+ groupId = `${currentGroup.value?.title}-${listItemArray.value.length - 1}`;
643
+ }
644
+ currentGroup.value = listItemArray.value?.find(
645
+ (item) => item.id === groupId,
646
+ );
647
+ }
648
+
649
+ selectCloudItem.value = {
650
+ id: '',
651
+ title: '',
652
+ icon: '',
653
+ moduleUrl: '',
654
+ };
655
+ selectCloudItemDialogVisible.value = false;
656
+ };
657
+
658
+ const returnLevel = (): void => {
659
+ currentGroup.value = undefined;
660
+ if (headerActions.length > 1) {
661
+ delete headerActions[1].icon;
662
+ delete headerActions[1].title;
663
+ }
664
+ headerActions.push(headerGroupAction);
665
+ };
666
+
667
+ const breadcrumbItems = ref([
668
+ {
669
+ title: app.vueI18n.t(
670
+ 'moduleSelector.configEditor.breadcrumbs.overview',
671
+ ),
672
+ disabled: false,
673
+ href: '#',
674
+ },
675
+ {
676
+ title: app.vueI18n.t('moduleSelector.configEditor.breadcrumbs.group'),
677
+ disabled: true,
678
+ href: '#',
679
+ },
680
+ ]);
681
+ watch(currentGroup, (currentG) => {
682
+ if (currentG && currentG.title) {
683
+ breadcrumbItems.value[1].title = `${app.vueI18n.t('moduleSelector.configEditor.breadcrumbs.group')}: ${currentG.title}`;
684
+ currentG.name = currentG.title;
685
+ }
686
+ });
687
+ return {
688
+ editingItem,
689
+ selectCloudItem,
690
+ editingItemDialogVisible,
691
+ selectCloudItemDialogVisible,
692
+ localConfig,
693
+ listItemArray,
694
+ breadcrumbItems,
695
+ currentGroup,
696
+ apply,
697
+ returnLevel,
698
+ updateItem,
699
+ updateCloudItem,
700
+ level,
701
+ listItems: listItems as unknown as unknown[],
702
+ basisModule,
703
+ basisModuleExists,
704
+ headerActions,
705
+ move({
706
+ item,
707
+ targetIndex,
708
+ }: {
709
+ item: VcsListItemWithLabel;
710
+ targetIndex: number;
711
+ }): void {
712
+ if (listItemArray.value && currentGroup.value === undefined) {
713
+ let target = targetIndex;
714
+ target = target >= 0 ? target : 0;
715
+ target =
716
+ target < listItemArray.value?.length
717
+ ? target
718
+ : listItemArray.value.length - 1;
719
+ const from = listItemArray.value?.indexOf(item);
720
+ if (from !== target) {
721
+ listItemArray.value?.splice(from, 1);
722
+ listItemArray.value?.splice(target, 0, item);
723
+ }
724
+ } else if ((currentGroup.value?.cards?.length ?? 0) > 1) {
725
+ let target = targetIndex;
726
+ target = target >= 0 ? target : 0;
727
+ target =
728
+ target < currentGroup.value!.cards!.length
729
+ ? target
730
+ : currentGroup.value!.cards!.length - 1;
731
+ const from = currentGroup.value!.cards!.indexOf(item);
732
+ if (from && from !== target) {
733
+ currentGroup.value!.cards!.splice(from, 1);
734
+ currentGroup.value!.cards!.splice(target, 0, item);
735
+ }
736
+ }
737
+ },
738
+ };
739
+ },
740
+ });
741
+ </script>
742
+
743
+ <style scoped>
744
+ .v-breadcrumbs {
745
+ padding: 16px 0 4px 0;
746
+ }
747
+ </style>