@innertia-solutions/nuxt-theme-spark 0.1.85 → 0.1.87
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/components/Admin/Base.vue +81 -58
- package/components/Admin/Page.vue +68 -2
- package/components/App/DevEnvironmentBar.vue +43 -0
- package/components/App/PageLoadingSpinner.vue +1 -1
- package/components/Layout/Admin.vue +51 -2
- package/components/Nav/Tabs.vue +18 -3
- package/components/Table/Database.vue +9 -5
- package/components/Table/DownloadDropdown.vue +4 -4
- package/components/Table/FilterDropdown.vue +3 -3
- package/components/Table/Grid.vue +9 -5
- package/components/Table/Kanban.vue +20 -3
- package/components/Table/List.vue +9 -4
- package/components/Table/Standard.vue +21 -15
- package/components/Table.vue +41 -21
- package/components/TableExportable.vue +147 -127
- package/package.json +1 -1
- package/public/favicon.png +0 -0
- package/public/icon.png +0 -0
- package/public/isologo-dark.png +0 -0
- package/public/isologo-light.png +0 -0
- package/spark.css +25 -20
- package/components/Admin/Header.vue +0 -32
|
@@ -7,29 +7,33 @@ import {
|
|
|
7
7
|
IconDownload,
|
|
8
8
|
} from '@tabler/icons-vue'
|
|
9
9
|
|
|
10
|
-
// Modal with format selector, pre-filled filename, columns checkboxes
|
|
11
10
|
const props = defineProps({
|
|
12
11
|
tableRef: { type: Object, default: null },
|
|
13
12
|
name: { type: String, default: 'export' },
|
|
14
|
-
columns: { type: Array, default: () => [] },
|
|
13
|
+
columns: { type: Array, default: () => [] },
|
|
15
14
|
})
|
|
16
15
|
|
|
17
16
|
const isOpen = ref(false)
|
|
18
17
|
const format = ref('xlsx')
|
|
19
18
|
const filename = ref(props.name)
|
|
20
19
|
const selectedColumns = ref([])
|
|
20
|
+
const btnRef = ref(null)
|
|
21
|
+
const panelRef = ref(null)
|
|
22
|
+
const panelStyle = ref({})
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
const exportableColumns = computed(() => props.columns.filter(c => c.label))
|
|
25
|
+
|
|
26
|
+
watch(exportableColumns, (cols) => {
|
|
23
27
|
selectedColumns.value = cols.map(c => c.key)
|
|
24
28
|
}, { immediate: true })
|
|
25
29
|
|
|
26
30
|
watch(() => props.name, (v) => { filename.value = v })
|
|
27
31
|
|
|
28
32
|
const formats = [
|
|
29
|
-
{ value: 'xlsx', label: 'Excel', icon:
|
|
30
|
-
{ value: 'csv',
|
|
31
|
-
{ value: 'pdf',
|
|
32
|
-
{ value: 'json', label: 'JSON',
|
|
33
|
+
{ value: 'xlsx', label: 'Excel', icon: IconFileTypeXls },
|
|
34
|
+
{ value: 'csv', label: 'CSV', icon: IconFileTypeCsv },
|
|
35
|
+
{ value: 'pdf', label: 'PDF', icon: IconFileTypePdf },
|
|
36
|
+
{ value: 'json', label: 'JSON', icon: IconCodeDots },
|
|
33
37
|
]
|
|
34
38
|
|
|
35
39
|
const toggleColumn = (key) => {
|
|
@@ -39,165 +43,181 @@ const toggleColumn = (key) => {
|
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
const toggleAll = () => {
|
|
42
|
-
if (selectedColumns.value.length ===
|
|
46
|
+
if (selectedColumns.value.length === exportableColumns.value.length)
|
|
43
47
|
selectedColumns.value = []
|
|
44
48
|
else
|
|
45
|
-
selectedColumns.value =
|
|
49
|
+
selectedColumns.value = exportableColumns.value.map(c => c.key)
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
const allSelected = computed(() => selectedColumns.value.length ===
|
|
49
|
-
|
|
52
|
+
const allSelected = computed(() => selectedColumns.value.length === exportableColumns.value.length)
|
|
53
|
+
|
|
54
|
+
const open = () => {
|
|
55
|
+
if (!btnRef.value) return
|
|
56
|
+
const rect = btnRef.value.getBoundingClientRect()
|
|
57
|
+
panelStyle.value = {
|
|
58
|
+
position: 'fixed',
|
|
59
|
+
top: (rect.bottom + 6) + 'px',
|
|
60
|
+
right: (window.innerWidth - rect.right) + 'px',
|
|
61
|
+
}
|
|
62
|
+
isOpen.value = true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const toggle = () => isOpen.value ? isOpen.value = false : open()
|
|
66
|
+
|
|
67
|
+
const onOutsideClick = (e) => {
|
|
68
|
+
if (
|
|
69
|
+
panelRef.value && !panelRef.value.contains(e.target) &&
|
|
70
|
+
btnRef.value && !btnRef.value.contains(e.target)
|
|
71
|
+
) {
|
|
72
|
+
isOpen.value = false
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
watch(isOpen, (v) => {
|
|
77
|
+
if (v) document.addEventListener('mousedown', onOutsideClick)
|
|
78
|
+
else document.removeEventListener('mousedown', onOutsideClick)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const selectedRows = computed(() => {
|
|
82
|
+
if (!props.tableRef) return { meta: { all: false }, rows: [] }
|
|
83
|
+
return props.tableRef.getSelectedRows() ?? { meta: { all: false }, rows: [] }
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const hasSelection = computed(() => selectedRows.value.rows.length > 0)
|
|
50
87
|
|
|
51
88
|
const doExport = () => {
|
|
52
|
-
if (props.tableRef)
|
|
89
|
+
if (!props.tableRef) return
|
|
90
|
+
if (hasSelection.value) {
|
|
91
|
+
const ids = selectedRows.value.rows.map(r => r.id)
|
|
92
|
+
props.tableRef.exportTable(format.value, false, false, ids)
|
|
93
|
+
} else {
|
|
53
94
|
props.tableRef.exportTable(format.value, true, true)
|
|
54
95
|
}
|
|
55
96
|
isOpen.value = false
|
|
56
97
|
}
|
|
57
98
|
|
|
58
|
-
const open = () => { isOpen.value = true }
|
|
59
|
-
|
|
60
99
|
defineExpose({ open })
|
|
61
100
|
</script>
|
|
62
101
|
|
|
63
102
|
<template>
|
|
64
|
-
<div>
|
|
103
|
+
<div class="relative">
|
|
65
104
|
<button
|
|
105
|
+
ref="btnRef"
|
|
66
106
|
type="button"
|
|
67
|
-
@click="
|
|
68
|
-
class="
|
|
107
|
+
@click="toggle"
|
|
108
|
+
:class="[
|
|
109
|
+
'py-1.5 px-3 inline-flex items-center gap-2 text-sm font-medium rounded-lg border transition-colors',
|
|
110
|
+
isOpen
|
|
111
|
+
? 'border-blue-500 bg-blue-50 text-blue-700 dark:bg-blue-900/20 dark:border-blue-500 dark:text-blue-300'
|
|
112
|
+
: 'border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-800 text-slate-600 dark:text-slate-300 hover:bg-slate-50 dark:hover:bg-slate-700'
|
|
113
|
+
]"
|
|
69
114
|
>
|
|
70
|
-
<IconDownload class="
|
|
115
|
+
<IconDownload class="size-4" stroke="1.5" />
|
|
71
116
|
Exportar
|
|
72
117
|
</button>
|
|
73
118
|
|
|
74
|
-
<!--
|
|
119
|
+
<!-- Dropdown panel — teleported to body to avoid overflow-hidden clipping -->
|
|
75
120
|
<Teleport to="body">
|
|
76
121
|
<Transition
|
|
77
|
-
enter-active-class="transition ease-out duration-
|
|
78
|
-
enter-from-class="opacity-0"
|
|
79
|
-
enter-to-class="opacity-100"
|
|
80
|
-
leave-active-class="transition ease-in duration-
|
|
81
|
-
leave-from-class="opacity-100"
|
|
82
|
-
leave-to-class="opacity-0"
|
|
122
|
+
enter-active-class="transition ease-out duration-150"
|
|
123
|
+
enter-from-class="opacity-0 translate-y-1 scale-95"
|
|
124
|
+
enter-to-class="opacity-100 translate-y-0 scale-100"
|
|
125
|
+
leave-active-class="transition ease-in duration-100"
|
|
126
|
+
leave-from-class="opacity-100 translate-y-0 scale-100"
|
|
127
|
+
leave-to-class="opacity-0 translate-y-1 scale-95"
|
|
83
128
|
>
|
|
84
129
|
<div
|
|
85
130
|
v-if="isOpen"
|
|
86
|
-
|
|
87
|
-
|
|
131
|
+
ref="panelRef"
|
|
132
|
+
:style="panelStyle"
|
|
133
|
+
class="z-50 w-72 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-xl shadow-2xl"
|
|
88
134
|
>
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
<div
|
|
95
|
-
v-if="isOpen"
|
|
96
|
-
class="bg-white dark:bg-slate-800 rounded-2xl shadow-2xl w-full max-w-md border border-slate-200 dark:border-slate-700"
|
|
97
|
-
>
|
|
98
|
-
<div class="flex items-center justify-between px-6 py-4 border-b border-slate-100 dark:border-slate-700">
|
|
99
|
-
<h3 class="font-semibold text-slate-800 dark:text-slate-100">Exportar tabla</h3>
|
|
135
|
+
<div class="p-3 space-y-4">
|
|
136
|
+
<!-- Format -->
|
|
137
|
+
<div>
|
|
138
|
+
<p class="text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-2">Formato</p>
|
|
139
|
+
<div class="grid grid-cols-4 gap-1.5">
|
|
100
140
|
<button
|
|
141
|
+
v-for="f in formats"
|
|
142
|
+
:key="f.value"
|
|
101
143
|
type="button"
|
|
102
|
-
@click="
|
|
103
|
-
class="
|
|
144
|
+
@click="format = f.value"
|
|
145
|
+
:class="[
|
|
146
|
+
'flex flex-col items-center gap-1 py-2 px-1 rounded-lg border text-xs font-medium transition-colors',
|
|
147
|
+
format === f.value
|
|
148
|
+
? 'border-blue-500 bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:border-blue-500 dark:text-blue-300'
|
|
149
|
+
: 'border-slate-200 dark:border-slate-700 text-slate-600 dark:text-slate-300 hover:bg-slate-50 dark:hover:bg-slate-700'
|
|
150
|
+
]"
|
|
104
151
|
>
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
</svg>
|
|
152
|
+
<component :is="f.icon" class="size-4" stroke="1.5" />
|
|
153
|
+
{{ f.label }}
|
|
108
154
|
</button>
|
|
109
155
|
</div>
|
|
156
|
+
</div>
|
|
110
157
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
v-for="f in formats"
|
|
118
|
-
:key="f.value"
|
|
119
|
-
type="button"
|
|
120
|
-
@click="format = f.value"
|
|
121
|
-
:class="[
|
|
122
|
-
'flex flex-col items-center gap-1.5 p-3 rounded-xl border text-sm font-medium transition-colors',
|
|
123
|
-
format === f.value
|
|
124
|
-
? 'border-indigo-500 bg-indigo-50 text-indigo-700 dark:bg-indigo-900/30 dark:border-indigo-500 dark:text-indigo-300'
|
|
125
|
-
: 'border-slate-200 dark:border-slate-700 text-slate-600 dark:text-slate-300 hover:bg-slate-50 dark:hover:bg-slate-700'
|
|
126
|
-
]"
|
|
127
|
-
>
|
|
128
|
-
<IconFileTypeXls v-if="f.value === 'xlsx'" class="size-5" stroke="1.5" />
|
|
129
|
-
<IconFileTypeCsv v-else-if="f.value === 'csv'" class="size-5" stroke="1.5" />
|
|
130
|
-
<IconFileTypePdf v-else-if="f.value === 'pdf'" class="size-5" stroke="1.5" />
|
|
131
|
-
<IconCodeDots v-else class="size-5" stroke="1.5" />
|
|
132
|
-
{{ f.label }}
|
|
133
|
-
</button>
|
|
134
|
-
</div>
|
|
135
|
-
</div>
|
|
136
|
-
|
|
137
|
-
<!-- Filename -->
|
|
138
|
-
<div>
|
|
139
|
-
<label class="text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wider block mb-2">
|
|
140
|
-
Nombre de archivo
|
|
141
|
-
</label>
|
|
142
|
-
<div class="flex items-center gap-2">
|
|
143
|
-
<input
|
|
144
|
-
v-model="filename"
|
|
145
|
-
type="text"
|
|
146
|
-
class="flex-1 rounded-lg border border-gray-200 dark:border-slate-700 bg-white dark:bg-slate-900 text-slate-900 dark:text-white py-2 px-3 text-sm focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
|
147
|
-
/>
|
|
148
|
-
<span class="text-sm text-slate-400">.{{ format }}</span>
|
|
149
|
-
</div>
|
|
150
|
-
</div>
|
|
151
|
-
|
|
152
|
-
<!-- Columns -->
|
|
153
|
-
<div v-if="columns.length > 0">
|
|
154
|
-
<div class="flex items-center justify-between mb-2">
|
|
155
|
-
<p class="text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wider">Columnas</p>
|
|
156
|
-
<button
|
|
157
|
-
type="button"
|
|
158
|
-
@click="toggleAll"
|
|
159
|
-
class="text-xs text-indigo-600 dark:text-indigo-400 hover:underline"
|
|
160
|
-
>
|
|
161
|
-
{{ allSelected ? 'Deseleccionar todas' : 'Seleccionar todas' }}
|
|
162
|
-
</button>
|
|
163
|
-
</div>
|
|
164
|
-
<div class="grid grid-cols-2 gap-1.5 max-h-40 overflow-y-auto pr-1">
|
|
165
|
-
<label
|
|
166
|
-
v-for="col in columns"
|
|
167
|
-
:key="col.key"
|
|
168
|
-
class="flex items-center gap-2 py-1.5 px-2 rounded-lg hover:bg-slate-50 dark:hover:bg-slate-700 cursor-pointer"
|
|
169
|
-
>
|
|
170
|
-
<input
|
|
171
|
-
type="checkbox"
|
|
172
|
-
:checked="selectedColumns.includes(col.key)"
|
|
173
|
-
@change="toggleColumn(col.key)"
|
|
174
|
-
class="rounded border-gray-300 dark:bg-slate-700 dark:border-slate-600 text-indigo-600"
|
|
175
|
-
/>
|
|
176
|
-
<span class="text-sm text-slate-700 dark:text-slate-200 truncate">{{ col.label }}</span>
|
|
177
|
-
</label>
|
|
178
|
-
</div>
|
|
179
|
-
</div>
|
|
158
|
+
<!-- Filename -->
|
|
159
|
+
<div>
|
|
160
|
+
<p class="text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1.5">Archivo</p>
|
|
161
|
+
<div class="flex items-center gap-1.5">
|
|
162
|
+
<Forms.Input v-model="filename" type="text" placeholder="nombre" class="flex-1" />
|
|
163
|
+
<span class="text-sm text-slate-400 shrink-0">.{{ format }}</span>
|
|
180
164
|
</div>
|
|
165
|
+
</div>
|
|
181
166
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
Cancelar
|
|
167
|
+
<!-- Columns -->
|
|
168
|
+
<div v-if="exportableColumns.length > 0">
|
|
169
|
+
<div class="flex items-center justify-between mb-1.5">
|
|
170
|
+
<p class="text-[10px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest">Columnas</p>
|
|
171
|
+
<button type="button" @click="toggleAll" class="text-[10px] text-blue-600 dark:text-blue-400 hover:underline font-medium">
|
|
172
|
+
{{ allSelected ? 'Quitar todas' : 'Todas' }}
|
|
189
173
|
</button>
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
174
|
+
</div>
|
|
175
|
+
<div class="grid grid-cols-2 gap-1 max-h-36 overflow-y-auto">
|
|
176
|
+
<label
|
|
177
|
+
v-for="col in exportableColumns"
|
|
178
|
+
:key="col.key"
|
|
179
|
+
class="flex items-center gap-2 py-1 px-2 rounded-lg hover:bg-slate-50 dark:hover:bg-slate-700 cursor-pointer"
|
|
194
180
|
>
|
|
195
|
-
<
|
|
196
|
-
|
|
197
|
-
|
|
181
|
+
<input
|
|
182
|
+
type="checkbox"
|
|
183
|
+
:checked="selectedColumns.includes(col.key)"
|
|
184
|
+
@change="toggleColumn(col.key)"
|
|
185
|
+
class="rounded border-gray-300 dark:bg-slate-700 dark:border-slate-600 text-blue-600"
|
|
186
|
+
/>
|
|
187
|
+
<span class="text-xs text-slate-700 dark:text-slate-200 truncate">{{ col.label }}</span>
|
|
188
|
+
</label>
|
|
198
189
|
</div>
|
|
199
190
|
</div>
|
|
200
|
-
</
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<!-- Selection info -->
|
|
194
|
+
<div class="px-3 pb-2">
|
|
195
|
+
<p v-if="hasSelection" class="text-xs text-blue-600 dark:text-blue-400 font-medium">
|
|
196
|
+
Se exportarán {{ selectedRows.rows.length }} fila{{ selectedRows.rows.length !== 1 ? 's' : '' }} seleccionada{{ selectedRows.rows.length !== 1 ? 's' : '' }}
|
|
197
|
+
</p>
|
|
198
|
+
<p v-else class="text-xs text-slate-400 dark:text-slate-500">
|
|
199
|
+
Se exportarán todos los registros
|
|
200
|
+
</p>
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<!-- Footer -->
|
|
204
|
+
<div class="flex gap-2 px-3 pb-3">
|
|
205
|
+
<button
|
|
206
|
+
type="button"
|
|
207
|
+
@click="isOpen = false"
|
|
208
|
+
class="flex-1 py-1.5 text-sm font-medium rounded-lg border border-slate-200 dark:border-slate-700 text-slate-600 dark:text-slate-300 hover:bg-slate-50 dark:hover:bg-slate-700 transition-colors"
|
|
209
|
+
>
|
|
210
|
+
Cancelar
|
|
211
|
+
</button>
|
|
212
|
+
<button
|
|
213
|
+
type="button"
|
|
214
|
+
@click="doExport"
|
|
215
|
+
class="flex-1 py-1.5 text-sm font-medium rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition-colors inline-flex items-center justify-center gap-1.5"
|
|
216
|
+
>
|
|
217
|
+
<IconDownload class="size-4" stroke="1.5" />
|
|
218
|
+
Exportar
|
|
219
|
+
</button>
|
|
220
|
+
</div>
|
|
201
221
|
</div>
|
|
202
222
|
</Transition>
|
|
203
223
|
</Teleport>
|
package/package.json
CHANGED
|
Binary file
|
package/public/icon.png
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/spark.css
CHANGED
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
@source "./shared/**/*.{js,ts}";
|
|
9
9
|
@source "./plugins/**/*.{js,ts}";
|
|
10
10
|
|
|
11
|
+
/* Safelist: clases dinámicas del colorMap (Admin/Page, Nav/Tabs, etc.) */
|
|
12
|
+
@source inline("{text,bg,border}-{blue,green,red,amber,purple,teal,slate}-{50,100,200,400,500,600,700,800,900}");
|
|
13
|
+
@source inline("dark:{text,bg,border}-{blue,green,red,amber,purple,teal,slate}-{50,100,200,400,500,600,700,800,900}");
|
|
14
|
+
@source inline("dark:bg-{blue,green,red,amber,purple,teal}-500/10 dark:border-{blue,green,red,amber,purple,teal}-500/30");
|
|
15
|
+
|
|
11
16
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
12
17
|
@custom-variant hover (&:hover);
|
|
13
18
|
|
|
@@ -113,9 +118,9 @@
|
|
|
113
118
|
|
|
114
119
|
/* ─── Dark theme ────────────────────────────────────────────── */
|
|
115
120
|
.dark {
|
|
116
|
-
--background: #020617;
|
|
117
|
-
--background-1: #0f172a;
|
|
118
|
-
--background-2: #
|
|
121
|
+
--background: #020617; /* slate-950 — base page */
|
|
122
|
+
--background-1: #0f172a; /* slate-900 — panels */
|
|
123
|
+
--background-2: #1e293b; /* slate-800 — elevated */
|
|
119
124
|
--foreground: #f8fafc;
|
|
120
125
|
--foreground-inverse: #020617;
|
|
121
126
|
|
|
@@ -125,35 +130,35 @@
|
|
|
125
130
|
--primary-focus: #93c5fd;
|
|
126
131
|
--primary-line: #3b82f6;
|
|
127
132
|
|
|
128
|
-
--card: #
|
|
129
|
-
--card-line: #
|
|
130
|
-
--card-divider: #
|
|
133
|
+
--card: #0f172a;
|
|
134
|
+
--card-line: #1e293b;
|
|
135
|
+
--card-divider: #1e293b;
|
|
131
136
|
|
|
132
|
-
--layer: #
|
|
133
|
-
--layer-line: #
|
|
137
|
+
--layer: #0f172a;
|
|
138
|
+
--layer-line: #1e293b;
|
|
134
139
|
--layer-hover: #1e293b;
|
|
135
140
|
--layer-focus: #334155;
|
|
136
141
|
|
|
137
|
-
--surface: #
|
|
142
|
+
--surface: #1e293b;
|
|
138
143
|
--surface-1: #334155;
|
|
139
|
-
--surface-foreground: #
|
|
144
|
+
--surface-foreground: #e2e8f0;
|
|
140
145
|
|
|
141
|
-
--muted: #
|
|
146
|
+
--muted: #0f172a;
|
|
142
147
|
--muted-foreground: #94a3b8;
|
|
143
148
|
--muted-foreground-1: #cbd5e1;
|
|
144
149
|
--muted-foreground-2: #64748b;
|
|
145
150
|
--muted-hover: #1e293b;
|
|
146
151
|
--muted-focus: #334155;
|
|
147
152
|
|
|
148
|
-
--navbar: #
|
|
149
|
-
--navbar-line: #
|
|
150
|
-
--sidebar: #
|
|
151
|
-
--sidebar-line: #
|
|
153
|
+
--navbar: #0f172a;
|
|
154
|
+
--navbar-line: #1e293b;
|
|
155
|
+
--sidebar: #0f172a;
|
|
156
|
+
--sidebar-line: #1e293b;
|
|
152
157
|
|
|
153
|
-
--dropdown: #
|
|
154
|
-
--dropdown-line: #
|
|
155
|
-
--dropdown-divider: #
|
|
156
|
-
--dropdown-item-foreground: #
|
|
158
|
+
--dropdown: #0f172a;
|
|
159
|
+
--dropdown-line: #1e293b;
|
|
160
|
+
--dropdown-divider: #1e293b;
|
|
161
|
+
--dropdown-item-foreground: #e2e8f0;
|
|
157
162
|
--dropdown-item-hover: #1e293b;
|
|
158
163
|
--dropdown-item-focus: #334155;
|
|
159
164
|
|
|
@@ -161,7 +166,7 @@
|
|
|
161
166
|
--tooltip-line: #f8fafc;
|
|
162
167
|
--tooltip-foreground: #020617;
|
|
163
168
|
|
|
164
|
-
--scrollbar-track: #
|
|
169
|
+
--scrollbar-track: #0f172a;
|
|
165
170
|
--scrollbar-thumb: #475569;
|
|
166
171
|
}
|
|
167
172
|
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
defineProps<{
|
|
3
|
-
title?: string
|
|
4
|
-
}>()
|
|
5
|
-
|
|
6
|
-
const sidebar = inject('vantage:sidebar', null) as any
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<template>
|
|
10
|
-
<header class="sticky top-0 z-40 bg-white dark:bg-slate-800 border-b border-slate-200 dark:border-slate-700 px-4 lg:px-6 h-14 flex items-center gap-x-3">
|
|
11
|
-
<!-- Hamburger mobile -->
|
|
12
|
-
<button type="button"
|
|
13
|
-
class="lg:hidden size-8 flex items-center justify-center text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
|
|
14
|
-
@click="sidebar?.open()">
|
|
15
|
-
<svg class="size-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
16
|
-
<line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="18" x2="21" y2="18" />
|
|
17
|
-
</svg>
|
|
18
|
-
</button>
|
|
19
|
-
|
|
20
|
-
<!-- Left slot -->
|
|
21
|
-
<div class="flex-1 flex items-center gap-x-3">
|
|
22
|
-
<slot name="left">
|
|
23
|
-
<span v-if="title" class="text-sm font-medium text-slate-700 dark:text-slate-300">{{ title }}</span>
|
|
24
|
-
</slot>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
<!-- Right slot -->
|
|
28
|
-
<div class="flex items-center gap-x-2">
|
|
29
|
-
<slot name="right" />
|
|
30
|
-
</div>
|
|
31
|
-
</header>
|
|
32
|
-
</template>
|