@elsapiens/cli 0.1.4 → 0.1.5

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.
@@ -1,4 +1,4 @@
1
- import { useState, useMemo, useCallback, useEffect } from 'react';
1
+ import { useState, useMemo, useCallback, useEffect, useRef } from 'react';
2
2
  import { useNavigate, useSearchParams, Link } from 'react-router-dom';
3
3
  import { cn } from '@elsapiens/utils';
4
4
  import { usePageHeader } from '@elsapiens/providers';
@@ -89,7 +89,36 @@ export function <%= pascalName %>ListPage({ className }: <%= pascalName %>ListPa
89
89
  const [itemToDelete, setItemToDelete] = useState<<%= pascalName %>Row | null>(null);
90
90
 
91
91
  // Loading state - set to true when fetching data
92
- const [loading] = useState(false);
92
+ const [loading, setLoading] = useState(false);
93
+ // Minimum loading time to prevent flickering
94
+ const [showLoading, setShowLoading] = useState(false);
95
+ const loadingStartTimeRef = useRef<number | null>(null);
96
+ const MIN_LOADING_TIME = 300; // milliseconds
97
+
98
+ useEffect(() => {
99
+ if (loading) {
100
+ // Start loading - record the start time
101
+ loadingStartTimeRef.current = Date.now();
102
+ setShowLoading(true);
103
+ } else if (loadingStartTimeRef.current !== null) {
104
+ // Loading finished - ensure minimum display time
105
+ const elapsed = Date.now() - loadingStartTimeRef.current;
106
+ const remaining = MIN_LOADING_TIME - elapsed;
107
+
108
+ if (remaining > 0) {
109
+ // Keep showing loading for the remaining time
110
+ const timer = setTimeout(() => {
111
+ setShowLoading(false);
112
+ loadingStartTimeRef.current = null;
113
+ }, remaining);
114
+ return () => clearTimeout(timer);
115
+ } else {
116
+ // Already past minimum time, hide immediately
117
+ setShowLoading(false);
118
+ loadingStartTimeRef.current = null;
119
+ }
120
+ }
121
+ }, [loading]);
93
122
 
94
123
  // Collapsible info state (persisted in localStorage)
95
124
  const [isInfoCollapsed, setIsInfoCollapsed] = useState(() => {
@@ -293,7 +322,7 @@ export function <%= pascalName %>ListPage({ className }: <%= pascalName %>ListPa
293
322
  key: 'status',
294
323
  header: 'Status',
295
324
  render: (item: <%= pascalName %>Row) => (
296
- <Badge className={cn('text-xs', statusColors[item.status])}>
325
+ <Badge className={cn(statusColors[item.status])}>
297
326
  {statusLabels[item.status]}
298
327
  </Badge>
299
328
  ),
@@ -408,21 +437,49 @@ export function <%= pascalName %>ListPage({ className }: <%= pascalName %>ListPa
408
437
  />
409
438
 
410
439
  {/* Table */}
411
- {loading && paginatedData.length === 0 ? (
412
- <div className="el-p-md el-space-y-md">
413
- {Array.from({ length: 5 }).map((_, i) => (
414
- <div key={i} className="flex items-center el-gap-md">
415
- <Skeleton className="h-8 w-8 rounded" />
416
- <Skeleton className="h-4 w-40 flex-1" />
417
- <Skeleton className="h-4 w-24" />
418
- <Skeleton className="h-4 w-20" />
419
- <Skeleton className="h-4 w-24" />
420
- </div>
421
- ))}
440
+ {showLoading && paginatedData.length === 0 ? (
441
+ <div className="el-table-aligned" style={{ marginLeft: 'calc(var(--el-table-spacer-width, var(--el-container-px)) * -1)', marginRight: 'calc(var(--el-table-spacer-width, var(--el-container-px)) * -1)', marginBottom: 'calc(var(--el-table-spacer-width, var(--el-container-px)) * -1)', width: 'calc(100% + var(--el-table-spacer-width, var(--el-container-px)) * 2)' }}>
442
+ <table className="w-full border-collapse el-table">
443
+ <thead>
444
+ <tr className="border-b border-border bg-wisteria-100 dark:bg-wisteria-800">
445
+ <th className="p-0 border-none" style={{ width: 'var(--el-table-spacer-width)' }} />
446
+ <th className="font-medium text-foreground text-left" style={{ paddingLeft: 0, paddingRight: 'var(--table-cell-padding-x)', paddingTop: 'var(--table-header-padding-y)', paddingBottom: 'var(--table-header-padding-y)', fontSize: 'var(--table-font-size)' }}>Name</th>
447
+ <th className="font-medium text-foreground text-left" style={{ width: '120px', paddingLeft: 'var(--table-cell-padding-x)', paddingRight: 'var(--table-cell-padding-x)', paddingTop: 'var(--table-header-padding-y)', paddingBottom: 'var(--table-header-padding-y)', fontSize: 'var(--table-font-size)' }}>Category</th>
448
+ <th className="font-medium text-foreground text-left" style={{ width: '100px', paddingLeft: 'var(--table-cell-padding-x)', paddingRight: 'var(--table-cell-padding-x)', paddingTop: 'var(--table-header-padding-y)', paddingBottom: 'var(--table-header-padding-y)', fontSize: 'var(--table-font-size)' }}>Status</th>
449
+ <th className="font-medium text-foreground text-left" style={{ width: '120px', paddingLeft: 'var(--table-cell-padding-x)', paddingRight: 'var(--table-cell-padding-x)', paddingTop: 'var(--table-header-padding-y)', paddingBottom: 'var(--table-header-padding-y)', fontSize: 'var(--table-font-size)' }}>Created</th>
450
+ <th style={{ width: '100px', paddingLeft: 'var(--table-cell-padding-x)', paddingRight: 0, paddingTop: 'var(--table-header-padding-y)', paddingBottom: 'var(--table-header-padding-y)' }} />
451
+ <th className="p-0 border-none" style={{ width: 'var(--el-table-spacer-width)' }} />
452
+ </tr>
453
+ </thead>
454
+ <tbody>
455
+ {Array.from({ length: 5 }).map((_, i) => (
456
+ <tr key={i} className="border-b border-border">
457
+ <td className="p-0 border-none" />
458
+ <td style={{ paddingLeft: 0, paddingRight: 'var(--table-cell-padding-x)', paddingTop: 'var(--table-cell-padding-y)', paddingBottom: 'var(--table-cell-padding-y)' }}>
459
+ <div className="flex items-center el-gap-sm">
460
+ <Skeleton className="h-8 w-8 rounded flex-shrink-0" />
461
+ <Skeleton className="h-4 w-32" />
462
+ </div>
463
+ </td>
464
+ <td style={{ paddingLeft: 'var(--table-cell-padding-x)', paddingRight: 'var(--table-cell-padding-x)', paddingTop: 'var(--table-cell-padding-y)', paddingBottom: 'var(--table-cell-padding-y)' }}>
465
+ <Skeleton className="h-6 w-20 rounded-full" />
466
+ </td>
467
+ <td style={{ paddingLeft: 'var(--table-cell-padding-x)', paddingRight: 'var(--table-cell-padding-x)', paddingTop: 'var(--table-cell-padding-y)', paddingBottom: 'var(--table-cell-padding-y)' }}>
468
+ <Skeleton className="h-6 w-14 rounded-full" />
469
+ </td>
470
+ <td style={{ paddingLeft: 'var(--table-cell-padding-x)', paddingRight: 'var(--table-cell-padding-x)', paddingTop: 'var(--table-cell-padding-y)', paddingBottom: 'var(--table-cell-padding-y)' }}>
471
+ <Skeleton className="h-4 w-20" />
472
+ </td>
473
+ <td style={{ paddingLeft: 'var(--table-cell-padding-x)', paddingRight: 0, paddingTop: 'var(--table-cell-padding-y)', paddingBottom: 'var(--table-cell-padding-y)' }} />
474
+ <td className="p-0 border-none" />
475
+ </tr>
476
+ ))}
477
+ </tbody>
478
+ </table>
422
479
  </div>
423
480
  ) : paginatedData.length === 0 && hasActiveFilters ? (
424
481
  /* Filtered empty state - no results for current filters */
425
- <div className="flex-1 flex flex-col items-center justify-center el-gap-md el-py-xl">
482
+ <div className="flex-1 flex flex-col items-center justify-center el-gap-lg el-py-xl">
426
483
  <div className="w-16 h-16 rounded-full bg-muted/50 flex items-center justify-center">
427
484
  <SearchX className="w-8 h-8 text-muted-foreground" />
428
485
  </div>
@@ -432,9 +489,11 @@ export function <%= pascalName %>ListPage({ className }: <%= pascalName %>ListPa
432
489
  No <%= title.toLowerCase() %> match your current filters. Try adjusting your search or filters.
433
490
  </p>
434
491
  </div>
435
- <Button variant="outline" onClick={clearFilters}>
436
- Clear filters
437
- </Button>
492
+ <div className="flex items-center el-gap-field">
493
+ <Button variant="outline" onClick={clearFilters}>
494
+ Clear filters
495
+ </Button>
496
+ </div>
438
497
  </div>
439
498
  ) : paginatedData.length === 0 ? (
440
499
  /* True empty state - no data at all */
@@ -495,8 +554,8 @@ export function <%= pascalName %>ListPage({ className }: <%= pascalName %>ListPa
495
554
  </div>
496
555
  )}
497
556
 
498
- {/* Collapsible Page Info - shows when items exist */}
499
- {paginatedData.length > 0 && (
557
+ {/* Collapsible Page Info - shows when data exists in the system */}
558
+ {sampleData.length > 0 && (
500
559
  <div className="relative">
501
560
  {isInfoCollapsed ? (
502
561
  <button
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elsapiens/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "CLI scaffolding tool for elSapiens SDK projects",
5
5
  "type": "module",
6
6
  "bin": {