@svadmin/ui 0.34.9 → 0.34.10

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 (64) hide show
  1. package/dist/component-registry.svelte.js +1 -0
  2. package/dist/components/AICommandBar.svelte +3 -3
  3. package/dist/components/AboutSettings.svelte +2 -2
  4. package/dist/components/AdminApp.svelte +2 -3
  5. package/dist/components/AnomalyBadge.svelte +1 -1
  6. package/dist/components/AppearanceSettings.svelte +5 -6
  7. package/dist/components/AuditLogDrawer.svelte +1 -1
  8. package/dist/components/AuditLogViewer.svelte +1 -1
  9. package/dist/components/AutoForm.svelte +5 -4
  10. package/dist/components/AutoTable.svelte +17 -17
  11. package/dist/components/Breadcrumbs.svelte +1 -0
  12. package/dist/components/ChatDialog.svelte +5 -4
  13. package/dist/components/ComboboxField.svelte +3 -3
  14. package/dist/components/CommandPalette.svelte +3 -3
  15. package/dist/components/CopilotPanel.svelte +2 -2
  16. package/dist/components/CreatePage.svelte +0 -1
  17. package/dist/components/DevTools.svelte +4 -3
  18. package/dist/components/DraggableHeader.svelte +2 -1
  19. package/dist/components/EditPage.svelte +1 -1
  20. package/dist/components/EmptyState.svelte +1 -1
  21. package/dist/components/FieldRenderer.svelte +7 -6
  22. package/dist/components/Header.svelte +1 -0
  23. package/dist/components/InferencerPanel.svelte +4 -3
  24. package/dist/components/InfiniteList.svelte +3 -4
  25. package/dist/components/KeyboardShortcuts.svelte +3 -3
  26. package/dist/components/Layout.svelte +5 -5
  27. package/dist/components/MarkdownRenderer.svelte +3 -5
  28. package/dist/components/ModalForm.svelte +1 -3
  29. package/dist/components/PageSkeleton.svelte +4 -4
  30. package/dist/components/PasswordInput.svelte +1 -2
  31. package/dist/components/PermissionMatrix.svelte +5 -5
  32. package/dist/components/ProfilePage.svelte +1 -1
  33. package/dist/components/RolesSettings.svelte +1 -2
  34. package/dist/components/SettingsPage.svelte +4 -5
  35. package/dist/components/ShowPage.svelte +4 -6
  36. package/dist/components/Sidebar.svelte +12 -11
  37. package/dist/components/SidebarItem.svelte +1 -2
  38. package/dist/components/StepsForm.svelte +1 -1
  39. package/dist/components/TaskList.svelte +1 -1
  40. package/dist/components/TaskQueueDrawer.svelte +2 -1
  41. package/dist/components/TenantSwitcher.svelte +1 -2
  42. package/dist/components/Toast.svelte +1 -0
  43. package/dist/components/TooltipButton.svelte +1 -0
  44. package/dist/components/VirtualTable.svelte +1 -1
  45. package/dist/components/VoiceInput.svelte +1 -0
  46. package/dist/components/buttons/ImportButton.svelte +1 -1
  47. package/dist/components/buttons/ListButton.svelte +1 -1
  48. package/dist/components/charts/BarChart.svelte +1 -1
  49. package/dist/components/charts/LineChart.svelte +3 -3
  50. package/dist/components/charts/PieChart.svelte +2 -2
  51. package/dist/components/fieldComponentMap.js +2 -1
  52. package/dist/components/fields/ArrayField.svelte +1 -1
  53. package/dist/components/fields/MarkdownField.svelte +1 -0
  54. package/dist/components/fields/MultiSelectField.svelte +1 -1
  55. package/dist/components/fields/TagField.svelte +1 -1
  56. package/dist/components/ui/alert/index.js +1 -0
  57. package/dist/components/ui/badge/index.js +1 -0
  58. package/dist/components/ui/button/button.svelte +1 -0
  59. package/dist/components/ui/button/index.js +1 -0
  60. package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +1 -0
  61. package/dist/components/ui/dropdown-menu/dropdown-menu.svelte +1 -1
  62. package/dist/components/ui/sheet/sheet.svelte +1 -0
  63. package/dist/components/ui/tabs/tabs.svelte +1 -0
  64. package/package.json +13 -13
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable svelte/no-useless-children-snippet */
2
3
  import type { Snippet } from 'svelte';
