@svadmin/ui 0.29.1 → 0.29.3

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 (224) hide show
  1. package/package.json +20 -9
  2. package/src/README.md +0 -18
  3. package/src/actions.ts +0 -110
  4. package/src/app.css +0 -673
  5. package/src/component-registry.svelte.ts +0 -60
  6. package/src/components/AICommandBar.svelte +0 -180
  7. package/src/components/AboutSettings.svelte +0 -106
  8. package/src/components/AdminApp.svelte +0 -199
  9. package/src/components/AnimatedCounter.svelte +0 -46
  10. package/src/components/AnomalyBadge.svelte +0 -65
  11. package/src/components/AppearanceSettings.svelte +0 -183
  12. package/src/components/AuditLogDrawer.svelte +0 -93
  13. package/src/components/AuditLogViewer.svelte +0 -226
  14. package/src/components/Authenticated.svelte +0 -51
  15. package/src/components/AutoForm.svelte +0 -242
  16. package/src/components/AutoSaveIndicator.svelte +0 -35
  17. package/src/components/AutoTable.svelte +0 -839
  18. package/src/components/Breadcrumbs.svelte +0 -58
  19. package/src/components/CanAccess.svelte +0 -23
  20. package/src/components/CatchAllNavigate.svelte +0 -21
  21. package/src/components/ChatDialog.svelte +0 -535
  22. package/src/components/ComboboxField.svelte +0 -129
  23. package/src/components/CommandPalette.svelte +0 -135
  24. package/src/components/ConfigErrorScreen.svelte +0 -126
  25. package/src/components/ConfirmDialog.svelte +0 -53
  26. package/src/components/CopilotPanel.svelte +0 -163
  27. package/src/components/CreatePage.svelte +0 -39
  28. package/src/components/DevTools.svelte +0 -149
  29. package/src/components/DraggableGrid.svelte +0 -86
  30. package/src/components/DraggableHeader.svelte +0 -112
  31. package/src/components/DrawerForm.svelte +0 -35
  32. package/src/components/EditPage.svelte +0 -52
  33. package/src/components/EmptyState.svelte +0 -31
  34. package/src/components/ErrorBoundary.svelte +0 -49
  35. package/src/components/ErrorComponent.svelte +0 -36
  36. package/src/components/FieldRenderer.svelte +0 -357
  37. package/src/components/ForgotPasswordPage.svelte +0 -112
  38. package/src/components/Header.svelte +0 -94
  39. package/src/components/InferencerPanel.svelte +0 -192
  40. package/src/components/InfiniteList.svelte +0 -93
  41. package/src/components/InlineEdit.svelte +0 -88
  42. package/src/components/InsightCard.svelte +0 -98
  43. package/src/components/KeyboardShortcuts.svelte +0 -61
  44. package/src/components/Layout.svelte +0 -167
  45. package/src/components/ListPage.svelte +0 -71
  46. package/src/components/LiveIndicator.svelte +0 -58
  47. package/src/components/LoginPage.svelte +0 -163
  48. package/src/components/MarkdownRenderer.svelte +0 -127
  49. package/src/components/ModalForm.svelte +0 -38
  50. package/src/components/NavigateToResource.svelte +0 -20
  51. package/src/components/PageHeader.svelte +0 -39
  52. package/src/components/PageSkeleton.svelte +0 -71
  53. package/src/components/PasswordInput.svelte +0 -96
  54. package/src/components/PermissionMatrix.svelte +0 -185
  55. package/src/components/ProfilePage.svelte +0 -284
  56. package/src/components/RegisterPage.svelte +0 -112
  57. package/src/components/RolesSettings.svelte +0 -146
  58. package/src/components/SettingsPage.svelte +0 -113
  59. package/src/components/ShowPage.svelte +0 -73
  60. package/src/components/Sidebar.svelte +0 -417
  61. package/src/components/SidebarItem.svelte +0 -129
  62. package/src/components/SmartSuggest.svelte +0 -158
  63. package/src/components/StatsCard.svelte +0 -79
  64. package/src/components/StepsForm.svelte +0 -192
  65. package/src/components/TaskQueueDrawer.svelte +0 -158
  66. package/src/components/TenantSwitcher.svelte +0 -84
  67. package/src/components/ThemedTitle.svelte +0 -32
  68. package/src/components/Toast.svelte +0 -46
  69. package/src/components/TooltipButton.svelte +0 -42
  70. package/src/components/UndoableNotification.svelte +0 -69
  71. package/src/components/UpdatePasswordPage.svelte +0 -89
  72. package/src/components/VirtualTable.svelte +0 -76
  73. package/src/components/VoiceInput.svelte +0 -120
  74. package/src/components/buttons/CloneButton.svelte +0 -30
  75. package/src/components/buttons/CreateButton.svelte +0 -29
  76. package/src/components/buttons/DeleteButton.svelte +0 -59
  77. package/src/components/buttons/EditButton.svelte +0 -30
  78. package/src/components/buttons/ExportButton.svelte +0 -30
  79. package/src/components/buttons/ImportButton.svelte +0 -56
  80. package/src/components/buttons/ListButton.svelte +0 -23
  81. package/src/components/buttons/RefreshButton.svelte +0 -36
  82. package/src/components/buttons/SaveButton.svelte +0 -27
  83. package/src/components/buttons/ShowButton.svelte +0 -31
  84. package/src/components/buttons/index.ts +0 -10
  85. package/src/components/charts/BarChart.svelte +0 -69
  86. package/src/components/charts/LineChart.svelte +0 -115
  87. package/src/components/charts/PieChart.svelte +0 -95
  88. package/src/components/charts/index.ts +0 -3
  89. package/src/components/fieldComponentMap.ts +0 -79
  90. package/src/components/fields/ArrayField.svelte +0 -86
  91. package/src/components/fields/BooleanField.svelte +0 -13
  92. package/src/components/fields/DateField.svelte +0 -6
  93. package/src/components/fields/EmailField.svelte +0 -9
  94. package/src/components/fields/FileField.svelte +0 -14
  95. package/src/components/fields/ImageField.svelte +0 -9
  96. package/src/components/fields/JsonField.svelte +0 -72
  97. package/src/components/fields/MarkdownField.svelte +0 -9
  98. package/src/components/fields/MultiSelectField.svelte +0 -21
  99. package/src/components/fields/NumberField.svelte +0 -6
  100. package/src/components/fields/RelationField.svelte +0 -24
  101. package/src/components/fields/RichTextField.svelte +0 -35
  102. package/src/components/fields/SelectField.svelte +0 -14
  103. package/src/components/fields/TagField.svelte +0 -12
  104. package/src/components/fields/TextField.svelte +0 -11
  105. package/src/components/fields/UrlField.svelte +0 -14
  106. package/src/components/ui/alert/alert-description.svelte +0 -17
  107. package/src/components/ui/alert/alert-title.svelte +0 -17
  108. package/src/components/ui/alert/alert.svelte +0 -44
  109. package/src/components/ui/alert/index.ts +0 -15
  110. package/src/components/ui/alert-dialog/alert-dialog-content.svelte +0 -29
  111. package/src/components/ui/alert-dialog/alert-dialog-description.svelte +0 -16
  112. package/src/components/ui/alert-dialog/alert-dialog-footer.svelte +0 -11
  113. package/src/components/ui/alert-dialog/alert-dialog-header.svelte +0 -11
  114. package/src/components/ui/alert-dialog/alert-dialog-overlay.svelte +0 -16
  115. package/src/components/ui/alert-dialog/alert-dialog-portal.svelte +0 -6
  116. package/src/components/ui/alert-dialog/alert-dialog-title.svelte +0 -16
  117. package/src/components/ui/alert-dialog/index.ts +0 -20
  118. package/src/components/ui/avatar/avatar.svelte +0 -63
  119. package/src/components/ui/avatar/index.ts +0 -2
  120. package/src/components/ui/badge/badge.svelte +0 -49
  121. package/src/components/ui/badge/index.ts +0 -3
  122. package/src/components/ui/breadcrumb/breadcrumb-ellipsis.svelte +0 -18
  123. package/src/components/ui/breadcrumb/breadcrumb-item.svelte +0 -15
  124. package/src/components/ui/breadcrumb/breadcrumb-link.svelte +0 -15
  125. package/src/components/ui/breadcrumb/breadcrumb-list.svelte +0 -15
  126. package/src/components/ui/breadcrumb/breadcrumb-page.svelte +0 -18
  127. package/src/components/ui/breadcrumb/breadcrumb-separator.svelte +0 -22
  128. package/src/components/ui/breadcrumb/breadcrumb.svelte +0 -11
  129. package/src/components/ui/breadcrumb/index.ts +0 -7
  130. package/src/components/ui/button/button.svelte +0 -90
  131. package/src/components/ui/button/index.ts +0 -18
  132. package/src/components/ui/card/card-action.svelte +0 -23
  133. package/src/components/ui/card/card-content.svelte +0 -20
  134. package/src/components/ui/card/card-description.svelte +0 -20
  135. package/src/components/ui/card/card-footer.svelte +0 -20
  136. package/src/components/ui/card/card-header.svelte +0 -23
  137. package/src/components/ui/card/card-title.svelte +0 -15
  138. package/src/components/ui/card/card.svelte +0 -22
  139. package/src/components/ui/card/index.ts +0 -25
  140. package/src/components/ui/checkbox/checkbox.svelte +0 -39
  141. package/src/components/ui/checkbox/index.ts +0 -6
  142. package/src/components/ui/collapsible/index.ts +0 -7
  143. package/src/components/ui/command/command-dialog.svelte +0 -31
  144. package/src/components/ui/command/index.ts +0 -2
  145. package/src/components/ui/context-menu/index.ts +0 -11
  146. package/src/components/ui/dialog/dialog-close.svelte +0 -11
  147. package/src/components/ui/dialog/dialog-content.svelte +0 -48
  148. package/src/components/ui/dialog/dialog-description.svelte +0 -17
  149. package/src/components/ui/dialog/dialog-footer.svelte +0 -32
  150. package/src/components/ui/dialog/dialog-header.svelte +0 -20
  151. package/src/components/ui/dialog/dialog-overlay.svelte +0 -17
  152. package/src/components/ui/dialog/dialog-portal.svelte +0 -7
  153. package/src/components/ui/dialog/dialog-title.svelte +0 -17
  154. package/src/components/ui/dialog/dialog-trigger.svelte +0 -11
  155. package/src/components/ui/dialog/dialog.svelte +0 -7
  156. package/src/components/ui/dialog/index.ts +0 -34
  157. package/src/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -43
  158. package/src/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -35
  159. package/src/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -36
  160. package/src/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -10
  161. package/src/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -27
  162. package/src/components/ui/dropdown-menu/dropdown-menu.svelte +0 -45
  163. package/src/components/ui/dropdown-menu/index.ts +0 -21
  164. package/src/components/ui/input/index.ts +0 -7
  165. package/src/components/ui/input/input.svelte +0 -48
  166. package/src/components/ui/label/index.ts +0 -1
  167. package/src/components/ui/label/label.svelte +0 -18
  168. package/src/components/ui/pagination/index.ts +0 -7
  169. package/src/components/ui/pagination/pagination-content.svelte +0 -11
  170. package/src/components/ui/pagination/pagination-ellipsis.svelte +0 -12
  171. package/src/components/ui/pagination/pagination-item.svelte +0 -11
  172. package/src/components/ui/pagination/pagination-link.svelte +0 -26
  173. package/src/components/ui/pagination/pagination-next.svelte +0 -22
  174. package/src/components/ui/pagination/pagination-previous.svelte +0 -22
  175. package/src/components/ui/pagination/pagination.svelte +0 -11
  176. package/src/components/ui/popover/index.ts +0 -12
  177. package/src/components/ui/popover/popover-content.svelte +0 -25
  178. package/src/components/ui/progress/index.ts +0 -1
  179. package/src/components/ui/progress/progress.svelte +0 -22
  180. package/src/components/ui/scroll-area/index.ts +0 -1
  181. package/src/components/ui/scroll-area/scroll-area.svelte +0 -20
  182. package/src/components/ui/select/index.ts +0 -2
  183. package/src/components/ui/select/select.svelte +0 -36
  184. package/src/components/ui/separator/index.ts +0 -7
  185. package/src/components/ui/separator/separator.svelte +0 -23
  186. package/src/components/ui/sheet/index.ts +0 -16
  187. package/src/components/ui/sheet/sheet-content.svelte +0 -28
  188. package/src/components/ui/sheet/sheet-description.svelte +0 -22
  189. package/src/components/ui/sheet/sheet-footer.svelte +0 -22
  190. package/src/components/ui/sheet/sheet-header.svelte +0 -22
  191. package/src/components/ui/sheet/sheet-title.svelte +0 -22
  192. package/src/components/ui/sheet/sheet.svelte +0 -78
  193. package/src/components/ui/skeleton/index.ts +0 -2
  194. package/src/components/ui/skeleton/skeleton.svelte +0 -21
  195. package/src/components/ui/switch/index.ts +0 -2
  196. package/src/components/ui/switch/switch.svelte +0 -49
  197. package/src/components/ui/table/index.ts +0 -28
  198. package/src/components/ui/table/table-body.svelte +0 -15
  199. package/src/components/ui/table/table-caption.svelte +0 -20
  200. package/src/components/ui/table/table-cell.svelte +0 -15
  201. package/src/components/ui/table/table-footer.svelte +0 -20
  202. package/src/components/ui/table/table-head.svelte +0 -15
  203. package/src/components/ui/table/table-header.svelte +0 -20
  204. package/src/components/ui/table/table-row.svelte +0 -15
  205. package/src/components/ui/table/table.svelte +0 -17
  206. package/src/components/ui/tabs/index.ts +0 -15
  207. package/src/components/ui/tabs/tabs-content.svelte +0 -30
  208. package/src/components/ui/tabs/tabs-list.svelte +0 -26
  209. package/src/components/ui/tabs/tabs-trigger.svelte +0 -37
  210. package/src/components/ui/tabs/tabs.svelte +0 -27
  211. package/src/components/ui/textarea/index.ts +0 -2
  212. package/src/components/ui/textarea/textarea.svelte +0 -24
  213. package/src/components/ui/tooltip/index.ts +0 -19
  214. package/src/components/ui/tooltip/tooltip-content.svelte +0 -52
  215. package/src/components/ui/tooltip/tooltip-portal.svelte +0 -7
  216. package/src/components/ui/tooltip/tooltip-provider.svelte +0 -7
  217. package/src/components/ui/tooltip/tooltip-trigger.svelte +0 -7
  218. package/src/components/ui/tooltip/tooltip.svelte +0 -10
  219. package/src/editor-config.svelte.ts +0 -23
  220. package/src/index.ts +0 -155
  221. package/src/markdown-deps.d.ts +0 -21
  222. package/src/router-state.svelte.ts +0 -65
  223. package/src/types.ts +0 -33
  224. package/src/utils.ts +0 -28
