cisse-vue-ui 0.5.25 → 0.5.27
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/README.md +763 -666
- package/dist/Button.vue_vue_type_script_setup_true_lang-BHpVJnRn.js.map +1 -1
- package/dist/Button.vue_vue_type_script_setup_true_lang-CLmHDal2.cjs.map +1 -1
- package/dist/{Combobox.vue_vue_type_script_setup_true_lang-B8WioleN.cjs → Combobox.vue_vue_type_script_setup_true_lang-C2z3wwmX.cjs} +2 -2
- package/dist/Combobox.vue_vue_type_script_setup_true_lang-C2z3wwmX.cjs.map +1 -0
- package/dist/{Combobox.vue_vue_type_script_setup_true_lang-DKDJV0Ey.js → Combobox.vue_vue_type_script_setup_true_lang-Dlza3xUG.js} +2 -2
- package/dist/Combobox.vue_vue_type_script_setup_true_lang-Dlza3xUG.js.map +1 -0
- package/dist/{ConfirmDialog.vue_vue_type_script_setup_true_lang-B1zS6nTR.js → ConfirmDialog.vue_vue_type_script_setup_true_lang-ClT3hod7.js} +2 -2
- package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-ClT3hod7.js.map +1 -0
- package/dist/{ConfirmDialog.vue_vue_type_script_setup_true_lang-CvEWAzaw.cjs → ConfirmDialog.vue_vue_type_script_setup_true_lang-iJCk_Dvc.cjs} +2 -2
- package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-iJCk_Dvc.cjs.map +1 -0
- package/dist/DarkModeToggle.vue_vue_type_script_setup_true_lang-BBIkEeLJ.js.map +1 -1
- package/dist/DarkModeToggle.vue_vue_type_script_setup_true_lang-BHabkuFp.cjs.map +1 -1
- package/dist/Dropdown.vue_vue_type_script_setup_true_lang-BNOHbbm5.cjs.map +1 -1
- package/dist/Dropdown.vue_vue_type_script_setup_true_lang-nyND94f_.js.map +1 -1
- package/dist/{PageLayout.vue_vue_type_script_setup_true_lang-BgTJd526.js → PageLayout.vue_vue_type_script_setup_true_lang-CbTq_AlS.js} +3 -3
- package/dist/PageLayout.vue_vue_type_script_setup_true_lang-CbTq_AlS.js.map +1 -0
- package/dist/{PageLayout.vue_vue_type_script_setup_true_lang-6OrQy9W4.cjs → PageLayout.vue_vue_type_script_setup_true_lang-DvLrltTx.cjs} +3 -3
- package/dist/PageLayout.vue_vue_type_script_setup_true_lang-DvLrltTx.cjs.map +1 -0
- package/dist/cisse-vue-ui.css +51 -51
- package/dist/components/feedback/index.cjs +1 -1
- package/dist/components/feedback/index.js +1 -1
- package/dist/components/form/index.cjs +1 -1
- package/dist/components/form/index.js +1 -1
- package/dist/components/index.cjs +3 -3
- package/dist/components/index.js +3 -3
- package/dist/components/layout/index.cjs +1 -1
- package/dist/components/layout/index.js +1 -1
- package/dist/{index-D5M6ePuo.cjs → index-BbswCyjp.cjs} +4 -4
- package/dist/index-BbswCyjp.cjs.map +1 -0
- package/dist/{index-yQvianuj.js → index-C7jYhMMH.js} +4 -4
- package/dist/index-C7jYhMMH.js.map +1 -0
- package/dist/index.cjs +4 -4
- package/dist/index.js +4 -4
- package/dist/style.css +1 -1
- package/dist/useDropdown-DHFnd259.cjs.map +1 -1
- package/dist/useDropdown-iVu14E6s.js.map +1 -1
- package/dist/useFocusTrap-AnlJsihM.js.map +1 -1
- package/dist/useFocusTrap-kcxO8AeU.cjs.map +1 -1
- package/dist/useId-nxrBaIC9.cjs.map +1 -1
- package/dist/useId-xeHj7rkg.js.map +1 -1
- package/dist/useToast-Bk60GArg.cjs.map +1 -1
- package/dist/useToast-ina5g3mj.js.map +1 -1
- package/package.json +1 -1
- package/dist/Combobox.vue_vue_type_script_setup_true_lang-B8WioleN.cjs.map +0 -1
- package/dist/Combobox.vue_vue_type_script_setup_true_lang-DKDJV0Ey.js.map +0 -1
- package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-B1zS6nTR.js.map +0 -1
- package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-CvEWAzaw.cjs.map +0 -1
- package/dist/PageLayout.vue_vue_type_script_setup_true_lang-6OrQy9W4.cjs.map +0 -1
- package/dist/PageLayout.vue_vue_type_script_setup_true_lang-BgTJd526.js.map +0 -1
- package/dist/index-D5M6ePuo.cjs.map +0 -1
- package/dist/index-yQvianuj.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,666 +1,763 @@
|
|
|
1
|
-
# cisse-vue-ui
|
|
2
|
-
|
|
3
|
-
A Vue 3 component library built with TypeScript and Tailwind CSS v4.
|
|
4
|
-
|
|
5
|
-
**[View Storybook Documentation](https://moulayecisse.github.io/cisse-vue-ui/)**
|
|
6
|
-
|
|
7
|
-
## Installation
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install cisse-vue-ui
|
|
11
|
-
# or
|
|
12
|
-
bun add cisse-vue-ui
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
### Peer Dependencies
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npm install vue@^3.4 tailwindcss@^4 @iconify/vue@^4
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Setup
|
|
22
|
-
|
|
23
|
-
### 1. Import Styles
|
|
24
|
-
|
|
25
|
-
Add the pre-compiled CSS to your main CSS file:
|
|
26
|
-
|
|
27
|
-
```css
|
|
28
|
-
@import 'cisse-vue-ui/style.css';
|
|
29
|
-
@import 'tailwindcss';
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### 2. Configure Primary Color (Optional)
|
|
33
|
-
|
|
34
|
-
Override the default primary color in your CSS:
|
|
35
|
-
|
|
36
|
-
```css
|
|
37
|
-
@theme {
|
|
38
|
-
--color-primary-50: oklch(97% 0.02 142);
|
|
39
|
-
--color-primary-100: oklch(94% 0.05 142);
|
|
40
|
-
--color-primary-200: oklch(88% 0.10 142);
|
|
41
|
-
--color-primary-300: oklch(78% 0.15 142);
|
|
42
|
-
--color-primary-400: oklch(65% 0.20 142);
|
|
43
|
-
--color-primary-500: oklch(55% 0.22 142);
|
|
44
|
-
--color-primary-600: oklch(48% 0.20 142);
|
|
45
|
-
--color-primary-700: oklch(40% 0.17 142);
|
|
46
|
-
--color-primary-800: oklch(32% 0.14 142);
|
|
47
|
-
--color-primary-900: oklch(25% 0.10 142);
|
|
48
|
-
--color-primary-950: oklch(18% 0.08 142);
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Usage
|
|
53
|
-
|
|
54
|
-
### Tree-Shaken Imports (Recommended)
|
|
55
|
-
|
|
56
|
-
```vue
|
|
57
|
-
<script setup lang="ts">
|
|
58
|
-
import { Button, CardComponent, FormInput } from 'cisse-vue-ui'
|
|
59
|
-
</script>
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Category Imports
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
import { Button, Tabs, TabPanel } from 'cisse-vue-ui/components/core'
|
|
66
|
-
import { FormInput, FormSelect, Switch } from 'cisse-vue-ui/components/form'
|
|
67
|
-
import { Modal, Alert, LoadingSpinner } from 'cisse-vue-ui/components/feedback'
|
|
68
|
-
import { BaseLayout, PageLayout } from 'cisse-vue-ui/components/layout'
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### Global Registration (Vue Plugin)
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
import { createApp } from 'vue'
|
|
75
|
-
import { VueTailwindUI } from 'cisse-vue-ui'
|
|
76
|
-
|
|
77
|
-
const app = createApp(App)
|
|
78
|
-
|
|
79
|
-
// Register all components
|
|
80
|
-
app.use(VueTailwindUI)
|
|
81
|
-
|
|
82
|
-
// Or with a prefix
|
|
83
|
-
app.use(VueTailwindUI, { prefix: 'Ui' }) // <UiButton>, <UiCard>, etc.
|
|
84
|
-
|
|
85
|
-
// Or specific components only
|
|
86
|
-
app.use(VueTailwindUI, { components: ['Button', 'CardComponent'] })
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Components
|
|
90
|
-
|
|
91
|
-
### Core
|
|
92
|
-
|
|
93
|
-
| Component | Description |
|
|
94
|
-
|-----------|-------------|
|
|
95
|
-
| `Button` | Button with variants (primary, secondary, outline, ghost, danger, success), sizes, icons, loading state |
|
|
96
|
-
| `CardComponent` | Card container with header, content, and footer slots |
|
|
97
|
-
| `TableComponent` | Data table with sorting, selection, actions, and custom column rendering |
|
|
98
|
-
| `MobileList` | Mobile-optimized card-based list with selection support |
|
|
99
|
-
| `ResponsiveList` | Combines MobileList (mobile) and TableComponent (desktop) with automatic breakpoint switching |
|
|
100
|
-
| `Tabs` | Tab navigation with variants (underline, pills, boxed) |
|
|
101
|
-
| `TabPanel` | Tab content panel (use with Tabs) |
|
|
102
|
-
| `Dropdown` | Dropdown menu with items, icons, and dividers |
|
|
103
|
-
| `Avatar` | User avatar with image, initials, or icon fallback |
|
|
104
|
-
| `AutocompleteComponent` | Searchable select with keyboard navigation |
|
|
105
|
-
| `MenuItem` | Navigation menu item with icon, active state detection, and route support |
|
|
106
|
-
| `StatusBadge` | Colored status indicator badge |
|
|
107
|
-
| `TableAction` | Icon button for table row actions |
|
|
108
|
-
| `Stepper` | Multi-step progress indicator with horizontal/vertical orientation |
|
|
109
|
-
| `CollapsibleCard` | Card that can expand/collapse its content |
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
|
114
|
-
|
|
115
|
-
| `
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
|
120
|
-
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
|
127
|
-
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
| `
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
|
146
|
-
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
###
|
|
278
|
-
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
const
|
|
470
|
-
{
|
|
471
|
-
{
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
</
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
</
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
<
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
1
|
+
# cisse-vue-ui
|
|
2
|
+
|
|
3
|
+
A Vue 3 component library built with TypeScript and Tailwind CSS v4.
|
|
4
|
+
|
|
5
|
+
**[View Storybook Documentation](https://moulayecisse.github.io/cisse-vue-ui/)**
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install cisse-vue-ui
|
|
11
|
+
# or
|
|
12
|
+
bun add cisse-vue-ui
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Peer Dependencies
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install vue@^3.4 tailwindcss@^4 @iconify/vue@^4
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
### 1. Import Styles
|
|
24
|
+
|
|
25
|
+
Add the pre-compiled CSS to your main CSS file:
|
|
26
|
+
|
|
27
|
+
```css
|
|
28
|
+
@import 'cisse-vue-ui/style.css';
|
|
29
|
+
@import 'tailwindcss';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. Configure Primary Color (Optional)
|
|
33
|
+
|
|
34
|
+
Override the default primary color in your CSS:
|
|
35
|
+
|
|
36
|
+
```css
|
|
37
|
+
@theme {
|
|
38
|
+
--color-primary-50: oklch(97% 0.02 142);
|
|
39
|
+
--color-primary-100: oklch(94% 0.05 142);
|
|
40
|
+
--color-primary-200: oklch(88% 0.10 142);
|
|
41
|
+
--color-primary-300: oklch(78% 0.15 142);
|
|
42
|
+
--color-primary-400: oklch(65% 0.20 142);
|
|
43
|
+
--color-primary-500: oklch(55% 0.22 142);
|
|
44
|
+
--color-primary-600: oklch(48% 0.20 142);
|
|
45
|
+
--color-primary-700: oklch(40% 0.17 142);
|
|
46
|
+
--color-primary-800: oklch(32% 0.14 142);
|
|
47
|
+
--color-primary-900: oklch(25% 0.10 142);
|
|
48
|
+
--color-primary-950: oklch(18% 0.08 142);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
### Tree-Shaken Imports (Recommended)
|
|
55
|
+
|
|
56
|
+
```vue
|
|
57
|
+
<script setup lang="ts">
|
|
58
|
+
import { Button, CardComponent, FormInput } from 'cisse-vue-ui'
|
|
59
|
+
</script>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Category Imports
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { Button, Tabs, TabPanel } from 'cisse-vue-ui/components/core'
|
|
66
|
+
import { FormInput, FormSelect, Switch } from 'cisse-vue-ui/components/form'
|
|
67
|
+
import { Modal, Alert, LoadingSpinner } from 'cisse-vue-ui/components/feedback'
|
|
68
|
+
import { BaseLayout, PageLayout } from 'cisse-vue-ui/components/layout'
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Global Registration (Vue Plugin)
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { createApp } from 'vue'
|
|
75
|
+
import { VueTailwindUI } from 'cisse-vue-ui'
|
|
76
|
+
|
|
77
|
+
const app = createApp(App)
|
|
78
|
+
|
|
79
|
+
// Register all components
|
|
80
|
+
app.use(VueTailwindUI)
|
|
81
|
+
|
|
82
|
+
// Or with a prefix
|
|
83
|
+
app.use(VueTailwindUI, { prefix: 'Ui' }) // <UiButton>, <UiCard>, etc.
|
|
84
|
+
|
|
85
|
+
// Or specific components only
|
|
86
|
+
app.use(VueTailwindUI, { components: ['Button', 'CardComponent'] })
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Components
|
|
90
|
+
|
|
91
|
+
### Core
|
|
92
|
+
|
|
93
|
+
| Component | Description |
|
|
94
|
+
|-----------|-------------|
|
|
95
|
+
| `Button` | Button with variants (primary, secondary, outline, ghost, danger, success), sizes, icons, loading state |
|
|
96
|
+
| `CardComponent` | Card container with header, content, and footer slots |
|
|
97
|
+
| `TableComponent` | Data table with sorting, selection, actions, and custom column rendering |
|
|
98
|
+
| `MobileList` | Mobile-optimized card-based list with selection support |
|
|
99
|
+
| `ResponsiveList` | Combines MobileList (mobile) and TableComponent (desktop) with automatic breakpoint switching |
|
|
100
|
+
| `Tabs` | Tab navigation with variants (underline, pills, boxed) |
|
|
101
|
+
| `TabPanel` | Tab content panel (use with Tabs) |
|
|
102
|
+
| `Dropdown` | Dropdown menu with items, icons, and dividers |
|
|
103
|
+
| `Avatar` | User avatar with image, initials, or icon fallback |
|
|
104
|
+
| `AutocompleteComponent` | Searchable select with keyboard navigation |
|
|
105
|
+
| `MenuItem` | Navigation menu item with icon, active state detection, and route support |
|
|
106
|
+
| `StatusBadge` | Colored status indicator badge |
|
|
107
|
+
| `TableAction` | Icon button for table row actions |
|
|
108
|
+
| `Stepper` | Multi-step progress indicator with horizontal/vertical orientation |
|
|
109
|
+
| `CollapsibleCard` | Card that can expand/collapse its content |
|
|
110
|
+
| `Accordion` | Expandable content sections with single/multiple mode |
|
|
111
|
+
| `Breadcrumb` | Navigation breadcrumb trail |
|
|
112
|
+
| `Drawer` | Slide-out panel from any edge (left, right, top, bottom) |
|
|
113
|
+
| `Popover` | Floating content panel triggered by click or hover |
|
|
114
|
+
| `Timeline` | Vertical timeline for events/history display |
|
|
115
|
+
| `Tooltip` | Hover tooltip with customizable position |
|
|
116
|
+
|
|
117
|
+
### Form
|
|
118
|
+
|
|
119
|
+
| Component | Description |
|
|
120
|
+
|-----------|-------------|
|
|
121
|
+
| `FormInput` | Text input with validation states and ARIA support |
|
|
122
|
+
| `FormSelect` | Select dropdown with search, multi-select, and validation |
|
|
123
|
+
| `FormGroup` | Form field wrapper with label, help text, and error states |
|
|
124
|
+
| `FormLabel` | Styled form label with required indicator |
|
|
125
|
+
| `FormHelp` | Help/error text for form fields |
|
|
126
|
+
| `SearchInput` | Search input with icon and clear button |
|
|
127
|
+
| `Switch` | Toggle switch with label and description |
|
|
128
|
+
| `Checkbox` | Checkbox with label, description, and indeterminate state |
|
|
129
|
+
| `Combobox` | Multi-select combobox with search and tags |
|
|
130
|
+
| `DatePicker` | Calendar date picker with min/max dates |
|
|
131
|
+
| `ColorPicker` | Color selection with swatches and custom input |
|
|
132
|
+
| `FileUpload` | Drag-and-drop file upload with preview |
|
|
133
|
+
| `Rating` | Star rating input with half-star support |
|
|
134
|
+
| `Slider` | Single value slider input |
|
|
135
|
+
| `RangeSlider` | Dual-handle range slider |
|
|
136
|
+
|
|
137
|
+
### Feedback
|
|
138
|
+
|
|
139
|
+
| Component | Description |
|
|
140
|
+
|-----------|-------------|
|
|
141
|
+
| `Modal` | Modal dialog with focus trap, ARIA support, and slots |
|
|
142
|
+
| `ConfirmDialog` | Confirmation modal with customizable actions |
|
|
143
|
+
| `Alert` | Alert banner with variants (info, success, warning, error) |
|
|
144
|
+
| `Toast` | Individual toast notification with auto-dismiss |
|
|
145
|
+
| `ToastContainer` | Toast notification container with positioning |
|
|
146
|
+
| `LoadingSpinner` | Loading indicator with size variants |
|
|
147
|
+
| `Progress` | Progress bar with percentage display |
|
|
148
|
+
| `Skeleton` | Loading placeholder with animation |
|
|
149
|
+
| `CardSkeleton` | Card loading skeleton |
|
|
150
|
+
| `ListSkeleton` | List loading skeleton |
|
|
151
|
+
| `TableSkeleton` | Table loading skeleton |
|
|
152
|
+
| `PaginationControls` | Pagination with page numbers and navigation |
|
|
153
|
+
| `NotificationList` | Notification list container |
|
|
154
|
+
| `NotificationComponent` | Individual notification item |
|
|
155
|
+
| `EmptyState` | Placeholder for empty content with icon and action slot |
|
|
156
|
+
|
|
157
|
+
### Layout
|
|
158
|
+
|
|
159
|
+
| Component | Description |
|
|
160
|
+
|-----------|-------------|
|
|
161
|
+
| `BaseLayout` | App shell with sidebar, header, main content area, and route-aware menu |
|
|
162
|
+
| `PageLayout` | Page wrapper with breadcrumbs |
|
|
163
|
+
|
|
164
|
+
### Type Display
|
|
165
|
+
|
|
166
|
+
| Component | Description |
|
|
167
|
+
|-----------|-------------|
|
|
168
|
+
| `TextType` | Text value display |
|
|
169
|
+
| `NumberType` | Formatted number display |
|
|
170
|
+
| `DateType` | Formatted date display |
|
|
171
|
+
| `BooleanType` | Boolean value display (check/cross icons) |
|
|
172
|
+
| `BadgeType` | Badge value display with colors |
|
|
173
|
+
|
|
174
|
+
## Composables
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import {
|
|
178
|
+
useNotifications,
|
|
179
|
+
useDarkMode,
|
|
180
|
+
useExportCSV,
|
|
181
|
+
useDropdown,
|
|
182
|
+
useModal,
|
|
183
|
+
useToast,
|
|
184
|
+
useFocusTrap,
|
|
185
|
+
useId
|
|
186
|
+
} from 'cisse-vue-ui/composables'
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### useModal
|
|
190
|
+
|
|
191
|
+
Manage modal state with data support:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import { useModal } from 'cisse-vue-ui/composables'
|
|
195
|
+
|
|
196
|
+
// Simple modal
|
|
197
|
+
const createModal = useModal()
|
|
198
|
+
createModal.open()
|
|
199
|
+
createModal.close()
|
|
200
|
+
|
|
201
|
+
// Modal with data (e.g., for editing)
|
|
202
|
+
const editModal = useModal<User>()
|
|
203
|
+
editModal.open(selectedUser)
|
|
204
|
+
// Access editModal.data.value in template
|
|
205
|
+
|
|
206
|
+
// With callbacks
|
|
207
|
+
const deleteModal = useModal<Item>({
|
|
208
|
+
onOpen: (data) => console.log('Opening with:', data),
|
|
209
|
+
onClose: () => refetchData()
|
|
210
|
+
})
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```vue
|
|
214
|
+
<template>
|
|
215
|
+
<!-- Use isOpen for v-model binding -->
|
|
216
|
+
<Modal v-model="editModal.isOpen.value" title="Edit User">
|
|
217
|
+
<FormInput v-model="editModal.data.value.name" label="Name" />
|
|
218
|
+
<template #footer>
|
|
219
|
+
<Button @click="editModal.close()">Cancel</Button>
|
|
220
|
+
<Button variant="primary" @click="save">Save</Button>
|
|
221
|
+
</template>
|
|
222
|
+
</Modal>
|
|
223
|
+
</template>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### useDropdown
|
|
227
|
+
|
|
228
|
+
Shared dropdown logic for custom dropdown components (used internally by Dropdown, FormSelect, AutocompleteComponent):
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import { useDropdown } from 'cisse-vue-ui/composables'
|
|
232
|
+
import { ref } from 'vue'
|
|
233
|
+
|
|
234
|
+
const triggerRef = ref<HTMLElement>()
|
|
235
|
+
const dropdownRef = ref<HTMLElement>()
|
|
236
|
+
|
|
237
|
+
const {
|
|
238
|
+
isOpen,
|
|
239
|
+
highlightedIndex,
|
|
240
|
+
dropdownStyle,
|
|
241
|
+
open,
|
|
242
|
+
close,
|
|
243
|
+
toggle,
|
|
244
|
+
handleKeydown,
|
|
245
|
+
scrollToHighlighted,
|
|
246
|
+
} = useDropdown(triggerRef, dropdownRef, {
|
|
247
|
+
teleport: true,
|
|
248
|
+
align: 'left',
|
|
249
|
+
gap: 8,
|
|
250
|
+
onOpen: () => console.log('Opened'),
|
|
251
|
+
onClose: () => console.log('Closed'),
|
|
252
|
+
})
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### useNotifications
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
const { notifications, addNotification, removeNotification } = useNotifications()
|
|
259
|
+
|
|
260
|
+
addNotification({
|
|
261
|
+
type: 'success',
|
|
262
|
+
title: 'Saved',
|
|
263
|
+
message: 'Your changes have been saved.'
|
|
264
|
+
})
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### useDarkMode
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
const { isDark, toggle, enable, disable } = useDarkMode({
|
|
271
|
+
selector: 'html', // Element to add .dark class
|
|
272
|
+
storageKey: 'theme', // localStorage key
|
|
273
|
+
defaultDark: false // Default state
|
|
274
|
+
})
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### useExportCSV
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
const { exportToCSV } = useExportCSV()
|
|
281
|
+
|
|
282
|
+
exportToCSV(data, columns, 'export.csv')
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### useToast
|
|
286
|
+
|
|
287
|
+
Toast notification system with positioning and auto-dismiss:
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
import { useToast } from 'cisse-vue-ui/composables'
|
|
291
|
+
|
|
292
|
+
const { toasts, addToast, removeToast, clearToasts } = useToast()
|
|
293
|
+
|
|
294
|
+
// Add a toast
|
|
295
|
+
addToast({
|
|
296
|
+
type: 'success',
|
|
297
|
+
title: 'Success!',
|
|
298
|
+
message: 'Your changes have been saved.',
|
|
299
|
+
duration: 5000 // auto-dismiss after 5s
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
// Different toast types
|
|
303
|
+
addToast({ type: 'error', title: 'Error', message: 'Something went wrong' })
|
|
304
|
+
addToast({ type: 'warning', title: 'Warning', message: 'Please review' })
|
|
305
|
+
addToast({ type: 'info', title: 'Info', message: 'New update available' })
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
```vue
|
|
309
|
+
<template>
|
|
310
|
+
<!-- Add ToastContainer to your app root -->
|
|
311
|
+
<ToastContainer position="top-right" />
|
|
312
|
+
</template>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### useFocusTrap
|
|
316
|
+
|
|
317
|
+
Trap focus within a container (used internally by Modal):
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { useFocusTrap } from 'cisse-vue-ui/composables'
|
|
321
|
+
import { ref } from 'vue'
|
|
322
|
+
|
|
323
|
+
const isActive = ref(true)
|
|
324
|
+
const { containerRef } = useFocusTrap({
|
|
325
|
+
active: isActive,
|
|
326
|
+
focusFirst: true, // Focus first focusable element on activate
|
|
327
|
+
restoreFocus: true // Restore focus on deactivate
|
|
328
|
+
})
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### useId
|
|
332
|
+
|
|
333
|
+
Generate unique IDs for accessibility (ARIA relationships):
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
import { useId } from 'cisse-vue-ui/composables'
|
|
337
|
+
|
|
338
|
+
const { id, related } = useId({ prefix: 'modal' })
|
|
339
|
+
// id.value = 'cisse-modal-1'
|
|
340
|
+
// related('title') = 'cisse-modal-1-title'
|
|
341
|
+
// related('description') = 'cisse-modal-1-description'
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
```vue
|
|
345
|
+
<template>
|
|
346
|
+
<div :id="id" role="dialog" :aria-labelledby="related('title')">
|
|
347
|
+
<h2 :id="related('title')">Dialog Title</h2>
|
|
348
|
+
</div>
|
|
349
|
+
</template>
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Types
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import type { Property, Notification, Breadcrumb } from 'cisse-vue-ui/types'
|
|
356
|
+
|
|
357
|
+
// Table column definition
|
|
358
|
+
const columns: Property[] = [
|
|
359
|
+
{ key: 'name', label: 'Name', sortable: true },
|
|
360
|
+
{ key: 'email', label: 'Email' },
|
|
361
|
+
{ key: 'status', label: 'Status', type: 'badge' }
|
|
362
|
+
]
|
|
363
|
+
|
|
364
|
+
// Breadcrumb navigation
|
|
365
|
+
const breadcrumbs: Breadcrumb[] = [
|
|
366
|
+
{ label: 'Home', to: '/' },
|
|
367
|
+
{ label: 'Users', to: '/users' },
|
|
368
|
+
{ label: 'Edit' }
|
|
369
|
+
]
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## Component Examples
|
|
373
|
+
|
|
374
|
+
### Button
|
|
375
|
+
|
|
376
|
+
```vue
|
|
377
|
+
<Button variant="primary" size="md" :loading="isLoading">
|
|
378
|
+
Save Changes
|
|
379
|
+
</Button>
|
|
380
|
+
|
|
381
|
+
<Button variant="outline" icon="lucide:plus">
|
|
382
|
+
Add Item
|
|
383
|
+
</Button>
|
|
384
|
+
|
|
385
|
+
<Button variant="danger" icon="lucide:trash">
|
|
386
|
+
Delete
|
|
387
|
+
</Button>
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Tabs
|
|
391
|
+
|
|
392
|
+
```vue
|
|
393
|
+
<script setup>
|
|
394
|
+
import { ref } from 'vue'
|
|
395
|
+
import { Tabs, TabPanel } from 'cisse-vue-ui'
|
|
396
|
+
|
|
397
|
+
const activeTab = ref('profile')
|
|
398
|
+
const tabs = [
|
|
399
|
+
{ key: 'profile', label: 'Profile' },
|
|
400
|
+
{ key: 'settings', label: 'Settings' },
|
|
401
|
+
{ key: 'notifications', label: 'Notifications' }
|
|
402
|
+
]
|
|
403
|
+
</script>
|
|
404
|
+
|
|
405
|
+
<template>
|
|
406
|
+
<Tabs v-model="activeTab" :tabs="tabs" variant="underline">
|
|
407
|
+
<TabPanel value="profile">Profile content</TabPanel>
|
|
408
|
+
<TabPanel value="settings">Settings content</TabPanel>
|
|
409
|
+
<TabPanel value="notifications">Notifications content</TabPanel>
|
|
410
|
+
</Tabs>
|
|
411
|
+
</template>
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Switch
|
|
415
|
+
|
|
416
|
+
```vue
|
|
417
|
+
<Switch
|
|
418
|
+
v-model="emailNotifications"
|
|
419
|
+
label="Email notifications"
|
|
420
|
+
description="Receive email updates about your account"
|
|
421
|
+
/>
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Alert
|
|
425
|
+
|
|
426
|
+
```vue
|
|
427
|
+
<Alert variant="success" title="Success!" dismissible>
|
|
428
|
+
Your changes have been saved successfully.
|
|
429
|
+
</Alert>
|
|
430
|
+
|
|
431
|
+
<Alert variant="error" title="Error">
|
|
432
|
+
Something went wrong. Please try again.
|
|
433
|
+
</Alert>
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Dropdown
|
|
437
|
+
|
|
438
|
+
```vue
|
|
439
|
+
<script setup>
|
|
440
|
+
import { Dropdown } from 'cisse-vue-ui'
|
|
441
|
+
|
|
442
|
+
const items = [
|
|
443
|
+
{ key: 'edit', label: 'Edit', icon: 'lucide:edit' },
|
|
444
|
+
{ key: 'duplicate', label: 'Duplicate', icon: 'lucide:copy' },
|
|
445
|
+
{ key: 'divider', divider: true },
|
|
446
|
+
{ key: 'delete', label: 'Delete', icon: 'lucide:trash', danger: true }
|
|
447
|
+
]
|
|
448
|
+
|
|
449
|
+
const handleSelect = (item) => {
|
|
450
|
+
console.log('Selected:', item.key)
|
|
451
|
+
}
|
|
452
|
+
</script>
|
|
453
|
+
|
|
454
|
+
<template>
|
|
455
|
+
<Dropdown :items="items" @select="handleSelect">
|
|
456
|
+
<template #trigger-label>Actions</template>
|
|
457
|
+
</Dropdown>
|
|
458
|
+
</template>
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Stepper
|
|
462
|
+
|
|
463
|
+
```vue
|
|
464
|
+
<script setup>
|
|
465
|
+
import { ref } from 'vue'
|
|
466
|
+
import { Stepper } from 'cisse-vue-ui'
|
|
467
|
+
|
|
468
|
+
const currentStep = ref('step2')
|
|
469
|
+
const steps = [
|
|
470
|
+
{ key: 'step1', title: 'Account', description: 'Create account', icon: 'lucide:user' },
|
|
471
|
+
{ key: 'step2', title: 'Profile', description: 'Set up profile', icon: 'lucide:settings' },
|
|
472
|
+
{ key: 'step3', title: 'Complete', description: 'Ready to go!', icon: 'lucide:check' }
|
|
473
|
+
]
|
|
474
|
+
</script>
|
|
475
|
+
|
|
476
|
+
<template>
|
|
477
|
+
<Stepper v-model="currentStep" :steps="steps" />
|
|
478
|
+
</template>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### EmptyState
|
|
482
|
+
|
|
483
|
+
```vue
|
|
484
|
+
<EmptyState
|
|
485
|
+
title="No results found"
|
|
486
|
+
message="Try adjusting your search or filters"
|
|
487
|
+
icon="lucide:search-x"
|
|
488
|
+
>
|
|
489
|
+
<template #action>
|
|
490
|
+
<Button variant="primary" size="sm">Clear filters</Button>
|
|
491
|
+
</template>
|
|
492
|
+
</EmptyState>
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Checkbox
|
|
496
|
+
|
|
497
|
+
```vue
|
|
498
|
+
<Checkbox
|
|
499
|
+
v-model="accepted"
|
|
500
|
+
label="Accept terms"
|
|
501
|
+
description="I agree to the terms and conditions"
|
|
502
|
+
/>
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### TableComponent
|
|
506
|
+
|
|
507
|
+
```vue
|
|
508
|
+
<script setup>
|
|
509
|
+
import { ref } from 'vue'
|
|
510
|
+
import { TableComponent } from 'cisse-vue-ui'
|
|
511
|
+
|
|
512
|
+
const properties = [
|
|
513
|
+
{ name: 'name', label: 'Name', main: true },
|
|
514
|
+
{ name: 'email', label: 'Email' },
|
|
515
|
+
{ name: 'role', label: 'Role', type: 'badge' }
|
|
516
|
+
]
|
|
517
|
+
|
|
518
|
+
const items = [
|
|
519
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin' },
|
|
520
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User' }
|
|
521
|
+
]
|
|
522
|
+
|
|
523
|
+
// Selection support
|
|
524
|
+
const selectedItems = ref(new Set())
|
|
525
|
+
const toggleSelect = (id) => {
|
|
526
|
+
if (selectedItems.value.has(id)) {
|
|
527
|
+
selectedItems.value.delete(id)
|
|
528
|
+
} else {
|
|
529
|
+
selectedItems.value.add(id)
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
</script>
|
|
533
|
+
|
|
534
|
+
<template>
|
|
535
|
+
<TableComponent
|
|
536
|
+
:properties="properties"
|
|
537
|
+
:items="items"
|
|
538
|
+
selectable
|
|
539
|
+
:selected-items="selectedItems"
|
|
540
|
+
@select="toggleSelect"
|
|
541
|
+
@select-all="toggleSelectAll"
|
|
542
|
+
>
|
|
543
|
+
<template #action="{ item }">
|
|
544
|
+
<TableAction icon="lucide:edit" @click="edit(item)" />
|
|
545
|
+
<TableAction icon="lucide:trash" variant="danger" @click="delete(item)" />
|
|
546
|
+
</template>
|
|
547
|
+
</TableComponent>
|
|
548
|
+
</template>
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### ResponsiveList
|
|
552
|
+
|
|
553
|
+
A component that automatically switches between a mobile card layout and a desktop table layout based on screen size.
|
|
554
|
+
|
|
555
|
+
```vue
|
|
556
|
+
<script setup>
|
|
557
|
+
import { ref } from 'vue'
|
|
558
|
+
import { ResponsiveList } from 'cisse-vue-ui'
|
|
559
|
+
|
|
560
|
+
const columns = [
|
|
561
|
+
{ key: 'name', label: 'Name' },
|
|
562
|
+
{ key: 'email', label: 'Email' },
|
|
563
|
+
{ key: 'status', label: 'Status' }
|
|
564
|
+
]
|
|
565
|
+
|
|
566
|
+
const items = [
|
|
567
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com', status: 'active' },
|
|
568
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'inactive' }
|
|
569
|
+
]
|
|
570
|
+
|
|
571
|
+
const selectedItems = ref(new Set())
|
|
572
|
+
|
|
573
|
+
const toggleSelect = (id) => {
|
|
574
|
+
if (selectedItems.value.has(id)) {
|
|
575
|
+
selectedItems.value.delete(id)
|
|
576
|
+
} else {
|
|
577
|
+
selectedItems.value.add(id)
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const toggleSelectAll = () => {
|
|
582
|
+
if (selectedItems.value.size === items.length) {
|
|
583
|
+
selectedItems.value.clear()
|
|
584
|
+
} else {
|
|
585
|
+
items.forEach(item => selectedItems.value.add(String(item.id)))
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
</script>
|
|
589
|
+
|
|
590
|
+
<template>
|
|
591
|
+
<ResponsiveList
|
|
592
|
+
:items="items"
|
|
593
|
+
:columns="columns"
|
|
594
|
+
key-field="id"
|
|
595
|
+
selectable
|
|
596
|
+
:selected-items="selectedItems"
|
|
597
|
+
breakpoint="lg"
|
|
598
|
+
@select="toggleSelect"
|
|
599
|
+
@select-all="toggleSelectAll"
|
|
600
|
+
>
|
|
601
|
+
<!-- Mobile view: avatar -->
|
|
602
|
+
<template #avatar="{ item }">
|
|
603
|
+
<div class="w-10 h-10 rounded-full bg-primary-500 flex items-center justify-center text-white">
|
|
604
|
+
{{ item.name[0] }}
|
|
605
|
+
</div>
|
|
606
|
+
</template>
|
|
607
|
+
|
|
608
|
+
<!-- Mobile view: content -->
|
|
609
|
+
<template #mobileContent="{ item }">
|
|
610
|
+
<h3 class="font-semibold">{{ item.name }}</h3>
|
|
611
|
+
<p class="text-sm text-gray-500">{{ item.email }}</p>
|
|
612
|
+
</template>
|
|
613
|
+
|
|
614
|
+
<!-- Mobile view: actions -->
|
|
615
|
+
<template #mobileActions="{ item }">
|
|
616
|
+
<button @click="viewItem(item)">View</button>
|
|
617
|
+
</template>
|
|
618
|
+
|
|
619
|
+
<!-- Desktop table: custom cell rendering -->
|
|
620
|
+
<template #cell-name="{ item }">
|
|
621
|
+
<span class="font-medium">{{ item.name }}</span>
|
|
622
|
+
</template>
|
|
623
|
+
|
|
624
|
+
<template #cell-status="{ item }">
|
|
625
|
+
<span :class="item.status === 'active' ? 'text-green-600' : 'text-red-600'">
|
|
626
|
+
{{ item.status }}
|
|
627
|
+
</span>
|
|
628
|
+
</template>
|
|
629
|
+
|
|
630
|
+
<!-- Desktop table: actions column -->
|
|
631
|
+
<template #actions="{ item }">
|
|
632
|
+
<Button size="sm" variant="ghost" @click="edit(item)">Edit</Button>
|
|
633
|
+
</template>
|
|
634
|
+
|
|
635
|
+
<!-- Empty state -->
|
|
636
|
+
<template #empty>
|
|
637
|
+
<EmptyState title="No items" message="No items to display" />
|
|
638
|
+
</template>
|
|
639
|
+
</ResponsiveList>
|
|
640
|
+
</template>
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
#### ResponsiveList Props
|
|
644
|
+
|
|
645
|
+
| Prop | Type | Default | Description |
|
|
646
|
+
|------|------|---------|-------------|
|
|
647
|
+
| `items` | `Array` | required | Array of items to display |
|
|
648
|
+
| `columns` | `Array` | required | Column definitions with `key` or `name`, `label`, and optional `type` |
|
|
649
|
+
| `keyField` | `string` | `'id'` | Field to use as unique key for items |
|
|
650
|
+
| `selectable` | `boolean` | `false` | Enable selection mode |
|
|
651
|
+
| `selectedItems` | `Set<string>` | - | Set of selected item keys |
|
|
652
|
+
| `selectableFilter` | `Function` | - | Filter function to determine if an item is selectable |
|
|
653
|
+
| `breakpoint` | `string` | `'lg'` | Breakpoint for switching views: `'sm'`, `'md'`, `'lg'`, `'xl'`, `'2xl'` |
|
|
654
|
+
|
|
655
|
+
### MobileList
|
|
656
|
+
|
|
657
|
+
A mobile-optimized card-based list component with selection support.
|
|
658
|
+
|
|
659
|
+
```vue
|
|
660
|
+
<script setup>
|
|
661
|
+
import { MobileList } from 'cisse-vue-ui'
|
|
662
|
+
</script>
|
|
663
|
+
|
|
664
|
+
<template>
|
|
665
|
+
<MobileList
|
|
666
|
+
:items="items"
|
|
667
|
+
key-field="id"
|
|
668
|
+
selectable
|
|
669
|
+
:selected-items="selectedItems"
|
|
670
|
+
@select="toggleSelect"
|
|
671
|
+
@select-all="toggleSelectAll"
|
|
672
|
+
>
|
|
673
|
+
<template #avatar="{ item }">
|
|
674
|
+
<div class="w-12 h-12 rounded-full bg-blue-500" />
|
|
675
|
+
</template>
|
|
676
|
+
|
|
677
|
+
<template #content="{ item }">
|
|
678
|
+
<h3>{{ item.name }}</h3>
|
|
679
|
+
<p>{{ item.description }}</p>
|
|
680
|
+
</template>
|
|
681
|
+
|
|
682
|
+
<template #actions="{ item }">
|
|
683
|
+
<button>View</button>
|
|
684
|
+
</template>
|
|
685
|
+
</MobileList>
|
|
686
|
+
</template>
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
### MenuItem
|
|
690
|
+
|
|
691
|
+
```vue
|
|
692
|
+
<script setup>
|
|
693
|
+
import { useRoute } from 'vue-router'
|
|
694
|
+
import { MenuItem } from 'cisse-vue-ui'
|
|
695
|
+
|
|
696
|
+
const route = useRoute()
|
|
697
|
+
|
|
698
|
+
const menuItem = {
|
|
699
|
+
label: 'Dashboard',
|
|
700
|
+
link: '/dashboard',
|
|
701
|
+
icon: 'lucide:layout-dashboard'
|
|
702
|
+
}
|
|
703
|
+
</script>
|
|
704
|
+
|
|
705
|
+
<template>
|
|
706
|
+
<!-- Auto-detect active state from current route -->
|
|
707
|
+
<MenuItem :menu-item="menuItem" :current-path="route.path" />
|
|
708
|
+
|
|
709
|
+
<!-- Or manually control active state -->
|
|
710
|
+
<MenuItem :menu-item="menuItem" :active="true" />
|
|
711
|
+
</template>
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### BaseLayout
|
|
715
|
+
|
|
716
|
+
```vue
|
|
717
|
+
<script setup>
|
|
718
|
+
import { useRoute } from 'vue-router'
|
|
719
|
+
import { BaseLayout } from 'cisse-vue-ui'
|
|
720
|
+
|
|
721
|
+
const route = useRoute()
|
|
722
|
+
|
|
723
|
+
const menuItems = [
|
|
724
|
+
{ label: 'Dashboard', link: '/', icon: 'lucide:home' },
|
|
725
|
+
{ label: 'Users', link: '/users', icon: 'lucide:users' },
|
|
726
|
+
{ label: 'Settings', link: '/settings', icon: 'lucide:settings' }
|
|
727
|
+
]
|
|
728
|
+
</script>
|
|
729
|
+
|
|
730
|
+
<template>
|
|
731
|
+
<BaseLayout
|
|
732
|
+
:menu-items="menuItems"
|
|
733
|
+
:current-path="route.path"
|
|
734
|
+
:show-dark-toggle="true"
|
|
735
|
+
>
|
|
736
|
+
<template #logo>
|
|
737
|
+
<img src="/logo.svg" alt="Logo" class="h-8" />
|
|
738
|
+
</template>
|
|
739
|
+
|
|
740
|
+
<RouterView />
|
|
741
|
+
</BaseLayout>
|
|
742
|
+
</template>
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
## Dark Mode
|
|
746
|
+
|
|
747
|
+
Components support dark mode via the `.dark` class on a parent element:
|
|
748
|
+
|
|
749
|
+
```html
|
|
750
|
+
<html class="dark">
|
|
751
|
+
<!-- Components will use dark theme -->
|
|
752
|
+
</html>
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
Use the `useDarkMode` composable or implement your own toggle:
|
|
756
|
+
|
|
757
|
+
```typescript
|
|
758
|
+
const { isDark, toggle } = useDarkMode()
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
## License
|
|
762
|
+
|
|
763
|
+
MIT
|