@veristone/nuxt-v-app 0.1.1 → 0.2.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.
@@ -0,0 +1,936 @@
1
+ <script setup lang="ts">
2
+ definePageMeta({
3
+ title: "CRUD Components",
4
+ });
5
+
6
+ const toast = useToast();
7
+
8
+ // ===== VACrudCreate Test State =====
9
+ const createBasicResult = ref<any>(null);
10
+ const createCustomResult = ref<any>(null);
11
+ const createInitialResult = ref<any>(null);
12
+ const createProgrammaticOpen = ref(false);
13
+ const createProgrammaticResult = ref<any>(null);
14
+ const createSizeResults = ref<Record<string, any>>({});
15
+ const createErrorResult = ref<any>(null);
16
+
17
+ // ===== VACrudUpdate Test State =====
18
+ const updateBasicResult = ref<any>(null);
19
+ const updateUsers = ref([
20
+ {
21
+ id: 1,
22
+ name: "John Doe",
23
+ email: "john@example.com",
24
+ role: "admin",
25
+ status: "active",
26
+ },
27
+ {
28
+ id: 2,
29
+ name: "Jane Smith",
30
+ email: "jane@example.com",
31
+ role: "user",
32
+ status: "active",
33
+ },
34
+ {
35
+ id: 3,
36
+ name: "Bob Wilson",
37
+ email: "bob@example.com",
38
+ role: "user",
39
+ status: "inactive",
40
+ },
41
+ ]);
42
+ const updateSelectedUserId = ref(1);
43
+ const updateSelectionResult = ref<any>(null);
44
+ const updateSizeResults = ref<Record<string, any>>({});
45
+ const updateProgrammaticOpen = ref(false);
46
+ const updateProgrammaticResult = ref<any>(null);
47
+ const updateCustomResult = ref<any>(null);
48
+ const updateErrorResult = ref<any>(null);
49
+
50
+ // ===== VACrudDelete Test State =====
51
+ const deleteBasicDeleted = ref(false);
52
+ const deleteMockItems = ref([
53
+ { id: 1, name: "Project Alpha", description: "Main development project" },
54
+ { id: 2, name: "Marketing Campaign", description: "Q1 marketing initiative" },
55
+ { id: 3, name: "Server Migration", description: "AWS to Azure migration" },
56
+ ]);
57
+ const deleteSelectedItemId = ref(1);
58
+ const deleteSelectionDeleted = ref(false);
59
+ const deleteCustomDeleted = ref(false);
60
+ const deleteProgrammaticOpen = ref(false);
61
+ const deleteProgrammaticDeleted = ref(false);
62
+ const deleteStyleResults = ref<Record<string, boolean>>({});
63
+ const deleteErrorResult = ref<any>(null);
64
+
65
+ // ===== Event Handlers =====
66
+ // Create handlers
67
+ const handleCreateBasic = (data: any) => {
68
+ createBasicResult.value = data;
69
+ toast.add({
70
+ title: "Created!",
71
+ description: `ID: ${data.id}`,
72
+ color: "success",
73
+ });
74
+ };
75
+ const handleCreateCustom = (data: any) => {
76
+ createCustomResult.value = data;
77
+ toast.add({
78
+ title: "Product Created!",
79
+ description: data.name,
80
+ color: "success",
81
+ });
82
+ };
83
+ const handleCreateInitial = (data: any) => {
84
+ createInitialResult.value = data;
85
+ toast.add({
86
+ title: "Created with Initial Data!",
87
+ description: data.name,
88
+ color: "success",
89
+ });
90
+ };
91
+ const handleCreateSize = (size: string, data: any) => {
92
+ createSizeResults.value[size] = data;
93
+ toast.add({
94
+ title: `${size.toUpperCase()} Modal Created!`,
95
+ description: data.name,
96
+ color: "success",
97
+ });
98
+ };
99
+ const handleCreateProgrammatic = (data: any) => {
100
+ createProgrammaticResult.value = data;
101
+ createProgrammaticOpen.value = false;
102
+ toast.add({
103
+ title: "Programmatic Create!",
104
+ description: data.name,
105
+ color: "success",
106
+ });
107
+ };
108
+ const handleCreateError = (error: any) => {
109
+ createErrorResult.value = error;
110
+ toast.add({
111
+ title: "Create Error",
112
+ description: error.message,
113
+ color: "error",
114
+ });
115
+ };
116
+
117
+ // Update handlers
118
+ const handleUpdateBasic = (data: any) => {
119
+ updateBasicResult.value = data;
120
+ toast.add({ title: "Updated!", description: data.name, color: "success" });
121
+ };
122
+ const handleUpdateSelection = (data: any) => {
123
+ updateSelectionResult.value = data;
124
+ toast.add({
125
+ title: "User Updated!",
126
+ description: data.name,
127
+ color: "success",
128
+ });
129
+ };
130
+ const handleUpdateSize = (size: string, data: any) => {
131
+ updateSizeResults.value[size] = data;
132
+ toast.add({
133
+ title: `${size.toUpperCase()} Update!`,
134
+ description: data.name,
135
+ color: "success",
136
+ });
137
+ };
138
+ const handleUpdateProgrammatic = (data: any) => {
139
+ updateProgrammaticResult.value = data;
140
+ updateProgrammaticOpen.value = false;
141
+ toast.add({
142
+ title: "Programmatic Update!",
143
+ description: data.name,
144
+ color: "success",
145
+ });
146
+ };
147
+ const handleUpdateCustom = (data: any) => {
148
+ updateCustomResult.value = data;
149
+ toast.add({
150
+ title: "Settings Updated!",
151
+ description: data.name,
152
+ color: "success",
153
+ });
154
+ };
155
+ const handleUpdateError = (error: any) => {
156
+ updateErrorResult.value = error;
157
+ toast.add({
158
+ title: "Update Error",
159
+ description: error.message,
160
+ color: "error",
161
+ });
162
+ };
163
+
164
+ // Delete handlers
165
+ const handleDeleteBasic = (id: number) => {
166
+ deleteBasicDeleted.value = true;
167
+ toast.add({
168
+ title: "Deleted!",
169
+ description: `Item #${id}`,
170
+ color: "success",
171
+ });
172
+ };
173
+ const handleDeleteSelection = (id: number) => {
174
+ deleteSelectionDeleted.value = true;
175
+ deleteMockItems.value = deleteMockItems.value.filter(
176
+ (item) => item.id !== id,
177
+ );
178
+ toast.add({
179
+ title: "Item Deleted!",
180
+ description: `ID: ${id}`,
181
+ color: "success",
182
+ });
183
+ if (deleteMockItems.value.length === 0) {
184
+ setTimeout(() => {
185
+ deleteMockItems.value = [
186
+ { id: 4, name: "New Project A", description: "Fresh start" },
187
+ { id: 5, name: "New Project B", description: "Another project" },
188
+ ];
189
+ deleteSelectionDeleted.value = false;
190
+ }, 2000);
191
+ }
192
+ };
193
+ const handleDeleteCustom = (id: number) => {
194
+ deleteCustomDeleted.value = true;
195
+ toast.add({
196
+ title: "Permanently Deleted!",
197
+ description: `ID: ${id}`,
198
+ color: "success",
199
+ });
200
+ };
201
+ const handleDeleteProgrammatic = (id: number) => {
202
+ deleteProgrammaticDeleted.value = true;
203
+ deleteProgrammaticOpen.value = false;
204
+ toast.add({
205
+ title: "Programmatic Delete!",
206
+ description: `ID: ${id}`,
207
+ color: "success",
208
+ });
209
+ };
210
+ const handleDeleteStyle = (style: string, id: number) => {
211
+ deleteStyleResults.value[style] = true;
212
+ toast.add({
213
+ title: `${style} Style Deleted!`,
214
+ description: `ID: ${id}`,
215
+ color: "success",
216
+ });
217
+ };
218
+ const handleDeleteError = (error: any) => {
219
+ deleteErrorResult.value = error;
220
+ toast.add({
221
+ title: "Delete Error",
222
+ description: error.message,
223
+ color: "error",
224
+ });
225
+ };
226
+ </script>
227
+
228
+ <template>
229
+ <UDashboardPanel grow>
230
+ <UContainer class="overflow-y-auto max-h-[calc(100vh-4rem)]">
231
+ <div class="py-8">
232
+ <h1 class="text-3xl font-bold mb-4">CRUD Components</h1>
233
+ <p class="text-gray-600 dark:text-gray-400 mb-8">
234
+ Modal-based CRUD operations with VACrudCreate, VACrudUpdate, and
235
+ VACrudDelete.
236
+ </p>
237
+
238
+ <!-- ========================================== -->
239
+ <!-- VACrudCreate Section -->
240
+ <!-- ========================================== -->
241
+ <h2 class="text-2xl font-semibold mb-4 mt-12 text-primary-500">
242
+ VACrudCreate
243
+ </h2>
244
+ <p class="text-gray-600 dark:text-gray-400 mb-6">
245
+ Modal component for creating new records with customizable triggers
246
+ and form slots.
247
+ </p>
248
+
249
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-12">
250
+ <!-- Basic Create -->
251
+ <UCard>
252
+ <template #header>
253
+ <h3 class="font-semibold flex items-center gap-2">
254
+ <UIcon name="i-lucide-plus-circle" class="text-primary-500" />
255
+ Basic Usage
256
+ </h3>
257
+ </template>
258
+ <p class="text-sm text-gray-500 mb-4">
259
+ Standard create modal with default trigger.
260
+ </p>
261
+ <VACrudCreate
262
+ endpoint="/api/test-items"
263
+ friendly-name="Item"
264
+ @created="handleCreateBasic"
265
+ >
266
+ <template #default="{ submit, loading }">
267
+ <form
268
+ @submit.prevent="submit({ name: 'New Test Item' })"
269
+ class="space-y-4"
270
+ >
271
+ <UFormField label="Item Name">
272
+ <UInput value="New Test Item" disabled />
273
+ </UFormField>
274
+ <div class="flex justify-end">
275
+ <VABtnSubmit :loading="loading" label="Create Item" />
276
+ </div>
277
+ </form>
278
+ </template>
279
+ </VACrudCreate>
280
+ <UAlert
281
+ v-if="createBasicResult"
282
+ class="mt-4"
283
+ color="success"
284
+ icon="i-lucide-check-circle"
285
+ title="Created!"
286
+ :description="`ID: ${createBasicResult.id}`"
287
+ />
288
+ </UCard>
289
+
290
+ <!-- Custom Trigger -->
291
+ <UCard>
292
+ <template #header>
293
+ <h3 class="font-semibold flex items-center gap-2">
294
+ <UIcon name="i-lucide-package" class="text-green-500" />
295
+ Custom Trigger
296
+ </h3>
297
+ </template>
298
+ <p class="text-sm text-gray-500 mb-4">
299
+ Custom icon, color, and label.
300
+ </p>
301
+ <VACrudCreate
302
+ endpoint="/api/products"
303
+ friendly-name="Product"
304
+ trigger-label="Add Product"
305
+ trigger-icon="i-lucide-package"
306
+ trigger-color="success"
307
+ @created="handleCreateCustom"
308
+ >
309
+ <template #default="{ submit, loading }">
310
+ <form
311
+ @submit.prevent="submit({ name: 'New Product' })"
312
+ class="space-y-4"
313
+ >
314
+ <UFormField label="Product">
315
+ <UInput value="New Product" disabled />
316
+ </UFormField>
317
+ <div class="flex justify-end">
318
+ <VABtnSubmit
319
+ :loading="loading"
320
+ label="Add Product"
321
+ color="green"
322
+ />
323
+ </div>
324
+ </form>
325
+ </template>
326
+ </VACrudCreate>
327
+ <UAlert
328
+ v-if="createCustomResult"
329
+ class="mt-4"
330
+ color="success"
331
+ title="Product Created!"
332
+ :description="createCustomResult.name"
333
+ />
334
+ </UCard>
335
+
336
+ <!-- Initial Data -->
337
+ <UCard>
338
+ <template #header>
339
+ <h3 class="font-semibold flex items-center gap-2">
340
+ <UIcon name="i-lucide-file-edit" class="text-blue-500" />
341
+ With Initial Data
342
+ </h3>
343
+ </template>
344
+ <p class="text-sm text-gray-500 mb-4">Pre-populated form fields.</p>
345
+ <VACrudCreate
346
+ endpoint="/api/users"
347
+ friendly-name="User"
348
+ :initial-data="{ name: 'John Doe', email: 'john@example.com' }"
349
+ @created="handleCreateInitial"
350
+ >
351
+ <template #default="{ submit, loading }">
352
+ <form
353
+ @submit.prevent="
354
+ submit({ name: 'John Doe', email: 'john@example.com' })
355
+ "
356
+ class="space-y-4"
357
+ >
358
+ <UFormField label="Name">
359
+ <UInput value="John Doe" disabled />
360
+ </UFormField>
361
+ <UFormField label="Email">
362
+ <UInput value="john@example.com" disabled />
363
+ </UFormField>
364
+ <div class="flex justify-end">
365
+ <VABtnSubmit :loading="loading" label="Create User" />
366
+ </div>
367
+ </form>
368
+ </template>
369
+ </VACrudCreate>
370
+ <UAlert
371
+ v-if="createInitialResult"
372
+ class="mt-4"
373
+ color="success"
374
+ title="User Created!"
375
+ :description="createInitialResult.name"
376
+ />
377
+ </UCard>
378
+
379
+ <!-- Programmatic Control -->
380
+ <UCard>
381
+ <template #header>
382
+ <h3 class="font-semibold flex items-center gap-2">
383
+ <UIcon name="i-lucide-code" class="text-orange-500" />
384
+ Programmatic Control
385
+ </h3>
386
+ </template>
387
+ <p class="text-sm text-gray-500 mb-4">Control via v-model:open.</p>
388
+ <div class="flex gap-2 mb-4">
389
+ <UButton
390
+ label="Open"
391
+ color="warning"
392
+ size="sm"
393
+ @click="createProgrammaticOpen = true"
394
+ />
395
+ </div>
396
+ <VACrudCreate
397
+ v-model:open="createProgrammaticOpen"
398
+ endpoint="/api/items"
399
+ friendly-name="Item"
400
+ @created="handleCreateProgrammatic"
401
+ >
402
+ <template #default="{ submit, loading }">
403
+ <form
404
+ @submit.prevent="submit({ name: 'Programmatic Item' })"
405
+ class="space-y-4"
406
+ >
407
+ <p class="text-sm text-gray-500">Opened programmatically!</p>
408
+ <div class="flex justify-end">
409
+ <VABtnSubmit :loading="loading" label="Create" />
410
+ </div>
411
+ </form>
412
+ </template>
413
+ </VACrudCreate>
414
+ <UAlert
415
+ v-if="createProgrammaticResult"
416
+ class="mt-4"
417
+ color="warning"
418
+ title="Programmatic Success!"
419
+ />
420
+ </UCard>
421
+ </div>
422
+
423
+ <!-- ========================================== -->
424
+ <!-- VACrudUpdate Section -->
425
+ <!-- ========================================== -->
426
+ <h2 class="text-2xl font-semibold mb-4 mt-12 text-blue-500">
427
+ VACrudUpdate
428
+ </h2>
429
+ <p class="text-gray-600 dark:text-gray-400 mb-6">
430
+ Update modal with data fetching, loading skeleton, and dirty tracking.
431
+ </p>
432
+
433
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-12">
434
+ <!-- Basic Update -->
435
+ <UCard>
436
+ <template #header>
437
+ <h3 class="font-semibold flex items-center gap-2">
438
+ <UIcon name="i-lucide-pencil" class="text-blue-500" />
439
+ Basic Update
440
+ </h3>
441
+ </template>
442
+ <p class="text-sm text-gray-500 mb-4">
443
+ Fetches data and tracks changes.
444
+ </p>
445
+ <VACrudUpdate
446
+ endpoint="/api/users"
447
+ :record-id="1"
448
+ friendly-name="User"
449
+ @updated="handleUpdateBasic"
450
+ >
451
+ <template
452
+ #default="{ submit, loading, data, isDirty, isFetching }"
453
+ >
454
+ <div v-if="isFetching" class="space-y-4">
455
+ <USkeleton class="h-4 w-full" />
456
+ <USkeleton class="h-4 w-3/4" />
457
+ <USkeleton class="h-4 w-1/2" />
458
+ </div>
459
+ <form v-else @submit.prevent="submit(data)" class="space-y-4">
460
+ <UFormField label="Name">
461
+ <UInput v-model="data.name" />
462
+ </UFormField>
463
+ <UFormField label="Email">
464
+ <UInput v-model="data.email" />
465
+ </UFormField>
466
+ <div class="flex justify-end">
467
+ <VABtnSubmit :loading="loading" label="Save Changes" />
468
+ </div>
469
+ </form>
470
+ </template>
471
+ </VACrudUpdate>
472
+ <UAlert
473
+ v-if="updateBasicResult"
474
+ class="mt-4"
475
+ color="success"
476
+ title="Updated!"
477
+ :description="updateBasicResult.name"
478
+ />
479
+ </UCard>
480
+
481
+ <!-- User Selection -->
482
+ <UCard>
483
+ <template #header>
484
+ <h3 class="font-semibold flex items-center gap-2">
485
+ <UIcon name="i-lucide-users" class="text-indigo-500" />
486
+ Dynamic Selection
487
+ </h3>
488
+ </template>
489
+ <p class="text-sm text-gray-500 mb-4">
490
+ Select different users to edit.
491
+ </p>
492
+
493
+ <VACrudUpdate
494
+ :endpoint="'/api/users'"
495
+ :record-id="updateSelectedUserId"
496
+ friendly-name="User"
497
+ @updated="handleUpdateSelection"
498
+ >
499
+ <template
500
+ #default="{ submit, loading, data, isFetching, isDirty }"
501
+ >
502
+ <div v-if="isFetching" class="space-y-4">
503
+ <USkeleton class="h-4 w-full" />
504
+ <USkeleton class="h-4 w-3/4" />
505
+ </div>
506
+ <form v-else @submit.prevent="submit(data)" class="space-y-4">
507
+ <div class="flex items-center gap-2">
508
+ <span class="text-xs text-gray-500"
509
+ >Editing User ID: {{ updateSelectedUserId }}</span
510
+ >
511
+ </div>
512
+ <UFormField label="Name">
513
+ <UInput v-model="data.name" />
514
+ </UFormField>
515
+ <div class="flex justify-end">
516
+ <VABtnSubmit :loading="loading" label="Update" />
517
+ </div>
518
+ </form>
519
+ </template>
520
+ </VACrudUpdate>
521
+ <UAlert
522
+ v-if="updateSelectionResult"
523
+ class="mt-4"
524
+ color="success"
525
+ title="User Updated!"
526
+ />
527
+ </UCard>
528
+
529
+ <!-- Programmatic Update -->
530
+ <UCard>
531
+ <template #header>
532
+ <h3 class="font-semibold flex items-center gap-2">
533
+ <UIcon name="i-lucide-code" class="text-orange-500" />
534
+ Programmatic Control
535
+ </h3>
536
+ </template>
537
+ <p class="text-sm text-gray-500 mb-4">External modal control.</p>
538
+ <div class="flex gap-2 mb-4">
539
+ <UButton
540
+ label="Open Update"
541
+ color="warning"
542
+ size="sm"
543
+ @click="updateProgrammaticOpen = true"
544
+ />
545
+ </div>
546
+ <VACrudUpdate
547
+ v-model:open="updateProgrammaticOpen"
548
+ endpoint="/api/users"
549
+ :record-id="2"
550
+ friendly-name="User"
551
+ @updated="handleUpdateProgrammatic"
552
+ >
553
+ <template
554
+ #default="{ submit, loading, data, isFetching, isDirty }"
555
+ >
556
+ <div v-if="isFetching" class="space-y-4">
557
+ <USkeleton class="h-4 w-full" />
558
+ <USkeleton class="h-4 w-3/4" />
559
+ </div>
560
+ <form v-else @submit.prevent="submit(data)" class="space-y-4">
561
+ <UFormField label="Name">
562
+ <UInput v-model="data.name" />
563
+ </UFormField>
564
+ <div class="flex justify-end">
565
+ <VABtnSubmit :loading="loading" label="Update" />
566
+ </div>
567
+ </form>
568
+ </template>
569
+ </VACrudUpdate>
570
+ <UAlert
571
+ v-if="updateProgrammaticResult"
572
+ class="mt-4"
573
+ color="warning"
574
+ title="Programmatic Update!"
575
+ />
576
+ </UCard>
577
+
578
+ <!-- Custom Style Update -->
579
+ <UCard>
580
+ <template #header>
581
+ <h3 class="font-semibold flex items-center gap-2">
582
+ <UIcon name="i-lucide-settings-2" class="text-green-500" />
583
+ Custom Trigger Style
584
+ </h3>
585
+ </template>
586
+ <p class="text-sm text-gray-500 mb-4">Styled trigger button.</p>
587
+ <VACrudUpdate
588
+ endpoint="/api/users"
589
+ :record-id="3"
590
+ friendly-name="User"
591
+ trigger-label="Edit Settings"
592
+ trigger-icon="i-lucide-settings"
593
+ trigger-color="green"
594
+ @updated="handleUpdateCustom"
595
+ >
596
+ <template #default="{ submit, loading, data, isFetching }">
597
+ <div v-if="isFetching" class="space-y-4">
598
+ <USkeleton class="h-4 w-full" />
599
+ </div>
600
+ <form v-else @submit.prevent="submit(data)" class="space-y-4">
601
+ <UFormField label="Name">
602
+ <UInput v-model="data.name" />
603
+ </UFormField>
604
+
605
+ <div class="flex justify-end">
606
+ <VABtnSubmit
607
+ :loading="loading"
608
+ label="Save Settings"
609
+ color="primary"
610
+ />
611
+ </div>
612
+ </form>
613
+ </template>
614
+ </VACrudUpdate>
615
+ <UAlert
616
+ v-if="updateCustomResult"
617
+ class="mt-4"
618
+ color="success"
619
+ title="Settings Updated!"
620
+ />
621
+ </UCard>
622
+ </div>
623
+
624
+ <!-- ========================================== -->
625
+ <!-- VACrudDelete Section -->
626
+ <!-- ========================================== -->
627
+ <h2 class="text-2xl font-semibold mb-4 mt-12 text-red-500">
628
+ VACrudDelete
629
+ </h2>
630
+ <p class="text-gray-600 dark:text-gray-400 mb-6">
631
+ Delete confirmation modal with VAModalConfirm integration.
632
+ </p>
633
+
634
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-12">
635
+ <!-- Basic Delete -->
636
+ <UCard>
637
+ <template #header>
638
+ <h3 class="font-semibold flex items-center gap-2">
639
+ <UIcon name="i-lucide-trash-2" class="text-red-500" />
640
+ Basic Delete
641
+ </h3>
642
+ </template>
643
+ <p class="text-sm text-gray-500 mb-4">
644
+ Standard delete confirmation.
645
+ </p>
646
+ <div
647
+ class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg mb-4"
648
+ >
649
+ <div>
650
+ <p class="font-medium">Project Alpha</p>
651
+ <p class="text-sm text-gray-500">ID: 1</p>
652
+ </div>
653
+ <VACrudDelete
654
+ endpoint="/api/projects"
655
+ :record-id="1"
656
+ item-name="Project Alpha"
657
+ @deleted="handleDeleteBasic"
658
+ />
659
+ </div>
660
+ <UAlert
661
+ v-if="deleteBasicDeleted"
662
+ color="success"
663
+ icon="i-lucide-check-circle"
664
+ title="Deleted Successfully"
665
+ description="Project Alpha removed"
666
+ />
667
+ </UCard>
668
+
669
+ <!-- Item List Delete -->
670
+ <UCard>
671
+ <template #header>
672
+ <h3 class="font-semibold flex items-center gap-2">
673
+ <UIcon name="i-lucide-list" class="text-blue-500" />
674
+ Item List with Delete
675
+ </h3>
676
+ </template>
677
+ <p class="text-sm text-gray-500 mb-4">Select and delete items.</p>
678
+ <div
679
+ class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg mb-4"
680
+ >
681
+ <div>
682
+ <p class="font-medium">
683
+ {{
684
+ deleteMockItems.find((i) => i.id === deleteSelectedItemId)
685
+ ?.name
686
+ }}
687
+ </p>
688
+ <p class="text-sm text-gray-500">
689
+ ID: {{ deleteSelectedItemId }}
690
+ </p>
691
+ </div>
692
+ <VACrudDelete
693
+ v-if="
694
+ deleteMockItems.find((i) => i.id === deleteSelectedItemId)
695
+ "
696
+ endpoint="/api/items"
697
+ :record-id="deleteSelectedItemId"
698
+ :item-name="
699
+ deleteMockItems.find((i) => i.id === deleteSelectedItemId)
700
+ ?.name
701
+ "
702
+ @deleted="handleDeleteSelection"
703
+ />
704
+ </div>
705
+ <p class="text-xs text-gray-500 mb-2">
706
+ Remaining: {{ deleteMockItems.length }}
707
+ </p>
708
+ <UAlert
709
+ v-if="deleteSelectionDeleted"
710
+ color="success"
711
+ icon="i-lucide-trash"
712
+ title="Item Deleted"
713
+ description="Removed from list"
714
+ />
715
+ </UCard>
716
+
717
+ <!-- Custom Confirm Message -->
718
+ <UCard>
719
+ <template #header>
720
+ <h3 class="font-semibold flex items-center gap-2">
721
+ <UIcon name="i-lucide-message-square" class="text-purple-500" />
722
+ Custom Confirm Message
723
+ </h3>
724
+ </template>
725
+ <p class="text-sm text-gray-500 mb-4">Custom confirmation text.</p>
726
+ <div
727
+ class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg mb-4"
728
+ >
729
+ <div>
730
+ <p class="font-medium">Important Document</p>
731
+ <p class="text-sm text-gray-500">ID: 42</p>
732
+ </div>
733
+ <VACrudDelete
734
+ endpoint="/api/documents"
735
+ :record-id="42"
736
+ item-name="Important Document"
737
+ confirm-title="⚠️ Permanent Deletion"
738
+ confirm-message="Critical data cannot be recovered. Are you sure?"
739
+ trigger-color="warning"
740
+ @deleted="handleDeleteCustom"
741
+ />
742
+ </div>
743
+ <UAlert
744
+ v-if="deleteCustomDeleted"
745
+ color="warning"
746
+ icon="i-lucide-alert-circle"
747
+ title="Permanently Deleted"
748
+ />
749
+ </UCard>
750
+
751
+ <!-- Programmatic Delete -->
752
+ <UCard>
753
+ <template #header>
754
+ <h3 class="font-semibold flex items-center gap-2">
755
+ <UIcon name="i-lucide-code" class="text-orange-500" />
756
+ Programmatic Control
757
+ </h3>
758
+ </template>
759
+ <p class="text-sm text-gray-500 mb-4">External modal control.</p>
760
+ <div class="flex gap-2 mb-4">
761
+ <UButton
762
+ label="Open Delete"
763
+ color="error"
764
+ size="sm"
765
+ @click="deleteProgrammaticOpen = true"
766
+ />
767
+ </div>
768
+ <VACrudDelete
769
+ v-model:open="deleteProgrammaticOpen"
770
+ endpoint="/api/items"
771
+ :record-id="99"
772
+ item-name="Programmatic Item"
773
+ @deleted="handleDeleteProgrammatic"
774
+ />
775
+ </UCard>
776
+
777
+ <!-- Trigger Style Variants -->
778
+ <UCard class="lg:col-span-2">
779
+ <template #header>
780
+ <h3 class="font-semibold flex items-center gap-2">
781
+ <UIcon name="i-lucide-palette" class="text-green-500" />
782
+ Trigger Style Variants
783
+ </h3>
784
+ </template>
785
+ <p class="text-sm text-gray-500 mb-4">
786
+ Different trigger button styles.
787
+ </p>
788
+ <div class="grid grid-cols-2 md:grid-cols-4 gap-4">
789
+ <div
790
+ class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg"
791
+ >
792
+ <span class="text-sm">Ghost (Default)</span>
793
+ <VACrudDelete
794
+ endpoint="/api/items"
795
+ :record-id="101"
796
+ item-name="Ghost Item"
797
+ trigger-variant="ghost"
798
+ @deleted="(id) => handleDeleteStyle('ghost', id)"
799
+ />
800
+ </div>
801
+ <div
802
+ class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg"
803
+ >
804
+ <span class="text-sm">Solid</span>
805
+ <VACrudDelete
806
+ endpoint="/api/items"
807
+ :record-id="102"
808
+ item-name="Solid Item"
809
+ trigger-variant="solid"
810
+ @deleted="(id) => handleDeleteStyle('solid', id)"
811
+ />
812
+ </div>
813
+ <div
814
+ class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg"
815
+ >
816
+ <span class="text-sm">With Label</span>
817
+ <VACrudDelete
818
+ endpoint="/api/items"
819
+ :record-id="103"
820
+ item-name="Labeled Item"
821
+ trigger-label="Remove"
822
+ trigger-icon="i-lucide-x"
823
+ trigger-variant="outline"
824
+ @deleted="(id) => handleDeleteStyle('label', id)"
825
+ />
826
+ </div>
827
+ <div
828
+ class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg"
829
+ >
830
+ <span class="text-sm">Large</span>
831
+ <VACrudDelete
832
+ endpoint="/api/items"
833
+ :record-id="104"
834
+ item-name="Large Item"
835
+ trigger-size="md"
836
+ @deleted="(id) => handleDeleteStyle('large', id)"
837
+ />
838
+ </div>
839
+ </div>
840
+ <div class="mt-4 flex flex-wrap gap-2">
841
+ <UBadge
842
+ v-for="(deleted, style) in deleteStyleResults"
843
+ :key="style"
844
+ color="success"
845
+ >
846
+ {{ style }} deleted
847
+ </UBadge>
848
+ </div>
849
+ </UCard>
850
+ </div>
851
+
852
+ <!-- ========================================== -->
853
+ <!-- API Reference -->
854
+ <!-- ========================================== -->
855
+ <h2 class="text-2xl font-semibold mb-4 mt-12">API Reference</h2>
856
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
857
+ <UCard>
858
+ <template #header>
859
+ <h3 class="font-semibold text-primary-500">VACrudCreate</h3>
860
+ </template>
861
+ <div class="space-y-2 text-sm">
862
+ <p><strong>Props:</strong></p>
863
+ <ul class="text-gray-600 dark:text-gray-400 space-y-1 ml-4">
864
+ <li>• endpoint (required)</li>
865
+ <li>• friendlyName (required)</li>
866
+ <li>• triggerLabel, triggerIcon</li>
867
+ <li>• triggerColor, modalSize</li>
868
+ <li>• initialData, open</li>
869
+ </ul>
870
+ <p class="mt-3"><strong>Events:</strong></p>
871
+ <ul class="text-gray-600 dark:text-gray-400 space-y-1 ml-4">
872
+ <li>• @created(data)</li>
873
+ <li>• @error(error)</li>
874
+ <li>• @opened, @closed</li>
875
+ </ul>
876
+ <p class="mt-3">
877
+ <strong>Slot:</strong> { submit, loading, error }
878
+ </p>
879
+ </div>
880
+ </UCard>
881
+
882
+ <UCard>
883
+ <template #header>
884
+ <h3 class="font-semibold text-blue-500">VACrudUpdate</h3>
885
+ </template>
886
+ <div class="space-y-2 text-sm">
887
+ <p><strong>Props:</strong></p>
888
+ <ul class="text-gray-600 dark:text-gray-400 space-y-1 ml-4">
889
+ <li>• endpoint (required)</li>
890
+ <li>• recordId (required)</li>
891
+ <li>• friendlyName</li>
892
+ <li>• triggerLabel, triggerIcon</li>
893
+ <li>• modalSize, open</li>
894
+ </ul>
895
+ <p class="mt-3"><strong>Events:</strong></p>
896
+ <ul class="text-gray-600 dark:text-gray-400 space-y-1 ml-4">
897
+ <li>• @updated(data)</li>
898
+ <li>• @error(error)</li>
899
+ <li>• @opened, @closed</li>
900
+ </ul>
901
+ <p class="mt-3">
902
+ <strong>Slot:</strong> { submit, loading, error, data, isDirty,
903
+ isFetching }
904
+ </p>
905
+ </div>
906
+ </UCard>
907
+
908
+ <UCard>
909
+ <template #header>
910
+ <h3 class="font-semibold text-red-500">VACrudDelete</h3>
911
+ </template>
912
+ <div class="space-y-2 text-sm">
913
+ <p><strong>Props:</strong></p>
914
+ <ul class="text-gray-600 dark:text-gray-400 space-y-1 ml-4">
915
+ <li>• endpoint (required)</li>
916
+ <li>• recordId (required)</li>
917
+ <li>• itemName</li>
918
+ <li>• triggerLabel, triggerIcon</li>
919
+ <li>• confirmTitle, confirmMessage</li>
920
+ </ul>
921
+ <p class="mt-3"><strong>Events:</strong></p>
922
+ <ul class="text-gray-600 dark:text-gray-400 space-y-1 ml-4">
923
+ <li>• @deleted(id)</li>
924
+ <li>• @error(error)</li>
925
+ <li>• @opened, @closed</li>
926
+ </ul>
927
+ <p class="mt-3">
928
+ <strong>Slot:</strong> No slot (uses VAModalConfirm)
929
+ </p>
930
+ </div>
931
+ </UCard>
932
+ </div>
933
+ </div>
934
+ </UContainer>
935
+ </UDashboardPanel>
936
+ </template>