@@ -1,71 +0,0 @@
1
- <script lang="ts">
2
- import { getResource } from '@svadmin/core';
3
- import { navigate } from '@svadmin/core/router';
4
- import { t } from '@svadmin/core/i18n';
5
- import type { Snippet } from 'svelte';
6
- import type { FieldDefinition } from '@svadmin/core';
7
- import PageHeader from './PageHeader.svelte';
8
- import AutoTable from './AutoTable.svelte';
9
- import { Button } from './ui/button/index.js';
10
- import { Plus } from '@lucide/svelte';
11
-
12
- interface Props {
13
- resourceName: string;
14
- title?: string;
15
- canCreate?: boolean;
16
- /** Passthrough: enable row selection checkboxes */
17
- selectable?: boolean;
18
- /** Passthrough: custom header actions */
19
- headerActions?: Snippet;
20
- /** Passthrough: custom cell renderer per field */
21
- cellRenderer?: Snippet<[{ field: FieldDefinition; value: unknown; record: Record<string, unknown> }]>;
22
- /** Passthrough: custom row actions */
23
- rowActions?: Snippet<[{ record: Record<string, unknown>; id: string | number }]>;
24
- /** Passthrough: custom empty state */
25
- emptyState?: Snippet;
26
- /** Passthrough: expandable row content */
27
- expandedRowRender?: Snippet<[{ record: Record<string, unknown> }]>;
28
- class?: string;
29
- }
30
-
31
- let {
32
- resourceName,
33
- title,
34
- canCreate,
35
- selectable,
36
- headerActions,
37
- cellRenderer,
38
- rowActions,
39
- emptyState,
40
- expandedRowRender,
41
- class: className = '',
42
- }: Props = $props();
43
-
44
- const resource = $derived(getResource(resourceName));
45
- const pageTitle = $derived(title ?? resource.label);
46
- const showCreate = $derived(canCreate ?? resource.canCreate !== false);
47
- </script>
48
-
49
- <div class="space-y-6 {className}">
50
- <PageHeader title={pageTitle}>
51
- {#snippet actions()}
52
- {#if showCreate}
53
- <Button onclick={() => navigate(`/${resourceName}/create`)}>
54
- <Plus class="h-4 w-4" data-icon="inline-start" /> {t('common.create')}
55
- </Button>
56
- {/if}
57
- {#if headerActions}
58
- {@render headerActions()}
59
- {/if}
60
- {/snippet}
61
- </PageHeader>
62
-
63
- <AutoTable
64
- {resourceName}
65
- {selectable}
66
- defaultCellRenderer={cellRenderer}
67
- {rowActions}
68
- {emptyState}
69
- {expandedRowRender}
70
- />
71
- </div>
@@ -1,58 +0,0 @@
1
- <script lang="ts">
2
- import { fade } from 'svelte/transition';
3
- import { Wifi, WifiOff, Loader2 } from '@lucide/svelte';
4
- import { Badge } from './ui/badge/index.js';
5
-
6
- let {
7
- status = 'disconnected',
8
- resource = '',
9
- lastEvent = null,
10
- showDetails = false,
11
- } = $props<{
12
- status: 'connecting' | 'connected' | 'disconnected';
13
- resource?: string;
14
- lastEvent?: { type: string; timestamp?: number } | null;
15
- showDetails?: boolean;
16
- }>();
17
-
18
- const statusConfigs = {
19
- connected: { variant: 'default' as const, dotClass: 'bg-success', label: 'Live', icon: Wifi },
20
- connecting: { variant: 'secondary' as const, dotClass: 'bg-warning', label: 'Connecting...', icon: Loader2 as typeof Wifi },
21
- disconnected: { variant: 'destructive' as const, dotClass: 'bg-destructive', label: 'Offline', icon: WifiOff },
22
- } as const;
23
- type StatusKey = 'connected' | 'connecting' | 'disconnected';
24
- const cfg = $derived(statusConfigs[status as StatusKey]);
25
-
26
- const timeSinceEvent = $derived(
27
- lastEvent?.timestamp
28
- ? Math.floor((Date.now() - lastEvent.timestamp) / 1000)
29
- : null
30
- );
31
- </script>
32
-
33
- {#key status}
34
- <div transition:fade={{ duration: 200 }}>
35
- <Badge variant={cfg.variant} class="gap-1.5 select-none" title={cfg.label}>
36
- <span class="relative flex h-2 w-2">
37
- <span class="{cfg.dotClass} rounded-full h-2 w-2"></span>
38
- {#if status === 'connected'}
39
- <span class="absolute inset-0 rounded-full {cfg.dotClass} opacity-40 animate-ping"></span>
40
- {/if}
41
- </span>
42
- <span class="text-[0.6875rem] font-semibold uppercase tracking-wide">{cfg.label}</span>
43
-
44
- {#if showDetails && resource}
45
- <span class="text-[0.625rem] font-mono opacity-70">{resource}</span>
46
- {/if}
47
-
48
- {#if showDetails && lastEvent}
49
- <span class="text-[0.625rem] opacity-70">
50
- {lastEvent.type}
51
- {#if timeSinceEvent !== null && timeSinceEvent < 60}
52
- <span class="opacity-60">{timeSinceEvent}s ago</span>
53
- {/if}
54
- </span>
55
- {/if}
56
- </Badge>
57
- </div>
58
- {/key}
@@ -1,163 +0,0 @@
1
- <script lang="ts">
2
- import { useLogin, getAuthProvider } from '@svadmin/core';
3
- import { t } from '@svadmin/core/i18n';
4
- import { navigate } from '@svadmin/core/router';
5
- import { Button } from './ui/button/index.js';
6
- import { Input } from './ui/input/index.js';
7
- import { Label } from './ui/label/index.js';
8
- import * as Card from './ui/card/index.js';
9
- import * as Alert from './ui/alert/index.js';
10
- import PasswordInput from './PasswordInput.svelte';
11
- import { Separator } from './ui/separator/index.js';
12
- import { LogIn, User, Loader2, AlertCircle } from '@lucide/svelte';
13
-
14
- /**
15
- * Social provider config for the login page.
16
- * Each entry renders a button that calls `onClick()` when clicked.
17
- *
18
- * @example
19
- * ```ts
20
- * const socialProviders = [
21
- * { name: 'Google', icon: '🔵', onClick: () => googleAuth.login({}) },
22
- * { name: 'GitHub', icon: '🐙', onClick: () => githubAuth.login({}) },
23
- * ];
24
- * ```
25
- */
26
- interface SocialProvider {
27
- /** Display name (e.g., 'Google') */
28
- name: string;
29
- /** Icon character, emoji, or SVG string */
30
- icon?: string;
31
- /** Handler to initiate social login */
32
- onClick: () => void | Promise<void>;
33
- }
34
-
35
- let { title = 'Admin', onSuccess, socialProviders = [] } = $props<{
36
- title?: string;
37
- onSuccess?: () => void;
38
- socialProviders?: SocialProvider[];
39
- }>();
40
-
41
- const login = useLogin();
42
- const authProvider = getAuthProvider();
43
-
44
- let identifier = $state('');
45
- let password = $state('');
46
- let error = $state('');
47
-
48
- async function handleSubmit(e: Event) {
49
- e.preventDefault();
50
- error = '';
51
-
52
- if (!identifier) { error = t('auth.usernameOrEmailRequired'); return; }
53
- if (!password) { error = t('auth.passwordRequired'); return; }
54
-
55
- const result = await login.mutate({ email: identifier, username: identifier, password });
56
- if (result.success) {
57
- onSuccess?.();
58
- } else {
59
- error = result.error?.message ?? t('common.loginFailed');
60
- }
61
- }
62
- </script>
63
-
64
- <div class="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-100 via-blue-50/30 to-indigo-50/40 dark:from-slate-950 dark:via-slate-900 dark:to-indigo-950/20 p-4">
65
- <div class="w-full max-w-[380px]">
66
- <Card.Card>
67
- <Card.CardHeader class="text-center pb-2">
68
- <div class="inline-flex items-center justify-center w-10 h-10 rounded-lg bg-primary/10 text-primary mx-auto mb-3">
69
- <LogIn class="h-5 w-5" />
70
- </div>
71
- <Card.CardTitle class="text-xl">{t('auth.welcomeBack')}</Card.CardTitle>
72
- <p class="text-sm text-muted-foreground">{t('auth.welcomeMessage')}</p>
73
- </Card.CardHeader>
74
- <Card.CardContent>
75
- <form onsubmit={handleSubmit} class="space-y-4">
76
- {#if error}
77
- <Alert.Root variant="destructive">
78
- <AlertCircle class="h-4 w-4" />
79
- <Alert.Description>{error}</Alert.Description>
80
- </Alert.Root>
81
- {/if}
82
-
83
- <div class="space-y-2">
84
- <Label for="login-identifier">{t('auth.usernameOrEmail')}</Label>
85
- <div class="relative">
86
- <User class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none z-[1]" />
87
- <Input
88
- id="login-identifier"
89
- type="text"
90
- placeholder={t('auth.identifierPlaceholder')}
91
- bind:value={identifier}
92
- class="pl-9"
93
- autocomplete="username"
94
- />
95
- </div>
96
- </div>
97
-
98
- <div>
99
- <div class="flex items-center justify-between mb-2">
100
- <Label for="login-password">{t('auth.password')}</Label>
101
- {#if authProvider.forgotPassword}
102
- <Button variant="link" class="text-xs h-auto p-0" onclick={() => navigate('/forgot-password')}>
103
- {t('auth.forgotPasswordLink')}
104
- </Button>
105
- {/if}
106
- </div>
107
- <PasswordInput
108
- id="login-password"
109
- label=""
110
- bind:value={password}
111
- autocomplete="current-password"
112
- />
113
- </div>
114
-
115
- <Button type="submit" class="w-full" disabled={login.isLoading}>
116
- {#if login.isLoading}
117
- <Loader2 class="h-4 w-4 animate-spin mr-2" />
118
- {/if}
119
- {t('auth.loginButton')}
120
- </Button>
121
- </form>
122
-
123
- {#if socialProviders.length > 0}
124
- <div class="relative my-5">
125
- <Separator />
126
- <span class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 bg-card px-3 text-xs text-muted-foreground">
127
- {t('auth.orContinueWith')}
128
- </span>
129
- </div>
130
-
131
- <div class="grid gap-2" class:grid-cols-2={socialProviders.length >= 2}>
132
- {#each socialProviders as provider (provider.name)}
133
- <Button
134
- variant="outline"
135
- class="w-full"
136
- onclick={provider.onClick}
137
- >
138
- {#if provider.icon}
139
- <span class="mr-2">{provider.icon}</span>
140
- {/if}
141
- {provider.name}
142
- </Button>
143
- {/each}
144
- </div>
145
- {/if}
146
-
147
- {#if authProvider.register}
148
- <div class="flex items-center justify-center gap-1 mt-5 pt-5 border-t">
149
- <span class="text-sm text-muted-foreground">{t('auth.noAccount')}</span>
150
- <Button variant="link" class="text-sm h-auto p-0 font-medium" onclick={() => navigate('/register')}>
151
- {t('auth.register')}
152
- </Button>
153
- </div>
154
- {/if}
155
- </Card.CardContent>
156
- </Card.Card>
157
-
158
- <p class="text-xs text-muted-foreground mt-4 text-center">
159
- Powered by {title}
160
- </p>
161
- </div>
162
- </div>
163
-
@@ -1,127 +0,0 @@
1
- <script lang="ts">
2
- import * as markedPkg from "marked";
3
- import * as markedHighlightPkg from "marked-highlight";
4
- import * as hljsPkg from "highlight.js";
5
- import * as DOMPurifyPkg from "isomorphic-dompurify";
6
- import { Check, Copy } from '@lucide/svelte';
7
- import { Button } from "./ui/button/index.js";
8
-
9
- const Marked = markedPkg.Marked;
10
- const markedHighlight = markedHighlightPkg.markedHighlight;
11
- const hljsModule = hljsPkg.default || hljsPkg;
12
- const DOMPurify = 'default' in DOMPurifyPkg ? DOMPurifyPkg.default : DOMPurifyPkg;
13
-
14
- // Only safely import css if hljs exists
15
- if (hljsModule && Object.keys(hljsModule).length > 0) {
16
- // @ts-ignore
17
- import("highlight.js/styles/github-dark.css").catch(() => {});
18
- }
19
-
20
- interface Props {
21
- /** The raw markdown string to render */
22
- content: string;
23
- /** Whether to enable streaming/typing effect styling */
24
- streaming?: boolean;
25
- /** Custom class for the container */
26
- class?: string;
27
- }
28
-
29
- let { content, streaming = false, class: className = "" }: Props = $props();
30
-
31
- const hasMarkdownDeps = !!(Marked && Object.keys(DOMPurify || {}).length > 0);
32
-
33
- // Configure marked with syntax highlighting if available
34
- const markedObj = hasMarkdownDeps ? new Marked(
35
- markedHighlight({
36
- langPrefix: "hljs language-",
37
- highlight(code: string, lang: string) {
38
- const language = hljsModule.getLanguage && hljsModule.getLanguage(lang) ? lang : "plaintext";
39
- return hljsModule.highlight ? hljsModule.highlight(code, { language }).value : code;
40
- },
41
- }),
42
- ) : null;
43
-
44
- // Render HTML safely
45
- const html = $derived(
46
- hasMarkdownDeps
47
- ? DOMPurify.sanitize(markedObj!.parse(content || "") as string)
48
- : `<div style="white-space: pre-wrap">${String(content || "").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</div>`
49
- );
50
-
51
- // Handle copy code blocks
52
- let copiedBlock = $state<string | null>(null);
53
-
54
- function handleCopy(event: MouseEvent) {
55
- const target = event.target as HTMLElement;
56
- const button = target.closest(".copy-btn");
57
- if (!button) return;
58
-
59
- const pre = button.closest(".code-block-wrapper")?.querySelector("pre");
60
- if (!pre) return;
61
-
62
- const code = pre.textContent || "";
63
- navigator.clipboard.writeText(code);
64
-
65
- const id = Math.random().toString(36);
66
- copiedBlock = id;
67
- button.setAttribute("data-copied-id", id);
68
-
69
- setTimeout(() => {
70
- if (copiedBlock === id) copiedBlock = null;
71
- }, 2000);
72
- }
73
-
74
- // Inject copy buttons into the HTML after rendering
75
- // We do this via action instead of raw string manipulation for safety
76
- function enhanceCodeBlocks(node: HTMLElement, _: string) {
77
- return {
78
- update(newHtml: string) {
79
- // Find all pre > code blocks that don't have wrappers yet
80
- const pres = node.querySelectorAll("pre:not(.enhanced)");
81
- pres.forEach((pre) => {
82
- pre.classList.add("enhanced");
83
- const wrapper = document.createElement("div");
84
- wrapper.className =
85
- "code-block-wrapper group relative my-4 rounded-md bg-foreground/95";
86
-
87
- const header = document.createElement("div");
88
- header.className =
89
- "flex items-center justify-between px-4 py-2 text-xs text-zinc-400 border-b border-zinc-800";
90
-
91
- const lang =
92
- Array.from(pre.querySelector("code")?.classList || [])
93
- .find((c) => c.startsWith("language-"))
94
- ?.replace("language-", "") || "Code";
95
- header.innerHTML = `
96
- <span>${lang}</span>
97
- <button class="copy-btn hover:text-white transition-colors flex items-center gap-1">
98
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-copy"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>
99
- </button>
100
- `;
101
-
102
- pre.replaceWith(wrapper);
103
- wrapper.appendChild(header);
104
-
105
- const scrollContainer = document.createElement("div");
106
- scrollContainer.className = "overflow-x-auto p-4";
107
- scrollContainer.appendChild(pre);
108
- wrapper.appendChild(scrollContainer);
109
- });
110
-
111
- // Add event listener for copy buttons
112
- node.addEventListener("click", handleCopy);
113
- },
114
- destroy() {
115
- node.removeEventListener("click", handleCopy);
116
- },
117
- };
118
- }
119
- </script>
120
-
121
- <div
122
- class="prose prose-sm dark:prose-invert max-w-none wrap-break-word {className}"
123
- class:streaming={streaming}
124
- use:enhanceCodeBlocks={html}
125
- >
126
- {@html html}
127
- </div>
@@ -1,38 +0,0 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
- import type { FieldDefinition } from '@svadmin/core';
4
- import { getResource, useForm } from '@svadmin/core';
5
- import { t } from '@svadmin/core/i18n';
6
- import * as Dialog from './ui/dialog/index.js';
7
- import AutoForm from './AutoForm.svelte';
8
-
9
- let { resourceName, mode = 'create', id, open = $bindable(false), onSuccess } = $props<{
10
- resourceName: string;
11
- mode?: 'create' | 'edit';
12
- id?: string | number;
13
- open: boolean;
14
- onSuccess?: () => void;
15
- }>();
16
-
17
- const resource = $derived(getResource(resourceName));
18
- const fieldCount = $derived(resource.fields.filter(f => f.showInForm !== false).length);
19
- const dialogWidth = $derived(fieldCount > 8 ? 'sm:max-w-3xl' : fieldCount > 5 ? 'sm:max-w-2xl' : 'sm:max-w-lg');
20
-
21
- function handleClose() {
22
- open = false;
23
- onSuccess?.();
24
- }
25
- </script>
26
-
27
- {#if open}
28
- <Dialog.Dialog bind:open>
29
- <Dialog.DialogContent class="{dialogWidth} max-h-[85vh] overflow-y-auto">
30
- <Dialog.DialogHeader>
31
- <Dialog.DialogTitle>
32
- {mode === 'create' ? `${t('common.create')}${resource.label}` : `${t('common.edit')}${resource.label}`}
33
- </Dialog.DialogTitle>
34
- </Dialog.DialogHeader>
35
- <AutoForm {resourceName} {mode} {id} />
36
- </Dialog.DialogContent>
37
- </Dialog.Dialog>
38
- {/if}
@@ -1,20 +0,0 @@
1
- <script lang="ts">
2
- import { useMenu } from '@svadmin/core';
3
- import { navigate } from '@svadmin/core/router';
4
-
5
- const { menuItems } = useMenu();
6
-
7
- $effect(() => {
8
- // Automatically navigate to the first defined resource
9
- if (menuItems.length > 0) {
10
- navigate(menuItems[0].route);
11
- }
12
- });
13
- </script>
14
-
15
- <div class="flex h-screen w-screen items-center justify-center p-4 text-muted-foreground">
16
- <div class="text-center">
17
- <div class="mb-4 inline-block h-8 w-8 animate-spin rounded-full border-4 border-primary border-r-transparent"></div>
18
- <p>Navigating to default resource...</p>
19
- </div>
20
- </div>
@@ -1,39 +0,0 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
- import Breadcrumbs from './Breadcrumbs.svelte';
4
-
5
- interface Props {
6
- title: string;
7
- description?: string;
8
- actions?: Snippet;
9
- showBreadcrumbs?: boolean;
10
- class?: string;
11
- }
12
-
13
- let {
14
- title,
15
- description,
16
- actions,
17
- showBreadcrumbs = true,
18
- class: className = '',
19
- }: Props = $props();
20
- </script>
21
-
22
- <div class="space-y-4 {className}">
23
- {#if showBreadcrumbs}
24
- <Breadcrumbs />
25
- {/if}
26
- <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
27
- <div>
28
- <h1 class="text-xl font-semibold tracking-tight text-foreground">{title}</h1>
29
- {#if description}
30
- <p class="text-sm text-muted-foreground">{description}</p>
31
- {/if}
32
- </div>
33
- {#if actions}
34
- <div class="flex items-center gap-2">
35
- {@render actions()}
36
- </div>
37
- {/if}
38
- </div>
39
- </div>
@@ -1,71 +0,0 @@
1
- <script lang="ts">
2
- import { fade } from 'svelte/transition';
3
- import { Skeleton } from './ui/skeleton';
4
-
5
- let {
6
- type = 'list',
7
- rows = 5,
8
- } = $props<{
9
- type?: 'list' | 'show' | 'form';
10
- rows?: number;
11
- }>();
12
- </script>
13
-
14
- <div class="w-full space-y-6" out:fade={{ duration: 200 }}>
15
- <!-- Header Skeleton -->
16
- <div class="flex items-center justify-between">
17
- <div class="space-y-2">
18
- <Skeleton class="h-8 w-[200px]" />
19
- <Skeleton class="h-4 w-[300px]" />
20
- </div>
21
- {#if type === 'list'}
22
- <Skeleton class="h-10 w-[120px]" />
23
- {/if}
24
- </div>
25
-
26
- <div class="rounded-md border p-4 space-y-4">
27
- {#if type === 'list'}
28
- <!-- Table Header -->
29
- <div class="flex gap-4 border-b pb-4">
30
- {#each Array(4) as _}
31
- <Skeleton class="h-6 flex-1" />
32
- {/each}
33
- </div>
34
- <!-- Table Rows -->
35
- <div class="space-y-4">
36
- {#each Array(rows) as _}
37
- <div class="flex gap-4">
38
- <Skeleton class="h-6 flex-1" />
39
- <Skeleton class="h-6 flex-1" />
40
- <Skeleton class="h-6 flex-1" />
41
- <Skeleton class="h-6 flex-1" />
42
- </div>
43
- {/each}
44
- </div>
45
- {:else if type === 'show'}
46
- <!-- Key-Value pairs -->
47
- <div class="space-y-6">
48
- {#each Array(rows) as _}
49
- <div class="space-y-2">
50
- <Skeleton class="h-4 w-[100px]" />
51
- <Skeleton class="h-6 w-[250px]" />
52
- </div>
53
- {/each}
54
- </div>
55
- {:else if type === 'form'}
56
- <!-- Form Inputs -->
57
- <div class="space-y-6">
58
- {#each Array(rows) as _}
59
- <div class="space-y-2">
60
- <Skeleton class="h-4 w-[100px]" />
61
- <Skeleton class="h-10 w-full max-w-md" />
62
- </div>
63
- {/each}
64
- <div class="pt-4 flex gap-2">
65
- <Skeleton class="h-10 w-[100px]" />
66
- <Skeleton class="h-10 w-[100px]" />
67
- </div>
68
- </div>
69
- {/if}
70
- </div>
71
- </div>
@@ -1,96 +0,0 @@
1
- <script lang="ts">
2
- import { Input } from './ui/input/index.js';
3
- import { Button } from './ui/button/index.js';
4
- import TooltipButton from './TooltipButton.svelte';
5
- import { Label } from './ui/label/index.js';
6
- import { Progress } from './ui/progress/index.js';
7
- import { Lock, Eye, EyeOff } from '@lucide/svelte';
8
- import { t } from '@svadmin/core/i18n';
9
-
10
- interface Props {
11
- id: string;
12
- label: string;
13
- value: string;
14
- placeholder?: string;
15
- autocomplete?: string;
16
- showStrength?: boolean;
17
- class?: string;
18
- }
19
-
20
- let {
21
- id,
22
- label,
23
- value = $bindable(''),
24
- placeholder = '••••••••',
25
- autocomplete = 'current-password',
26
- showStrength = false,
27
- class: className = '',
28
- }: Props = $props();
29
-
30
- let showPassword = $state(false);
31
-
32
- // Password strength calculation
33
- const strength = $derived.by(() => {
34
- if (!showStrength || !value) return 0;
35
- let score = 0;
36
- if (value.length >= 8) score += 25;
37
- if (value.length >= 12) score += 10;
38
- if (/[a-z]/.test(value) && /[A-Z]/.test(value)) score += 25;
39
- if (/\d/.test(value)) score += 20;
40
- if (/[^a-zA-Z0-9]/.test(value)) score += 20;
41
- return Math.min(score, 100);
42
- });
43
-
44
- const strengthColor = $derived(
45
- strength < 30 ? 'bg-destructive' :
46
- strength < 60 ? 'bg-warning' :
47
- strength < 80 ? 'bg-info' : 'bg-success'
48
- );
49
-
50
- const strengthLabel = $derived(
51
- strength < 30 ? 'Weak' :
52
- strength < 60 ? 'Fair' :
53
- strength < 80 ? 'Good' : 'Strong'
54
- );
55
- </script>
56
-
57
- <div class="space-y-2 {className}">
58
- <Label for={id}>{label}</Label>
59
- <div class="relative">
60
- <Lock class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none z-[1]" />
61
- <Input
62
- {id}
63
- type={showPassword ? 'text' : 'password'}
64
- {placeholder}
65
- bind:value
66
- class="pl-9 pr-9"
67
- autocomplete={autocomplete as any}
68
- />
69
- <TooltipButton
70
- tooltip={showPassword ? t('common.hidePassword') : t('common.showPassword')}
71
- variant="ghost"
72
- size="icon"
73
- type="button"
74
- class="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7 z-[1]"
75
- onclick={(e) => { e.preventDefault(); showPassword = !showPassword; }}
76
- tabindex={-1}
77
- >
78
- {#if showPassword}
79
- <EyeOff class="h-4 w-4" />
80
- {:else}
81
- <Eye class="h-4 w-4" />
82
- {/if}
83
- </TooltipButton>
84
- </div>
85
- {#if showStrength && value}
86
- <div class="flex items-center gap-2">
87
- <div class="flex-1 h-1.5 rounded-full bg-muted overflow-hidden">
88
- <div
89
- class="h-full rounded-full transition-all duration-300 {strengthColor}"
90
- style="width: {strength}%"
91
- ></div>
92
- </div>
93
- <span class="text-xs text-muted-foreground w-12 text-right">{strengthLabel}</span>
94
- </div>
95
- {/if}
96
- </div>