@svadmin/ui 0.38.2 → 0.38.7
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.
- package/dist/app.css +8 -4
- package/dist/app.theme.css +8 -4
- package/dist/components/AICommandBar.svelte +16 -15
- package/dist/components/AboutSettings.svelte +12 -11
- package/dist/components/AdminApp.svelte +144 -70
- package/dist/components/AdminApp.svelte.d.ts +6 -3
- package/dist/components/ApiSettings.svelte +19 -16
- package/dist/components/AppearanceSettings.svelte +18 -16
- package/dist/components/AuditLogDrawer.svelte +6 -3
- package/dist/components/AuditLogViewer.svelte +18 -15
- package/dist/components/Authenticated.svelte +4 -4
- package/dist/components/AutoForm.svelte +19 -16
- package/dist/components/AutoSaveIndicator.svelte +7 -5
- package/dist/components/AutoTable.svelte +185 -159
- package/dist/components/AutoTable.svelte.d.ts +1 -1
- package/dist/components/Breadcrumbs.svelte +17 -13
- package/dist/components/CancelTaskButton.svelte +5 -2
- package/dist/components/CatchAllNavigate.svelte +3 -3
- package/dist/components/ChatDialog.svelte +22 -19
- package/dist/components/ComboboxField.svelte +6 -4
- package/dist/components/CommandPalette.svelte +20 -20
- package/dist/components/ConfigErrorScreen.svelte +12 -10
- package/dist/components/ConfirmDialog.svelte +6 -4
- package/dist/components/CreatePage.svelte +4 -2
- package/dist/components/DevTools.svelte +11 -14
- package/dist/components/DrawerForm.svelte +5 -2
- package/dist/components/EditPage.svelte +8 -5
- package/dist/components/EmptyState.svelte +5 -3
- package/dist/components/ErrorBoundary.svelte +5 -3
- package/dist/components/ErrorComponent.svelte +6 -4
- package/dist/components/ErrorPage.svelte +12 -10
- package/dist/components/FieldRenderer.svelte +17 -15
- package/dist/components/ForgotPasswordPage.svelte +22 -19
- package/dist/components/Header.svelte +7 -4
- package/dist/components/InfiniteList.svelte +6 -3
- package/dist/components/IntegrationsSettings.svelte +9 -6
- package/dist/components/KeyboardShortcuts.svelte +4 -2
- package/dist/components/Layout.svelte +12 -13
- package/dist/components/LazyPage.svelte +47 -0
- package/dist/components/LazyPage.svelte.d.ts +14 -0
- package/dist/components/ListPage.svelte +8 -5
- package/dist/components/LoginPage.svelte +24 -22
- package/dist/components/MarkdownRenderer.svelte +89 -35
- package/dist/components/ModalForm.svelte +4 -2
- package/dist/components/NavigateToResource.svelte +3 -3
- package/dist/components/NotificationsSettings.svelte +26 -24
- package/dist/components/PasswordInput.svelte +4 -2
- package/dist/components/PermissionMatrix.svelte +15 -12
- package/dist/components/ProfilePage.svelte +23 -21
- package/dist/components/RegisterPage.svelte +21 -19
- package/dist/components/ResourceOperationsPage.svelte +3 -2
- package/dist/components/RetryTaskButton.svelte +5 -2
- package/dist/components/RolesSettings.svelte +10 -8
- package/dist/components/SecuritySettings.svelte +26 -23
- package/dist/components/SettingsPage.svelte +14 -11
- package/dist/components/ShowPage.svelte +9 -7
- package/dist/components/Sidebar.svelte +36 -28
- package/dist/components/SidebarItem.svelte +4 -4
- package/dist/components/SidebarItem.svelte.d.ts +1 -1
- package/dist/components/StepsForm.svelte +11 -8
- package/dist/components/TaskDetails.svelte +14 -11
- package/dist/components/TaskList.svelte +14 -11
- package/dist/components/TaskQueueDrawer.svelte +34 -32
- package/dist/components/TaskStatusBadge.svelte +5 -2
- package/dist/components/Toast.svelte +18 -4
- package/dist/components/TooltipButton.svelte +25 -3
- package/dist/components/TwoFactorAuthPage.svelte +26 -24
- package/dist/components/UndoableNotification.svelte +5 -2
- package/dist/components/UpdatePasswordPage.svelte +18 -15
- package/dist/components/VirtualTable.svelte +0 -4
- package/dist/components/account/CompanyProfilePage.svelte +13 -11
- package/dist/components/account/GetStartedPage.svelte +15 -13
- package/dist/components/account/ImportMembersPage.svelte +14 -12
- package/dist/components/account/MembersStarterPage.svelte +10 -8
- package/dist/components/account/SecurityLogPage.svelte +24 -22
- package/dist/components/account/SettingsEnterprisePage.svelte +6 -4
- package/dist/components/account/SettingsPlainPage.svelte +14 -12
- package/dist/components/account/SettingsSidebarPage.svelte +11 -9
- package/dist/components/account/TeamMembersPage.svelte +10 -8
- package/dist/components/buttons/CloneButton.svelte +4 -2
- package/dist/components/buttons/CreateButton.svelte +4 -2
- package/dist/components/buttons/DeleteButton.svelte +6 -4
- package/dist/components/buttons/EditButton.svelte +4 -2
- package/dist/components/buttons/ExportButton.svelte +4 -2
- package/dist/components/buttons/ImportButton.svelte +4 -2
- package/dist/components/buttons/RefreshButton.svelte +4 -2
- package/dist/components/buttons/SaveButton.svelte +4 -2
- package/dist/components/buttons/ShowButton.svelte +4 -2
- package/dist/components/fieldComponentMap.js +0 -3
- package/dist/components/fields/ArrayField.svelte +6 -4
- package/dist/components/fields/JsonField.svelte +5 -3
- package/dist/components/fields/RelationField.svelte +3 -3
- package/dist/components/fields/RichTextField.svelte +4 -2
- package/dist/components/network/TeamCrewTablePage.svelte +18 -16
- package/dist/components/network/UserCardsNFTPage.svelte +11 -9
- package/dist/components/profile/ActivityTimeline.svelte +10 -8
- package/dist/components/profile/ProfileCard.svelte +13 -11
- package/dist/components/profile/ProjectsGrid.svelte +7 -5
- package/dist/components/profile/PublicProfilePage.svelte +18 -16
- package/dist/components/profile/TeamsShowcase.svelte +7 -5
- package/dist/components/toast-host.svelte.d.ts +5 -0
- package/dist/components/toast-host.svelte.js +21 -0
- package/dist/components/ui/command/command-dialog.svelte +29 -13
- package/dist/components/ui/command/command-dialog.svelte.d.ts +4 -3
- package/dist/components/ui/command/command-empty.svelte +18 -0
- package/dist/components/ui/command/command-empty.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-group.svelte +41 -0
- package/dist/components/ui/command/command-group.svelte.d.ts +8 -0
- package/dist/components/ui/command/command-input.svelte +23 -0
- package/dist/components/ui/command/command-input.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-item.svelte +43 -0
- package/dist/components/ui/command/command-item.svelte.d.ts +11 -0
- package/dist/components/ui/command/command-list.svelte +18 -0
- package/dist/components/ui/command/command-list.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-loading.svelte +12 -0
- package/dist/components/ui/command/command-loading.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-separator.svelte +23 -0
- package/dist/components/ui/command/command-separator.svelte.d.ts +7 -0
- package/dist/components/ui/command/command.svelte +26 -0
- package/dist/components/ui/command/command.svelte.d.ts +4 -0
- package/dist/components/ui/command/index.d.ts +55 -2
- package/dist/components/ui/command/index.js +21 -2
- package/dist/components/ui/sheet/sheet-content.svelte +1 -4
- package/dist/components/ui/sheet/sheet-content.svelte.d.ts +1 -3
- package/dist/components/ui/tabs/tabs-content.svelte +6 -2
- package/dist/components/ui/tabs/tabs-context.svelte.d.ts +5 -0
- package/dist/components/ui/tabs/tabs-context.svelte.js +2 -0
- package/dist/components/ui/tabs/tabs-trigger.svelte +49 -4
- package/dist/components/ui/tabs/tabs.svelte +12 -1
- package/dist/components/ui/tooltip/index.d.ts +4 -1
- package/dist/components/ui/tooltip/index.js +3 -1
- package/dist/components/ui/tooltip/tooltip-content.svelte +308 -35
- package/dist/components/ui/tooltip/tooltip-content.svelte.d.ts +42 -3
- package/dist/components/ui/tooltip/tooltip-context.svelte.d.ts +37 -0
- package/dist/components/ui/tooltip/tooltip-context.svelte.js +220 -0
- package/dist/components/ui/tooltip/tooltip-layer-registry.svelte.d.ts +11 -0
- package/dist/components/ui/tooltip/tooltip-layer-registry.svelte.js +93 -0
- package/dist/components/ui/tooltip/tooltip-trigger.svelte +56 -3
- package/dist/components/ui/tooltip/tooltip-trigger.svelte.d.ts +23 -2
- package/dist/components/ui/tooltip/tooltip.svelte +63 -3
- package/dist/components/ui/tooltip/tooltip.svelte.d.ts +23 -2
- package/dist/router-state.svelte.d.ts +13 -0
- package/dist/router-state.svelte.js +72 -37
- package/package.json +14 -11
package/dist/app.css
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/* Typography — Inter font for clean, modern look */
|
|
2
2
|
|
|
3
|
+
/* Tailwind v4 resolves this path relative to the published CSS file, so both
|
|
4
|
+
* src/app.css in the workspace and dist/app*.css on npm scan real components. */
|
|
5
|
+
@source "./components";
|
|
6
|
+
|
|
3
7
|
/* @svadmin/ui — Design Tokens (clean admin shell)
|
|
4
8
|
* Auto-imported by AdminApp. Can be overridden by consumer's CSS.
|
|
5
9
|
*
|
|
@@ -8,12 +12,12 @@
|
|
|
8
12
|
*/
|
|
9
13
|
|
|
10
14
|
@layer base {
|
|
11
|
-
/*
|
|
12
|
-
*
|
|
15
|
+
/* Use the semantic token so consumers can normalize legacy channel-only
|
|
16
|
+
* values without the base reset falling back to currentColor. */
|
|
13
17
|
*,
|
|
14
18
|
::after,
|
|
15
19
|
::before {
|
|
16
|
-
border-color: var(--border);
|
|
20
|
+
border-color: var(--color-border, var(--border));
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
:root {
|
|
@@ -382,7 +386,7 @@ button:active:not(:disabled) {
|
|
|
382
386
|
animation: svadmin-page-enter 0.25s ease-out;
|
|
383
387
|
}
|
|
384
388
|
|
|
385
|
-
/* ⑥ Toast slide-in refinement (sonner
|
|
389
|
+
/* ⑥ Toast slide-in refinement (svelte-sonner) — tighter timing */
|
|
386
390
|
[data-sonner-toaster] [data-sonner-toast] {
|
|
387
391
|
transition-duration: 200ms !important;
|
|
388
392
|
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1) !important;
|
package/dist/app.theme.css
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/* Typography — Inter font for clean, modern look */
|
|
2
2
|
|
|
3
|
+
/* Tailwind v4 resolves this path relative to the published CSS file, so both
|
|
4
|
+
* src/app.css in the workspace and dist/app*.css on npm scan real components. */
|
|
5
|
+
@source "./components";
|
|
6
|
+
|
|
3
7
|
/* @svadmin/ui — Design Tokens (clean admin shell)
|
|
4
8
|
* Auto-imported by AdminApp. Can be overridden by consumer's CSS.
|
|
5
9
|
*
|
|
@@ -8,12 +12,12 @@
|
|
|
8
12
|
*/
|
|
9
13
|
|
|
10
14
|
@layer base {
|
|
11
|
-
/*
|
|
12
|
-
*
|
|
15
|
+
/* Use the semantic token so consumers can normalize legacy channel-only
|
|
16
|
+
* values without the base reset falling back to currentColor. */
|
|
13
17
|
*,
|
|
14
18
|
::after,
|
|
15
19
|
::before {
|
|
16
|
-
border-color: var(--border);
|
|
20
|
+
border-color: var(--color-border, var(--border));
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
:root {
|
|
@@ -382,7 +386,7 @@ button:active:not(:disabled) {
|
|
|
382
386
|
animation: svadmin-page-enter 0.25s ease-out;
|
|
383
387
|
}
|
|
384
388
|
|
|
385
|
-
/* ⑥ Toast slide-in refinement (sonner
|
|
389
|
+
/* ⑥ Toast slide-in refinement (svelte-sonner) — tighter timing */
|
|
386
390
|
[data-sonner-toaster] [data-sonner-toast] {
|
|
387
391
|
transition-duration: 200ms !important;
|
|
388
392
|
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1) !important;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { getResources, getChatProvider } from '@svadmin/core';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { toggleTheme } from '@svadmin/core';
|
|
6
|
-
import { Command } from 'cmdk-sv';
|
|
2
|
+
import { captureAdminContext, getResources, getChatProvider, toggleTheme } from '@svadmin/core';
|
|
3
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
4
|
+
import { Command } from './ui/command/index.js';
|
|
7
5
|
import * as Dialog from './ui/dialog/index.js';
|
|
8
6
|
import { Search, LayoutDashboard, Plus, Sun, FileText, Sparkles, Loader2 } from '@lucide/svelte';
|
|
9
7
|
import MarkdownRenderer from './MarkdownRenderer.svelte';
|
|
10
8
|
|
|
9
|
+
const i18n = useTranslation();
|
|
10
|
+
|
|
11
11
|
let { open = $bindable(false) } = $props<{ open?: boolean }>();
|
|
12
|
+
const adminContext = captureAdminContext();
|
|
12
13
|
let searchValue = $state('');
|
|
13
14
|
|
|
14
15
|
const resources = getResources();
|
|
@@ -80,14 +81,14 @@
|
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
|
|
83
|
-
const itemClass = 'relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[selected
|
|
84
|
+
const itemClass = 'relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[selected]:bg-accent data-[selected]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50';
|
|
84
85
|
</script>
|
|
85
86
|
|
|
86
87
|
<Dialog.Dialog bind:open onOpenChange={(v: boolean) => !v && close()}>
|
|
87
88
|
<Dialog.DialogContent class="overflow-hidden p-0 sm:max-w-[600px] border-none shadow-2xl">
|
|
88
89
|
<Command.Root
|
|
89
90
|
shouldFilter={!aiMode}
|
|
90
|
-
class="flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground [&_[data-
|
|
91
|
+
class="flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground [&_[data-command-group-heading]]:text-muted-foreground [&_[data-command-group-heading]]:px-2 [&_[data-command-group-heading]]:py-1.5 [&_[data-command-group-heading]]:text-xs [&_[data-command-group-heading]]:font-semibold [&_[data-command-group-heading]]:uppercase [&_[data-command-group-heading]]:tracking-wider"
|
|
91
92
|
>
|
|
92
93
|
<div class="flex items-center border-b px-3 h-12 relative" data-cmdk-input-wrapper="">
|
|
93
94
|
{#if aiMode}
|
|
@@ -119,13 +120,13 @@
|
|
|
119
120
|
</Command.Empty>
|
|
120
121
|
|
|
121
122
|
<!-- Navigation -->
|
|
122
|
-
<Command.Group heading={t('common.home')}>
|
|
123
|
-
<Command.Item value="home" onSelect={() => act(() => navigate('/'))} class={itemClass}>
|
|
123
|
+
<Command.Group heading={i18n.t('common.home')}>
|
|
124
|
+
<Command.Item value="home" onSelect={() => act(() => adminContext.navigate('/'))} class={itemClass}>
|
|
124
125
|
<LayoutDashboard class="h-4 w-4 text-muted-foreground" />
|
|
125
|
-
{t('common.home')}
|
|
126
|
+
{i18n.t('common.home')}
|
|
126
127
|
</Command.Item>
|
|
127
128
|
{#each resources as r, _i (_i)}
|
|
128
|
-
<Command.Item value={r.name} onSelect={() => act(() => navigate(`/${r.name}`))} class={itemClass}>
|
|
129
|
+
<Command.Item value={r.name} onSelect={() => act(() => adminContext.navigate(`/${r.name}`))} class={itemClass}>
|
|
129
130
|
<FileText class="h-4 w-4 text-muted-foreground" />
|
|
130
131
|
{r.label}
|
|
131
132
|
</Command.Item>
|
|
@@ -135,16 +136,16 @@
|
|
|
135
136
|
<Command.Separator class="mx-1 my-1 h-px bg-border" />
|
|
136
137
|
|
|
137
138
|
<!-- Actions -->
|
|
138
|
-
<Command.Group heading={t('common.actions')}>
|
|
139
|
+
<Command.Group heading={i18n.t('common.actions')}>
|
|
139
140
|
{#each resources as r, _i (_i)}
|
|
140
|
-
<Command.Item value={`create-${r.name}`} onSelect={() => act(() => navigate(`/${r.name}/create`))} class={itemClass}>
|
|
141
|
+
<Command.Item value={`create-${r.name}`} onSelect={() => act(() => adminContext.navigate(`/${r.name}/create`))} class={itemClass}>
|
|
141
142
|
<Plus class="h-4 w-4 text-muted-foreground" />
|
|
142
|
-
{t('common.create')} {r.label}
|
|
143
|
+
{i18n.t('common.create')} {r.label}
|
|
143
144
|
</Command.Item>
|
|
144
145
|
{/each}
|
|
145
146
|
<Command.Item value="toggle-theme" onSelect={() => act(() => toggleTheme())} class={itemClass}>
|
|
146
147
|
<Sun class="h-4 w-4 text-muted-foreground" />
|
|
147
|
-
{t('common.toggleTheme')}
|
|
148
|
+
{i18n.t('common.toggleTheme')}
|
|
148
149
|
</Command.Item>
|
|
149
150
|
</Command.Group>
|
|
150
151
|
</Command.List>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
3
3
|
import { getResources, getDataProviderNames } from '@svadmin/core';
|
|
4
|
-
import { getLocale } from '@svadmin/core/i18n';
|
|
5
4
|
import { getResolvedTheme, getColorTheme } from '@svadmin/core';
|
|
6
5
|
import * as Card from './ui/card/index.js';
|
|
7
6
|
import { Badge } from './ui/badge/index.js';
|
|
8
7
|
import { Info, Database, Globe, Palette, Layers } from '@lucide/svelte';
|
|
9
8
|
|
|
9
|
+
const i18n = useTranslation();
|
|
10
|
+
|
|
10
11
|
const resources = getResources();
|
|
11
12
|
const providerNames = getDataProviderNames();
|
|
12
13
|
|
|
@@ -15,7 +16,7 @@
|
|
|
15
16
|
|
|
16
17
|
<div class="space-y-6">
|
|
17
18
|
<div>
|
|
18
|
-
<h2 class="text-xl font-semibold text-foreground">{t('settings.about')}</h2>
|
|
19
|
+
<h2 class="text-xl font-semibold text-foreground">{i18n.t('settings.about')}</h2>
|
|
19
20
|
</div>
|
|
20
21
|
|
|
21
22
|
<!-- Version -->
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
<Card.CardContent>
|
|
30
31
|
<div class="grid gap-4 text-sm">
|
|
31
32
|
<div class="flex items-center justify-between">
|
|
32
|
-
<span class="text-muted-foreground">{t('settings.version')}</span>
|
|
33
|
+
<span class="text-muted-foreground">{i18n.t('settings.version')}</span>
|
|
33
34
|
<Badge variant="secondary" class="font-mono text-xs">{version}</Badge>
|
|
34
35
|
</div>
|
|
35
36
|
</div>
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
<Card.CardHeader class="pb-3">
|
|
42
43
|
<Card.CardTitle class="text-base flex items-center gap-2">
|
|
43
44
|
<Layers class="h-4 w-4 text-muted-foreground" />
|
|
44
|
-
{t('settings.registeredResources')}
|
|
45
|
+
{i18n.t('settings.registeredResources')}
|
|
45
46
|
</Card.CardTitle>
|
|
46
47
|
</Card.CardHeader>
|
|
47
48
|
<Card.CardContent>
|
|
@@ -61,7 +62,7 @@
|
|
|
61
62
|
<Card.CardHeader class="pb-3">
|
|
62
63
|
<Card.CardTitle class="text-base flex items-center gap-2">
|
|
63
64
|
<Database class="h-4 w-4 text-muted-foreground" />
|
|
64
|
-
{t('settings.dataProvider')}
|
|
65
|
+
{i18n.t('settings.dataProvider')}
|
|
65
66
|
</Card.CardTitle>
|
|
66
67
|
</Card.CardHeader>
|
|
67
68
|
<Card.CardContent>
|
|
@@ -78,25 +79,25 @@
|
|
|
78
79
|
<Card.CardHeader class="pb-3">
|
|
79
80
|
<Card.CardTitle class="text-base flex items-center gap-2">
|
|
80
81
|
<Globe class="h-4 w-4 text-muted-foreground" />
|
|
81
|
-
{t('settings.currentEnvironment')}
|
|
82
|
+
{i18n.t('settings.currentEnvironment')}
|
|
82
83
|
</Card.CardTitle>
|
|
83
84
|
</Card.CardHeader>
|
|
84
85
|
<Card.CardContent>
|
|
85
86
|
<div class="grid gap-3 text-sm">
|
|
86
87
|
<div class="flex items-center justify-between">
|
|
87
|
-
<span class="text-muted-foreground">{t('settings.language')}</span>
|
|
88
|
-
<span class="font-mono text-xs">{
|
|
88
|
+
<span class="text-muted-foreground">{i18n.t('settings.language')}</span>
|
|
89
|
+
<span class="font-mono text-xs">{i18n.locale}</span>
|
|
89
90
|
</div>
|
|
90
91
|
<div class="h-px bg-border"></div>
|
|
91
92
|
<div class="flex items-center justify-between">
|
|
92
|
-
<span class="text-muted-foreground">{t('settings.themeMode')}</span>
|
|
93
|
+
<span class="text-muted-foreground">{i18n.t('settings.themeMode')}</span>
|
|
93
94
|
<span class="font-mono text-xs">{getResolvedTheme()}</span>
|
|
94
95
|
</div>
|
|
95
96
|
<div class="h-px bg-border"></div>
|
|
96
97
|
<div class="flex items-center justify-between">
|
|
97
98
|
<span class="text-muted-foreground flex items-center gap-1.5">
|
|
98
99
|
<Palette class="h-3.5 w-3.5" />
|
|
99
|
-
{t('settings.colorAccent')}
|
|
100
|
+
{i18n.t('settings.colorAccent')}
|
|
100
101
|
</span>
|
|
101
102
|
<span class="font-mono text-xs">{getColorTheme()}</span>
|
|
102
103
|
</div>
|
|
@@ -1,11 +1,35 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
const loadPublicProfilePage = () => import('./profile/PublicProfilePage.svelte');
|
|
3
|
+
const loadGetStartedPage = () => import('./account/GetStartedPage.svelte');
|
|
4
|
+
const loadCompanyProfilePage = () => import('./account/CompanyProfilePage.svelte');
|
|
5
|
+
const loadSettingsPlainPage = () => import('./account/SettingsPlainPage.svelte');
|
|
6
|
+
const loadSettingsSidebarPage = () => import('./account/SettingsSidebarPage.svelte');
|
|
7
|
+
const loadSettingsEnterprisePage = () => import('./account/SettingsEnterprisePage.svelte');
|
|
8
|
+
const loadImportMembersPage = () => import('./account/ImportMembersPage.svelte');
|
|
9
|
+
const loadMembersStarterPage = () => import('./account/MembersStarterPage.svelte');
|
|
10
|
+
const loadTeamMembersPage = () => import('./account/TeamMembersPage.svelte');
|
|
11
|
+
const loadSecurityLogPage = () => import('./account/SecurityLogPage.svelte');
|
|
12
|
+
const loadUserCardsNFTPage = () => import('./network/UserCardsNFTPage.svelte');
|
|
13
|
+
const loadTeamCrewTablePage = () => import('./network/TeamCrewTablePage.svelte');
|
|
14
|
+
const loadTwoFactorAuthPage = () => import('./TwoFactorAuthPage.svelte');
|
|
15
|
+
</script>
|
|
16
|
+
|
|
1
17
|
<script lang="ts">
|
|
2
18
|
// Auto-inject design tokens so consumers don't need to manually import
|
|
3
19
|
import '../app.css';
|
|
4
|
-
import type
|
|
5
|
-
import type { DataProvider, AuthProvider, ResourceDefinition, ThemeMode, RouterProvider, ThemeConfig, MenuItem, TaskProvider } from '@svadmin/core';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
20
|
+
import { onDestroy, onMount, untrack, type Component, type Snippet } from 'svelte';
|
|
21
|
+
import type { DataProvider, AuthProvider, ResourceDefinition, ThemeMode, RouterProvider, ThemeConfig, MenuItem, TaskProvider, I18nProvider } from '@svadmin/core';
|
|
22
|
+
import {
|
|
23
|
+
captureAdminContext,
|
|
24
|
+
createHashRouterProvider,
|
|
25
|
+
createI18nScope,
|
|
26
|
+
provideAdminContext,
|
|
27
|
+
provideI18nScope,
|
|
28
|
+
registerThemeOwner,
|
|
29
|
+
unregisterThemeOwner,
|
|
30
|
+
updateThemeOwner,
|
|
31
|
+
} from '@svadmin/core';
|
|
32
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
9
33
|
import { QueryClient, QueryClientProvider, type DefaultOptions } from '@tanstack/svelte-query';
|
|
10
34
|
import { setComponentRegistry, type ComponentRegistry } from '../component-registry.svelte.js';
|
|
11
35
|
import Layout from './Layout.svelte';
|
|
@@ -24,24 +48,12 @@
|
|
|
24
48
|
import TaskQueueDrawer from './TaskQueueDrawer.svelte';
|
|
25
49
|
import SettingsPage from './SettingsPage.svelte';
|
|
26
50
|
import ErrorPage from './ErrorPage.svelte';
|
|
27
|
-
import
|
|
28
|
-
import GetStartedPage from './account/GetStartedPage.svelte';
|
|
29
|
-
import CompanyProfilePage from './account/CompanyProfilePage.svelte';
|
|
30
|
-
import SettingsPlainPage from './account/SettingsPlainPage.svelte';
|
|
31
|
-
import SettingsSidebarPage from './account/SettingsSidebarPage.svelte';
|
|
32
|
-
import SettingsEnterprisePage from './account/SettingsEnterprisePage.svelte';
|
|
33
|
-
import ImportMembersPage from './account/ImportMembersPage.svelte';
|
|
34
|
-
import MembersStarterPage from './account/MembersStarterPage.svelte';
|
|
35
|
-
import TeamMembersPage from './account/TeamMembersPage.svelte';
|
|
36
|
-
import SecurityLogPage from './account/SecurityLogPage.svelte';
|
|
37
|
-
import UserCardsNFTPage from './network/UserCardsNFTPage.svelte';
|
|
38
|
-
import TeamCrewTablePage from './network/TeamCrewTablePage.svelte';
|
|
39
|
-
import TwoFactorAuthPage from './TwoFactorAuthPage.svelte';
|
|
51
|
+
import LazyPage from './LazyPage.svelte';
|
|
40
52
|
import { Button } from './ui/button/index.js';
|
|
41
53
|
import { Input } from './ui/input/index.js';
|
|
42
54
|
import { Badge } from './ui/badge/index.js';
|
|
43
55
|
import { Skeleton } from './ui/skeleton/index.js';
|
|
44
|
-
import {
|
|
56
|
+
import { provideRouterState } from '../router-state.svelte.js';
|
|
45
57
|
|
|
46
58
|
interface Props {
|
|
47
59
|
dataProvider: DataProvider;
|
|
@@ -49,7 +61,10 @@
|
|
|
49
61
|
taskProvider?: TaskProvider;
|
|
50
62
|
routerProvider?: RouterProvider;
|
|
51
63
|
resources: ResourceDefinition[];
|
|
64
|
+
/** Bindable tree-local locale; defaults to the provider locale or per-tree browser detection (English during SSR). */
|
|
52
65
|
locale?: string;
|
|
66
|
+
/** Optional tree-local translation provider. */
|
|
67
|
+
i18nProvider?: I18nProvider;
|
|
53
68
|
title?: string;
|
|
54
69
|
defaultTheme?: ThemeMode;
|
|
55
70
|
/** Theme configuration for dark-first mode, CSS overrides, etc. */
|
|
@@ -90,7 +105,8 @@
|
|
|
90
105
|
taskProvider,
|
|
91
106
|
routerProvider,
|
|
92
107
|
resources,
|
|
93
|
-
locale,
|
|
108
|
+
locale = $bindable(),
|
|
109
|
+
i18nProvider,
|
|
94
110
|
title = 'Admin',
|
|
95
111
|
defaultTheme,
|
|
96
112
|
themeConfig: userThemeConfig,
|
|
@@ -122,28 +138,89 @@
|
|
|
122
138
|
const resolvedRouter = $derived(routerProvider ?? createHashRouterProvider());
|
|
123
139
|
const resolvedRouteMode = $derived(routeMode ?? (routerProvider ? 'auto' : 'hash'));
|
|
124
140
|
|
|
141
|
+
const routerState = provideRouterState(untrack(() => resolvedRouter));
|
|
142
|
+
const scopedRouterProvider: RouterProvider = {
|
|
143
|
+
go(options) {
|
|
144
|
+
resolvedRouter.go(options);
|
|
145
|
+
routerState.sync();
|
|
146
|
+
},
|
|
147
|
+
back() {
|
|
148
|
+
resolvedRouter.back();
|
|
149
|
+
routerState.sync();
|
|
150
|
+
},
|
|
151
|
+
parse() {
|
|
152
|
+
return resolvedRouter.parse();
|
|
153
|
+
},
|
|
154
|
+
formatLink(path) {
|
|
155
|
+
return resolvedRouter.formatLink?.(path) ?? `#${path.replace(/^#/, '')}`;
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
$effect.pre(() => routerState.init(resolvedRouter));
|
|
160
|
+
onDestroy(() => routerState.destroy());
|
|
161
|
+
|
|
162
|
+
function updateBoundLocale(nextLocale: string) {
|
|
163
|
+
locale = nextLocale;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const i18nScope = createI18nScope({
|
|
167
|
+
locale: untrack(() => locale),
|
|
168
|
+
provider: untrack(() => i18nProvider),
|
|
169
|
+
onLocaleChange: updateBoundLocale,
|
|
170
|
+
});
|
|
171
|
+
provideI18nScope(i18nScope);
|
|
172
|
+
const translation = useTranslation();
|
|
173
|
+
|
|
174
|
+
$effect.pre(() => {
|
|
175
|
+
const ownerProvider = i18nProvider;
|
|
176
|
+
const ownerLocale = locale;
|
|
177
|
+
untrack(() => i18nScope.updateOwner({
|
|
178
|
+
locale: ownerLocale,
|
|
179
|
+
provider: ownerProvider,
|
|
180
|
+
onLocaleChange: updateBoundLocale,
|
|
181
|
+
}));
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
let themeOwner = $state.raw<ReturnType<typeof registerThemeOwner>>(undefined);
|
|
185
|
+
|
|
186
|
+
onMount(() => {
|
|
187
|
+
themeOwner = registerThemeOwner({
|
|
188
|
+
defaultTheme,
|
|
189
|
+
themeConfig: userThemeConfig,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
return () => {
|
|
193
|
+
unregisterThemeOwner(themeOwner);
|
|
194
|
+
themeOwner = undefined;
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
$effect(() => {
|
|
199
|
+
const owner = themeOwner;
|
|
200
|
+
const ownerOptions = {
|
|
201
|
+
defaultTheme,
|
|
202
|
+
themeConfig: userThemeConfig,
|
|
203
|
+
};
|
|
204
|
+
untrack(() => updateThemeOwner(owner, ownerOptions));
|
|
205
|
+
});
|
|
206
|
+
|
|
125
207
|
function syncComponentRegistry() {
|
|
126
208
|
setComponentRegistry(mergedComponents);
|
|
127
209
|
}
|
|
128
210
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (defaultTheme) setTheme(defaultTheme);
|
|
138
|
-
}
|
|
211
|
+
provideAdminContext({
|
|
212
|
+
get dataProvider() { return dataProvider; },
|
|
213
|
+
get authProvider() { return authProvider ?? null; },
|
|
214
|
+
get taskProvider() { return taskProvider; },
|
|
215
|
+
get resources() { return resources; },
|
|
216
|
+
get routerProvider() { return scopedRouterProvider; },
|
|
217
|
+
});
|
|
218
|
+
const adminContext = captureAdminContext();
|
|
139
219
|
|
|
140
|
-
//
|
|
220
|
+
// Context must be available synchronously to descendants during their first render.
|
|
141
221
|
syncComponentRegistry();
|
|
142
|
-
syncAppContext();
|
|
143
222
|
|
|
144
|
-
// Set up context — use $effect so prop changes are tracked
|
|
145
223
|
$effect.pre(syncComponentRegistry);
|
|
146
|
-
$effect.pre(syncAppContext);
|
|
147
224
|
|
|
148
225
|
const queryClient = $derived(providedQueryClient ?? new QueryClient({
|
|
149
226
|
defaultOptions: {
|
|
@@ -152,24 +229,20 @@
|
|
|
152
229
|
},
|
|
153
230
|
}));
|
|
154
231
|
|
|
155
|
-
function syncRouter() {
|
|
156
|
-
initRouter(resolvedRouter);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Initialize router with provider synchronously
|
|
160
|
-
syncRouter();
|
|
161
|
-
$effect.pre(syncRouter);
|
|
162
|
-
|
|
163
232
|
// Reactive getters for route state
|
|
164
|
-
const route = $derived(
|
|
165
|
-
const params = $derived(
|
|
233
|
+
const route = $derived(routerState.route);
|
|
234
|
+
const params = $derived(routerState.params);
|
|
166
235
|
const resourceNames = $derived(new Set(resources.map((resource) => resource.name)));
|
|
167
236
|
const hasRouteResource = $derived(!params.resource || resourceNames.has(params.resource));
|
|
168
237
|
const currentResourcePages = $derived(params.resource ? resourcePages?.[params.resource] : undefined);
|
|
169
238
|
|
|
170
239
|
// Auth check
|
|
171
|
-
let isAuthenticated = $state(
|
|
172
|
-
let authChecked = $state(
|
|
240
|
+
let isAuthenticated = $state(untrack(() => !authProvider));
|
|
241
|
+
let authChecked = $state(untrack(() => !authProvider));
|
|
242
|
+
|
|
243
|
+
async function navigateWithinApp(path: string) {
|
|
244
|
+
await adminContext.navigate(path);
|
|
245
|
+
}
|
|
173
246
|
|
|
174
247
|
$effect(() => {
|
|
175
248
|
let cancelled = false;
|
|
@@ -183,12 +256,13 @@
|
|
|
183
256
|
}
|
|
184
257
|
return;
|
|
185
258
|
}
|
|
259
|
+
authChecked = false;
|
|
186
260
|
authProvider.check().then(result => {
|
|
187
261
|
if (cancelled) return;
|
|
188
262
|
isAuthenticated = result.authenticated;
|
|
189
263
|
authChecked = true;
|
|
190
264
|
if (!result.authenticated && _route !== '/login' && _route !== '/register' && _route !== '/forgot-password' && _route !== '/update-password') {
|
|
191
|
-
|
|
265
|
+
void navigateWithinApp(result.redirectTo ?? '/login');
|
|
192
266
|
}
|
|
193
267
|
}).catch(err => {
|
|
194
268
|
if (cancelled) return;
|
|
@@ -196,7 +270,7 @@
|
|
|
196
270
|
isAuthenticated = false;
|
|
197
271
|
authChecked = true;
|
|
198
272
|
if (_route !== '/login' && _route !== '/register' && _route !== '/forgot-password' && _route !== '/update-password') {
|
|
199
|
-
|
|
273
|
+
void navigateWithinApp('/login');
|
|
200
274
|
}
|
|
201
275
|
});
|
|
202
276
|
|
|
@@ -220,7 +294,7 @@
|
|
|
220
294
|
defaultIdentifier={loginDefaults?.identifier}
|
|
221
295
|
defaultPassword={loginDefaults?.password}
|
|
222
296
|
loginHint={loginDefaults?.hint}
|
|
223
|
-
onSuccess={() => { isAuthenticated = true;
|
|
297
|
+
onSuccess={() => { isAuthenticated = true; void navigateWithinApp('/'); }}
|
|
224
298
|
/>
|
|
225
299
|
{:else if route === '/register' && authProvider?.register}
|
|
226
300
|
<RegisterPage {title} />
|
|
@@ -229,49 +303,49 @@
|
|
|
229
303
|
{:else if route === '/update-password' && authProvider?.updatePassword}
|
|
230
304
|
<UpdatePasswordPage {title} />
|
|
231
305
|
{:else if route === '/login' || route === '/register' || route === '/forgot-password' || route === '/update-password'}
|
|
232
|
-
<ConfigErrorScreen title="{title} — {t('common.configRequired')}" />
|
|
306
|
+
<ConfigErrorScreen title="{title} — {translation.t('common.configRequired')}" />
|
|
233
307
|
{:else if isAuthenticated || !authProvider}
|
|
234
308
|
<Layout {title} {menu} {siteUrl} routeMode={resolvedRouteMode}>
|
|
235
309
|
{#key route + (params.resource ?? '') + (params.id ?? '') + (params.variant ?? '') + (params.columns ?? '')}
|
|
236
310
|
<div class="svadmin-page-enter">
|
|
237
311
|
{#if route === '/2fa' || route === '/authentication/branded/2fa'}
|
|
238
|
-
<
|
|
312
|
+
<LazyPage loader={loadTwoFactorAuthPage} props={{}} />
|
|
239
313
|
{:else if route === '/public-profile'}
|
|
240
|
-
<
|
|
314
|
+
<LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'projects' }} />
|
|
241
315
|
{:else if route === '/public-profile/projects/:columns'}
|
|
242
|
-
<
|
|
316
|
+
<LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'projects', columns: params.columns?.includes('3') ? 3 : 2 }} />
|
|
243
317
|
{:else if route === '/public-profile/activity'}
|
|
244
|
-
<
|
|
318
|
+
<LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'activity' }} />
|
|
245
319
|
{:else if route === '/public-profile/teams'}
|
|
246
|
-
<
|
|
320
|
+
<LazyPage loader={loadPublicProfilePage} props={{ variant: 'default', initialTab: 'teams' }} />
|
|
247
321
|
{:else if route === '/public-profile/profiles/:variant'}
|
|
248
|
-
<
|
|
322
|
+
<LazyPage loader={loadPublicProfilePage} props={{ variant: (params.variant === 'company' || params.variant === 'gamer' || params.variant === 'default' ? params.variant : 'default') as 'company' | 'gamer' | 'default' }} />
|
|
249
323
|
{:else if route === '/account/get-started' || route === '/account/home/get-started'}
|
|
250
|
-
<
|
|
324
|
+
<LazyPage loader={loadGetStartedPage} props={{}} />
|
|
251
325
|
{:else if route === '/account/home/user-profile'}
|
|
252
326
|
<SettingsPage />
|
|
253
327
|
{:else if route === '/account/company-profile' || route === '/account/home/company-profile'}
|
|
254
|
-
<
|
|
328
|
+
<LazyPage loader={loadCompanyProfilePage} props={{}} />
|
|
255
329
|
{:else if route === '/account/settings-plain' || route === '/account/home/settings-plain'}
|
|
256
|
-
<
|
|
330
|
+
<LazyPage loader={loadSettingsPlainPage} props={{}} />
|
|
257
331
|
{:else if route === '/account/settings-sidebar' || route === '/account/home/settings-sidebar'}
|
|
258
|
-
<
|
|
332
|
+
<LazyPage loader={loadSettingsSidebarPage} props={{}} />
|
|
259
333
|
{:else if route === '/account/settings-enterprise' || route === '/account/home/settings-enterprise'}
|
|
260
|
-
<
|
|
334
|
+
<LazyPage loader={loadSettingsEnterprisePage} props={{}} />
|
|
261
335
|
{:else if route === '/account/:tab'}
|
|
262
336
|
<SettingsPage />
|
|
263
337
|
{:else if route === '/account/import-members' || route === '/account/members/import-members'}
|
|
264
|
-
<
|
|
338
|
+
<LazyPage loader={loadImportMembersPage} props={{}} />
|
|
265
339
|
{:else if route === '/account/members-starter' || route === '/account/members/members-starter'}
|
|
266
|
-
<
|
|
340
|
+
<LazyPage loader={loadMembersStarterPage} props={{}} />
|
|
267
341
|
{:else if route === '/account/team-members' || route === '/account/members/team-members'}
|
|
268
|
-
<
|
|
342
|
+
<LazyPage loader={loadTeamMembersPage} props={{}} />
|
|
269
343
|
{:else if route === '/account/security-log' || route === '/account/security/security-log'}
|
|
270
|
-
<
|
|
344
|
+
<LazyPage loader={loadSecurityLogPage} props={{}} />
|
|
271
345
|
{:else if route === '/network/user-cards' || route === '/network/user-cards/nft'}
|
|
272
|
-
<
|
|
346
|
+
<LazyPage loader={loadUserCardsNFTPage} props={{}} />
|
|
273
347
|
{:else if route === '/network/team-crew' || route === '/network/user-table/team-crew'}
|
|
274
|
-
<
|
|
348
|
+
<LazyPage loader={loadTeamCrewTablePage} props={{}} />
|
|
275
349
|
{:else if route.startsWith('/settings')}
|
|
276
350
|
<SettingsPage />
|
|
277
351
|
{:else if route === '/500' || (route === '/:resource' && params.resource === '500')}
|
|
@@ -282,8 +356,8 @@
|
|
|
282
356
|
{@render dashboard()}
|
|
283
357
|
{:else}
|
|
284
358
|
<div class="space-y-4">
|
|
285
|
-
<h1 class="text-xl font-semibold text-foreground">{t('common.welcome', { title })}</h1>
|
|
286
|
-
<p class="text-muted-foreground">{t('common.dashboardHint')}</p>
|
|
359
|
+
<h1 class="text-xl font-semibold text-foreground">{translation.t('common.welcome', { title })}</h1>
|
|
360
|
+
<p class="text-muted-foreground">{translation.t('common.dashboardHint')}</p>
|
|
287
361
|
</div>
|
|
288
362
|
{/if}
|
|
289
363
|
{:else if (route === '/:resource' || route === '/:parent/:parentId/:resource') && hasRouteResource}
|
|
@@ -320,7 +394,7 @@
|
|
|
320
394
|
</Layout>
|
|
321
395
|
{:else}
|
|
322
396
|
<div class="flex h-screen items-center justify-center">
|
|
323
|
-
<p class="text-muted-foreground">{t('common.redirecting')}</p>
|
|
397
|
+
<p class="text-muted-foreground">{translation.t('common.redirecting')}</p>
|
|
324
398
|
</div>
|
|
325
399
|
{/if}
|
|
326
400
|
<Toast />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '../app.css';
|
|
2
|
-
import type
|
|
3
|
-
import type { DataProvider, AuthProvider, ResourceDefinition, ThemeMode, RouterProvider, ThemeConfig, MenuItem, TaskProvider } from '@svadmin/core';
|
|
2
|
+
import { type Component, type Snippet } from 'svelte';
|
|
3
|
+
import type { DataProvider, AuthProvider, ResourceDefinition, ThemeMode, RouterProvider, ThemeConfig, MenuItem, TaskProvider, I18nProvider } from '@svadmin/core';
|
|
4
4
|
import { QueryClient, type DefaultOptions } from '@tanstack/svelte-query';
|
|
5
5
|
import { type ComponentRegistry } from '../component-registry.svelte.js';
|
|
6
6
|
interface Props {
|
|
@@ -9,7 +9,10 @@ interface Props {
|
|
|
9
9
|
taskProvider?: TaskProvider;
|
|
10
10
|
routerProvider?: RouterProvider;
|
|
11
11
|
resources: ResourceDefinition[];
|
|
12
|
+
/** Bindable tree-local locale; defaults to the provider locale or per-tree browser detection (English during SSR). */
|
|
12
13
|
locale?: string;
|
|
14
|
+
/** Optional tree-local translation provider. */
|
|
15
|
+
i18nProvider?: I18nProvider;
|
|
13
16
|
title?: string;
|
|
14
17
|
defaultTheme?: ThemeMode;
|
|
15
18
|
/** Theme configuration for dark-first mode, CSS overrides, etc. */
|
|
@@ -59,6 +62,6 @@ interface Props {
|
|
|
59
62
|
/** Optional TanStack Query default options override when QueryClient is not supplied. */
|
|
60
63
|
queryClientDefaultOptions?: DefaultOptions;
|
|
61
64
|
}
|
|
62
|
-
declare const AdminApp: Component<Props, {}, "">;
|
|
65
|
+
declare const AdminApp: Component<Props, {}, "locale">;
|
|
63
66
|
type AdminApp = ReturnType<typeof AdminApp>;
|
|
64
67
|
export default AdminApp;
|