cisse-vue-ui 0.1.0

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.
Files changed (96) hide show
  1. package/README.md +15 -0
  2. package/dist/BadgeType.vue_vue_type_script_setup_true_lang-CJb63H1I.cjs +145 -0
  3. package/dist/BadgeType.vue_vue_type_script_setup_true_lang-CJb63H1I.cjs.map +1 -0
  4. package/dist/BadgeType.vue_vue_type_script_setup_true_lang-CnB5eNEM.js +146 -0
  5. package/dist/BadgeType.vue_vue_type_script_setup_true_lang-CnB5eNEM.js.map +1 -0
  6. package/dist/NotificationList.vue_vue_type_script_setup_true_lang-B2hjbMm4.js +351 -0
  7. package/dist/NotificationList.vue_vue_type_script_setup_true_lang-B2hjbMm4.js.map +1 -0
  8. package/dist/NotificationList.vue_vue_type_script_setup_true_lang-Ci3zIvrv.cjs +350 -0
  9. package/dist/NotificationList.vue_vue_type_script_setup_true_lang-Ci3zIvrv.cjs.map +1 -0
  10. package/dist/SearchInput.vue_vue_type_script_setup_true_lang-Be73hShP.cjs +234 -0
  11. package/dist/SearchInput.vue_vue_type_script_setup_true_lang-Be73hShP.cjs.map +1 -0
  12. package/dist/SearchInput.vue_vue_type_script_setup_true_lang-DjT2qdcp.js +235 -0
  13. package/dist/SearchInput.vue_vue_type_script_setup_true_lang-DjT2qdcp.js.map +1 -0
  14. package/dist/TableAction.vue_vue_type_script_setup_true_lang-BHskhVhK.js +540 -0
  15. package/dist/TableAction.vue_vue_type_script_setup_true_lang-BHskhVhK.js.map +1 -0
  16. package/dist/TableAction.vue_vue_type_script_setup_true_lang-CojbKn7E.cjs +539 -0
  17. package/dist/TableAction.vue_vue_type_script_setup_true_lang-CojbKn7E.cjs.map +1 -0
  18. package/dist/components/core/AutocompleteComponent.vue.d.ts +19 -0
  19. package/dist/components/core/CardComponent.vue.d.ts +24 -0
  20. package/dist/components/core/MenuItem.vue.d.ts +6 -0
  21. package/dist/components/core/StatusBadge.vue.d.ts +21 -0
  22. package/dist/components/core/TableAction.vue.d.ts +8 -0
  23. package/dist/components/core/TableComponent.vue.d.ts +40 -0
  24. package/dist/components/core/index.cjs +11 -0
  25. package/dist/components/core/index.cjs.map +1 -0
  26. package/dist/components/core/index.d.ts +6 -0
  27. package/dist/components/core/index.js +11 -0
  28. package/dist/components/core/index.js.map +1 -0
  29. package/dist/components/feedback/LoadingSpinner.vue.d.ts +7 -0
  30. package/dist/components/feedback/Modal.vue.d.ts +32 -0
  31. package/dist/components/feedback/NotificationComponent.vue.d.ts +12 -0
  32. package/dist/components/feedback/NotificationList.vue.d.ts +12 -0
  33. package/dist/components/feedback/PaginationControls.vue.d.ts +21 -0
  34. package/dist/components/feedback/index.cjs +9 -0
  35. package/dist/components/feedback/index.cjs.map +1 -0
  36. package/dist/components/feedback/index.d.ts +5 -0
  37. package/dist/components/feedback/index.js +9 -0
  38. package/dist/components/feedback/index.js.map +1 -0
  39. package/dist/components/form/FormGroup.vue.d.ts +30 -0
  40. package/dist/components/form/FormHelp.vue.d.ts +21 -0
  41. package/dist/components/form/FormInput.vue.d.ts +13 -0
  42. package/dist/components/form/FormLabel.vue.d.ts +21 -0
  43. package/dist/components/form/FormSelect.vue.d.ts +26 -0
  44. package/dist/components/form/SearchInput.vue.d.ts +12 -0
  45. package/dist/components/form/index.cjs +10 -0
  46. package/dist/components/form/index.cjs.map +1 -0
  47. package/dist/components/form/index.d.ts +6 -0
  48. package/dist/components/form/index.js +10 -0
  49. package/dist/components/form/index.js.map +1 -0
  50. package/dist/components/index.cjs +29 -0
  51. package/dist/components/index.cjs.map +1 -0
  52. package/dist/components/index.d.ts +4 -0
  53. package/dist/components/index.js +29 -0
  54. package/dist/components/index.js.map +1 -0
  55. package/dist/components/type/BadgeType.vue.d.ts +11 -0
  56. package/dist/components/type/BooleanType.vue.d.ts +11 -0
  57. package/dist/components/type/DateType.vue.d.ts +10 -0
  58. package/dist/components/type/NumberType.vue.d.ts +9 -0
  59. package/dist/components/type/TextType.vue.d.ts +8 -0
  60. package/dist/components/type/index.cjs +9 -0
  61. package/dist/components/type/index.cjs.map +1 -0
  62. package/dist/components/type/index.d.ts +5 -0
  63. package/dist/components/type/index.js +9 -0
  64. package/dist/components/type/index.js.map +1 -0
  65. package/dist/composables/index.cjs +7 -0
  66. package/dist/composables/index.cjs.map +1 -0
  67. package/dist/composables/index.d.ts +3 -0
  68. package/dist/composables/index.js +7 -0
  69. package/dist/composables/index.js.map +1 -0
  70. package/dist/composables/useDarkMode.d.ts +14 -0
  71. package/dist/composables/useExportCSV.d.ts +10 -0
  72. package/dist/composables/useNotifications.d.ts +27 -0
  73. package/dist/index-BoCtJCg0.cjs +32 -0
  74. package/dist/index-BoCtJCg0.cjs.map +1 -0
  75. package/dist/index-CGhDI10m.js +33 -0
  76. package/dist/index-CGhDI10m.js.map +1 -0
  77. package/dist/index.cjs +49 -0
  78. package/dist/index.cjs.map +1 -0
  79. package/dist/index.d.ts +5 -0
  80. package/dist/index.js +49 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/plugin.d.ts +24 -0
  83. package/dist/types/components.d.ts +18 -0
  84. package/dist/types/form.d.ts +27 -0
  85. package/dist/types/index.cjs +2 -0
  86. package/dist/types/index.cjs.map +1 -0
  87. package/dist/types/index.d.ts +4 -0
  88. package/dist/types/index.js +2 -0
  89. package/dist/types/index.js.map +1 -0
  90. package/dist/types/notification.d.ts +12 -0
  91. package/dist/types/property.d.ts +34 -0
  92. package/dist/useExportCSV-B9o9lJ3D.js +130 -0
  93. package/dist/useExportCSV-B9o9lJ3D.js.map +1 -0
  94. package/dist/useExportCSV-BPC_hd25.cjs +129 -0
  95. package/dist/useExportCSV-BPC_hd25.cjs.map +1 -0
  96. package/package.json +131 -0