3
4
  import { fade, fly } from 'svelte/transition';
4
5
  import Sidebar from './Sidebar.svelte';
@@ -13,7 +14,6 @@
13
14
  import { navigate } from '@svadmin/core/router';
14
15
  import { getPath } from '../router-state.svelte.js';
15
16
  import { Skeleton } from './ui/skeleton/index.js';
16
- import { Button } from './ui/button/index.js';
17
17
  import * as Sheet from './ui/sheet/index.js';
18
18
  import { Menu } from '@lucide/svelte';
19
19
  import { getComponentRegistry } from '../component-registry.svelte.js';
@@ -24,12 +24,12 @@
24
24
 
25
25
  let { children, title = 'Admin', menu, siteUrl, routeMode = 'auto' }: { children: Snippet; title?: string; menu?: MenuItem[]; siteUrl?: string; routeMode?: 'hash' | 'path' | 'auto' } = $props();
26
26
 
27
- let hasAuth = true;
27
+ let _hasAuth = true;
28
28
  let auth: ReturnType<typeof getAuthProvider> | null = null;
29
29
  try {
30
30
  auth = getAuthProvider();
31
31
  } catch {
32
- hasAuth = false;
32
+ _hasAuth = false;
33
33
  }
34
34
  let loading = $state(true);
35
35
  let identity = $state<Identity | null>(null);
@@ -108,7 +108,7 @@
108
108
  <div class="hidden md:block w-64 bg-sidebar/80 p-4 space-y-4">
109
109
  <Skeleton class="h-8 w-32" />
110
110
  <div class="space-y-2 mt-6">
