grav-svelte 0.0.35 → 0.0.37
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.
|
@@ -16,10 +16,18 @@ import ImageModal from "./ImageModal.svelte";
|
|
|
16
16
|
export let todosLosRegistros: any[] = [];
|
|
17
17
|
export let tableHeaders: TableHeader[];
|
|
18
18
|
export let loading: boolean = false;
|
|
19
|
+
export let dragEnabled: boolean = false;
|
|
20
|
+
export let orderField: string = 'inOrden';
|
|
19
21
|
|
|
20
22
|
let selectedAscOrDesc = "asc";
|
|
21
23
|
let selectedSort = "";
|
|
22
24
|
let selectedRowId: string | number | null = null;
|
|
25
|
+
|
|
26
|
+
// Drag and drop variables
|
|
27
|
+
let draggedIndex: number | null = null;
|
|
28
|
+
let dragOverIndex: number | null = null;
|
|
29
|
+
let isDragging = false;
|
|
30
|
+
let reorderedItems: any[] = [];
|
|
23
31
|
|
|
24
32
|
function handleRowClick(id: string | number) {
|
|
25
33
|
selectedRowId = selectedRowId === id ? null : id;
|
|
@@ -43,6 +51,90 @@ import ImageModal from "./ImageModal.svelte";
|
|
|
43
51
|
closeModal("crud-image-modal");
|
|
44
52
|
openModal("crud-image-modal", ImageModal, { src });
|
|
45
53
|
}
|
|
54
|
+
|
|
55
|
+
// Drag and drop functions
|
|
56
|
+
function handleDragStart(event: DragEvent, index: number) {
|
|
57
|
+
if (!dragEnabled) return;
|
|
58
|
+
|
|
59
|
+
draggedIndex = index;
|
|
60
|
+
isDragging = true;
|
|
61
|
+
|
|
62
|
+
if (event.dataTransfer) {
|
|
63
|
+
event.dataTransfer.effectAllowed = 'move';
|
|
64
|
+
event.dataTransfer.setData('text/html', '');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function handleDragOver(event: DragEvent, index: number) {
|
|
69
|
+
if (!dragEnabled || draggedIndex === null) return;
|
|
70
|
+
|
|
71
|
+
event.preventDefault();
|
|
72
|
+
dragOverIndex = index;
|
|
73
|
+
|
|
74
|
+
if (event.dataTransfer) {
|
|
75
|
+
event.dataTransfer.dropEffect = 'move';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function handleDragLeave() {
|
|
80
|
+
dragOverIndex = null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function handleDrop(event: DragEvent, dropIndex: number) {
|
|
84
|
+
if (!dragEnabled || draggedIndex === null || draggedIndex === dropIndex) {
|
|
85
|
+
resetDragState();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
|
|
91
|
+
// Create a new array with reordered items
|
|
92
|
+
const newItems = [...todosLosRegistros];
|
|
93
|
+
const draggedItem = newItems[draggedIndex];
|
|
94
|
+
|
|
95
|
+
// Remove the dragged item from its original position
|
|
96
|
+
newItems.splice(draggedIndex, 1);
|
|
97
|
+
|
|
98
|
+
// Insert the dragged item at the new position
|
|
99
|
+
newItems.splice(dropIndex, 0, draggedItem);
|
|
100
|
+
|
|
101
|
+
// Update the order values and track changes
|
|
102
|
+
const changes: any[] = [];
|
|
103
|
+
|
|
104
|
+
newItems.forEach((item, index) => {
|
|
105
|
+
const newOrder = index + 1;
|
|
106
|
+
const originalOrder = item[orderField];
|
|
107
|
+
|
|
108
|
+
if (originalOrder !== newOrder) {
|
|
109
|
+
changes.push({
|
|
110
|
+
...item,
|
|
111
|
+
[orderField]: newOrder
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Update the item's order in the array
|
|
116
|
+
item[orderField] = newOrder;
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Update the items array
|
|
120
|
+
todosLosRegistros = newItems;
|
|
121
|
+
reorderedItems = changes;
|
|
122
|
+
|
|
123
|
+
// Emit the reorder event
|
|
124
|
+
dispatch("reorderChange", { reorderedItems: changes });
|
|
125
|
+
|
|
126
|
+
resetDragState();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function handleDragEnd() {
|
|
130
|
+
resetDragState();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function resetDragState() {
|
|
134
|
+
draggedIndex = null;
|
|
135
|
+
dragOverIndex = null;
|
|
136
|
+
isDragging = false;
|
|
137
|
+
}
|
|
46
138
|
</script>
|
|
47
139
|
|
|
48
140
|
<div class="table-container">
|
|
@@ -50,10 +142,34 @@ import ImageModal from "./ImageModal.svelte";
|
|
|
50
142
|
<table class="data-table" bind:this={tablaExport}>
|
|
51
143
|
<thead class="table-header">
|
|
52
144
|
<tr>
|
|
145
|
+
{#if dragEnabled}
|
|
146
|
+
<th class="table-header-cell drag-header borderleft non-sortable">
|
|
147
|
+
<div class="drag-handle-header">
|
|
148
|
+
<svg
|
|
149
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
150
|
+
width="16"
|
|
151
|
+
height="16"
|
|
152
|
+
viewBox="0 0 24 24"
|
|
153
|
+
fill="none"
|
|
154
|
+
stroke="currentColor"
|
|
155
|
+
stroke-width="2"
|
|
156
|
+
stroke-linecap="round"
|
|
157
|
+
stroke-linejoin="round"
|
|
158
|
+
>
|
|
159
|
+
<circle cx="9" cy="12" r="1"></circle>
|
|
160
|
+
<circle cx="9" cy="5" r="1"></circle>
|
|
161
|
+
<circle cx="9" cy="19" r="1"></circle>
|
|
162
|
+
<circle cx="15" cy="12" r="1"></circle>
|
|
163
|
+
<circle cx="15" cy="5" r="1"></circle>
|
|
164
|
+
<circle cx="15" cy="19" r="1"></circle>
|
|
165
|
+
</svg>
|
|
166
|
+
</div>
|
|
167
|
+
</th>
|
|
168
|
+
{/if}
|
|
53
169
|
{#each tableHeaders as tableHeader, index}
|
|
54
170
|
{#if tableHeader.biSort == false}
|
|
55
171
|
<th
|
|
56
|
-
class="table-header-cell {index == 0
|
|
172
|
+
class="table-header-cell {index == 0 && !dragEnabled
|
|
57
173
|
? 'borderleft'
|
|
58
174
|
: ''} non-sortable"
|
|
59
175
|
style="text-align: {tableHeader.align ?? 'center'}"
|
|
@@ -63,7 +179,7 @@ import ImageModal from "./ImageModal.svelte";
|
|
|
63
179
|
{:else}
|
|
64
180
|
<th
|
|
65
181
|
on:click={() => dispatchSort(tableHeader.campo)}
|
|
66
|
-
class="table-header-cell {index == 0
|
|
182
|
+
class="table-header-cell {index == 0 && !dragEnabled
|
|
67
183
|
? 'borderleft'
|
|
68
184
|
: ''} sortable"
|
|
69
185
|
style="text-align: {tableHeader.align ?? 'left'}"
|
|
@@ -122,13 +238,47 @@ import ImageModal from "./ImageModal.svelte";
|
|
|
122
238
|
<tr
|
|
123
239
|
class="table-row {selectedRowId === index
|
|
124
240
|
? 'selected'
|
|
241
|
+
: ''} {dragEnabled ? 'draggable-row' : ''} {draggedIndex === index
|
|
242
|
+
? 'dragging'
|
|
243
|
+
: ''} {dragOverIndex === index
|
|
244
|
+
? 'drag-over'
|
|
125
245
|
: ''}"
|
|
246
|
+
draggable={dragEnabled}
|
|
126
247
|
on:click={() => handleRowClick(index)}
|
|
248
|
+
on:dragstart={(e) => handleDragStart(e, index)}
|
|
249
|
+
on:dragover={(e) => handleDragOver(e, index)}
|
|
250
|
+
on:dragleave={handleDragLeave}
|
|
251
|
+
on:drop={(e) => handleDrop(e, index)}
|
|
252
|
+
on:dragend={handleDragEnd}
|
|
127
253
|
>
|
|
254
|
+
{#if dragEnabled}
|
|
255
|
+
<td class="table-cell drag-handle-cell sticky-cell">
|
|
256
|
+
<div class="drag-handle" title="Drag to reorder">
|
|
257
|
+
<svg
|
|
258
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
259
|
+
width="16"
|
|
260
|
+
height="16"
|
|
261
|
+
viewBox="0 0 24 24"
|
|
262
|
+
fill="none"
|
|
263
|
+
stroke="currentColor"
|
|
264
|
+
stroke-width="2"
|
|
265
|
+
stroke-linecap="round"
|
|
266
|
+
stroke-linejoin="round"
|
|
267
|
+
>
|
|
268
|
+
<circle cx="9" cy="12" r="1"></circle>
|
|
269
|
+
<circle cx="9" cy="5" r="1"></circle>
|
|
270
|
+
<circle cx="9" cy="19" r="1"></circle>
|
|
271
|
+
<circle cx="15" cy="12" r="1"></circle>
|
|
272
|
+
<circle cx="15" cy="5" r="1"></circle>
|
|
273
|
+
<circle cx="15" cy="19" r="1"></circle>
|
|
274
|
+
</svg>
|
|
275
|
+
</div>
|
|
276
|
+
</td>
|
|
277
|
+
{/if}
|
|
128
278
|
{#each tableHeaders as tableBodyItem, i}
|
|
129
279
|
{#if tableBodyItem.tipo == "Text"}
|
|
130
280
|
<td
|
|
131
|
-
class="table-cell {i == 0
|
|
281
|
+
class="table-cell {i == 0 && !dragEnabled
|
|
132
282
|
? 'sticky-cell'
|
|
133
283
|
: ''}"
|
|
134
284
|
>
|
|
@@ -143,7 +293,7 @@ import ImageModal from "./ImageModal.svelte";
|
|
|
143
293
|
</td>
|
|
144
294
|
{:else if tableBodyItem.tipo == "Number"}
|
|
145
295
|
<td
|
|
146
|
-
class="table-cell {i == 0
|
|
296
|
+
class="table-cell {i == 0 && !dragEnabled
|
|
147
297
|
? 'sticky-cell'
|
|
148
298
|
: ''}"
|
|
149
299
|
>
|
|
@@ -158,7 +308,7 @@ import ImageModal from "./ImageModal.svelte";
|
|
|
158
308
|
</td>
|
|
159
309
|
{:else if tableBodyItem.tipo == "Bool"}
|
|
160
310
|
<td
|
|
161
|
-
class="table-cell {i == 0
|
|
311
|
+
class="table-cell {i == 0 && !dragEnabled
|
|
162
312
|
? 'sticky-cell'
|
|
163
313
|
: ''}"
|
|
164
314
|
>
|
|
@@ -177,7 +327,7 @@ import ImageModal from "./ImageModal.svelte";
|
|
|
177
327
|
</td>
|
|
178
328
|
{:else if tableBodyItem.tipo == "Image"}
|
|
179
329
|
<td
|
|
180
|
-
class="table-cell {i == 0
|
|
330
|
+
class="table-cell {i == 0 && !dragEnabled
|
|
181
331
|
? 'sticky-cell'
|
|
182
332
|
: ''}"
|
|
183
333
|
>
|
|
@@ -203,7 +353,7 @@ import ImageModal from "./ImageModal.svelte";
|
|
|
203
353
|
{:else if !loading}
|
|
204
354
|
<tbody>
|
|
205
355
|
<tr>
|
|
206
|
-
<td colspan={tableHeaders.length} class="no-data">
|
|
356
|
+
<td colspan={tableHeaders.length + (dragEnabled ? 1 : 0)} class="no-data">
|
|
207
357
|
No hay datos disponibles
|
|
208
358
|
</td>
|
|
209
359
|
</tr>
|
|
@@ -410,4 +560,103 @@ import ImageModal from "./ImageModal.svelte";
|
|
|
410
560
|
object-fit: contain;
|
|
411
561
|
margin: auto;
|
|
412
562
|
}
|
|
563
|
+
|
|
564
|
+
/* Drag and drop styles */
|
|
565
|
+
.drag-header {
|
|
566
|
+
width: 40px;
|
|
567
|
+
text-align: center;
|
|
568
|
+
cursor: default;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
.drag-handle-header {
|
|
572
|
+
display: flex;
|
|
573
|
+
align-items: center;
|
|
574
|
+
justify-content: center;
|
|
575
|
+
color: #9ca3af;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.drag-handle-cell {
|
|
579
|
+
width: 40px;
|
|
580
|
+
text-align: center;
|
|
581
|
+
padding: 0.5rem;
|
|
582
|
+
cursor: grab;
|
|
583
|
+
border-right: 1px solid #e0e0e0;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.drag-handle {
|
|
587
|
+
display: flex;
|
|
588
|
+
align-items: center;
|
|
589
|
+
justify-content: center;
|
|
590
|
+
color: #9ca3af;
|
|
591
|
+
transition: color 0.2s;
|
|
592
|
+
padding: 0.25rem;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.drag-handle:hover {
|
|
596
|
+
color: #6b7280;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.draggable-row {
|
|
600
|
+
transition: all 0.3s ease;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
.draggable-row:hover .drag-handle {
|
|
604
|
+
color: #4b5563;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
.draggable-row.dragging {
|
|
608
|
+
opacity: 0.5;
|
|
609
|
+
transform: scale(0.98);
|
|
610
|
+
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.2);
|
|
611
|
+
background-color: #f9fafb;
|
|
612
|
+
cursor: grabbing;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
.draggable-row.dragging .drag-handle {
|
|
616
|
+
cursor: grabbing;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.draggable-row.drag-over {
|
|
620
|
+
background-color: #e0f2fe;
|
|
621
|
+
border-top: 2px solid #0284c7;
|
|
622
|
+
border-bottom: 2px solid #0284c7;
|
|
623
|
+
box-shadow: 0 4px 8px -2px rgba(2, 132, 199, 0.2);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
.draggable-row.drag-over .sticky-cell {
|
|
627
|
+
background-color: #e0f2fe;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
.draggable-row.drag-over .drag-handle-cell {
|
|
631
|
+
background-color: #e0f2fe;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.draggable-row.selected.drag-over {
|
|
635
|
+
background-color: #bfdbfe;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
.draggable-row.selected.drag-over .sticky-cell {
|
|
639
|
+
background-color: #bfdbfe;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.draggable-row.selected.drag-over .drag-handle-cell {
|
|
643
|
+
background-color: #bfdbfe;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/* Ensure sticky cells follow drag states */
|
|
647
|
+
.draggable-row.dragging .sticky-cell {
|
|
648
|
+
background-color: #f9fafb;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.draggable-row.dragging .drag-handle-cell {
|
|
652
|
+
background-color: #f9fafb;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.draggable-row:hover .drag-handle-cell {
|
|
656
|
+
background-color: #f5f5f5;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
.draggable-row.selected .drag-handle-cell {
|
|
660
|
+
background-color: #e8e8e8;
|
|
661
|
+
}
|
|
413
662
|
</style>
|
|
@@ -5,10 +5,13 @@ declare const __propDef: {
|
|
|
5
5
|
todosLosRegistros?: any[];
|
|
6
6
|
tableHeaders: TableHeader[];
|
|
7
7
|
loading?: boolean;
|
|
8
|
+
dragEnabled?: boolean;
|
|
9
|
+
orderField?: string;
|
|
8
10
|
};
|
|
9
11
|
events: {
|
|
10
12
|
rowClick: CustomEvent<any>;
|
|
11
13
|
selectedSort: CustomEvent<any>;
|
|
14
|
+
reorderChange: CustomEvent<any>;
|
|
12
15
|
} & {
|
|
13
16
|
[evt: string]: CustomEvent<any>;
|
|
14
17
|
};
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
on:mouseenter={() => (showTooltip = button.tooltip)}
|
|
26
26
|
on:mouseleave={() => (showTooltip = "")}
|
|
27
27
|
type="button"
|
|
28
|
-
class="action-buttons-group {i == 0 ? 'rounded-left' : i == visibleButtons.length - 1 ? 'rounded-right' : ''} {button.color}"
|
|
28
|
+
class="action-buttons-group {visibleButtons.length === 1 ? 'rounded-left rounded-right' : i == 0 ? 'rounded-left' : i == visibleButtons.length - 1 ? 'rounded-right' : ''} {button.color}"
|
|
29
29
|
>
|
|
30
30
|
<i class={button.icon}> </i>
|
|
31
31
|
</button>
|
|
@@ -18,10 +18,13 @@ import { ModalContainer } from "../Modals/index.js";
|
|
|
18
18
|
export let showAddButton: boolean = true;
|
|
19
19
|
export let showImportButton: boolean = true;
|
|
20
20
|
export let Titulo_Crud: string;
|
|
21
|
+
export let dragEnabled: boolean = false;
|
|
22
|
+
export let orderField: string = 'inOrden';
|
|
21
23
|
|
|
22
24
|
// Event handlers from parent
|
|
23
25
|
export let onFilter: (filters: FiltrosI[]) => void;
|
|
24
26
|
export let onAdd: () => void;
|
|
27
|
+
export let onReorder: (reorderedItems: any[]) => void = () => {};
|
|
25
28
|
|
|
26
29
|
function handleFiltroAplicado() {
|
|
27
30
|
onFilter(Filtros);
|
|
@@ -65,6 +68,16 @@ import { ModalContainer } from "../Modals/index.js";
|
|
|
65
68
|
createPDF(table);
|
|
66
69
|
}
|
|
67
70
|
}
|
|
71
|
+
|
|
72
|
+
interface ReorderEvent {
|
|
73
|
+
detail: {
|
|
74
|
+
reorderedItems: any[];
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function handleReorder(event: ReorderEvent) {
|
|
79
|
+
onReorder(event.detail.reorderedItems);
|
|
80
|
+
}
|
|
68
81
|
</script>
|
|
69
82
|
|
|
70
83
|
<div class="crud-wrapper">
|
|
@@ -81,7 +94,10 @@ import { ModalContainer } from "../Modals/index.js";
|
|
|
81
94
|
tableHeaders={tableH}
|
|
82
95
|
todosLosRegistros={todosLosObjetos}
|
|
83
96
|
on:selectedSort={handleSort}
|
|
97
|
+
on:reorderChange={handleReorder}
|
|
84
98
|
{loading}
|
|
99
|
+
{dragEnabled}
|
|
100
|
+
{orderField}
|
|
85
101
|
/>
|
|
86
102
|
<PaginationCrud
|
|
87
103
|
perPage={PageSize}
|
|
@@ -14,8 +14,11 @@ declare const __propDef: {
|
|
|
14
14
|
showAddButton?: boolean;
|
|
15
15
|
showImportButton?: boolean;
|
|
16
16
|
Titulo_Crud: string;
|
|
17
|
+
dragEnabled?: boolean;
|
|
18
|
+
orderField?: string;
|
|
17
19
|
onFilter: (filters: FiltrosI[]) => void;
|
|
18
20
|
onAdd: () => void;
|
|
21
|
+
onReorder?: (reorderedItems: any[]) => void;
|
|
19
22
|
};
|
|
20
23
|
events: {
|
|
21
24
|
[evt: string]: CustomEvent<any>;
|