@@ -0,0 +1,351 @@
1
+ import { defineComponent, createElementBlock, openBlock, createElementVNode, createCommentVNode, normalizeClass, toDisplayString, onMounted, onUnmounted, withModifiers, renderSlot, createTextVNode, createVNode, unref, Fragment, renderList, computed, createBlock } from "vue";
2
+ import { Icon } from "@iconify/vue";
3
+ const _hoisted_1$4 = { class: "flex items-center justify-center py-12" };
4
+ const _hoisted_2$3 = { class: "text-center" };
5
+ const _hoisted_3$3 = {
6
+ key: 0,
7
+ class: "mt-4 text-gray-600 dark:text-gray-400"
8
+ };
9
+ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
10
+ __name: "LoadingSpinner",
11
+ props: {
12
+ text: {},
13
+ size: { default: "md" }
14
+ },
15
+ setup(__props) {
16
+ const sizeClasses = {
17
+ sm: "h-8 w-8",
18
+ md: "h-12 w-12",
19
+ lg: "h-16 w-16"
20
+ };
21
+ return (_ctx, _cache) => {
22
+ return openBlock(), createElementBlock("div", _hoisted_1$4, [
23
+ createElementVNode("div", _hoisted_2$3, [
24
+ createElementVNode("div", {
25
+ class: normalizeClass([sizeClasses[__props.size], "border-primary inline-block animate-spin rounded-full border-4 border-solid border-r-transparent"])
26
+ }, null, 2),
27
+ __props.text ? (openBlock(), createElementBlock("p", _hoisted_3$3, toDisplayString(__props.text), 1)) : createCommentVNode("", true)
28
+ ])
29
+ ]);
30
+ };
31
+ }
32
+ });
33
+ const _hoisted_1$3 = {
34
+ key: 0,
35
+ class: "flex items-center justify-between border-b border-gray-200 px-6 py-4 dark:border-gray-700"
36
+ };
37
+ const _hoisted_2$2 = { class: "text-xl font-semibold text-gray-900 dark:text-gray-100" };
38
+ const _hoisted_3$2 = { class: "sr-only" };
39
+ const _hoisted_4$2 = { class: "flex-1 overflow-y-auto px-6 py-4" };
40
+ const _hoisted_5$1 = {
41
+ key: 1,
42
+ class: "flex items-center justify-end gap-3 border-t border-gray-200 px-6 py-4 dark:border-gray-700"
43
+ };
44
+ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
45
+ __name: "Modal",
46
+ props: {
47
+ title: { default: "" },
48
+ size: { default: "default" },
49
+ closeOnBackdrop: { type: Boolean, default: true },
50
+ closeOnEscape: { type: Boolean, default: true },
51
+ closeButtonLabel: { default: "Close" }
52
+ },
53
+ emits: ["close"],
54
+ setup(__props, { emit: __emit }) {
55
+ const emit = __emit;
56
+ const sizeClasses = {
57
+ sm: "max-w-md",
58
+ default: "max-w-3xl",
59
+ lg: "max-w-5xl",
60
+ xl: "max-w-7xl",
61
+ full: "max-w-full mx-4"
62
+ };
63
+ const handleBackdropClick = () => {
64
+ if (__props.closeOnBackdrop) {
65
+ emit("close");
66
+ }
67
+ };
68
+ const handleEscape = (e) => {
69
+ if (e.key === "Escape" && __props.closeOnEscape) {
70
+ emit("close");
71
+ }
72
+ };
73
+ onMounted(() => {
74
+ document.addEventListener("keydown", handleEscape);
75
+ document.body.style.overflow = "hidden";
76
+ });
77
+ onUnmounted(() => {
78
+ document.removeEventListener("keydown", handleEscape);
79
+ document.body.style.overflow = "";
80
+ });
81
+ return (_ctx, _cache) => {
82
+ return openBlock(), createElementBlock("div", {
83
+ class: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4",
84
+ onClick: withModifiers(handleBackdropClick, ["self"])
85
+ }, [
86
+ createElementVNode("div", {
87
+ class: normalizeClass([sizeClasses[__props.size], "flex max-h-[90vh] w-full flex-col rounded-lg bg-white shadow-xl dark:bg-gray-900"])
88
+ }, [
89
+ __props.title || _ctx.$slots.header || _ctx.$slots.title ? (openBlock(), createElementBlock("div", _hoisted_1$3, [
90
+ createElementVNode("h3", _hoisted_2$2, [
91
+ renderSlot(_ctx.$slots, "header", {}, () => [
92
+ renderSlot(_ctx.$slots, "title", {}, () => [
93
+ createTextVNode(toDisplayString(__props.title), 1)
94
+ ])
95
+ ])
96
+ ]),
97
+ createElementVNode("button", {
98
+ class: "rounded-lg p-1.5 text-gray-400 hover:bg-gray-100 hover:text-gray-900 dark:hover:bg-gray-800 dark:hover:text-gray-100",
99
+ type: "button",
100
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
101
+ }, [
102
+ createVNode(unref(Icon), {
103
+ class: "h-5 w-5",
104
+ icon: "lucide:x"
105
+ }),
106
+ createElementVNode("span", _hoisted_3$2, toDisplayString(__props.closeButtonLabel), 1)
107
+ ])
108
+ ])) : createCommentVNode("", true),
109
+ createElementVNode("div", _hoisted_4$2, [
110
+ renderSlot(_ctx.$slots, "default")
111
+ ]),
112
+ _ctx.$slots.footer ? (openBlock(), createElementBlock("div", _hoisted_5$1, [
113
+ renderSlot(_ctx.$slots, "footer")
114
+ ])) : createCommentVNode("", true)
115
+ ], 2)
116
+ ]);
117
+ };
118
+ }
119
+ });
120
+ const _hoisted_1$2 = {
121
+ key: 0,
122
+ class: "flex items-center justify-between border-t border-gray-200 px-6 py-4 dark:border-gray-700"
123
+ };
124
+ const _hoisted_2$1 = { class: "flex items-center gap-4" };
125
+ const _hoisted_3$1 = { class: "text-sm text-gray-700 dark:text-gray-300" };
126
+ const _hoisted_4$1 = {
127
+ key: 0,
128
+ class: "flex items-center gap-2"
129
+ };
130
+ const _hoisted_5 = {
131
+ class: "text-sm text-gray-600 dark:text-gray-400",
132
+ for: "page-size"
133
+ };
134
+ const _hoisted_6 = ["value"];
135
+ const _hoisted_7 = ["value"];
136
+ const _hoisted_8 = { class: "flex gap-2" };
137
+ const _hoisted_9 = ["disabled"];
138
+ const _hoisted_10 = ["disabled"];
139
+ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
140
+ __name: "PaginationControls",
141
+ props: {
142
+ currentPage: {},
143
+ totalPages: {},
144
+ loading: { type: Boolean, default: false },
145
+ pageSize: { default: 10 },
146
+ pageSizeOptions: { default: () => [10, 20, 50, 100] },
147
+ showPageSize: { type: Boolean, default: true },
148
+ pageLabel: { default: "Page" },
149
+ ofLabel: { default: "of" },
150
+ itemsPerPageLabel: { default: "Items per page:" },
151
+ previousLabel: { default: "Previous" },
152
+ nextLabel: { default: "Next" }
153
+ },
154
+ emits: ["update:page", "update:pageSize"],
155
+ setup(__props, { emit: __emit }) {
156
+ const emit = __emit;
157
+ const changePage = (page) => {
158
+ if (page >= 1 && page <= __props.totalPages && !__props.loading) {
159
+ emit("update:page", page);
160
+ }
161
+ };
162
+ const changePageSize = (event) => {
163
+ const target = event.target;
164
+ emit("update:pageSize", Number(target.value));
165
+ };
166
+ return (_ctx, _cache) => {
167
+ return __props.totalPages > 1 ? (openBlock(), createElementBlock("div", _hoisted_1$2, [
168
+ createElementVNode("div", _hoisted_2$1, [
169
+ createElementVNode("div", _hoisted_3$1, toDisplayString(__props.pageLabel) + " " + toDisplayString(__props.currentPage) + " " + toDisplayString(__props.ofLabel) + " " + toDisplayString(__props.totalPages), 1),
170
+ __props.showPageSize ? (openBlock(), createElementBlock("div", _hoisted_4$1, [
171
+ createElementVNode("label", _hoisted_5, toDisplayString(__props.itemsPerPageLabel), 1),
172
+ createElementVNode("select", {
173
+ id: "page-size",
174
+ value: __props.pageSize,
175
+ class: "focus:border-primary focus:ring-primary rounded border border-gray-300 bg-white px-2 py-1 text-sm text-gray-900 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100",
176
+ onChange: changePageSize
177
+ }, [
178
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.pageSizeOptions, (size) => {
179
+ return openBlock(), createElementBlock("option", {
180
+ key: size,
181
+ value: size
182
+ }, toDisplayString(size), 9, _hoisted_7);
183
+ }), 128))
184
+ ], 40, _hoisted_6)
185
+ ])) : createCommentVNode("", true)
186
+ ]),
187
+ createElementVNode("div", _hoisted_8, [
188
+ createElementVNode("button", {
189
+ disabled: __props.currentPage === 1 || __props.loading,
190
+ class: "focus:ring-primary inline-flex items-center gap-1 rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700",
191
+ onClick: _cache[0] || (_cache[0] = ($event) => changePage(__props.currentPage - 1))
192
+ }, [
193
+ createVNode(unref(Icon), {
194
+ class: "h-4 w-4",
195
+ icon: "lucide:chevron-left"
196
+ }),
197
+ createTextVNode(" " + toDisplayString(__props.previousLabel), 1)
198
+ ], 8, _hoisted_9),
199
+ createElementVNode("button", {
200
+ disabled: __props.currentPage === __props.totalPages || __props.loading,
201
+ class: "focus:ring-primary inline-flex items-center gap-1 rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700",
202
+ onClick: _cache[1] || (_cache[1] = ($event) => changePage(__props.currentPage + 1))
203
+ }, [
204
+ createTextVNode(toDisplayString(__props.nextLabel) + " ", 1),
205
+ createVNode(unref(Icon), {
206
+ class: "h-4 w-4",
207
+ icon: "lucide:chevron-right"
208
+ })
209
+ ], 8, _hoisted_10)
210
+ ])
211
+ ])) : createCommentVNode("", true);
212
+ };
213
+ }
214
+ });
215
+ const _hoisted_1$1 = { class: "flex max-w-md items-start space-x-3 rounded-lg border border-gray-200 bg-white p-4 shadow-lg dark:border-gray-800 dark:bg-black" };
216
+ const _hoisted_2 = { class: "flex min-w-0 flex-1 flex-col" };
217
+ const _hoisted_3 = {
218
+ key: 0,
219
+ class: "text-sm font-semibold text-gray-900 dark:text-gray-100"
220
+ };
221
+ const _hoisted_4 = {
222
+ key: 1,
223
+ class: "mt-1 text-sm text-gray-600 dark:text-gray-400"
224
+ };
225
+ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
226
+ __name: "NotificationComponent",
227
+ props: {
228
+ notification: {},
229
+ autoDismiss: { type: Boolean },
230
+ duration: {}
231
+ },
232
+ emits: ["dismiss"],
233
+ setup(__props, { emit: __emit }) {
234
+ const props = __props;
235
+ const emit = __emit;
236
+ const iconName = computed(() => {
237
+ switch (props.notification.type) {
238
+ case "success":
239
+ return "lucide:check-circle";
240
+ case "info":
241
+ return "lucide:info";
242
+ case "warning":
243
+ return "lucide:alert-triangle";
244
+ case "error":
245
+ return "lucide:x-circle";
246
+ default:
247
+ return "lucide:bell";
248
+ }
249
+ });
250
+ const iconColor = computed(() => {
251
+ switch (props.notification.type) {
252
+ case "success":
253
+ return "text-green-600 dark:text-green-400";
254
+ case "info":
255
+ return "text-blue-600 dark:text-blue-400";
256
+ case "warning":
257
+ return "text-yellow-600 dark:text-yellow-400";
258
+ case "error":
259
+ return "text-red-600 dark:text-red-400";
260
+ default:
261
+ return "text-gray-600 dark:text-gray-400";
262
+ }
263
+ });
264
+ const bgColor = computed(() => {
265
+ switch (props.notification.type) {
266
+ case "success":
267
+ return "bg-green-50 dark:bg-green-950";
268
+ case "info":
269
+ return "bg-blue-50 dark:bg-blue-950";
270
+ case "warning":
271
+ return "bg-yellow-50 dark:bg-yellow-950";
272
+ case "error":
273
+ return "bg-red-50 dark:bg-red-950";
274
+ default:
275
+ return "bg-gray-50 dark:bg-gray-950";
276
+ }
277
+ });
278
+ const handleDismiss = () => {
279
+ if (props.notification.id) {
280
+ emit("dismiss", props.notification.id);
281
+ }
282
+ };
283
+ onMounted(() => {
284
+ const duration = props.notification.duration ?? props.duration ?? 5e3;
285
+ if (props.autoDismiss !== false && duration > 0) {
286
+ setTimeout(() => {
287
+ handleDismiss();
288
+ }, duration);
289
+ }
290
+ });
291
+ return (_ctx, _cache) => {
292
+ return openBlock(), createElementBlock("div", _hoisted_1$1, [
293
+ createElementVNode("div", {
294
+ class: normalizeClass([bgColor.value, "flex items-center justify-center rounded-full p-2"])
295
+ }, [
296
+ createVNode(unref(Icon), {
297
+ class: normalizeClass([iconColor.value, "h-5 w-5"]),
298
+ icon: iconName.value
299
+ }, null, 8, ["class", "icon"])
300
+ ], 2),
301
+ createElementVNode("div", _hoisted_2, [
302
+ __props.notification.title ? (openBlock(), createElementBlock("h4", _hoisted_3, toDisplayString(__props.notification.title), 1)) : createCommentVNode("", true),
303
+ __props.notification.message ? (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString(__props.notification.message), 1)) : createCommentVNode("", true)
304
+ ]),
305
+ createElementVNode("button", {
306
+ class: "shrink-0 text-gray-400 transition-colors hover:text-gray-600 dark:text-gray-600 dark:hover:text-gray-400",
307
+ onClick: handleDismiss
308
+ }, [
309
+ createVNode(unref(Icon), {
310
+ class: "h-4 w-4",
311
+ icon: "lucide:x"
312
+ })
313
+ ])
314
+ ]);
315
+ };
316
+ }
317
+ });
318
+ const _hoisted_1 = { class: "fixed top-5 right-5 z-50 flex flex-col gap-3" };
319
+ const _sfc_main = /* @__PURE__ */ defineComponent({
320
+ __name: "NotificationList",
321
+ props: {
322
+ notifications: {},
323
+ autoDismiss: { type: Boolean },
324
+ duration: {}
325
+ },
326
+ emits: ["dismiss"],
327
+ setup(__props, { emit: __emit }) {
328
+ const emit = __emit;
329
+ return (_ctx, _cache) => {
330
+ return openBlock(), createElementBlock("div", _hoisted_1, [
331
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.notifications, (notification) => {
332
+ return openBlock(), createBlock(_sfc_main$1, {
333
+ key: notification.id,
334
+ notification,
335
+ "auto-dismiss": __props.autoDismiss,
336
+ duration: __props.duration,
337
+ onDismiss: _cache[0] || (_cache[0] = ($event) => emit("dismiss", $event))
338
+ }, null, 8, ["notification", "auto-dismiss", "duration"]);
339
+ }), 128))
340
+ ]);
341
+ };
342
+ }
343
+ });
344
+ export {
345
+ _sfc_main$4 as _,
346
+ _sfc_main$3 as a,
347
+ _sfc_main$2 as b,
348
+ _sfc_main$1 as c,
349
+ _sfc_main as d
350
+ };
351
+ //# sourceMappingURL=NotificationList.vue_vue_type_script_setup_true_lang-B2hjbMm4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationList.vue_vue_type_script_setup_true_lang-B2hjbMm4.js","sources":["../src/components/feedback/LoadingSpinner.vue","../src/components/feedback/Modal.vue","../src/components/feedback/PaginationControls.vue","../src/components/feedback/NotificationComponent.vue","../src/components/feedback/NotificationList.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type { SpinnerSize } from '@/types'\n\nconst { text, size = 'md' } = defineProps<{\n text?: string\n size?: SpinnerSize\n}>()\n\nconst sizeClasses: Record<SpinnerSize, string> = {\n sm: 'h-8 w-8',\n md: 'h-12 w-12',\n lg: 'h-16 w-16',\n}\n</script>\n\n<template>\n <div class=\"flex items-center justify-center py-12\">\n <div class=\"text-center\">\n <div\n :class=\"sizeClasses[size]\"\n class=\"border-primary inline-block animate-spin rounded-full border-4 border-solid border-r-transparent\"\n ></div>\n <p v-if=\"text\" class=\"mt-4 text-gray-600 dark:text-gray-400\">{{ text }}</p>\n </div>\n </div>\n</template>\n","<script lang=\"ts\" setup>\nimport { Icon } from '@iconify/vue'\nimport { onMounted, onUnmounted } from 'vue'\nimport type { ModalSize } from '@/types'\n\nconst {\n title = '',\n size = 'default',\n closeOnBackdrop = true,\n closeOnEscape = true,\n closeButtonLabel = 'Close',\n} = defineProps<{\n title?: string\n size?: ModalSize\n closeOnBackdrop?: boolean\n closeOnEscape?: boolean\n closeButtonLabel?: string\n}>()\n\nconst emit = defineEmits<{\n close: []\n}>()\n\nconst sizeClasses: Record<ModalSize, string> = {\n sm: 'max-w-md',\n default: 'max-w-3xl',\n lg: 'max-w-5xl',\n xl: 'max-w-7xl',\n full: 'max-w-full mx-4',\n}\n\nconst handleBackdropClick = () => {\n if (closeOnBackdrop) {\n emit('close')\n }\n}\n\nconst handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && closeOnEscape) {\n emit('close')\n }\n}\n\nonMounted(() => {\n document.addEventListener('keydown', handleEscape)\n document.body.style.overflow = 'hidden'\n})\n\nonUnmounted(() => {\n document.removeEventListener('keydown', handleEscape)\n document.body.style.overflow = ''\n})\n</script>\n\n<template>\n <div\n class=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n @click.self=\"handleBackdropClick\"\n >\n <div\n :class=\"sizeClasses[size]\"\n class=\"flex max-h-[90vh] w-full flex-col rounded-lg bg-white shadow-xl dark:bg-gray-900\"\n >\n <!-- Header -->\n <div\n v-if=\"title || $slots.header || $slots.title\"\n class=\"flex items-center justify-between border-b border-gray-200 px-6 py-4 dark:border-gray-700\"\n >\n <h3 class=\"text-xl font-semibold text-gray-900 dark:text-gray-100\">\n <slot name=\"header\">\n <slot name=\"title\">\n {{ title }}\n </slot>\n </slot>\n </h3>\n <button\n class=\"rounded-lg p-1.5 text-gray-400 hover:bg-gray-100 hover:text-gray-900 dark:hover:bg-gray-800 dark:hover:text-gray-100\"\n type=\"button\"\n @click=\"emit('close')\"\n >\n <Icon class=\"h-5 w-5\" icon=\"lucide:x\" />\n <span class=\"sr-only\">{{ closeButtonLabel }}</span>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"flex-1 overflow-y-auto px-6 py-4\">\n <slot />\n </div>\n\n <!-- Footer -->\n <div\n v-if=\"$slots.footer\"\n class=\"flex items-center justify-end gap-3 border-t border-gray-200 px-6 py-4 dark:border-gray-700\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n</template>\n","<script lang=\"ts\" setup>\nimport { Icon } from '@iconify/vue'\n\nconst {\n currentPage,\n totalPages,\n loading = false,\n pageSize = 10,\n pageSizeOptions = [10, 20, 50, 100],\n showPageSize = true,\n pageLabel = 'Page',\n ofLabel = 'of',\n itemsPerPageLabel = 'Items per page:',\n previousLabel = 'Previous',\n nextLabel = 'Next',\n} = defineProps<{\n currentPage: number\n totalPages: number\n loading?: boolean\n pageSize?: number\n pageSizeOptions?: number[]\n showPageSize?: boolean\n pageLabel?: string\n ofLabel?: string\n itemsPerPageLabel?: string\n previousLabel?: string\n nextLabel?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:page': [page: number]\n 'update:pageSize': [size: number]\n}>()\n\nconst changePage = (page: number) => {\n if (page >= 1 && page <= totalPages && !loading) {\n emit('update:page', page)\n }\n}\n\nconst changePageSize = (event: Event) => {\n const target = event.target as HTMLSelectElement\n emit('update:pageSize', Number(target.value))\n}\n</script>\n\n<template>\n <div\n v-if=\"totalPages > 1\"\n class=\"flex items-center justify-between border-t border-gray-200 px-6 py-4 dark:border-gray-700\"\n >\n <div class=\"flex items-center gap-4\">\n <div class=\"text-sm text-gray-700 dark:text-gray-300\">\n {{ pageLabel }} {{ currentPage }} {{ ofLabel }} {{ totalPages }}\n </div>\n <div v-if=\"showPageSize\" class=\"flex items-center gap-2\">\n <label class=\"text-sm text-gray-600 dark:text-gray-400\" for=\"page-size\">\n {{ itemsPerPageLabel }}\n </label>\n <select\n id=\"page-size\"\n :value=\"pageSize\"\n class=\"focus:border-primary focus:ring-primary rounded border border-gray-300 bg-white px-2 py-1 text-sm text-gray-900 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100\"\n @change=\"changePageSize\"\n >\n <option v-for=\"size in pageSizeOptions\" :key=\"size\" :value=\"size\">\n {{ size }}\n </option>\n </select>\n </div>\n </div>\n <div class=\"flex gap-2\">\n <button\n :disabled=\"currentPage === 1 || loading\"\n class=\"focus:ring-primary inline-flex items-center gap-1 rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700\"\n @click=\"changePage(currentPage - 1)\"\n >\n <Icon class=\"h-4 w-4\" icon=\"lucide:chevron-left\" />\n {{ previousLabel }}\n </button>\n <button\n :disabled=\"currentPage === totalPages || loading\"\n class=\"focus:ring-primary inline-flex items-center gap-1 rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700\"\n @click=\"changePage(currentPage + 1)\"\n >\n {{ nextLabel }}\n <Icon class=\"h-4 w-4\" icon=\"lucide:chevron-right\" />\n </button>\n </div>\n </div>\n</template>\n","<script lang=\"ts\" setup>\nimport type { Notification } from '@/types'\nimport { computed, onMounted } from 'vue'\nimport { Icon } from '@iconify/vue'\n\nconst props = defineProps<{\n notification: Notification\n autoDismiss?: boolean\n duration?: number\n}>()\n\nconst emit = defineEmits<{\n dismiss: [id: string]\n}>()\n\nconst iconName = computed(() => {\n switch (props.notification.type) {\n case 'success':\n return 'lucide:check-circle'\n case 'info':\n return 'lucide:info'\n case 'warning':\n return 'lucide:alert-triangle'\n case 'error':\n return 'lucide:x-circle'\n default:\n return 'lucide:bell'\n }\n})\n\nconst iconColor = computed(() => {\n switch (props.notification.type) {\n case 'success':\n return 'text-green-600 dark:text-green-400'\n case 'info':\n return 'text-blue-600 dark:text-blue-400'\n case 'warning':\n return 'text-yellow-600 dark:text-yellow-400'\n case 'error':\n return 'text-red-600 dark:text-red-400'\n default:\n return 'text-gray-600 dark:text-gray-400'\n }\n})\n\nconst bgColor = computed(() => {\n switch (props.notification.type) {\n case 'success':\n return 'bg-green-50 dark:bg-green-950'\n case 'info':\n return 'bg-blue-50 dark:bg-blue-950'\n case 'warning':\n return 'bg-yellow-50 dark:bg-yellow-950'\n case 'error':\n return 'bg-red-50 dark:bg-red-950'\n default:\n return 'bg-gray-50 dark:bg-gray-950'\n }\n})\n\nconst handleDismiss = () => {\n if (props.notification.id) {\n emit('dismiss', props.notification.id)\n }\n}\n\nonMounted(() => {\n const duration = props.notification.duration ?? props.duration ?? 5000\n if (props.autoDismiss !== false && duration > 0) {\n setTimeout(() => {\n handleDismiss()\n }, duration)\n }\n})\n</script>\n\n<template>\n <div\n class=\"flex max-w-md items-start space-x-3 rounded-lg border border-gray-200 bg-white p-4 shadow-lg dark:border-gray-800 dark:bg-black\"\n >\n <div :class=\"[bgColor, 'flex items-center justify-center rounded-full p-2']\">\n <Icon :class=\"iconColor\" :icon=\"iconName\" class=\"h-5 w-5\" />\n </div>\n\n <div class=\"flex min-w-0 flex-1 flex-col\">\n <h4 v-if=\"notification.title\" class=\"text-sm font-semibold text-gray-900 dark:text-gray-100\">\n {{ notification.title }}\n </h4>\n <p v-if=\"notification.message\" class=\"mt-1 text-sm text-gray-600 dark:text-gray-400\">\n {{ notification.message }}\n </p>\n </div>\n\n <button\n class=\"shrink-0 text-gray-400 transition-colors hover:text-gray-600 dark:text-gray-600 dark:hover:text-gray-400\"\n @click=\"handleDismiss\"\n >\n <Icon class=\"h-4 w-4\" icon=\"lucide:x\" />\n </button>\n </div>\n</template>\n","<script lang=\"ts\" setup>\nimport type { Notification } from '@/types'\nimport NotificationComponent from './NotificationComponent.vue'\n\ndefineProps<{\n notifications: Notification[]\n autoDismiss?: boolean\n duration?: number\n}>()\n\nconst emit = defineEmits<{\n dismiss: [id: string]\n}>()\n</script>\n\n<template>\n <div class=\"fixed top-5 right-5 z-50 flex flex-col gap-3\">\n <NotificationComponent\n v-for=\"notification in notifications\"\n :key=\"notification.id\"\n :notification=\"notification\"\n :auto-dismiss=\"autoDismiss\"\n :duration=\"duration\"\n @dismiss=\"emit('dismiss', $event)\"\n />\n </div>\n</template>\n"],"names":["_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_normalizeClass","_hoisted_3","_toDisplayString","$slots","_renderSlot","_createVNode","_unref","_hoisted_4","_hoisted_5","_Fragment","_renderList","_createTextVNode","_createBlock","NotificationComponent"],"mappings":"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"}