@innertia-solutions/nuxt-theme-spark 0.1.115 → 0.1.117

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.
@@ -140,8 +140,10 @@ onBeforeUnmount(() => {
140
140
  })
141
141
 
142
142
  // ─── Column panel ─────────────────────────────────────────────────────────────
143
- const showColumnPanel = ref(false)
144
- const columnPanelRef = ref(null)
143
+ const showColumnPanel = ref(false)
144
+ const columnPanelRef = ref(null)
145
+ const columnButtonRef = ref(null)
146
+ const columnPanelStyle = ref({})
145
147
 
146
148
  const orderedColumns = computed(() => {
147
149
  if (!tableRef.value) return props.columns.filter(c => c.label)
@@ -171,7 +173,10 @@ const onDrop = (key) => {
171
173
  }
172
174
 
173
175
  const onColumnPanelOutsideClick = (e) => {
174
- if (columnPanelRef.value && !columnPanelRef.value.contains(e.target)) {
176
+ if (
177
+ columnPanelRef.value && !columnPanelRef.value.contains(e.target) &&
178
+ columnButtonRef.value && !columnButtonRef.value.contains(e.target)
179
+ ) {
175
180
  showColumnPanel.value = false
176
181
  }
177
182
  }
@@ -181,9 +186,20 @@ const onFilterPanelOutsideClick = (e) => {
181
186
  }
182
187
  }
183
188
 
184
- watch(showColumnPanel, (v) => {
185
- if (v) document.addEventListener('mousedown', onColumnPanelOutsideClick)
186
- else document.removeEventListener('mousedown', onColumnPanelOutsideClick)
189
+ watch(showColumnPanel, async (v) => {
190
+ if (v) {
191
+ await nextTick()
192
+ const rect = columnButtonRef.value?.getBoundingClientRect()
193
+ if (rect) {
194
+ columnPanelStyle.value = {
195
+ top: rect.bottom + 6 + 'px',
196
+ right: window.innerWidth - rect.right + 'px',
197
+ }
198
+ }
199
+ document.addEventListener('mousedown', onColumnPanelOutsideClick)
200
+ } else {
201
+ document.removeEventListener('mousedown', onColumnPanelOutsideClick)
202
+ }
187
203
  })
188
204
  watch(showFilterPanel, (v) => {
189
205
  if (v) document.addEventListener('mousedown', onFilterPanelOutsideClick)
@@ -249,6 +265,7 @@ defineExpose({ getSelectedRows, reload, clearCache, exportTable, tableRef })
249
265
  <slot name="toolbar" />
250
266
 
251
267
  <button
268
+ ref="columnButtonRef"
252
269
  type="button"
253
270
  @click="showColumnPanel = !showColumnPanel"
254
271
  :class="[
@@ -321,47 +338,50 @@ defineExpose({ getSelectedRows, reload, clearCache, exportTable, tableRef })
321
338
  </div>
322
339
  </div>
323
340
 
324
- <!-- Column panel — outside overflow-hidden so never clipped -->
325
- <Transition
326
- enter-active-class="transition ease-out duration-150"
327
- enter-from-class="opacity-0 translate-y-1 scale-95"
328
- enter-to-class="opacity-100 translate-y-0 scale-100"
329
- leave-active-class="transition ease-in duration-100"
330
- leave-from-class="opacity-100 translate-y-0 scale-100"
331
- leave-to-class="opacity-0 translate-y-1 scale-95"
332
- >
333
- <div
334
- v-if="showColumnPanel"
335
- ref="columnPanelRef"
336
- class="absolute top-12 right-0 z-50 bg-dropdown border border-dropdown-line rounded-xl shadow-2xl p-3 min-w-56 max-h-80 overflow-y-auto"
341
+ <!-- Column panel — teleported to body to escape overflow-hidden -->
342
+ <Teleport to="body">
343
+ <Transition
344
+ enter-active-class="transition ease-out duration-150"
345
+ enter-from-class="opacity-0 translate-y-1 scale-95"
346
+ enter-to-class="opacity-100 translate-y-0 scale-100"
347
+ leave-active-class="transition ease-in duration-100"
348
+ leave-from-class="opacity-100 translate-y-0 scale-100"
349
+ leave-to-class="opacity-0 translate-y-1 scale-95"
337
350
  >
338
- <p class="text-[10px] font-bold text-muted-foreground uppercase tracking-widest mb-2 px-1">
339
- Columnas visibles
340
- </p>
341
351
  <div
342
- v-for="col in orderedColumns"
343
- :key="col.key"
344
- draggable="true"
345
- @dragstart="onDragStart(col.key)"
346
- @dragover="(e) => onDragOver(e, col.key)"
347
- @dragleave="onDragLeave"
348
- @drop="onDrop(col.key)"
349
- class="flex items-center gap-2 py-1.5 px-2 rounded-lg select-none transition-colors"
350
- :class="dragOverKey === col.key
351
- ? 'bg-blue-50 dark:bg-blue-900/20 ring-1 ring-blue-300 dark:ring-blue-700'
352
- : 'hover:bg-muted-hover cursor-grab'"
352
+ v-if="showColumnPanel"
353
+ ref="columnPanelRef"
354
+ class="fixed z-50 bg-dropdown border border-dropdown-line rounded-xl shadow-2xl p-3 min-w-56 max-h-80 overflow-y-auto"
355
+ :style="columnPanelStyle"
353
356
  >
354
- <IconGripVertical class="size-4 text-muted-foreground-2 shrink-0" />
355
- <input
356
- type="checkbox"
357
- :checked="tableRef?.table.getColumn(col.key)?.getIsVisible() ?? true"
358
- @change="tableRef?.table.getColumn(col.key)?.toggleVisibility()"
359
- @click.stop
360
- class="rounded border-card-line bg-surface shrink-0 cursor-pointer"
361
- />
362
- <span class="text-sm text-foreground truncate">{{ col.label }}</span>
357
+ <p class="text-[10px] font-bold text-muted-foreground uppercase tracking-widest mb-2 px-1">
358
+ Columnas visibles
359
+ </p>
360
+ <div
361
+ v-for="col in orderedColumns"
362
+ :key="col.key"
363
+ draggable="true"
364
+ @dragstart="onDragStart(col.key)"
365
+ @dragover="(e) => onDragOver(e, col.key)"
366
+ @dragleave="onDragLeave"
367
+ @drop="onDrop(col.key)"
368
+ class="flex items-center gap-2 py-1.5 px-2 rounded-lg select-none transition-colors"
369
+ :class="dragOverKey === col.key
370
+ ? 'bg-blue-50 dark:bg-blue-900/20 ring-1 ring-blue-300 dark:ring-blue-700'
371
+ : 'hover:bg-muted-hover cursor-grab'"
372
+ >
373
+ <IconGripVertical class="size-4 text-muted-foreground-2 shrink-0" />
374
+ <input
375
+ type="checkbox"
376
+ :checked="tableRef?.table.getColumn(col.key)?.getIsVisible() ?? true"
377
+ @change="tableRef?.table.getColumn(col.key)?.toggleVisibility()"
378
+ @click.stop
379
+ class="rounded border-card-line bg-surface shrink-0 cursor-pointer"
380
+ />
381
+ <span class="text-sm text-foreground truncate">{{ col.label }}</span>
382
+ </div>
363
383
  </div>
364
- </div>
365
- </Transition>
384
+ </Transition>
385
+ </Teleport>
366
386
  </div>
367
387
  </template>
@@ -13,12 +13,24 @@ const props = defineProps({
13
13
  columns: { type: Array, default: () => [] },
14
14
  })
15
15
 
16
- const isOpen = ref(false)
17
- const format = ref('xlsx')
18
- const filename = ref(props.name)
16
+ const isOpen = ref(false)
17
+ const format = ref('xlsx')
18
+ const filename = ref(props.name)
19
+ const selectedColumns = ref([])
19
20
 
21
+ watch(() => props.columns, (cols) => { selectedColumns.value = cols.map(c => c.key) }, { immediate: true })
20
22
  watch(() => props.name, (v) => { filename.value = v })
21
23
 
24
+ const toggleColumn = (key) => {
25
+ const idx = selectedColumns.value.indexOf(key)
26
+ if (idx >= 0) selectedColumns.value.splice(idx, 1)
27
+ else selectedColumns.value.push(key)
28
+ }
29
+ const allSelected = computed(() => selectedColumns.value.length === props.columns.length)
30
+ const toggleAll = () => {
31
+ selectedColumns.value = allSelected.value ? [] : props.columns.map(c => c.key)
32
+ }
33
+
22
34
  const formats = [
23
35
  { value: 'xlsx', label: 'Excel' },
24
36
  { value: 'csv', label: 'CSV' },
@@ -27,7 +39,7 @@ const formats = [
27
39
  ]
28
40
 
29
41
  const doExport = () => {
30
- props.tableRef?.exportTable(format.value, true, true)
42
+ props.tableRef?.exportTable(format.value, true, true, selectedColumns.value)
31
43
  isOpen.value = false
32
44
  }
33
45
 
@@ -118,6 +130,31 @@ defineExpose({ open: () => { isOpen.value = true } })
118
130
  </div>
119
131
  </div>
120
132
 
133
+ <!-- Columns -->
134
+ <div v-if="columns.length > 0" class="mb-3 px-1">
135
+ <div class="flex items-center justify-between mb-1.5">
136
+ <label class="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">Columnas</label>
137
+ <button type="button" @click="toggleAll" class="text-[10px] text-blue-600 dark:text-blue-400 hover:underline">
138
+ {{ allSelected ? 'Ninguna' : 'Todas' }}
139
+ </button>
140
+ </div>
141
+ <div class="max-h-32 overflow-y-auto space-y-0.5">
142
+ <label
143
+ v-for="col in columns"
144
+ :key="col.key"
145
+ class="flex items-center gap-2 py-1 px-1.5 rounded-lg hover:bg-muted-hover cursor-pointer"
146
+ >
147
+ <input
148
+ type="checkbox"
149
+ :checked="selectedColumns.includes(col.key)"
150
+ @change="toggleColumn(col.key)"
151
+ class="rounded border-card-line bg-surface shrink-0 cursor-pointer"
152
+ />
153
+ <span class="text-xs text-foreground truncate">{{ col.label }}</span>
154
+ </label>
155
+ </div>
156
+ </div>
157
+
121
158
  <!-- Export button -->
122
159
  <button
123
160
  type="button"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@innertia-solutions/nuxt-theme-spark",
3
- "version": "0.1.115",
3
+ "version": "0.1.117",
4
4
  "description": "Innertia Solutions — Spark theme: backoffice, landing and mobile components and layouts",
5
5
  "keywords": [
6
6
  "nuxt",