111
- {#each Array(5) as _}
111
+ {#each Array(5) as _, _i (_i)}
112
112
  <Skeleton class="h-9 w-full rounded-lg" />
113
113
  {/each}
114
114
  </div>
@@ -116,7 +116,7 @@
116
116
  <div class="flex-1 p-8 space-y-6">
117
117
  <Skeleton class="h-8 w-48" />
118
118
  <div class="space-y-3">
119
- {#each Array(4) as _}
119
+ {#each Array(4) as _, _i (_i)}
120
120
  <Skeleton class="h-12 w-full" />
121
121
  {/each}
122
122
  </div>
@@ -1,10 +1,9 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable svelte/no-at-html-tags */
2
3
  import * as markedPkg from "marked";
3
4
  import * as markedHighlightPkg from "marked-highlight";
4
5
  import * as hljsPkg from "highlight.js";
5
6
  import * as DOMPurifyPkg from "isomorphic-dompurify";
6
- import { Check, Copy } from '@lucide/svelte';
7
- import { Button } from "./ui/button/index.js";
8
7
 
9
8
  const Marked = markedPkg.Marked;
10
9
  const markedHighlight = markedHighlightPkg.markedHighlight;
@@ -13,7 +12,6 @@
13
12
 
14
13
  // Only safely import css if hljs exists
15
14
  if (hljsModule && Object.keys(hljsModule).length > 0) {
16
- // @ts-ignore
17
15
  import("highlight.js/styles/github-dark.css").catch(() => {});
18
16
  }
19
17
 
@@ -44,7 +42,7 @@
44
42
  // Render HTML safely
45
43
  const html = $derived(
46
44
  hasMarkdownDeps
47
- ? DOMPurify.sanitize(markedObj!.parse(content || "") as string)
45
+ ? DOMPurify.sanitize(markedObj?.parse(content || "") as string)
48
46
  : `<div style="white-space: pre-wrap">${String(content || "").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</div>`
49
47
  );
50
48
 
@@ -75,7 +73,7 @@
75
73
  // We do this via action instead of raw string manipulation for safety
76
74
  function enhanceCodeBlocks(node: HTMLElement, _: string) {
77
75
  return {
78
- update(newHtml: string) {
76
+ update(_newHtml: string) {
79
77
  // Find all pre > code blocks that don't have wrappers yet
80
78
  const pres = node.querySelectorAll("pre:not(.enhanced)");
81
79
  pres.forEach((pre) => {
@@ -1,7 +1,5 @@
1
1
  <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
- import type { FieldDefinition } from '@svadmin/core';
4
- import { getResource, useForm } from '@svadmin/core';
2
+ import { getResource } from '@svadmin/core';
5
3
  import { t } from '@svadmin/core/i18n';
6
4
  import * as Dialog from './ui/dialog/index.js';
7
5
  import AutoForm from './AutoForm.svelte';
@@ -27,13 +27,13 @@
27
27
  {#if type === 'list'}
28
28
  <!-- Table Header -->
29
29
  <div class="flex gap-4 border-b pb-4">
30
- {#each Array(4) as _}
30
+ {#each Array(4) as _, _i (_i)}
31
31
  <Skeleton class="h-6 flex-1" />
32
32
  {/each}
33
33
  </div>
34
34
  <!-- Table Rows -->
35
35
  <div class="space-y-4">
36
- {#each Array(rows) as _}
36
+ {#each Array(rows) as _, _i (_i)}
37
37
  <div class="flex gap-4">
38
38
  <Skeleton class="h-6 flex-1" />
39
39
  <Skeleton class="h-6 flex-1" />
@@ -45,7 +45,7 @@
45
45
  {:else if type === 'show'}
46
46
  <!-- Key-Value pairs -->
47
47
  <div class="space-y-6">
48
- {#each Array(rows) as _}
48
+ {#each Array(rows) as _, _i (_i)}
49
49
  <div class="space-y-2">
50
50
  <Skeleton class="h-4 w-[100px]" />
51
51
  <Skeleton class="h-6 w-[250px]" />
@@ -55,7 +55,7 @@
55
55
  {:else if type === 'form'}
56
56
  <!-- Form Inputs -->
57
57
  <div class="space-y-6">
58
- {#each Array(rows) as _}
58
+ {#each Array(rows) as _, _i (_i)}
59
59
  <div class="space-y-2">
60
60
  <Skeleton class="h-4 w-[100px]" />
61
61
  <Skeleton class="h-10 w-full max-w-md" />
@@ -1,9 +1,8 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
3
  import { Input } from './ui/input/index.js';
3
- import { Button } from './ui/button/index.js';
4
4
  import TooltipButton from './TooltipButton.svelte';
5
5
  import { Label } from './ui/label/index.js';
6
- import { Progress } from './ui/progress/index.js';
7
6
  import { Lock, Eye, EyeOff } from '@lucide/svelte';
8
7
  import { t } from '@svadmin/core/i18n';
9
8
 
@@ -80,7 +80,7 @@
80
80
  <div class="w-full md:w-64 flex-shrink-0 bg-card rounded-xl shadow-sm border border-border p-4 flex flex-col">
81
81
  <h2 class="text-sm font-semibold text-muted-foreground uppercase tracking-wider mb-4 px-2">{t('permissions.roles') || 'Roles'}</h2>
82
82
  <div class="space-y-1 flex-1 overflow-y-auto">
83
- {#each roles as role}
83
+ {#each roles as role, _i (_i)}
84
84
  <button
85
85
  onclick={() => selectedRole = role.code}
86
86
  class="w-full text-left px-3 py-2.5 rounded-lg text-sm transition-all duration-200 {selectedRole === role.code ? 'bg-primary/10 text-primary font-medium shadow-sm ring-1 ring-primary/20' : 'text-foreground hover:bg-muted'}"
@@ -133,7 +133,7 @@
133
133
  <thead class="bg-muted/50">
134
134
  <tr>
135
135
  <th scope="col" class="py-3 pr-3 pl-4 text-left text-sm font-semibold text-foreground w-48">{t('permissions.resources') || 'Resources'}</th>
136
- {#each actions as action}
136
+ {#each actions as action, _i (_i)}
137
137
  <th scope="col" class="px-2 py-3 text-center text-sm font-semibold text-foreground">
138
138
  <div class="flex flex-col items-center">
139
139
  <span>{action.name}</span>
@@ -149,7 +149,7 @@
149
149
  <td colspan={actions.length + 1} class="py-10 text-center text-muted-foreground">{t('permissions.noResources') || 'No resources available'}</td>
150
150
  </tr>
151
151
  {/if}
152
- {#each resources as resource, i}
152
+ {#each resources as resource, i (i)}
153
153
  <!-- Section Grouping Header -->
154
154
  {#if resource.section && (i === 0 || resource.section !== resources[i-1].section)}
155
155
  <tr class="bg-primary/5">
@@ -164,14 +164,14 @@
164
164
  </td>
165
165
 
166
166
  <!-- Action Checkboxes -->
167
- {#each actions as action}
167
+ {#each actions as action, _i (_i)}
168
168
  {@const granted = selectedRole ? isGranted(selectedRole, resource.code, action.code) : false}
169
169
  <td class="whitespace-nowrap px-3 py-3 text-center">
170
170
  <div class="flex items-center justify-center">
171
171
  <button
172
172
  disabled={loading || !selectedRole}
173
173
  aria-label="Toggle {action.name}"
174
- onclick={() => onToggle(selectedRole!, resource.code, action.code, !granted)}
174
+ onclick={() => onToggle(selectedRole as string, resource.code, action.code, !granted)}
175
175
  class="w-6 h-6 rounded border flex items-center justify-center transition-all focus:outline-none focus:ring-2 focus:ring-primary/50 {granted ? 'bg-primary border-primary text-primary-foreground' : 'border-input bg-background hover:bg-accent'} {loading || !selectedRole ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}"
176
176
  >
177
177
  <svg class="w-3.5 h-3.5 {granted ? 'block' : 'hidden'}" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="3">
@@ -53,7 +53,7 @@
53
53
 
54
54
  // Avatar upload
55
55
  let avatarUploading = $state(false);
56
- let fileInput = $state<HTMLInputElement>(null!);
56
+ let fileInput = $state<HTMLInputElement>(null!); // eslint-disable-line @typescript-eslint/no-non-null-assertion
57
57
 
58
58
  async function handleAvatarChange(e: Event) {
59
59
  const file = (e.target as HTMLInputElement).files?.[0];
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { t } from '@svadmin/core/i18n';
3
3
  import { getAuthProvider, getResources } from '@svadmin/core';
4
- import type { Role } from '@svadmin/core';
5
4
  import PermissionMatrix from './PermissionMatrix.svelte';
6
5
  import type { RoleInfo, ResourceInfo, ActionInfo } from '../types.js';
7
6
  import { toast } from '@svadmin/core/toast';
@@ -117,7 +116,7 @@
117
116
  } catch (e) {
118
117
  toast.error((e as Error).message);
119
118
  // Rollback on fail
120
- delete permissionsCache[roleCode];
119
+ delete permissionsCache[roleCode]; // eslint-disable-line @typescript-eslint/no-dynamic-delete
121
120
  loadPermissionsForRole(roleCode);
122
121
  } finally {
123
122
  saving = false;
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { t } from '@svadmin/core/i18n';
3
3
  import { navigate } from '@svadmin/core/router';
4
- import { currentPath } from '@svadmin/core/router';
5
4
  import { User, Palette, Info, Shield, FileSearch } from '@lucide/svelte';
6
5
  import ProfilePage from './ProfilePage.svelte';
7
6
  import AppearanceSettings from './AppearanceSettings.svelte';
@@ -56,8 +55,8 @@
56
55
  <nav class="w-full lg:w-56 shrink-0 bg-muted/10 shadow-[inset_0_-1px_0_rgba(0,0,0,0.05)] lg:shadow-[inset_-1px_0_0_rgba(0,0,0,0.05)] dark:shadow-[inset_-1px_0_0_rgba(255,255,255,0.05)]">
57
56
  <!-- Mobile: horizontal scroll tabs -->
58
57
  <div class="flex lg:hidden overflow-x-auto px-4 py-2 gap-1">
59
- {#each sections as section}
60
- {#each section.items as item}
58
+ {#each sections as section, _i (_i)}
59
+ {#each section.items as item, _i (_i)}
61
60
  {@const active = activeKey === item.key}
62
61
  <button
63
62
  class="flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md whitespace-nowrap transition-colors
@@ -77,13 +76,13 @@
77
76
  <h2 class="text-lg font-semibold text-foreground">{t('settings.title')}</h2>
78
77
  <p class="text-xs text-muted-foreground mt-1">{t('settings.settingsDescription')}</p>
79
78
  </div>
80
- {#each sections as section}
79
+ {#each sections as section, _i (_i)}
81
80
  <div>
82
81
  <h3 class="px-3 mb-1 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/60">
83
82
  {t(section.group)}
84
83
  </h3>
85
84
  <div class="space-y-0.5">
86
- {#each section.items as item}
85
+ {#each section.items as item, _i (_i)}
87
86
  {@const active = activeKey === item.key}
88
87
  <button
89
88
  class="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm transition-all
@@ -1,9 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { useShow, getResource } from '@svadmin/core';
3
- import type { FieldDefinition } from '@svadmin/core';
4
3
  import { navigate } from '@svadmin/core/router';
5
- import { t, getLocale } from '@svadmin/core/i18n';
6
- import { Button } from './ui/button/index.js';
4
+ import { t } from '@svadmin/core/i18n';
7
5
  import * as Card from './ui/card/index.js';
8
6
  import { Skeleton } from './ui/skeleton/index.js';
9
7
  import PageHeader from './PageHeader.svelte';
@@ -42,7 +40,7 @@
42
40
  {#if query.isLoading}
43
41
  <Card.Root class="overflow-hidden border-border/40 shadow-sm">
44
42
  <Card.Content class="p-0">
45
- {#each showFields.slice(0, 6) as _, i}
43
+ {#each showFields.slice(0, 6) as _, i (i)}
46
44
  <div class="flex flex-col sm:flex-row px-4 sm:px-6 py-3 sm:py-4 {i % 2 === 1 ? 'bg-muted/20' : ''}">
47
45
  <Skeleton class="h-4 w-1/2 sm:w-1/4" />
48
46
  <Skeleton class="h-4 w-3/4 sm:w-2/5 mt-1 sm:mt-0 sm:ml-auto" />
@@ -53,8 +51,8 @@
53
51
  {:else if query.data?.data}
54
52
  <Card.Root class="overflow-hidden border-border/40 shadow-sm">
55
53
  <Card.Content class="p-0">
56
- {#each showFields as field, i}
57
- {@const value = (query.data!.data as Record<string, unknown>)[field.key]}
54
+ {#each showFields as field, i (i)}
55
+ {@const value = ((query.data as { data: Record<string, unknown> }).data as Record<string, unknown>)[field.key]}
58
56
  {@const DisplayComponent = getDisplayComponent(field.type)}
59
57
  <div class="flex flex-col sm:flex-row px-4 sm:px-6 py-3 sm:py-4 {i % 2 === 1 ? 'bg-muted/20' : ''}">
60
58
  <div class="sm:w-1/3 text-xs sm:text-sm font-medium text-muted-foreground mb-1 sm:mb-0">{field.label}</div>
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable svelte/prefer-svelte-reactivity */
2
3
  import { getResources, canAccessAsync } from '@svadmin/core';
3
4
  import type { Identity, MenuItem } from '@svadmin/core';
4
5
  import { navigate } from '@svadmin/core/router';
@@ -37,7 +38,7 @@
37
38
  : routeMode
38
39
  );
39
40
 
40
- const resources = getResources();
41
+ const _resources = getResources();
41
42
 
42
43
  const iconMap: Record<string, typeof LayoutDashboard> = {
43
44
  'dashboard': LayoutDashboard,
@@ -80,7 +81,7 @@
80
81
  let navItems = $state.raw<NavItem[]>([]);
81
82
 
82
83
  $effect(() => {
83
- const localeVal = getLocale();
84
+ const _localeVal = getLocale();
84
85
  const currentResources = getResources();
85
86
  let cancelled = false;
86
87
 
@@ -132,7 +133,7 @@
132
133
 
133
134
  /** Prefetch resource data on hover for instant navigation */
134
135
  const prefetchedResources = new Set<string>();
135
- function prefetchResource(resourceName: string) {
136
+ function _prefetchResource(resourceName: string) {
136
137
  if (resourceName === '/' || prefetchedResources.has(resourceName)) return;
137
138
  prefetchedResources.add(resourceName);
138
139
  // Trigger a background fetch by navigating the browser cache
@@ -148,9 +149,9 @@
148
149
  const key = item.group ?? null;
149
150
  if (!groupMap.has(key)) {
150
151
  groupMap.set(key, []);
151
- groups.push({ name: key, items: groupMap.get(key)! });
152
+ groups.push({ name: key, items: groupMap.get(key) ?? [] });
152
153
  }
153
- groupMap.get(key)!.push(item);
154
+ (groupMap.get(key) ?? []).push(item);
154
155
  }
155
156
 
156
157
  return groups;
@@ -233,17 +234,17 @@
233
234
  <nav aria-label="Main menu" class="py-4 px-3 space-y-1">
234
235
  {#if menu && menu.length > 0}
235
236
  <!-- Custom multi-level menu -->
236
- {#each menu as item}
237
+ {#each menu as item, _i (_i)}
237
238
  <SidebarItem {item} currentPath={path} {collapsed} depth={0} />
238
239
  {/each}
239
240
  {:else}
240
241
  <!-- Auto-generated menu from resources (fallback) -->
241
- {#each navGroups as group}
242
+ {#each navGroups as group, _i (_i)}
242
243
  {#if group.name && !collapsed}
243
244
  <!-- Grouped section with Collapsible -->
244
245
  <Collapsible.Root open={openGroups.has(group.name)} onOpenChange={(isOpen) => {
245
246
  const next = new Set(openGroups);
246
- if (isOpen) next.add(group.name!); else next.delete(group.name!);
247
+ if (isOpen) next.add(group.name as string); else next.delete(group.name as string);
247
248
  openGroups = next;
248
249
  }}>
249
250
  <Collapsible.Trigger
@@ -254,7 +255,7 @@
254
255
  </Collapsible.Trigger>
255
256
  <Collapsible.Content>
256
257
  <div class="mt-1 space-y-1">
257
- {#each group.items as item}
258
+ {#each group.items as item, _i (_i)}
258
259
  {@const active = isActive(item.path)}
259
260
  <a
260
261
  href={effectiveRouteMode === 'hash' ? `#${item.path}` : item.path}
@@ -273,7 +274,7 @@
273
274
  </Collapsible.Root>
274
275
  {:else}
275
276
  <!-- Ungrouped items (flat) -->
276
- {#each group.items as item}
277
+ {#each group.items as item, _i (_i)}
277
278
  {@const active = isActive(item.path)}
278
279
  {#if collapsed}
279
280
  <Tooltip.Root>
@@ -336,7 +337,7 @@
336
337
  </Button>
337
338
  {#if colorPickerOpen}
338
339
  <div class="absolute bottom-full left-0 mb-1 z-50 w-40 rounded-lg border bg-popover p-1 text-popover-foreground shadow-lg animate-in fade-in-0 zoom-in-95">
339
- {#each getColorThemes() as ct}
340
+ {#each getColorThemes() as ct, _i (_i)}
340
341
  <button
341
342
  class="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground transition-colors"
342
343
  onclick={() => { setColorTheme(ct.id as typeof ct.id & import('@svadmin/core').ColorTheme); colorPickerOpen = false; }}
@@ -1,6 +1,5 @@
1
1
  <script lang="ts">
2
2
  import type { MenuItem } from '@svadmin/core';
3
- import { t } from '@svadmin/core/i18n';
4
3
  import * as Collapsible from './ui/collapsible/index.js';
5
4
  import * as Tooltip from './ui/tooltip/index.js';
6
5
  import SidebarItem from './SidebarItem.svelte';
@@ -84,7 +83,7 @@
84
83
  </Collapsible.Trigger>
85
84
  <Collapsible.Content>
86
85
  <div class="mt-0.5 space-y-0.5" style="padding-left: {depth > 0 ? 0 : 0}px">
87
- {#each item.children as child}
86
+ {#each item.children as child, _i (_i)}
88
87
  <SidebarItem item={child} {currentPath} {collapsed} depth={depth + 1} />
89
88
  {/each}
90
89
  </div>
@@ -111,7 +111,7 @@
111
111
  <!-- Step indicators -->
112
112
  <div class="space-y-3">
113
113
  <div class="flex items-center justify-between text-sm">
114
- {#each steps as step, i}
114
+ {#each steps as step, i (i)}
115
115
  <Button
116
116
  variant="ghost"
117
117
  type="button"
@@ -110,7 +110,7 @@
110
110
  </Table.Row>
111
111
  </Table.Header>
112
112
  <Table.Body>
113
- {#each resolvedTasks as task}
113
+ {#each resolvedTasks as task, _i (_i)}
114
114
  <Table.Row class="cursor-pointer hover:bg-muted/40" onclick={() => onSelect?.(task)}>
115
115
  <Table.Cell class="min-w-[240px]">
116
116
  <div class="space-y-1">
@@ -36,6 +36,7 @@
36
36
  initialTab?: TaskTab;
37
37
  } = $props();
38
38
 
39
+ // eslint-disable-next-line svelte/prefer-writable-derived
39
40
  let activeTab = $state<TaskTab>('tasks');
40
41
  let selectedTaskId = $state<string | null>(null);
41
42
  let searchQuery = $state('');
@@ -283,7 +284,7 @@
283
284
  </div>
284
285
  <Select bind:value={statusFilter} aria-label={t('task.statusFilterLabel')}>
285
286
  <option value="all">{t('task.statusAll')}</option>
286
- {#each availableStatuses as status}
287
+ {#each availableStatuses as status, _i (_i)}
287
288
  <option value={status}>{status}</option>
288
289
  {/each}
289
290
  </Select>
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import { ChevronsUpDown, Building2, Check } from '@lucide/svelte';
4
- import { Button } from './ui/button/index.js';
5
4
  import * as DropdownMenu from './ui/dropdown-menu/index.js';
6
5
  import type { Tenant } from '../types.js';
7
6
 
@@ -61,7 +60,7 @@
61
60
  <DropdownMenu.Separator />
62
61
  {/if}
63
62
  <div class="px-2 py-1.5 text-xs text-muted-foreground">Workspaces</div>
64
- {#each tenants as tenant}
63
+ {#each tenants as tenant, _i (_i)}
65
64
  <DropdownMenu.Item
66
65
  class="flex items-center gap-3 cursor-pointer"
67
66
  onclick={() => selectTenant(tenant.id)}
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
3
  import { Toaster, toast as sonner } from 'sonner-svelte';
3
4
  import { getResolvedTheme, getToastQueue, consumeToastQueue, getPromiseQueue, consumePromiseQueue } from '@svadmin/core';
4
5
 
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
3
  import * as Tooltip from './ui/tooltip/index.js';
3
4
  import { Button } from './ui/button/index.js';
4
5
  import type { Snippet } from 'svelte';
@@ -37,7 +37,7 @@
37
37
  let scrollTop = $state(0);
38
38
  let containerRef = $state<HTMLDivElement | null>(null);
39
39
 
40
- const totalHeight = $derived(items.length * rowHeight);
40
+ const _totalHeight = $derived(items.length * rowHeight);
41
41
 
42
42
  const visibleRange = $derived.by(() => {
43
43
  const start = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable no-undef */
2
3
  import { Mic, MicOff, Loader2 } from '@lucide/svelte';
3
4
  import TooltipButton from './TooltipButton.svelte';
4
5
 
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { useImport, useCan, t, type UseImportOptions } from '@svadmin/core';
2
+ import { useImport, useCan, t } from '@svadmin/core';
3
3
  import { Button } from '../ui/button/index.js';
4
4
  import { Upload } from '@lucide/svelte';
5
5
 
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { useNavigation, t } from '@svadmin/core';
2
+ import { useNavigation } from '@svadmin/core';
3
3
  import { Button } from '../ui/button/index.js';
4
4
  import { List } from '@lucide/svelte';
5
5
 
@@ -24,7 +24,7 @@
24
24
  <div class="w-full overflow-x-auto {className}">
25
25
  <svg viewBox="0 0 {totalWidth} {height + 30}" class="w-full" style="min-width: {Math.min(totalWidth, 300)}px;">
26
26
  <!-- Bars -->
27
- {#each data as point, i}
27
+ {#each data as point, i (i)}
28
28
  {@const barHeight = (point.value / maxValue) * (height - 20)}
29
29
  {@const x = 20 + i * (barWidth + gap)}
30
30
  {@const y = height - barHeight}
@@ -46,7 +46,7 @@
46
46
  <div class="w-full overflow-x-auto {className}">
47
47
  <svg viewBox="0 0 {chartWidth} {height}" class="w-full" style="min-width: {Math.min(chartWidth, 300)}px;">
48
48
  <!-- Grid lines -->
49
- {#each [0, 0.25, 0.5, 0.75, 1] as ratio}
49
+ {#each [0, 0.25, 0.5, 0.75, 1] as ratio, _i (_i)}
50
50
  {@const y = padding.top + chartHeight * (1 - ratio)}
51
51
  <line
52
52
  x1={padding.left}
@@ -88,7 +88,7 @@
88
88
 
89
89
  <!-- Dots -->
90
90
  {#if showDots}
91
- {#each data as point, i}
91
+ {#each data as point, i (i)}
92
92
  <circle
93
93
  cx={getX(i)}
94
94
  cy={getY(point.value)}
@@ -102,7 +102,7 @@
102
102
  {/if}
103
103
 
104
104
  <!-- X-axis labels -->
105
- {#each data as point, i}
105
+ {#each data as point, i (i)}
106
106
  <text
107
107
  x={getX(i)}
108
108
  y={height - 4}
@@ -59,7 +59,7 @@
59
59
 
60
60
  <div class="inline-flex flex-col items-center gap-3 {className}">
61
61
  <svg viewBox="0 0 {size} {size}" width={size} height={size}>
62
- {#each slices as slice, i}
62
+ {#each slices as slice, i (i)}
63
63
  <path
64
64
  d={getArcPath(slice.startAngle, slice.endAngle, radius, innerRadius)}
65
65
  fill={slice.color}
@@ -84,7 +84,7 @@
84
84
 
85
85
  <!-- Legend -->
86
86
  <div class="flex flex-wrap justify-center gap-x-4 gap-y-1">
87
- {#each slices as slice}
87
+ {#each slices as slice, _i (_i)}
88
88
  <div class="flex items-center gap-1.5 text-xs">
89
89
  <span class="h-2.5 w-2.5 rounded-full" style="background-color: {slice.color};"></span>
90
90
  <span class="text-muted-foreground">{slice.label}</span>
@@ -1,9 +1,10 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  // Shared field type → display component mapping
2
3
  // Used by both ShowPage and FieldRenderer to avoid duplicate if/else chains.
3
4
  // Components are lazily resolved by field type at runtime.
4
5
  // Default display component map (read-only field display)
5
6
  // Dynamically imports components only when first used
6
- const displayCache = new Map();
7
+ const _displayCache = new Map();
7
8
  // Pre-import all field display components (tree-shaken by bundler)
8
9
  import BooleanField from './fields/BooleanField.svelte';
9
10
  import ImageField from './fields/ImageField.svelte';
@@ -59,7 +59,7 @@
59
59
  </div>
60
60
 
61
61
  <div class="space-y-4 pt-2">
62
- {#each arrayVal as item, i}
62
+ {#each arrayVal as item, i (i)}
63
63
  <div class="relative rounded-md border bg-card p-4 pt-6 shadow-sm">
64
64
  <div class="absolute right-2 top-2">
65
65
  <TooltipButton tooltip={t('common.remove') || 'Remove'} variant="ghost" size="icon" class="h-8 w-8 text-muted-foreground hover:text-destructive transition-colors" onclick={() => handleRemove(i)}>
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable svelte/no-at-html-tags */
2
3
  import * as DOMPurifyPkg from "isomorphic-dompurify";
3
4
  interface Props { value: string | null | undefined }
4
5
  let { value }: Props = $props();
@@ -11,7 +11,7 @@
11
11
 
12
12
  {#if items.length > 0}
13
13
  <div class="flex flex-wrap gap-1">
14
- {#each items as v}
14
+ {#each items as v, _i (_i)}
15
15
  {@const label = options?.find((o: { label: string; value: string | number }) => o.value === v)?.label ?? String(v)}
16
16
  <Badge variant="secondary" class="font-normal">{label}</Badge>
17
17
  {/each}
@@ -5,7 +5,7 @@
5
5
  const tags = $derived(Array.isArray(value) ? value : value ? [value] : []);
6
6
  </script>
7
7
  <span class="inline-flex flex-wrap gap-1">
8
- {#each tags as tag}
8
+ {#each tags as tag, _i (_i)}
9
9
  <Badge variant="secondary">{tag}</Badge>
10
10
  {/each}
11
11
  {#if tags.length === 0}<span class="text-muted-foreground">—</span>{/if}
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
1
2
  // @ts-nocheck
2
3
  import Alert, { alertVariants } from "./alert.svelte";
3
4
  import AlertTitle from "./alert-title.svelte";
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
1
2
  // @ts-nocheck
2
3
  export { default as Badge } from "./badge.svelte";
3
4
  export { badgeVariants } from "./badge.svelte";
@@ -42,6 +42,7 @@
42
42
  </script>
43
43
 
44
44
  <script lang="ts">
45
+ /* eslint-disable no-useless-assignment, @typescript-eslint/no-explicit-any */
45
46
  let {
46
47
  class: className,
47
48
  variant = "default",
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
1
2
  // @ts-nocheck
2
3
  import Root, { buttonVariants, } from "./button.svelte";
3
4
  export { Root,
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
3
  import { cn, type WithElementRef } from "../../../utils.js";
3
4
  import type { HTMLButtonAttributes } from "svelte/elements";
4
5
  import { getContext } from "svelte";