@svadmin/ui 0.34.9 → 0.35.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 (123) hide show
  1. package/dist/app.css +372 -0
  2. package/dist/component-registry.svelte.d.ts +1 -0
  3. package/dist/component-registry.svelte.js +1 -0
  4. package/dist/components/AICommandBar.svelte +3 -3
  5. package/dist/components/AboutSettings.svelte +2 -2
  6. package/dist/components/AdminApp.svelte +96 -18
  7. package/dist/components/AdminApp.svelte.d.ts +32 -2
  8. package/dist/components/AnomalyBadge.svelte +1 -1
  9. package/dist/components/ApiSettings.svelte +191 -0
  10. package/dist/components/ApiSettings.svelte.d.ts +3 -0
  11. package/dist/components/AppearanceSettings.svelte +5 -6
  12. package/dist/components/AuditLogDrawer.svelte +1 -1
  13. package/dist/components/AuditLogViewer.svelte +1 -1
  14. package/dist/components/AutoForm.svelte +50 -44
  15. package/dist/components/AutoTable.svelte +44 -39
  16. package/dist/components/Breadcrumbs.svelte +1 -0
  17. package/dist/components/ChatDialog.svelte +5 -4
  18. package/dist/components/ComboboxField.svelte +3 -3
  19. package/dist/components/CommandPalette.svelte +3 -3
  20. package/dist/components/CopilotPanel.svelte +2 -2
  21. package/dist/components/CreatePage.svelte +0 -1
  22. package/dist/components/DevTools.svelte +4 -3
  23. package/dist/components/DraggableHeader.svelte +2 -1
  24. package/dist/components/EditPage.svelte +1 -1
  25. package/dist/components/EmptyState.svelte +1 -1
  26. package/dist/components/ErrorPage.svelte +58 -0
  27. package/dist/components/ErrorPage.svelte.d.ts +8 -0
  28. package/dist/components/FieldRenderer.svelte +9 -8
  29. package/dist/components/ForgotPasswordPage.svelte +111 -68
  30. package/dist/components/Header.svelte +7 -7
  31. package/dist/components/InferencerPanel.svelte +4 -3
  32. package/dist/components/InfiniteList.svelte +3 -4
  33. package/dist/components/IntegrationsSettings.svelte +70 -0
  34. package/dist/components/IntegrationsSettings.svelte.d.ts +4 -0
  35. package/dist/components/KeyboardShortcuts.svelte +3 -3
  36. package/dist/components/Layout.svelte +13 -13
  37. package/dist/components/LoginPage.svelte +207 -105
  38. package/dist/components/LoginPage.svelte.d.ts +3 -15
  39. package/dist/components/MarkdownRenderer.svelte +3 -5
  40. package/dist/components/ModalForm.svelte +1 -3
  41. package/dist/components/NotificationsSettings.svelte +115 -0
  42. package/dist/components/NotificationsSettings.svelte.d.ts +3 -0
  43. package/dist/components/PageHeader.svelte +9 -7
  44. package/dist/components/PageSkeleton.svelte +4 -4
  45. package/dist/components/PasswordInput.svelte +1 -2
  46. package/dist/components/PermissionMatrix.svelte +5 -5
  47. package/dist/components/ProfilePage.svelte +1 -1
  48. package/dist/components/RegisterPage.svelte +103 -65
  49. package/dist/components/ResourceOperationsPage.svelte +153 -0
  50. package/dist/components/ResourceOperationsPage.svelte.d.ts +37 -0
  51. package/dist/components/RolesSettings.svelte +1 -2
  52. package/dist/components/SecuritySettings.svelte +179 -0
  53. package/dist/components/SecuritySettings.svelte.d.ts +4 -0
  54. package/dist/components/SettingsPage.svelte +121 -55
  55. package/dist/components/SettingsPage.svelte.d.ts +25 -1
  56. package/dist/components/ShowPage.svelte +13 -15
  57. package/dist/components/Sidebar.svelte +107 -58
  58. package/dist/components/SidebarItem.svelte +38 -14
  59. package/dist/components/StepsForm.svelte +1 -1
  60. package/dist/components/TaskList.svelte +1 -1
  61. package/dist/components/TaskQueueDrawer.svelte +2 -1
  62. package/dist/components/TenantSwitcher.svelte +1 -2
  63. package/dist/components/Toast.svelte +1 -0
  64. package/dist/components/TooltipButton.svelte +1 -0
  65. package/dist/components/TwoFactorAuthPage.svelte +247 -0
  66. package/dist/components/TwoFactorAuthPage.svelte.d.ts +3 -0
  67. package/dist/components/UpdatePasswordPage.svelte +86 -48
  68. package/dist/components/VirtualTable.svelte +1 -1
  69. package/dist/components/VoiceInput.svelte +1 -0
  70. package/dist/components/account/CompanyProfilePage.svelte +99 -0
  71. package/dist/components/account/CompanyProfilePage.svelte.d.ts +3 -0
  72. package/dist/components/account/GetStartedPage.svelte +123 -0
  73. package/dist/components/account/GetStartedPage.svelte.d.ts +4 -0
  74. package/dist/components/account/ImportMembersPage.svelte +143 -0
  75. package/dist/components/account/ImportMembersPage.svelte.d.ts +3 -0
  76. package/dist/components/account/MembersStarterPage.svelte +104 -0
  77. package/dist/components/account/MembersStarterPage.svelte.d.ts +3 -0
  78. package/dist/components/account/SecurityLogPage.svelte +108 -0
  79. package/dist/components/account/SecurityLogPage.svelte.d.ts +3 -0
  80. package/dist/components/account/SettingsEnterprisePage.svelte +131 -0
  81. package/dist/components/account/SettingsEnterprisePage.svelte.d.ts +3 -0
  82. package/dist/components/account/SettingsPlainPage.svelte +81 -0
  83. package/dist/components/account/SettingsPlainPage.svelte.d.ts +3 -0
  84. package/dist/components/account/SettingsSidebarPage.svelte +98 -0
  85. package/dist/components/account/SettingsSidebarPage.svelte.d.ts +3 -0
  86. package/dist/components/account/TeamMembersPage.svelte +98 -0
  87. package/dist/components/account/TeamMembersPage.svelte.d.ts +3 -0
  88. package/dist/components/buttons/ImportButton.svelte +1 -1
  89. package/dist/components/buttons/ListButton.svelte +1 -1
  90. package/dist/components/charts/BarChart.svelte +1 -1
  91. package/dist/components/charts/LineChart.svelte +3 -3
  92. package/dist/components/charts/PieChart.svelte +2 -2
  93. package/dist/components/fieldComponentMap.js +2 -1
  94. package/dist/components/fields/ArrayField.svelte +1 -1
  95. package/dist/components/fields/MarkdownField.svelte +1 -0
  96. package/dist/components/fields/MultiSelectField.svelte +1 -1
  97. package/dist/components/fields/TagField.svelte +1 -1
  98. package/dist/components/network/TeamCrewTablePage.svelte +122 -0
  99. package/dist/components/network/TeamCrewTablePage.svelte.d.ts +3 -0
  100. package/dist/components/network/UserCardsNFTPage.svelte +134 -0
  101. package/dist/components/network/UserCardsNFTPage.svelte.d.ts +3 -0
  102. package/dist/components/profile/ActivityTimeline.svelte +77 -0
  103. package/dist/components/profile/ActivityTimeline.svelte.d.ts +16 -0
  104. package/dist/components/profile/ProfileCard.svelte +216 -0
  105. package/dist/components/profile/ProfileCard.svelte.d.ts +27 -0
  106. package/dist/components/profile/ProjectsGrid.svelte +91 -0
  107. package/dist/components/profile/ProjectsGrid.svelte.d.ts +17 -0
  108. package/dist/components/profile/PublicProfilePage.svelte +179 -0
  109. package/dist/components/profile/PublicProfilePage.svelte.d.ts +10 -0
  110. package/dist/components/profile/TeamsShowcase.svelte +98 -0
  111. package/dist/components/profile/TeamsShowcase.svelte.d.ts +19 -0
  112. package/dist/components/ui/alert/index.js +1 -0
  113. package/dist/components/ui/badge/index.js +1 -0
  114. package/dist/components/ui/button/button.svelte +1 -0
  115. package/dist/components/ui/button/index.js +1 -0
  116. package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +1 -0
  117. package/dist/components/ui/dropdown-menu/dropdown-menu.svelte +1 -1
  118. package/dist/components/ui/sheet/sheet.svelte +1 -0
  119. package/dist/components/ui/tabs/tabs.svelte +1 -0
  120. package/dist/index.d.ts +23 -0
  121. package/dist/index.js +27 -0
  122. package/dist/router-state.svelte.js +17 -0
  123. package/package.json +13 -13
