@innertia-solutions/innertia-nuxt 0.1.1
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/.github/workflows/auto-publish.yml +64 -0
- package/.github/workflows/release.yml +59 -0
- package/README.md +60 -0
- package/app.config.ts +70 -0
- package/components/Admin/Base.vue +144 -0
- package/components/Admin/Header.vue +32 -0
- package/components/Admin/Page.vue +65 -0
- package/components/Admin/PageHeader.vue +31 -0
- package/components/App/Button.vue +59 -0
- package/components/App/DevEnvironmentBar.vue +43 -0
- package/components/App/Dropdown.vue +286 -0
- package/components/App/EmptyState.vue +433 -0
- package/components/App/LoadingState.vue +40 -0
- package/components/App/PageLoadingSpinner.vue +118 -0
- package/components/App/PreviewDock.vue +64 -0
- package/components/App/SwitchColorTheme.vue +51 -0
- package/components/App/Tag.vue +193 -0
- package/components/DataTable.vue +713 -0
- package/components/Forms/DatePicker.vue +255 -0
- package/components/Forms/Input.vue +75 -0
- package/components/Forms/Select.vue +100 -0
- package/components/Forms/SelectServer.vue +726 -0
- package/components/Layout/Admin.vue +32 -0
- package/components/Layout/Auth.vue +29 -0
- package/components/Layout/SidebarWithAppColumn.vue +388 -0
- package/components/Layout/TopBar.vue +113 -0
- package/components/MobileBlocker.vue +85 -0
- package/components/MobileLoginPicker.vue +83 -0
- package/components/Modal/Base.vue +29 -0
- package/components/Modal/DeleteConfirm.vue +48 -0
- package/components/Modal.vue +103 -0
- package/components/Nav/Tabs.vue +55 -0
- package/components/PermissionsTree.vue +272 -0
- package/components/Table/Database.vue +183 -0
- package/components/Table/DownloadDropdown.vue +111 -0
- package/components/Table/Enterprise.vue +540 -0
- package/components/Table/FilterDropdown.vue +226 -0
- package/components/Table/Grid.vue +62 -0
- package/components/Table/Kanban.vue +188 -0
- package/components/Table/List.vue +128 -0
- package/components/Table/PreviewTimeline.vue +118 -0
- package/components/Table/Standard.vue +1217 -0
- package/components/Table/index.vue +974 -0
- package/components/TableExportable.vue +172 -0
- package/components/TableFilter.vue +93 -0
- package/components/Toast/Alert.vue +113 -0
- package/components/Toast/Container.vue +34 -0
- package/components/Toast/Notification.vue +45 -0
- package/components/Toast/Process.vue +88 -0
- package/composables/useApi.js +95 -0
- package/composables/useApp.ts +46 -0
- package/composables/useAuth.js +82 -0
- package/composables/useContext.js +44 -0
- package/composables/useDate.js +241 -0
- package/composables/useDevice.js +21 -0
- package/composables/useDockedPreviews.js +56 -0
- package/composables/useDownload.js +87 -0
- package/composables/useEntity.js +82 -0
- package/composables/useForm.js +119 -0
- package/composables/useInnertiaMode.ts +25 -0
- package/composables/useMobileGuard.ts +81 -0
- package/composables/useNotifications.js +22 -0
- package/composables/usePermissions.js +23 -0
- package/composables/useRealtime.js +123 -0
- package/composables/useRequestInterceptors.js +27 -0
- package/composables/useRoles.js +53 -0
- package/composables/useRutFormatter.js +39 -0
- package/composables/useTable.ts +94 -0
- package/composables/useTablePreferences.ts +33 -0
- package/composables/useTenant.js +27 -0
- package/composables/useTimeAgo.js +37 -0
- package/composables/useToast.js +69 -0
- package/composables/useUserRealtime.js +17 -0
- package/composables/useUsers.js +111 -0
- package/css/themes/autumn.css +401 -0
- package/css/themes/bubblegum.css +408 -0
- package/css/themes/cashmere.css +412 -0
- package/css/themes/harvest.css +416 -0
- package/css/themes/moon.css +140 -0
- package/css/themes/ocean.css +273 -0
- package/css/themes/olive.css +413 -0
- package/css/themes/retro.css +431 -0
- package/css/themes/theme.css +725 -0
- package/error.vue +78 -0
- package/middleware/01.detect-subdomain.global.ts +43 -0
- package/middleware/02.validate-tenant.global.ts +67 -0
- package/middleware/03.apps.global.ts +88 -0
- package/middleware/auth.ts +9 -0
- package/middleware/guest.ts +9 -0
- package/nuxt.config.ts +42 -0
- package/package.json +60 -0
- package/pages/tenant-error.vue +50 -0
- package/plugins/api-auth.ts +12 -0
- package/plugins/api-tenant.client.ts +21 -0
- package/plugins/appearance.ts +8 -0
- package/plugins/auth-init.ts +34 -0
- package/plugins/dark-state.client.ts +29 -0
- package/plugins/dockedPreviewsSync.client.js +17 -0
- package/plugins/preline.client.ts +68 -0
- package/plugins/theme.client.ts +7 -0
- package/plugins/vue-query.ts +29 -0
- package/public/init-theme.js +15 -0
- package/spark.css +721 -0
- package/stores/auth.js +130 -0
- package/stores/dockedPreviews.js +34 -0
- package/stores/notifications.js +24 -0
- package/stores/tenant.js +54 -0
- package/stores/toast.js +129 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
defineProps({
|
|
3
|
+
title: { type: String, default: "No hay contenido" },
|
|
4
|
+
description: { type: String, default: "Aún no hay datos que mostrar." },
|
|
5
|
+
actionText: { type: String, default: "" },
|
|
6
|
+
actionLink: { type: String, default: "" },
|
|
7
|
+
showAction: { type: Boolean, default: false },
|
|
8
|
+
shape: {
|
|
9
|
+
type: String,
|
|
10
|
+
default: "square",
|
|
11
|
+
validator: (value) => ["square", "circle"].includes(value),
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
</script>
|
|
15
|
+
<template>
|
|
16
|
+
<div>
|
|
17
|
+
<slot v-if="shape == 'square'" name="icon">
|
|
18
|
+
<!-- Ícono por defecto (tu SVG) -->
|
|
19
|
+
<svg
|
|
20
|
+
class="w-48 mx-auto mb-4"
|
|
21
|
+
width="178"
|
|
22
|
+
height="90"
|
|
23
|
+
viewBox="0 0 178 90"
|
|
24
|
+
fill="none"
|
|
25
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
26
|
+
>
|
|
27
|
+
<rect
|
|
28
|
+
x="27"
|
|
29
|
+
y="50.5"
|
|
30
|
+
width="124"
|
|
31
|
+
height="39"
|
|
32
|
+
rx="7.5"
|
|
33
|
+
fill="currentColor"
|
|
34
|
+
class="fill-white dark:fill-slate-800"
|
|
35
|
+
/>
|
|
36
|
+
<rect
|
|
37
|
+
x="27"
|
|
38
|
+
y="50.5"
|
|
39
|
+
width="124"
|
|
40
|
+
height="39"
|
|
41
|
+
rx="7.5"
|
|
42
|
+
stroke="currentColor"
|
|
43
|
+
class="stroke-slate-50 dark:stroke-slate-700/10"
|
|
44
|
+
/>
|
|
45
|
+
<rect
|
|
46
|
+
x="34.5"
|
|
47
|
+
y="58"
|
|
48
|
+
width="24"
|
|
49
|
+
height="24"
|
|
50
|
+
rx="4"
|
|
51
|
+
fill="currentColor"
|
|
52
|
+
class="fill-slate-50 dark:fill-slate-700/30"
|
|
53
|
+
/>
|
|
54
|
+
<rect
|
|
55
|
+
x="66.5"
|
|
56
|
+
y="61"
|
|
57
|
+
width="60"
|
|
58
|
+
height="6"
|
|
59
|
+
rx="3"
|
|
60
|
+
fill="currentColor"
|
|
61
|
+
class="fill-slate-50 dark:fill-slate-700/30"
|
|
62
|
+
/>
|
|
63
|
+
<rect
|
|
64
|
+
x="66.5"
|
|
65
|
+
y="73"
|
|
66
|
+
width="77"
|
|
67
|
+
height="6"
|
|
68
|
+
rx="3"
|
|
69
|
+
fill="currentColor"
|
|
70
|
+
class="fill-slate-50 dark:fill-slate-700/30"
|
|
71
|
+
/>
|
|
72
|
+
<rect
|
|
73
|
+
x="19.5"
|
|
74
|
+
y="28.5"
|
|
75
|
+
width="139"
|
|
76
|
+
height="39"
|
|
77
|
+
rx="7.5"
|
|
78
|
+
fill="currentColor"
|
|
79
|
+
class="fill-white dark:fill-slate-800"
|
|
80
|
+
/>
|
|
81
|
+
<rect
|
|
82
|
+
x="19.5"
|
|
83
|
+
y="28.5"
|
|
84
|
+
width="139"
|
|
85
|
+
height="39"
|
|
86
|
+
rx="7.5"
|
|
87
|
+
stroke="currentColor"
|
|
88
|
+
class="stroke-slate-100 dark:stroke-slate-700/30"
|
|
89
|
+
/>
|
|
90
|
+
<rect
|
|
91
|
+
x="27"
|
|
92
|
+
y="36"
|
|
93
|
+
width="24"
|
|
94
|
+
height="24"
|
|
95
|
+
rx="4"
|
|
96
|
+
fill="currentColor"
|
|
97
|
+
class="fill-slate-100 dark:fill-slate-700/70"
|
|
98
|
+
/>
|
|
99
|
+
<rect
|
|
100
|
+
x="59"
|
|
101
|
+
y="39"
|
|
102
|
+
width="60"
|
|
103
|
+
height="6"
|
|
104
|
+
rx="3"
|
|
105
|
+
fill="currentColor"
|
|
106
|
+
class="fill-slate-100 dark:fill-slate-700/70"
|
|
107
|
+
/>
|
|
108
|
+
<rect
|
|
109
|
+
x="59"
|
|
110
|
+
y="51"
|
|
111
|
+
width="92"
|
|
112
|
+
height="6"
|
|
113
|
+
rx="3"
|
|
114
|
+
fill="currentColor"
|
|
115
|
+
class="fill-slate-100 dark:fill-slate-700/70"
|
|
116
|
+
/>
|
|
117
|
+
<g filter="url(#filter15)">
|
|
118
|
+
<rect
|
|
119
|
+
x="12"
|
|
120
|
+
y="6"
|
|
121
|
+
width="154"
|
|
122
|
+
height="40"
|
|
123
|
+
rx="8"
|
|
124
|
+
fill="currentColor"
|
|
125
|
+
class="fill-white dark:fill-slate-800"
|
|
126
|
+
shape-rendering="crispEdges"
|
|
127
|
+
/>
|
|
128
|
+
<rect
|
|
129
|
+
x="12.5"
|
|
130
|
+
y="6.5"
|
|
131
|
+
width="153"
|
|
132
|
+
height="39"
|
|
133
|
+
rx="7.5"
|
|
134
|
+
stroke="currentColor"
|
|
135
|
+
class="stroke-slate-100 dark:stroke-slate-700/60"
|
|
136
|
+
shape-rendering="crispEdges"
|
|
137
|
+
/>
|
|
138
|
+
<rect
|
|
139
|
+
x="20"
|
|
140
|
+
y="14"
|
|
141
|
+
width="24"
|
|
142
|
+
height="24"
|
|
143
|
+
rx="4"
|
|
144
|
+
fill="currentColor"
|
|
145
|
+
class="fill-slate-200 dark:fill-slate-700"
|
|
146
|
+
/>
|
|
147
|
+
<rect
|
|
148
|
+
x="52"
|
|
149
|
+
y="17"
|
|
150
|
+
width="60"
|
|
151
|
+
height="6"
|
|
152
|
+
rx="3"
|
|
153
|
+
fill="currentColor"
|
|
154
|
+
class="fill-slate-200 dark:fill-slate-700"
|
|
155
|
+
/>
|
|
156
|
+
<rect
|
|
157
|
+
x="52"
|
|
158
|
+
y="29"
|
|
159
|
+
width="106"
|
|
160
|
+
height="6"
|
|
161
|
+
rx="3"
|
|
162
|
+
fill="currentColor"
|
|
163
|
+
class="fill-slate-200 dark:fill-slate-700"
|
|
164
|
+
/>
|
|
165
|
+
</g>
|
|
166
|
+
<defs>
|
|
167
|
+
<filter
|
|
168
|
+
id="filter15"
|
|
169
|
+
x="0"
|
|
170
|
+
y="0"
|
|
171
|
+
width="178"
|
|
172
|
+
height="64"
|
|
173
|
+
filterUnits="userSpaceOnUse"
|
|
174
|
+
color-interpolation-filters="sRGB"
|
|
175
|
+
>
|
|
176
|
+
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
|
177
|
+
<feColorMatrix
|
|
178
|
+
in="SourceAlpha"
|
|
179
|
+
type="matrix"
|
|
180
|
+
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
|
181
|
+
result="hardAlpha"
|
|
182
|
+
/>
|
|
183
|
+
<feOffset dy="6" />
|
|
184
|
+
<feGaussianBlur stdDeviation="6" />
|
|
185
|
+
<feComposite in2="hardAlpha" operator="out" />
|
|
186
|
+
<feColorMatrix
|
|
187
|
+
type="matrix"
|
|
188
|
+
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.03 0"
|
|
189
|
+
/>
|
|
190
|
+
<feBlend
|
|
191
|
+
mode="normal"
|
|
192
|
+
in2="BackgroundImageFix"
|
|
193
|
+
result="effect1_dropShadow_1187_14810"
|
|
194
|
+
/>
|
|
195
|
+
<feBlend
|
|
196
|
+
mode="normal"
|
|
197
|
+
in="SourceGraphic"
|
|
198
|
+
in2="effect1_dropShadow_1187_14810"
|
|
199
|
+
result="shape"
|
|
200
|
+
/>
|
|
201
|
+
</filter>
|
|
202
|
+
</defs>
|
|
203
|
+
</svg>
|
|
204
|
+
</slot>
|
|
205
|
+
<slot v-else name="icon">
|
|
206
|
+
<svg
|
|
207
|
+
class="w-48 mx-auto mb-4"
|
|
208
|
+
width="178"
|
|
209
|
+
height="90"
|
|
210
|
+
viewBox="0 0 178 90"
|
|
211
|
+
fill="none"
|
|
212
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
213
|
+
>
|
|
214
|
+
<rect
|
|
215
|
+
x="27"
|
|
216
|
+
y="50.5"
|
|
217
|
+
width="124"
|
|
218
|
+
height="39"
|
|
219
|
+
rx="7.5"
|
|
220
|
+
fill="currentColor"
|
|
221
|
+
class="fill-white dark:fill-slate-800"
|
|
222
|
+
/>
|
|
223
|
+
<rect
|
|
224
|
+
x="27"
|
|
225
|
+
y="50.5"
|
|
226
|
+
width="124"
|
|
227
|
+
height="39"
|
|
228
|
+
rx="7.5"
|
|
229
|
+
stroke="currentColor"
|
|
230
|
+
class="stroke-slate-50 dark:stroke-slate-700/10"
|
|
231
|
+
/>
|
|
232
|
+
<rect
|
|
233
|
+
x="34.5"
|
|
234
|
+
y="58"
|
|
235
|
+
width="24"
|
|
236
|
+
height="24"
|
|
237
|
+
rx="12"
|
|
238
|
+
fill="currentColor"
|
|
239
|
+
class="fill-slate-50 dark:fill-slate-700/30"
|
|
240
|
+
/>
|
|
241
|
+
<rect
|
|
242
|
+
x="66.5"
|
|
243
|
+
y="61"
|
|
244
|
+
width="60"
|
|
245
|
+
height="6"
|
|
246
|
+
rx="3"
|
|
247
|
+
fill="currentColor"
|
|
248
|
+
class="fill-slate-50 dark:fill-slate-700/30"
|
|
249
|
+
/>
|
|
250
|
+
<rect
|
|
251
|
+
x="66.5"
|
|
252
|
+
y="73"
|
|
253
|
+
width="77"
|
|
254
|
+
height="6"
|
|
255
|
+
rx="3"
|
|
256
|
+
fill="currentColor"
|
|
257
|
+
class="fill-slate-50 dark:fill-slate-700/30"
|
|
258
|
+
/>
|
|
259
|
+
<rect
|
|
260
|
+
x="19.5"
|
|
261
|
+
y="28.5"
|
|
262
|
+
width="139"
|
|
263
|
+
height="39"
|
|
264
|
+
rx="7.5"
|
|
265
|
+
fill="currentColor"
|
|
266
|
+
class="fill-white dark:fill-slate-800"
|
|
267
|
+
/>
|
|
268
|
+
<rect
|
|
269
|
+
x="19.5"
|
|
270
|
+
y="28.5"
|
|
271
|
+
width="139"
|
|
272
|
+
height="39"
|
|
273
|
+
rx="7.5"
|
|
274
|
+
stroke="currentColor"
|
|
275
|
+
class="stroke-slate-100 dark:stroke-slate-700/30"
|
|
276
|
+
/>
|
|
277
|
+
<rect
|
|
278
|
+
x="27"
|
|
279
|
+
y="36"
|
|
280
|
+
width="24"
|
|
281
|
+
height="24"
|
|
282
|
+
rx="12"
|
|
283
|
+
fill="currentColor"
|
|
284
|
+
class="fill-slate-100 dark:fill-slate-700/70"
|
|
285
|
+
/>
|
|
286
|
+
<rect
|
|
287
|
+
x="59"
|
|
288
|
+
y="39"
|
|
289
|
+
width="60"
|
|
290
|
+
height="6"
|
|
291
|
+
rx="3"
|
|
292
|
+
fill="currentColor"
|
|
293
|
+
class="fill-slate-100 dark:fill-slate-700/70"
|
|
294
|
+
/>
|
|
295
|
+
<rect
|
|
296
|
+
x="59"
|
|
297
|
+
y="51"
|
|
298
|
+
width="92"
|
|
299
|
+
height="6"
|
|
300
|
+
rx="3"
|
|
301
|
+
fill="currentColor"
|
|
302
|
+
class="fill-slate-100 dark:fill-slate-700/70"
|
|
303
|
+
/>
|
|
304
|
+
<g filter="url(#filter4)">
|
|
305
|
+
<rect
|
|
306
|
+
x="12"
|
|
307
|
+
y="6"
|
|
308
|
+
width="154"
|
|
309
|
+
height="40"
|
|
310
|
+
rx="8"
|
|
311
|
+
class="fill-white dark:fill-slate-800"
|
|
312
|
+
shape-rendering="crispEdges"
|
|
313
|
+
/>
|
|
314
|
+
<rect
|
|
315
|
+
x="12.5"
|
|
316
|
+
y="6.5"
|
|
317
|
+
width="153"
|
|
318
|
+
height="39"
|
|
319
|
+
rx="7.5"
|
|
320
|
+
stroke="currentColor"
|
|
321
|
+
class="stroke-slate-100 dark:stroke-slate-700/60"
|
|
322
|
+
shape-rendering="crispEdges"
|
|
323
|
+
/>
|
|
324
|
+
<rect
|
|
325
|
+
x="20"
|
|
326
|
+
y="14"
|
|
327
|
+
width="24"
|
|
328
|
+
height="24"
|
|
329
|
+
rx="12"
|
|
330
|
+
fill="currentColor"
|
|
331
|
+
class="fill-slate-200 dark:fill-slate-700"
|
|
332
|
+
/>
|
|
333
|
+
<rect
|
|
334
|
+
x="52"
|
|
335
|
+
y="17"
|
|
336
|
+
width="60"
|
|
337
|
+
height="6"
|
|
338
|
+
rx="3"
|
|
339
|
+
fill="currentColor"
|
|
340
|
+
class="fill-slate-200 dark:fill-slate-700"
|
|
341
|
+
/>
|
|
342
|
+
<rect
|
|
343
|
+
x="52"
|
|
344
|
+
y="29"
|
|
345
|
+
width="106"
|
|
346
|
+
height="6"
|
|
347
|
+
rx="3"
|
|
348
|
+
fill="currentColor"
|
|
349
|
+
class="fill-slate-200 dark:fill-slate-700"
|
|
350
|
+
/>
|
|
351
|
+
</g>
|
|
352
|
+
<defs>
|
|
353
|
+
<filter
|
|
354
|
+
id="filter4"
|
|
355
|
+
x="0"
|
|
356
|
+
y="0"
|
|
357
|
+
width="178"
|
|
358
|
+
height="64"
|
|
359
|
+
filterUnits="userSpaceOnUse"
|
|
360
|
+
color-interpolation-filters="sRGB"
|
|
361
|
+
>
|
|
362
|
+
<feFlood flood-opacity="0" result="BackgroundImageFix" />
|
|
363
|
+
<feColorMatrix
|
|
364
|
+
in="SourceAlpha"
|
|
365
|
+
type="matrix"
|
|
366
|
+
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
|
367
|
+
result="hardAlpha"
|
|
368
|
+
/>
|
|
369
|
+
<feOffset dy="6" />
|
|
370
|
+
<feGaussianBlur stdDeviation="6" />
|
|
371
|
+
<feComposite in2="hardAlpha" operator="out" />
|
|
372
|
+
<feColorMatrix
|
|
373
|
+
type="matrix"
|
|
374
|
+
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.03 0"
|
|
375
|
+
/>
|
|
376
|
+
<feBlend
|
|
377
|
+
mode="normal"
|
|
378
|
+
in2="BackgroundImageFix"
|
|
379
|
+
result="effect1_dropShadow_1187_14810"
|
|
380
|
+
/>
|
|
381
|
+
<feBlend
|
|
382
|
+
mode="normal"
|
|
383
|
+
in="SourceGraphic"
|
|
384
|
+
in2="effect1_dropShadow_1187_14810"
|
|
385
|
+
result="shape"
|
|
386
|
+
/>
|
|
387
|
+
</filter>
|
|
388
|
+
</defs>
|
|
389
|
+
</svg>
|
|
390
|
+
</slot>
|
|
391
|
+
|
|
392
|
+
<div class="max-w-sm mx-auto">
|
|
393
|
+
<p class="mt-2 font-medium text-foreground">
|
|
394
|
+
{{ title }}
|
|
395
|
+
</p>
|
|
396
|
+
<p class="mb-5 text-sm text-muted-foreground text-wrap">
|
|
397
|
+
{{ description }}
|
|
398
|
+
</p>
|
|
399
|
+
</div>
|
|
400
|
+
|
|
401
|
+
<a
|
|
402
|
+
v-if="showAction"
|
|
403
|
+
:href="actionLink"
|
|
404
|
+
class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-card-line bg-card text-foreground shadow-2xs hover:bg-muted-hover focus:outline-hidden focus:bg-muted-hover"
|
|
405
|
+
>
|
|
406
|
+
{{ actionText }}
|
|
407
|
+
</a>
|
|
408
|
+
|
|
409
|
+
<template name="footer">
|
|
410
|
+
<button
|
|
411
|
+
type="button"
|
|
412
|
+
class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none focus:outline-hidden focus:ring-2 focus:ring-blue-500"
|
|
413
|
+
data-hs-overlay="#hs-pro-empty"
|
|
414
|
+
>
|
|
415
|
+
<svg
|
|
416
|
+
class="hidden sm:block shrink-0 size-4"
|
|
417
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
418
|
+
width="24"
|
|
419
|
+
height="24"
|
|
420
|
+
viewBox="0 0 24 24"
|
|
421
|
+
fill="none"
|
|
422
|
+
stroke="currentColor"
|
|
423
|
+
stroke-width="2"
|
|
424
|
+
stroke-linecap="round"
|
|
425
|
+
stroke-linejoin="round"
|
|
426
|
+
>
|
|
427
|
+
<path d="M5 12h14" />
|
|
428
|
+
<path d="M12 5v14" /></svg
|
|
429
|
+
>Add user
|
|
430
|
+
</button>
|
|
431
|
+
</template>
|
|
432
|
+
</div>
|
|
433
|
+
</template>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="flex flex-col items-center justify-center py-10 px-4 space-y-6 w-full h-full text-center"
|
|
4
|
+
>
|
|
5
|
+
<!-- Ícono/loader -->
|
|
6
|
+
<svg
|
|
7
|
+
class="animate-spin w-10 h-10 text-muted-foreground-2"
|
|
8
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
9
|
+
viewBox="0 0 24 24"
|
|
10
|
+
fill="none"
|
|
11
|
+
stroke="currentColor"
|
|
12
|
+
stroke-width="2"
|
|
13
|
+
stroke-linecap="round"
|
|
14
|
+
stroke-linejoin="round"
|
|
15
|
+
>
|
|
16
|
+
<circle cx="12" cy="12" r="10" opacity=".25" />
|
|
17
|
+
<path d="M22 12a10 10 0 0 1-10 10" />
|
|
18
|
+
</svg>
|
|
19
|
+
|
|
20
|
+
<!-- Skeleton líneas -->
|
|
21
|
+
<div class="w-full max-w-xs space-y-3">
|
|
22
|
+
<div
|
|
23
|
+
class="h-4 bg-surface-1 rounded animate-pulse"
|
|
24
|
+
></div>
|
|
25
|
+
<div
|
|
26
|
+
class="h-4 bg-surface-1 rounded animate-pulse"
|
|
27
|
+
></div>
|
|
28
|
+
<div
|
|
29
|
+
v-if="showHint"
|
|
30
|
+
class="h-4 w-1/2 bg-surface-1 rounded animate-pulse mx-auto"
|
|
31
|
+
></div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script setup>
|
|
37
|
+
defineProps({
|
|
38
|
+
showHint: { type: Boolean, default: false },
|
|
39
|
+
});
|
|
40
|
+
</script>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const isLoading = ref(false);
|
|
3
|
+
let hideTimer;
|
|
4
|
+
let cleanup = [];
|
|
5
|
+
|
|
6
|
+
const showLoader = () => {
|
|
7
|
+
clearTimeout(hideTimer);
|
|
8
|
+
isLoading.value = true;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const hideLoader = () => {
|
|
12
|
+
clearTimeout(hideTimer);
|
|
13
|
+
hideTimer = setTimeout(() => {
|
|
14
|
+
isLoading.value = false;
|
|
15
|
+
}, 120);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
onMounted(() => {
|
|
19
|
+
const nuxtApp = useNuxtApp();
|
|
20
|
+
const router = useRouter();
|
|
21
|
+
|
|
22
|
+
cleanup = [
|
|
23
|
+
nuxtApp.hooks.hook("page:start", showLoader),
|
|
24
|
+
nuxtApp.hooks.hook("page:finish", hideLoader),
|
|
25
|
+
nuxtApp.hooks.hook("app:error", hideLoader),
|
|
26
|
+
router.beforeEach((to, from) => {
|
|
27
|
+
if (to.fullPath !== from.fullPath) {
|
|
28
|
+
showLoader();
|
|
29
|
+
}
|
|
30
|
+
}),
|
|
31
|
+
router.afterEach(hideLoader),
|
|
32
|
+
router.onError(hideLoader),
|
|
33
|
+
].filter(Boolean);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
onBeforeUnmount(() => {
|
|
37
|
+
clearTimeout(hideTimer);
|
|
38
|
+
cleanup.forEach((unregister) => unregister());
|
|
39
|
+
});
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<template>
|
|
43
|
+
<ClientOnly>
|
|
44
|
+
<Transition name="page-loading-spinner">
|
|
45
|
+
<div
|
|
46
|
+
v-if="isLoading"
|
|
47
|
+
class="page-loading-spinner"
|
|
48
|
+
aria-label="Cargando pagina"
|
|
49
|
+
role="status"
|
|
50
|
+
>
|
|
51
|
+
<span class="page-loading-spinner__ring"></span>
|
|
52
|
+
</div>
|
|
53
|
+
</Transition>
|
|
54
|
+
</ClientOnly>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<style scoped>
|
|
58
|
+
.page-loading-spinner {
|
|
59
|
+
position: fixed;
|
|
60
|
+
top: 0.625rem;
|
|
61
|
+
right: 0.5rem;
|
|
62
|
+
z-index: 2147483647;
|
|
63
|
+
display: flex;
|
|
64
|
+
width: 2.5rem;
|
|
65
|
+
height: 2.5rem;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
border: 1px solid rgb(226 232 240 / 0.9);
|
|
69
|
+
border-radius: 9999px;
|
|
70
|
+
background: rgb(255 255 255 / 0.88);
|
|
71
|
+
box-shadow: 0 10px 30px rgb(15 23 42 / 0.16);
|
|
72
|
+
backdrop-filter: blur(10px);
|
|
73
|
+
pointer-events: none;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.page-loading-spinner__ring {
|
|
77
|
+
width: 1.25rem;
|
|
78
|
+
height: 1.25rem;
|
|
79
|
+
border: 2px solid rgb(148 163 184 / 0.38);
|
|
80
|
+
border-top-color: rgb(20 184 166);
|
|
81
|
+
border-radius: 9999px;
|
|
82
|
+
animation: page-loading-spinner-rotate 0.75s linear infinite;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.page-loading-spinner-enter-active,
|
|
86
|
+
.page-loading-spinner-leave-active {
|
|
87
|
+
transition: opacity 0.15s ease, transform 0.15s ease;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.page-loading-spinner-enter-from,
|
|
91
|
+
.page-loading-spinner-leave-to {
|
|
92
|
+
opacity: 0;
|
|
93
|
+
transform: scale(0.92);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@media (min-width: 640px) {
|
|
97
|
+
.page-loading-spinner {
|
|
98
|
+
right: 1.25rem;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
:global(.dark) .page-loading-spinner {
|
|
103
|
+
border-color: rgb(51 65 85 / 0.85);
|
|
104
|
+
background: rgb(15 23 42 / 0.78);
|
|
105
|
+
box-shadow: 0 10px 30px rgb(0 0 0 / 0.3);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
:global(.dark) .page-loading-spinner__ring {
|
|
109
|
+
border-color: rgb(100 116 139 / 0.42);
|
|
110
|
+
border-top-color: rgb(45 212 191);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@keyframes page-loading-spinner-rotate {
|
|
114
|
+
to {
|
|
115
|
+
transform: rotate(360deg);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
</style>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { IconX } from '@tabler/icons-vue'
|
|
3
|
+
|
|
4
|
+
const { docked, undock, expandDock, activeDockId } = useDockedPreviews()
|
|
5
|
+
const router = useRouter()
|
|
6
|
+
const route = useRoute()
|
|
7
|
+
|
|
8
|
+
async function open(item, event) {
|
|
9
|
+
// Misma ruta → la tabla está montada, mostrar float encima del tab
|
|
10
|
+
if (route.path === item.route) {
|
|
11
|
+
const rect = event.currentTarget.getBoundingClientRect()
|
|
12
|
+
expandDock(item.id, rect)
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
// Ruta diferente → navegar y restaurar como preview completo
|
|
16
|
+
await router.push(item.route)
|
|
17
|
+
await nextTick()
|
|
18
|
+
useNuxtApp().hooks.callHook('preview:restore', item)
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<Transition
|
|
24
|
+
enter-active-class="transition ease-out duration-200"
|
|
25
|
+
enter-from-class="opacity-0 translate-y-4"
|
|
26
|
+
enter-to-class="opacity-100 translate-y-0"
|
|
27
|
+
leave-active-class="transition ease-in duration-150"
|
|
28
|
+
leave-from-class="opacity-100 translate-y-0"
|
|
29
|
+
leave-to-class="opacity-0 translate-y-4"
|
|
30
|
+
>
|
|
31
|
+
<div
|
|
32
|
+
v-if="docked.length"
|
|
33
|
+
class="fixed bottom-0 left-0 right-0 z-50 flex items-center gap-2 px-4 py-2 bg-card/95 backdrop-blur-md border-t border-card-line shadow-lg"
|
|
34
|
+
>
|
|
35
|
+
<span class="text-xs text-muted-foreground shrink-0 mr-1">Minimizados</span>
|
|
36
|
+
|
|
37
|
+
<div class="flex items-center gap-2 flex-1 overflow-x-auto">
|
|
38
|
+
<button
|
|
39
|
+
v-for="item in docked"
|
|
40
|
+
:key="item.id"
|
|
41
|
+
type="button"
|
|
42
|
+
class="group inline-flex items-center gap-2 rounded-lg border px-3 py-1.5 text-sm transition-all shrink-0"
|
|
43
|
+
:class="activeDockId === item.id
|
|
44
|
+
? 'border-primary/50 bg-primary/10 text-primary shadow-sm'
|
|
45
|
+
: 'border-card-line bg-surface hover:bg-muted-hover text-foreground'"
|
|
46
|
+
@click="open(item, $event)"
|
|
47
|
+
>
|
|
48
|
+
<span class="size-5 rounded-full bg-primary flex items-center justify-center text-[10px] font-bold text-primary-foreground shrink-0">
|
|
49
|
+
{{ (item.label?.[0] ?? '?').toUpperCase() }}
|
|
50
|
+
</span>
|
|
51
|
+
<span class="font-medium max-w-32 truncate">{{ item.label }}</span>
|
|
52
|
+
<span v-if="item.subtitle" class="text-muted-foreground text-xs max-w-28 truncate hidden sm:inline">{{ item.subtitle }}</span>
|
|
53
|
+
|
|
54
|
+
<span
|
|
55
|
+
class="size-4 inline-flex items-center justify-center rounded hover:bg-red-100 dark:hover:bg-red-900/30 hover:text-red-600 dark:hover:text-red-400 transition-colors ml-0.5"
|
|
56
|
+
@click.stop="undock(item.id)"
|
|
57
|
+
>
|
|
58
|
+
<IconX class="size-3" />
|
|
59
|
+
</span>
|
|
60
|
+
</button>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</Transition>
|
|
64
|
+
</template>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const isDark = ref(false)
|
|
3
|
+
|
|
4
|
+
onMounted(() => {
|
|
5
|
+
isDark.value = document.documentElement.classList.contains('dark')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
async function setTheme(value) {
|
|
9
|
+
const dark = value === 'dark'
|
|
10
|
+
isDark.value = dark
|
|
11
|
+
document.documentElement.classList.toggle('dark', dark)
|
|
12
|
+
localStorage.setItem('hs_theme', value)
|
|
13
|
+
document.cookie = `hs_theme=${value};path=/;max-age=${60 * 60 * 24 * 365};SameSite=Lax`
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const api = useApi()
|
|
17
|
+
await api.put('auth/me/preferences/appearance', { value })
|
|
18
|
+
} catch { /* best-effort */ }
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<button
|
|
24
|
+
v-if="isDark"
|
|
25
|
+
type="button"
|
|
26
|
+
class="font-medium text-slate-800 rounded-full hover:bg-surface focus:outline-hidden focus:bg-surface dark:text-foreground dark:hover:bg-card dark:focus:bg-card"
|
|
27
|
+
@click="setTheme('light')"
|
|
28
|
+
>
|
|
29
|
+
<span class="group inline-flex shrink-0 justify-center items-center size-9">
|
|
30
|
+
<svg class="shrink-0 size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
31
|
+
<circle cx="12" cy="12" r="4"></circle>
|
|
32
|
+
<path d="M12 2v2"></path><path d="M12 20v2"></path>
|
|
33
|
+
<path d="m4.93 4.93 1.41 1.41"></path><path d="m17.66 17.66 1.41 1.41"></path>
|
|
34
|
+
<path d="M2 12h2"></path><path d="M20 12h2"></path>
|
|
35
|
+
<path d="m6.34 17.66-1.41 1.41"></path><path d="m19.07 4.93-1.41 1.41"></path>
|
|
36
|
+
</svg>
|
|
37
|
+
</span>
|
|
38
|
+
</button>
|
|
39
|
+
<button
|
|
40
|
+
v-else
|
|
41
|
+
type="button"
|
|
42
|
+
class="font-medium text-slate-400 rounded-full hover:bg-surface focus:outline-hidden focus:bg-surface dark:text-foreground dark:hover:bg-card dark:focus:bg-card"
|
|
43
|
+
@click="setTheme('dark')"
|
|
44
|
+
>
|
|
45
|
+
<span class="group inline-flex shrink-0 justify-center items-center size-9">
|
|
46
|
+
<svg class="shrink-0 size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
47
|
+
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path>
|
|
48
|
+
</svg>
|
|
49
|
+
</span>
|
|
50
|
+
</button>
|
|
51
|
+
</template>
|