@@ -25,7 +25,7 @@
25
25
  table_toggleAllRowsSelected,
26
26
  row_getIsSelected,
27
27
  row_toggleSelected,
28
- row_getAllVisibleCells,
28
+ row_getVisibleCells,
29
29
  row_getIsExpanded,
30
30
  row_toggleExpanded,
31
31
  cell_getValue,
@@ -484,13 +484,17 @@
484
484
  }
485
485
  </script>
486
486
 
487
- <div class="space-y-4">
487
+ <div class="space-y-5" data-svadmin-list>
488
488
  <!-- Header -->
489
- <div class="flex flex-wrap items-center justify-between gap-2">
490
- <h1 class="text-lg sm:text-xl font-semibold text-foreground">{resource.label}</h1>
491
- <div class="flex flex-wrap items-center gap-2">
489
+ <div class="rounded-3xl border border-border/70 bg-card/90 p-5 shadow-sm shadow-slate-900/[0.03] backdrop-blur" data-svadmin-list-header>
490
+ <div class="flex flex-wrap items-center justify-between gap-4">
491
+ <div class="min-w-0">
492
+ <h1 class="truncate text-2xl font-semibold tracking-tight text-foreground">{resource.label}</h1>
493
+ <p class="mt-1 text-sm text-muted-foreground">{t('common.list')}</p>
494
+ </div>
495
+ <div class="flex flex-wrap items-center gap-2" data-svadmin-list-actions>
492
496
  {#if canExport}
493
- <Button variant="outline" size="sm" onclick={exportCSV}>
497
+ <Button variant="outline" size="sm" class="h-10 rounded-xl" onclick={exportCSV}>
494
498
  <Download class="h-4 w-4" data-icon="inline-start" /> {t('common.export')}
495
499
  </Button>
496
500
  {/if}
@@ -513,13 +517,13 @@
513
517
  <DropdownMenu.Root>
514
518
  <DropdownMenu.Trigger>
515
519
  {#snippet child({ props })}
516
- <Button variant="outline" size="sm" {...props}>
517
- <SlidersHorizontal class="h-4 w-4" data-icon="inline-start" /> {t('common.columns') || 'Columns'}
520
+ <Button variant="outline" size="sm" class="h-10 rounded-xl" {...props}>
521
+ <SlidersHorizontal class="h-4 w-4" data-icon="inline-start" /> {t('common.columns')}
518
522
  </Button>
519
523
  {/snippet}
520
524
  </DropdownMenu.Trigger>
521
525
  <DropdownMenu.Content align="end" class="w-48">
522
- {#each table_getAllLeafColumns(tbl).filter((c: any) => !c.id.startsWith('_')) as column}
526
+ {#each table_getAllLeafColumns(tbl).filter((c: any) => !c.id.startsWith('_')) as column, _i (_i)}
523
527
  <DropdownMenu.CheckboxItem
524
528
  checked={column_getIsVisible(column)}
525
529
  onCheckedChange={(v) => column_toggleVisibility(column, !!v)}
@@ -533,15 +537,16 @@
533
537
  {@render headerActions()}
534
538
  {/if}
535
539
  {#if canCreate}
536
- <Button onclick={() => navigate(`/${resourceName}/create`)}>
540
+ <Button class="h-10 rounded-xl px-4 shadow-sm shadow-primary/15" onclick={() => navigate(`/${resourceName}/create`)}>
537
541
  <Plus class="h-4 w-4" data-icon="inline-start" /> {t('common.create')}
538
542
  </Button>
539
543
  {/if}
544
+ </div>
540
545
  </div>
541
546
  </div>
542
547
 
543
548
  <!-- Search and Advanced Filters -->
544
- <div class="flex flex-wrap items-center gap-2">
549
+ <div class="flex flex-wrap items-center gap-3 rounded-3xl border border-border/70 bg-card/80 p-3 shadow-sm shadow-slate-900/[0.02] backdrop-blur" data-svadmin-table-toolbar>
545
550
  {#if searchableFields.length > 0}
546
551
  <div class="relative max-w-sm flex-1 sm:min-w-[250px]">
547
552
  <Search class="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
@@ -550,7 +555,7 @@
550
555
  bind:value={searchText}
551
556
  oninput={() => { pagination = { ...pagination, current: 1 }; }}
552
557
  placeholder={t('common.search')}
553
- class="pl-10 h-9"
558
+ class="h-10 rounded-xl border-border/70 bg-background/85 pl-10"
554
559
  />
555
560
  </div>
556
561
  {/if}
@@ -559,7 +564,7 @@
559
564
  <Popover.Root>
560
565
  <Popover.Trigger>
561
566
  {#snippet child({ props })}
562
- <Button variant="outline" size="sm" class="h-9 px-3" {...props}>
567
+ <Button variant="outline" size="sm" class="h-10 rounded-xl px-3" {...props}>
563
568
  <FilterIcon class="h-4 w-4" data-icon="inline-start" />
564
569
  {t('common.filter')}
565
570
  {#if activeFilterCount > 0}
@@ -571,18 +576,18 @@
571
576
  <Popover.Content class="w-80">
572
577
  <div class="space-y-3">
573
578
  <h4 class="font-medium text-sm">{t('common.filter')}</h4>
574
- {#each filterableFields as field}
579
+ {#each filterableFields as field, _i (_i)}
575
580
  <div class="space-y-1">
576
581
  <label class="text-xs text-muted-foreground" for="filter-{field.key}">{field.label}</label>
577
582
  {#if field.type === 'select' && field.options}
578
583
  <select
579
584
  id="filter-{field.key}"
580
- class="h-9 text-sm w-full font-normal flex w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
585
+ class="flex h-10 w-full items-center justify-between rounded-xl border border-input bg-background px-3 py-2 text-sm font-normal ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
581
586
  value={filterValues[field.key] ?? ''}
582
587
  onchange={(e) => filterValues[field.key] = (e.currentTarget as HTMLSelectElement).value}
583
588
  >
584
589
  <option value="">{t('common.all')}</option>
585
- {#each field.options as opt}
590
+ {#each field.options as opt, _i (_i)}
586
591
  <option value={opt.value}>{opt.label}</option>
587
592
  {/each}
588
593
  </select>
@@ -593,7 +598,7 @@
593
598
  value={filterValues[field.key] ?? ''}
594
599
  oninput={(e) => filterValues[field.key] = (e.currentTarget as HTMLInputElement).value}
595
600
  placeholder={field.label}
596
- class="h-9 text-sm"
601
+ class="h-10 rounded-xl text-sm"
597
602
  />
598
603
  {/if}
599
604
  </div>
@@ -616,17 +621,17 @@
616
621
  </div>
617
622
 
618
623
  <!-- Table (TanStack-powered) -->
619
- <div class="rounded-[24px] bg-card/80 backdrop-blur-3xl shadow-[0_8px_30px_rgb(0,0,0,0.04)] overflow-hidden ring-1 ring-border/30" role="region" aria-label="{resource.label} {t('common.list')}">
624
+ <div class="overflow-hidden rounded-3xl border border-border/70 bg-card/95 shadow-sm shadow-slate-900/[0.03] backdrop-blur" data-svadmin-table-card role="region" aria-label="{resource.label} {t('common.list')}">
620
625
  {#if query.isLoading}
621
626
  <div class="p-4 space-y-3">
622
627
  <div class="flex gap-4 mb-2">
623
- {#each visibleFields.slice(0, 4) as _}
628
+ {#each visibleFields.slice(0, 4) as _, _i (_i)}
624
629
  <Skeleton class="h-4 flex-1" />
625
630
  {/each}
626
631
  </div>
627
- {#each Array(5) as _}
632
+ {#each Array(5) as _, _i (_i)}
628
633
  <div class="flex gap-4">
629
- {#each visibleFields.slice(0, 4) as __}
634
+ {#each visibleFields.slice(0, 4) as __, _i (_i)}
630
635
  <Skeleton class="h-8 flex-1" />
631
636
  {/each}
632
637
  </div>
@@ -640,19 +645,19 @@
640
645
  <div in:fade={{ duration: 150 }}>
641
646
  <!-- Desktop Table (hidden on mobile) -->
642
647
  <div class="hidden md:block">
643
- <Table.Root>
644
- <Table.Header>
645
- {#each table_getHeaderGroups(tbl) as headerGroup}
648
+ <Table.Root class="svadmin-data-table" data-svadmin-datatable>
649
+ <Table.Header data-svadmin-table-head>
650
+ {#each table_getHeaderGroups(tbl) as headerGroup, _i (_i)}
646
651
  <DraggableHeader
647
652
  columns={headerGroup.headers.map((h: any) => ({ id: h.column.id, header: h }))}
648
653
  resourceName={resourceName}
649
654
  onReorder={(newOrder) => { columnOrder = newOrder.map((c: any) => c.id); }}
650
655
  >
651
- {#snippet header(col, index, dragProps)}
656
+ {#snippet header(col, _index, dragProps)}
652
657
  {@const header = col.header as typeof headerGroup.headers[0]}
653
658
  <Table.Head
654
659
  {...dragProps}
655
- class={cn("bg-transparent hover:bg-muted/10 border-b border-border/20 uppercase tracking-[0.12em] text-[10px] text-muted-foreground/70 font-semibold py-4", dragProps.class)}
660
+ class={cn("border-b border-border/50 bg-muted/35 px-4 py-4 text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground/75 hover:bg-muted/45", dragProps.class)}
656
661
  style={header_getSize(header) != null && header_getSize(header) !== 150 ? `width:${header_getSize(header)}px` : undefined}
657
662
  >
658
663
  {#if header.id === '_select'}
@@ -688,15 +693,15 @@
688
693
  {/each}
689
694
  </Table.Header>
690
695
  <Table.Body>
691
- {#each table_getRowModel(tbl).rows as row}
696
+ {#each table_getRowModel(tbl).rows as row, _i (_i)}
692
697
  {@const record = row.original}
693
698
  {@const id = record[primaryKey] as string | number}
694
699
  <ContextMenu.Root>
695
700
  <ContextMenu.Trigger>
696
701
  {#snippet child({ props })}
697
- <Table.Row {...props} class="transition-all duration-300 border-b border-border/10 {row_getIsSelected(row) ? 'bg-primary/5' : 'hover:bg-muted/20'}">
698
- {#each row_getAllVisibleCells(row) as cell}
699
- <Table.Cell>
702
+ <Table.Row {...props} data-svadmin-table-row class="border-b border-border/30 transition-colors duration-200 {row_getIsSelected(row) ? 'bg-primary/5' : 'hover:bg-muted/25'}">
703
+ {#each row_getVisibleCells(row) as cell, _i (_i)}
704
+ <Table.Cell class="px-4 py-3.5">
700
705
  {#if cell.column.id === '_select'}
701
706
  <Checkbox
702
707
  checked={row_getIsSelected(row)}
@@ -739,7 +744,7 @@
739
744
  {new Date(cell_getValue(cell) as string).toLocaleDateString()}
740
745
  {:else if field?.type === 'tags' && Array.isArray(cell_getValue(cell))}
741
746
  <div class="flex flex-wrap gap-1">
742
- {#each (cell_getValue(cell) as string[]).slice(0, 3) as tag}
747
+ {#each (cell_getValue(cell) as string[]).slice(0, 3) as tag, _i (_i)}
743
748
  <Badge variant="secondary">{tag}</Badge>
744
749
  {/each}
745
750
  </div>
@@ -787,7 +792,7 @@
787
792
  </ContextMenu.Root>
788
793
  {#if expandedRowRender && row_getIsExpanded(row)}
789
794
  <Table.Row class="bg-muted/10 border-b border-border/10 transition-all">
790
- <Table.Cell colspan={row_getAllVisibleCells(row).length}>
795
+ <Table.Cell colspan={row_getVisibleCells(row).length}>
791
796
  {@render expandedRowRender({ record })}
792
797
  </Table.Cell>
793
798
  </Table.Row>
@@ -803,7 +808,7 @@
803
808
  <path stroke-linecap="round" stroke-linejoin="round" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
804
809
  </svg>
805
810
  <p class="text-sm font-medium text-muted-foreground mb-1">{t('common.noData')}</p>
806
- <p class="text-xs text-muted-foreground/60 mb-4">{t('common.noDataHint') || 'Get started by creating your first record.'}</p>
811
+ <p class="text-xs text-muted-foreground/60 mb-4">{t('common.noDataHint')}</p>
807
812
  {#if canCreate}
808
813
  <Button variant="outline" size="sm" class="gap-2" onclick={() => navigate(`/${resourceName}/create`)}>
809
814
  <Plus class="h-3.5 w-3.5" />
@@ -821,11 +826,11 @@
821
826
 
822
827
  <!-- Mobile Card View (visible only on small screens) -->
823
828
  <div class="md:hidden space-y-3 p-2">
824
- {#each table_getRowModel(tbl).rows as row}
829
+ {#each table_getRowModel(tbl).rows as row, _i (_i)}
825
830
  {@const record = row.original}
826
831
  {@const id = record[primaryKey] as string | number}
827
832
  <div
828
- class="rounded-[20px] shadow-[0_4px_20px_rgb(0,0,0,0.03)] ring-1 ring-border/20 bg-card p-5 transition-all {row_getIsSelected(row) ? 'ring-2 ring-primary/50 bg-primary/5' : ''}"
833
+ class="rounded-3xl border border-border/60 bg-card p-5 shadow-sm shadow-slate-900/[0.03] transition-all {row_getIsSelected(row) ? 'border-primary/35 bg-primary/5 ring-2 ring-primary/20' : ''}"
829
834
  >
830
835
  <!-- Card header: ID + select + actions -->
831
836
  <div class="flex items-center justify-between mb-3">
@@ -860,7 +865,7 @@
860
865
  </div>
861
866
  <!-- Card fields -->
862
867
  <div class="space-y-2">
863
- {#each visibleFields.slice(0, 6) as field}
868
+ {#each visibleFields.slice(0, 6) as field, _i (_i)}
864
869
  {@const value = record[field.key]}
865
870
  <div class="flex items-start justify-between gap-4">
866
871
  <span class="text-xs font-medium text-muted-foreground shrink-0">{field.label}</span>
@@ -875,7 +880,7 @@
875
880
  {new Date(value as string).toLocaleDateString()}
876
881
  {:else if field.type === 'tags' && Array.isArray(value)}
877
882
  <div class="flex flex-wrap gap-1 justify-end">
878
- {#each (value as string[]).slice(0, 2) as tag}
883
+ {#each (value as string[]).slice(0, 2) as tag, _i (_i)}
879
884
  <Badge variant="secondary" class="text-[10px]">{tag}</Badge>
880
885
  {/each}
881
886
  </div>
@@ -906,7 +911,7 @@
906
911
 
907
912
  <!-- Pagination (shadcn) -->
908
913
  {#if totalPages > 0}
909
- <div class="flex flex-col sm:flex-row items-center justify-between gap-2 text-sm text-muted-foreground">
914
+ <div class="flex flex-col sm:flex-row items-center justify-between gap-2 text-sm text-muted-foreground" data-svadmin-pagination>
910
915
  <div class="flex items-center gap-2">
911
916
  <span>{t('common.total', { total: query.data?.total ?? 0 })}</span>
912
917
  <select
@@ -933,7 +938,7 @@
933
938
  disabled={currentPage <= 1}
934
939
  />
935
940
  </PaginationUI.Item>
936
- {#each pages as page}
941
+ {#each pages as page, _i (_i)}
937
942
  <PaginationUI.Item>
938
943
  {#if page === '...'}
939
944
  <PaginationUI.Ellipsis />
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
3
  import { getResources } from '@svadmin/core';
3
4
  import { getPath } from '../router-state.svelte.js';
4
5
  import { formatLink } from '@svadmin/core/router';
@@ -1,12 +1,13 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable no-undef, svelte/no-at-html-tags */
2
3
  import { getChatProvider, getChatContext, setChatContext, getAgentProvider, registerApproval, resolveApproval } from '@svadmin/core';
3
- import type { ChatMessage, ChatAction, AgentEvent } from '@svadmin/core';
4
+ import type { ChatMessage, ChatAction } from '@svadmin/core';
4
5
  import { t } from '@svadmin/core/i18n';
5
6
  import { useParsed } from '@svadmin/core';
6
7
  import { fly, fade, scale } from 'svelte/transition';
7
8
  import { Button } from './ui/button/index.js';
8
9
  import TooltipButton from './TooltipButton.svelte';
9
- import { MessageCircle, X, Minus, Send, Loader2, Bot, Trash2, ShieldCheck, ShieldX, Wrench, LayoutDashboard } from '@lucide/svelte';
10
+ import { MessageCircle, X, Minus, Send, Loader2, Bot, Trash2 } from '@lucide/svelte';
10
11
 
11
12
  interface Props {
12
13
  /** localStorage key for chat history persistence. Set to '' to disable. */
@@ -508,7 +509,7 @@
508
509
  {t('chat.welcomeDesc') || 'Ask me anything about your admin panel.'}
509
510
  </p>
510
511
  <div class="flex flex-col gap-2 w-full max-w-[240px]">
511
- {#each suggestions as suggestion}
512
+ {#each suggestions as suggestion, _i (_i)}
512
513
  <button
513
514
  class="text-left text-xs px-3 py-2 rounded-lg border border-border hover:bg-accent hover:text-accent-foreground transition-colors cursor-pointer"
514
515
  onclick={() => { inputValue = suggestion; }}
@@ -535,7 +536,7 @@
535
536
  <!-- Action Buttons -->
536
537
  {#if msg.actions && msg.actions.length > 0}
537
538
  <div class="flex flex-wrap gap-1.5 mt-2 pt-2 border-t border-border/50">
538
- {#each msg.actions as action}
539
+ {#each msg.actions as action, _i (_i)}
539
540
  <Button
540
541
  variant={action.variant ?? 'outline'}
541
542
  size="sm"
@@ -1,10 +1,10 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
3
  import { t } from '@svadmin/core/i18n';
3
4
  import { useSelect } from '@svadmin/core';
4
5
  import type { Filter } from '@svadmin/core';
5
6
  import { Button } from './ui/button/index.js';
6
7
  import TooltipButton from './TooltipButton.svelte';
7
- import { Badge } from './ui/badge/index.js';
8
8
  import { Command } from 'cmdk-sv';
9
9
  import { Skeleton } from './ui/skeleton/index.js';
10
10
  import { ChevronsUpDown, Check, X, Search } from '@lucide/svelte';
@@ -117,11 +117,11 @@
117
117
  No results.
118
118
  </Command.Empty>
119
119
  {#if query.isLoading}
120
- {#each Array(3) as _}
120
+ {#each Array(3) as _, _i (_i)}
121
121
  <div class="px-2 py-1.5"><Skeleton class="h-5 w-full" /></div>
122
122
  {/each}
123
123
  {:else}
124
- {#each (options as { label: string; value: string | number }[]) ?? [] as opt}
124
+ {#each (options as { label: string; value: string | number }[]) ?? [] as opt, _i (_i)}
125
125
  <Command.Item
126
126
  value={opt.label}
127
127
  onSelect={() => handleSelect(opt.value)}
@@ -5,7 +5,7 @@
5
5
  import { toggleTheme } from '@svadmin/core';
6
6
  import { Command } from 'cmdk-sv';
7
7
  import * as Dialog from './ui/dialog/index.js';
8
- import { Search, LayoutDashboard, Plus, Sun, FileText, Bot, Sparkles } from '@lucide/svelte';
8
+ import { Search, LayoutDashboard, Plus, Sun, FileText, Sparkles } from '@lucide/svelte';
9
9
 
10
10
  interface Props {
11
11
  open?: boolean;
@@ -93,7 +93,7 @@
93
93
  <LayoutDashboard class="h-4 w-4 text-muted-foreground" />
94
94
  {t('common.home')}
95
95
  </Command.Item>
96
- {#each resources as r}
96
+ {#each resources as r, _i (_i)}
97
97
  <Command.Item
98
98
  value={r.name}
99
99
  onSelect={() => act(() => navigate(`/${r.name}`))}
@@ -109,7 +109,7 @@
109
109
 
110
110
  <!-- Actions -->
111
111
  <Command.Group heading={t('common.actions')}>
112
- {#each resources as r}
112
+ {#each resources as r, _i (_i)}
113
113
  <Command.Item
114
114
  value={"create-" + r.name}
115
115
  onSelect={() => act(() => navigate(`/${r.name}/create`))}
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { getChatProvider, getChatContext } from '@svadmin/core';
3
- import { Sparkles, X, ChevronRight, Check, RefreshCcw } from '@lucide/svelte';
4
- import { fade, slide } from 'svelte/transition';
3
+ import { Sparkles, X, Check, RefreshCcw } from '@lucide/svelte';
4
+ import { slide } from 'svelte/transition';
5
5
  import { Button } from './ui/button/index.js';
6
6
  import MarkdownRenderer from './MarkdownRenderer.svelte';
7
7
  import TooltipButton from './TooltipButton.svelte';
@@ -1,6 +1,5 @@
1
1
  <script lang="ts">
2
2
  import { getResource } from '@svadmin/core';
3
- import { navigate } from '@svadmin/core/router';
4
3
  import { t } from '@svadmin/core/i18n';
5
4
  import type { Snippet } from 'svelte';
6
5
  import PageHeader from './PageHeader.svelte';
@@ -1,10 +1,10 @@
1
1
  <script lang="ts">
2
- import { fly, scale } from 'svelte/transition';
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ import { fly } from 'svelte/transition';
3
4
  import { getResources } from '@svadmin/core';
4
5
  import { getTheme, getColorTheme } from '@svadmin/core';
5
6
  import { getLocale, t } from '@svadmin/core/i18n';
6
7
  import { currentPath } from '@svadmin/core/router';
7
- import { Button } from './ui/button/index.js';
8
8
  import TooltipButton from './TooltipButton.svelte';
9
9
  import * as Tabs from './ui/tabs/index.js';
10
10
  import { Badge } from './ui/badge/index.js';
@@ -35,6 +35,7 @@
35
35
 
36
36
  // Auto-trace state changes in dev mode via Svelte 5 $inspect
37
37
  if ((import.meta as any).env?.DEV) {
38
+ // eslint-disable-next-line svelte/no-inspect
38
39
  $inspect({ path, theme, colorTheme, locale, resourceCount: resources.length });
39
40
  }
40
41
  </script>
@@ -119,7 +120,7 @@
119
120
  <!-- Resources -->
120
121
  <div class="py-1">
121
122
  <h4 class="text-[0.6875rem] font-bold uppercase tracking-widest text-muted-foreground mb-1 px-1">Resources ({resources.length})</h4>
122
- {#each resources as r}
123
+ {#each resources as r, _i (_i)}
123
124
  <div class="flex items-center justify-between px-1 py-0.5 rounded hover:bg-muted/50">
124
125
  <span class="text-xs text-foreground">{r.name}</span>
125
126
  <Badge variant="outline" class="font-mono text-[0.6875rem]">{r.fields.length} fields</Badge>
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
3
  /**
3
4
  * DraggableHeader — Wraps table header cells with HTML5 Drag and Drop
4
5
  * to enable column reorder. Persists order to localStorage.
@@ -99,7 +100,7 @@
99
100
  </script>
100
101
 
101
102
  <tr class="hover:bg-muted/50 data-[state=selected]:bg-muted transition-colors bg-muted/50">
102
- {#each columns as column, index}
103
+ {#each columns as column, index (index)}
103
104
  {@render header(column, index, {
104
105
  draggable: true,
105
106
  ondragstart: (e: DragEvent) => handleDragStart(e, index),
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { getResource, useDelete } from '@svadmin/core';
2
+ import { getResource } from '@svadmin/core';
3
3
  import { navigate } from '@svadmin/core/router';
4
4
  import { t } from '@svadmin/core/i18n';
5
5
  import type { Snippet } from 'svelte';
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { fade, scale } from 'svelte/transition';
2
+ import { scale } from 'svelte/transition';
3
3
  import { PackageOpen } from '@lucide/svelte';
4
4
  import { t } from '@svadmin/core';
5
5
 
@@ -0,0 +1,58 @@
1
+ <script lang="ts">
2
+ import { t } from '@svadmin/core/i18n';
3
+ import { navigate } from '@svadmin/core/router';
4
+ import { AlertTriangle, ArrowLeft, FileQuestion, Home } from '@lucide/svelte';
5
+ import { Button } from './ui/button/index.js';
6
+ import * as Card from './ui/card/index.js';
7
+
8
+ interface Props {
9
+ status?: '404' | '500';
10
+ title?: string;
11
+ description?: string;
12
+ }
13
+
14
+ let { status = '404', title, description }: Props = $props();
15
+
16
+ function goBack() {
17
+ if (typeof window !== 'undefined') {
18
+ window.history.back();
19
+ }
20
+ }
21
+
22
+ const isNotFound = $derived(status === '404');
23
+ const resolvedTitle = $derived(title ?? (isNotFound ? t('common.pageNotFound') : t('common.error')));
24
+ const resolvedDescription = $derived(
25
+ description ?? (isNotFound ? t('error.pageNotFoundDescription') : t('error.internalServerErrorDescription')),
26
+ );
27
+ </script>
28
+
29
+ <div class="flex min-h-[70vh] items-center justify-center p-4">
30
+ <Card.Card class="w-full max-w-md border-border/60">
31
+ <Card.CardContent class="space-y-6 px-6 py-10 text-center">
32
+ <div class="mx-auto inline-flex h-16 w-16 items-center justify-center rounded-lg bg-muted/50 text-muted-foreground">
33
+ {#if isNotFound}
34
+ <FileQuestion class="h-8 w-8" />
35
+ {:else}
36
+ <AlertTriangle class="h-8 w-8 text-destructive" />
37
+ {/if}
38
+ </div>
39
+
40
+ <div class="space-y-2">
41
+ <p class="text-xs font-semibold uppercase text-muted-foreground">{status}</p>
42
+ <h1 class="text-2xl font-semibold text-foreground">{resolvedTitle}</h1>
43
+ <p class="mx-auto max-w-sm text-sm leading-relaxed text-muted-foreground">{resolvedDescription}</p>
44
+ </div>
45
+
46
+ <div class="flex flex-col justify-center gap-2 sm:flex-row">
47
+ <Button variant="outline" onclick={goBack}>
48
+ <ArrowLeft class="h-4 w-4" />
49
+ {t('common.back')}
50
+ </Button>
51
+ <Button onclick={() => navigate('/')}>
52
+ <Home class="h-4 w-4" />
53
+ {t('common.returnHome')}
54
+ </Button>
55
+ </div>
56
+ </Card.CardContent>
57
+ </Card.Card>
58
+ </div>
@@ -0,0 +1,8 @@
1
+ interface Props {
2
+ status?: '404' | '500';
3
+ title?: string;
4
+ description?: string;
5
+ }
6
+ declare const ErrorPage: import("svelte").Component<Props, {}, "">;
7
+ type ErrorPage = ReturnType<typeof ErrorPage>;
8
+ export default ErrorPage;
@@ -1,4 +1,5 @@
1
1
  <script lang="ts" module>
2
+ /* eslint-disable no-import-assign */
2
3
  export type { FieldDefinition } from '@svadmin/core';
3
4
  </script>
4
5
 
@@ -84,8 +85,8 @@
84
85
  }
85
86
  </script>
86
87
 
87
- <div class="space-y-1.5">
88
- <Label for={field.key} id="label-{field.key}">
88
+ <div class="space-y-1.5" data-svadmin-field>
89
+ <Label for={field.key} id="label-{field.key}" data-svadmin-field-label>
89
90
  {field.label}
90
91
  {#if field.required}
91
92
  <span class="text-destructive">*</span>
@@ -240,7 +241,7 @@
240
241
  disabled={disabled}
241
242
  >
242
243
  <option value="">{t('field.selectPlaceholder')}</option>
243
- {#each field.options ?? [] as opt}
244
+ {#each field.options ?? [] as opt, _i (_i)}
244
245
  <option value={opt.value}>{opt.label}</option>
245
246
  {/each}
246
247
  </select>
@@ -253,7 +254,7 @@
253
254
  {disabled}
254
255
  placeholder={t('field.selectPlaceholder')}
255
256
  >
256
- {#each field.options ?? [] as opt}
257
+ {#each field.options ?? [] as opt, _i (_i)}
257
258
  <option value={opt.value}>{opt.label}</option>
258
259
  {/each}
259
260
  </Select>
@@ -265,7 +266,7 @@
265
266
  role="group"
266
267
  aria-labelledby="label-{field.key}"
267
268
  >
268
- {#each field.options ?? [] as opt}
269
+ {#each field.options ?? [] as opt, _i (_i)}
269
270
  <label class="flex items-center gap-2 text-sm cursor-pointer hover:bg-muted/50 rounded px-1 py-0.5 transition-colors">
270
271
  <Checkbox
271
272
  id={`${field.key}-${opt.value}`}
@@ -282,7 +283,7 @@
282
283
  </div>
283
284
  {#if multiVal.length > 0}
284
285
  <div class="flex flex-wrap gap-1 mt-1">
285
- {#each multiVal as v}
286
+ {#each multiVal as v, _i (_i)}
286
287
  {@const label = field.options?.find((o: { label: string; value: string | number }) => o.value === v)?.label ?? String(v)}
287
288
  <Badge variant="secondary" class="gap-1">
288
289
  {label}
@@ -306,7 +307,7 @@
306
307
  {:else if field.type === 'tags'}
307
308
  <div class="space-y-2">
308
309
  <div class="flex flex-wrap gap-1.5">
309
- {#each tagsVal as tag, i}
310
+ {#each tagsVal as tag, i (i)}
310
311
  <Badge variant="secondary" class="gap-1">
311
312
  {tag}
312
313
  <button
@@ -339,7 +340,7 @@
339
340
 
340
341
  {:else if field.type === 'images'}
341
342
  <div class="space-y-2">
342
- {#each imagesVal as url, i}
343
+ {#each imagesVal as url, i (i)}
343
344
  <div class="flex items-center gap-2">
344
345
  <Input
345
346
  id={i === 0 ? field.key : undefined}