@svadmin/ui 0.38.1 → 0.38.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.css +10 -5
- package/dist/app.theme.css +1374 -0
- 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 +85 -71
- 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 -9
- 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 +18 -12
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { getResources, canAccessAsync } from '@svadmin/core';
|
|
2
|
+
import { captureAdminContext, getResources, canAccessAsync } from '@svadmin/core';
|
|
3
3
|
import type { Identity, MenuItem } from '@svadmin/core';
|
|
4
|
-
import { navigate } from '@svadmin/core/router';
|
|
5
4
|
import { getPath } from '../router-state.svelte.js';
|
|
6
|
-
import {
|
|
5
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
6
|
+
|
|
7
7
|
import { toggleTheme, getResolvedTheme, getColorThemes, getColorTheme, setColorTheme } from '@svadmin/core';
|
|
8
8
|
import { Button } from './ui/button/index.js';
|
|
9
9
|
import TooltipButton from './TooltipButton.svelte';
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
Calendar, Bell, Clock, Tag, Trash2, Shield
|
|
23
23
|
} from '@lucide/svelte';
|
|
24
24
|
|
|
25
|
+
const i18n = useTranslation();
|
|
26
|
+
|
|
25
27
|
let { collapsed, identity, title, onToggle, onLogout, menu, routeMode = 'auto' }: {
|
|
26
28
|
collapsed: boolean;
|
|
27
29
|
identity: Identity | null;
|
|
@@ -31,6 +33,7 @@
|
|
|
31
33
|
menu?: MenuItem[];
|
|
32
34
|
routeMode?: 'hash' | 'path' | 'auto';
|
|
33
35
|
} = $props();
|
|
36
|
+
const adminContext = captureAdminContext();
|
|
34
37
|
|
|
35
38
|
const effectiveRouteMode = $derived(
|
|
36
39
|
routeMode === 'auto'
|
|
@@ -38,6 +41,11 @@
|
|
|
38
41
|
: routeMode
|
|
39
42
|
);
|
|
40
43
|
|
|
44
|
+
function formatSidebarLink(path: string): string {
|
|
45
|
+
if (adminContext.routerProvider) return adminContext.formatLink(path);
|
|
46
|
+
return effectiveRouteMode === 'hash' ? `#${path}` : path;
|
|
47
|
+
}
|
|
48
|
+
|
|
41
49
|
const iconMap: Record<string, typeof LayoutDashboard> = {
|
|
42
50
|
'dashboard': LayoutDashboard,
|
|
43
51
|
'posts': FileText,
|
|
@@ -97,7 +105,7 @@
|
|
|
97
105
|
let navItems = $state.raw<NavItem[]>([]);
|
|
98
106
|
|
|
99
107
|
$effect(() => {
|
|
100
|
-
|
|
108
|
+
const homeLabel = i18n.t('common.home');
|
|
101
109
|
const currentResources = getResources();
|
|
102
110
|
let cancelled = false;
|
|
103
111
|
|
|
@@ -110,7 +118,7 @@
|
|
|
110
118
|
}
|
|
111
119
|
})).then(results => {
|
|
112
120
|
if (cancelled) return;
|
|
113
|
-
const items: NavItem[] = [{ path: '/', label:
|
|
121
|
+
const items: NavItem[] = [{ path: '/', label: homeLabel, Icon: LayoutDashboard }];
|
|
114
122
|
for (const { r, can } of results) {
|
|
115
123
|
if (can) {
|
|
116
124
|
items.push({
|
|
@@ -128,14 +136,14 @@
|
|
|
128
136
|
});
|
|
129
137
|
|
|
130
138
|
function toggleLocale() {
|
|
131
|
-
const locales = getAvailableLocales();
|
|
132
|
-
const current =
|
|
139
|
+
const locales = i18n.getAvailableLocales();
|
|
140
|
+
const current = i18n.locale;
|
|
133
141
|
const idx = locales.indexOf(current);
|
|
134
142
|
const next = locales[(idx + 1) % locales.length];
|
|
135
|
-
setLocale(next);
|
|
143
|
+
i18n.setLocale(next);
|
|
136
144
|
}
|
|
137
145
|
|
|
138
|
-
const localeLabel = $derived(
|
|
146
|
+
const localeLabel = $derived(i18n.locale === 'zh-CN' ? '中' : 'EN');
|
|
139
147
|
|
|
140
148
|
const path = $derived(getPath());
|
|
141
149
|
|
|
@@ -210,12 +218,12 @@
|
|
|
210
218
|
>
|
|
211
219
|
<div class="flex h-[70px] items-center shrink-0" class:px-5={!collapsed} class:justify-center={collapsed}>
|
|
212
220
|
{#if !collapsed}
|
|
213
|
-
<a href=
|
|
221
|
+
<a href={formatSidebarLink('/')} class="flex items-center gap-2.5 group" onclick={(e) => { e.preventDefault(); adminContext.navigate('/'); }}>
|
|
214
222
|
<div class="w-[34px] h-[34px] rounded-lg bg-gradient-to-tr from-primary to-purple-500 shrink-0 transition-transform group-hover:scale-105" style="box-shadow: 0 4px 12px oklch(0.488 0.243 264.376 / 20%);"></div>
|
|
215
223
|
<span class="font-semibold text-[15px] tracking-[-0.01em] text-sidebar-foreground">{title}</span>
|
|
216
224
|
</a>
|
|
217
225
|
{:else}
|
|
218
|
-
<a href=
|
|
226
|
+
<a href={formatSidebarLink('/')} class="group" aria-label={title} onclick={(e) => { e.preventDefault(); adminContext.navigate('/'); }}>
|
|
219
227
|
<div class="w-[34px] h-[34px] rounded-lg bg-gradient-to-tr from-primary to-purple-500 shrink-0 transition-transform group-hover:scale-105" style="box-shadow: 0 4px 12px oklch(0.488 0.243 264.376 / 20%);"></div>
|
|
220
228
|
</a>
|
|
221
229
|
{/if}
|
|
@@ -248,8 +256,8 @@
|
|
|
248
256
|
{#each group.items as item, _i (_i)}
|
|
249
257
|
{@const active = isActive(item.path)}
|
|
250
258
|
<a
|
|
251
|
-
href={
|
|
252
|
-
onclick={(e) => { e.preventDefault(); navigate(item.path); }}
|
|
259
|
+
href={formatSidebarLink(item.path)}
|
|
260
|
+
onclick={(e) => { e.preventDefault(); adminContext.navigate(item.path); }}
|
|
253
261
|
class="sidebar-menu-item flex items-center gap-2.5 rounded-md px-[10px] {pyClassGroupItem} text-[13px] font-medium transition-colors duration-150
|
|
254
262
|
{active
|
|
255
263
|
? 'sidebar-menu-item-active bg-sidebar-accent text-primary'
|
|
@@ -271,8 +279,8 @@
|
|
|
271
279
|
{#snippet child({ props }: { props: Record<string, unknown> })}
|
|
272
280
|
<a
|
|
273
281
|
{...props}
|
|
274
|
-
href={
|
|
275
|
-
onclick={(e) => { e.preventDefault(); navigate(item.path); }}
|
|
282
|
+
href={formatSidebarLink(item.path)}
|
|
283
|
+
onclick={(e) => { e.preventDefault(); adminContext.navigate(item.path); }}
|
|
276
284
|
class="sidebar-menu-item flex items-center justify-center rounded-md px-2 {pyClass} transition-colors duration-150
|
|
277
285
|
{active
|
|
278
286
|
? 'sidebar-menu-item-active bg-sidebar-accent text-primary'
|
|
@@ -288,8 +296,8 @@
|
|
|
288
296
|
</Tooltip.Root>
|
|
289
297
|
{:else}
|
|
290
298
|
<a
|
|
291
|
-
href={
|
|
292
|
-
onclick={(e) => { e.preventDefault(); navigate(item.path); }}
|
|
299
|
+
href={formatSidebarLink(item.path)}
|
|
300
|
+
onclick={(e) => { e.preventDefault(); adminContext.navigate(item.path); }}
|
|
293
301
|
class="sidebar-menu-item flex items-center gap-2.5 rounded-md px-[10px] {pyClass} text-[13px] font-medium transition-colors duration-150
|
|
294
302
|
{active
|
|
295
303
|
? 'sidebar-menu-item-active bg-sidebar-accent text-primary'
|
|
@@ -315,7 +323,7 @@
|
|
|
315
323
|
onclick={() => { if (!colorPickerOpen) colorPickerOpenedAt = Date.now(); colorPickerOpen = !colorPickerOpen; }}
|
|
316
324
|
>
|
|
317
325
|
<Palette class="h-3.5 w-3.5" />
|
|
318
|
-
<span class="flex-1 text-left">{t('common.toggleTheme')}</span>
|
|
326
|
+
<span class="flex-1 text-left">{i18n.t('common.toggleTheme')}</span>
|
|
319
327
|
<span
|
|
320
328
|
class="h-3 w-3 rounded-full ring-1 ring-offset-1 ring-offset-sidebar"
|
|
321
329
|
style="background-color: {getColorThemes().find(c => c.id === getColorTheme())?.color ?? '#6366f1'}; --tw-ring-color: {getColorThemes().find(c => c.id === getColorTheme())?.color ?? '#6366f1'}"
|
|
@@ -363,21 +371,21 @@
|
|
|
363
371
|
</div>
|
|
364
372
|
<div class="mt-1 flex items-center justify-between px-1">
|
|
365
373
|
<div class="flex items-center gap-0.5">
|
|
366
|
-
<TooltipButton tooltip={t('common.switchLanguage')} variant="ghost" size="icon-sm" onclick={toggleLocale} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
374
|
+
<TooltipButton tooltip={i18n.t('common.switchLanguage')} variant="ghost" size="icon-sm" onclick={toggleLocale} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
367
375
|
<span class="text-[11px] font-semibold">{localeLabel}</span>
|
|
368
376
|
</TooltipButton>
|
|
369
|
-
<TooltipButton tooltip={t('common.toggleTheme')} variant="ghost" size="icon-sm" onclick={toggleTheme} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
377
|
+
<TooltipButton tooltip={i18n.t('common.toggleTheme')} variant="ghost" size="icon-sm" onclick={toggleTheme} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
370
378
|
{#if getResolvedTheme() === 'dark'}
|
|
371
379
|
<Sun class="h-3.5 w-3.5" />
|
|
372
380
|
{:else}
|
|
373
381
|
<Moon class="h-3.5 w-3.5" />
|
|
374
382
|
{/if}
|
|
375
383
|
</TooltipButton>
|
|
376
|
-
<TooltipButton tooltip={t('settings.title')} variant="ghost" size="icon-sm" onclick={() => navigate('/settings')} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
384
|
+
<TooltipButton tooltip={i18n.t('settings.title')} variant="ghost" size="icon-sm" onclick={() => adminContext.navigate('/settings')} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
377
385
|
<Settings class="h-3.5 w-3.5" />
|
|
378
386
|
</TooltipButton>
|
|
379
387
|
</div>
|
|
380
|
-
<TooltipButton tooltip={t('common.toggleSidebar')} variant="ghost" size="icon-sm" onclick={onToggle} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
388
|
+
<TooltipButton tooltip={i18n.t('common.toggleSidebar')} variant="ghost" size="icon-sm" onclick={onToggle} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
381
389
|
<ChevronLeft class="h-3.5 w-3.5" />
|
|
382
390
|
</TooltipButton>
|
|
383
391
|
</div>
|
|
@@ -392,7 +400,7 @@
|
|
|
392
400
|
</Button>
|
|
393
401
|
{/snippet}
|
|
394
402
|
</Tooltip.Trigger>
|
|
395
|
-
<Tooltip.Content side="right">{t('common.switchLanguage')}</Tooltip.Content>
|
|
403
|
+
<Tooltip.Content side="right">{i18n.t('common.switchLanguage')}</Tooltip.Content>
|
|
396
404
|
</Tooltip.Root>
|
|
397
405
|
<Tooltip.Root>
|
|
398
406
|
<Tooltip.Trigger>
|
|
@@ -406,7 +414,7 @@
|
|
|
406
414
|
</Button>
|
|
407
415
|
{/snippet}
|
|
408
416
|
</Tooltip.Trigger>
|
|
409
|
-
<Tooltip.Content side="right">{t('common.toggleTheme')}</Tooltip.Content>
|
|
417
|
+
<Tooltip.Content side="right">{i18n.t('common.toggleTheme')}</Tooltip.Content>
|
|
410
418
|
</Tooltip.Root>
|
|
411
419
|
<Tooltip.Root>
|
|
412
420
|
<Tooltip.Trigger>
|
|
@@ -416,7 +424,7 @@
|
|
|
416
424
|
</Button>
|
|
417
425
|
{/snippet}
|
|
418
426
|
</Tooltip.Trigger>
|
|
419
|
-
<Tooltip.Content side="right">{t('common.toggleSidebar')}</Tooltip.Content>
|
|
427
|
+
<Tooltip.Content side="right">{i18n.t('common.toggleSidebar')}</Tooltip.Content>
|
|
420
428
|
</Tooltip.Root>
|
|
421
429
|
<Tooltip.Root>
|
|
422
430
|
<Tooltip.Trigger>
|
|
@@ -426,15 +434,15 @@
|
|
|
426
434
|
</Button>
|
|
427
435
|
{/snippet}
|
|
428
436
|
</Tooltip.Trigger>
|
|
429
|
-
<Tooltip.Content side="right">{t('common.logout')}</Tooltip.Content>
|
|
437
|
+
<Tooltip.Content side="right">{i18n.t('common.logout')}</Tooltip.Content>
|
|
430
438
|
</Tooltip.Root>
|
|
431
439
|
</div>
|
|
432
440
|
{:else}
|
|
433
441
|
<div class="flex justify-center gap-1 p-3">
|
|
434
|
-
<TooltipButton tooltip={t('common.switchLanguage')} variant="ghost" size="icon" onclick={toggleLocale} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
442
|
+
<TooltipButton tooltip={i18n.t('common.switchLanguage')} variant="ghost" size="icon" onclick={toggleLocale} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
435
443
|
<span class="text-[11px] font-semibold">{localeLabel}</span>
|
|
436
444
|
</TooltipButton>
|
|
437
|
-
<TooltipButton tooltip={t('common.toggleTheme')} variant="ghost" size="icon" onclick={toggleTheme} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
445
|
+
<TooltipButton tooltip={i18n.t('common.toggleTheme')} variant="ghost" size="icon" onclick={toggleTheme} class="h-8 w-8 rounded-md text-sidebar-foreground/50 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground">
|
|
438
446
|
{#if getResolvedTheme() === 'dark'}
|
|
439
447
|
<Sun class="h-3.5 w-3.5" />
|
|
440
448
|
{:else}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type
|
|
2
|
+
import { captureAdminContext, type MenuItem } from '@svadmin/core';
|
|
3
3
|
import * as Collapsible from './ui/collapsible/index.js';
|
|
4
4
|
import * as Tooltip from './ui/tooltip/index.js';
|
|
5
5
|
import { Badge } from './ui/badge/index.js';
|
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
Circle,
|
|
13
13
|
} from '@lucide/svelte';
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
|
|
17
16
|
let { item, currentPath, collapsed = false, depth = 0 }: {
|
|
18
17
|
item: MenuItem;
|
|
19
18
|
currentPath: string;
|
|
20
19
|
collapsed?: boolean;
|
|
21
20
|
depth?: number;
|
|
22
21
|
} = $props();
|
|
22
|
+
const adminContext = captureAdminContext();
|
|
23
23
|
|
|
24
24
|
const iconMap: Record<string, typeof LayoutDashboard> = {
|
|
25
25
|
dashboard: LayoutDashboard,
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
const childActive = $derived(hasActiveChild(item));
|
|
91
91
|
const isExternal = $derived(item.target === '_blank' || item.href?.startsWith('http'));
|
|
92
92
|
|
|
93
|
-
const finalHref = $derived(isExternal ? item.href : (item.href ? formatLink(item.href) : undefined));
|
|
93
|
+
const finalHref = $derived(isExternal ? item.href : (item.href ? adminContext.formatLink(item.href) : undefined));
|
|
94
94
|
|
|
95
95
|
let isOpen = $state(false);
|
|
96
96
|
$effect(() => { if (childActive) isOpen = true; });
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { fly } from 'svelte/transition';
|
|
3
|
-
import { useStepsForm, deriveValidator } from '@svadmin/core';
|
|
3
|
+
import { captureAdminContext, useStepsForm, deriveValidator } from '@svadmin/core';
|
|
4
4
|
import type { FieldDefinition } from '@svadmin/core';
|
|
5
5
|
import { getResource } from '@svadmin/core';
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
7
|
+
|
|
8
8
|
import { Button } from './ui/button/index.js';
|
|
9
9
|
import * as Card from './ui/card/index.js';
|
|
10
10
|
import { Badge } from './ui/badge/index.js';
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
import { Save, ArrowLeft, ArrowRight, Check, Loader2 } from '@lucide/svelte';
|
|
13
13
|
import FieldRenderer from './FieldRenderer.svelte';
|
|
14
14
|
|
|
15
|
+
const i18n = useTranslation();
|
|
16
|
+
|
|
15
17
|
interface StepDef {
|
|
16
18
|
title: string;
|
|
17
19
|
fields: string[];
|
|
@@ -25,6 +27,7 @@
|
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
let { resourceName, id, mode = 'create', steps }: Props = $props();
|
|
30
|
+
const adminContext = captureAdminContext();
|
|
28
31
|
|
|
29
32
|
const resource = $derived(getResource(resourceName));
|
|
30
33
|
const primaryKey = $derived(resource.primaryKey ?? 'id');
|
|
@@ -53,7 +56,7 @@
|
|
|
53
56
|
return d;
|
|
54
57
|
})());
|
|
55
58
|
|
|
56
|
-
const validator = $derived(deriveValidator(flatStepsFields));
|
|
59
|
+
const validator = $derived(deriveValidator(flatStepsFields, { translate: i18n.t }));
|
|
57
60
|
const stepsCount = $derived(steps.length);
|
|
58
61
|
|
|
59
62
|
// ─── useStepsForm: form state + step navigation ──────────────────
|
|
@@ -147,7 +150,7 @@
|
|
|
147
150
|
<Card.CardHeader>
|
|
148
151
|
<Card.CardTitle>{steps[form.steps.currentStep]?.title ?? ''}</Card.CardTitle>
|
|
149
152
|
<Badge variant="outline" class="w-fit">
|
|
150
|
-
{t('common.step')} {form.steps.currentStep + 1} / {totalSteps}
|
|
153
|
+
{i18n.t('common.step')} {form.steps.currentStep + 1} / {totalSteps}
|
|
151
154
|
</Badge>
|
|
152
155
|
</Card.CardHeader>
|
|
153
156
|
<Card.CardContent>
|
|
@@ -168,10 +171,10 @@
|
|
|
168
171
|
<Button
|
|
169
172
|
type="button"
|
|
170
173
|
variant="outline"
|
|
171
|
-
onclick={() => form.steps.currentStep === 0 ? navigate(`/${resourceName}`) : form.steps.prevStep()}
|
|
174
|
+
onclick={() => form.steps.currentStep === 0 ? adminContext.navigate(`/${resourceName}`) : form.steps.prevStep()}
|
|
172
175
|
>
|
|
173
176
|
<ArrowLeft class="h-4 w-4" data-icon="inline-start" />
|
|
174
|
-
{form.steps.currentStep === 0 ? t('common.cancel') : t('common.back')}
|
|
177
|
+
{form.steps.currentStep === 0 ? i18n.t('common.cancel') : i18n.t('common.back')}
|
|
175
178
|
</Button>
|
|
176
179
|
|
|
177
180
|
<Button type="submit" disabled={form.submitting}>
|
|
@@ -182,7 +185,7 @@
|
|
|
182
185
|
{:else}
|
|
183
186
|
<ArrowRight class="h-4 w-4" data-icon="inline-start" />
|
|
184
187
|
{/if}
|
|
185
|
-
{isLastStep ? t('common.save') : t('common.next')}
|
|
188
|
+
{isLastStep ? i18n.t('common.save') : i18n.t('common.next')}
|
|
186
189
|
</Button>
|
|
187
190
|
</div>
|
|
188
191
|
</form>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { useTask, getTaskProvider } from '@svadmin/core';
|
|
3
|
-
import {
|
|
3
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
4
|
+
|
|
4
5
|
import type { TaskProvider, TaskRecord } from '@svadmin/core';
|
|
5
6
|
import { Loader2 } from '@lucide/svelte';
|
|
6
7
|
import * as Card from './ui/card/index.js';
|
|
@@ -21,6 +22,8 @@
|
|
|
21
22
|
resolveTaskUpdatedAt,
|
|
22
23
|
} from './task-utils.js';
|
|
23
24
|
|
|
25
|
+
const i18n = useTranslation();
|
|
26
|
+
|
|
24
27
|
let {
|
|
25
28
|
task,
|
|
26
29
|
taskId,
|
|
@@ -57,7 +60,7 @@
|
|
|
57
60
|
});
|
|
58
61
|
|
|
59
62
|
const resolvedTask = $derived(task ?? query.data);
|
|
60
|
-
const resolvedTitle = $derived(title ?? t('task.detailsTitle'));
|
|
63
|
+
const resolvedTitle = $derived(title ?? i18n.t('task.detailsTitle'));
|
|
61
64
|
|
|
62
65
|
function formatDate(value: unknown) {
|
|
63
66
|
if (!value) return '—';
|
|
@@ -82,7 +85,7 @@
|
|
|
82
85
|
{#if resolvedTask}
|
|
83
86
|
{resolveTaskTitle(resolvedTask)}
|
|
84
87
|
{:else}
|
|
85
|
-
{t('task.detailsSummary')}
|
|
88
|
+
{i18n.t('task.detailsSummary')}
|
|
86
89
|
{/if}
|
|
87
90
|
</Card.Description>
|
|
88
91
|
</Card.Header>
|
|
@@ -90,7 +93,7 @@
|
|
|
90
93
|
{#if useProviderData && taskProvider && query.isLoading}
|
|
91
94
|
<div class="flex h-40 items-center justify-center text-muted-foreground">
|
|
92
95
|
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
|
|
93
|
-
{t('task.loadingDetail')}
|
|
96
|
+
{i18n.t('task.loadingDetail')}
|
|
94
97
|
</div>
|
|
95
98
|
{:else if resolvedTask}
|
|
96
99
|
<div class="flex flex-wrap items-center gap-2">
|
|
@@ -104,38 +107,38 @@
|
|
|
104
107
|
|
|
105
108
|
<div class="grid gap-4 md:grid-cols-2">
|
|
106
109
|
<div class="space-y-1">
|
|
107
|
-
<div class="text-xs uppercase tracking-wide text-muted-foreground">{t('task.createdLabel')}</div>
|
|
110
|
+
<div class="text-xs uppercase tracking-wide text-muted-foreground">{i18n.t('task.createdLabel')}</div>
|
|
108
111
|
<div class="text-sm">{formatDate(resolveTaskCreatedAt(resolvedTask))}</div>
|
|
109
112
|
</div>
|
|
110
113
|
<div class="space-y-1">
|
|
111
|
-
<div class="text-xs uppercase tracking-wide text-muted-foreground">{t('task.updatedLabel')}</div>
|
|
114
|
+
<div class="text-xs uppercase tracking-wide text-muted-foreground">{i18n.t('task.updatedLabel')}</div>
|
|
112
115
|
<div class="text-sm">{formatDate(resolveTaskUpdatedAt(resolvedTask))}</div>
|
|
113
116
|
</div>
|
|
114
117
|
</div>
|
|
115
118
|
|
|
116
119
|
{#if resolveTaskMessage(resolvedTask)}
|
|
117
120
|
<div class="space-y-1">
|
|
118
|
-
<div class="text-xs uppercase tracking-wide text-muted-foreground">{t('task.messageLabel')}</div>
|
|
121
|
+
<div class="text-xs uppercase tracking-wide text-muted-foreground">{i18n.t('task.messageLabel')}</div>
|
|
119
122
|
<div class="rounded-md border border-border/60 bg-muted/30 p-3 text-sm">{resolveTaskMessage(resolvedTask)}</div>
|
|
120
123
|
</div>
|
|
121
124
|
{/if}
|
|
122
125
|
|
|
123
126
|
{#if resolveTaskError(resolvedTask)}
|
|
124
127
|
<div class="space-y-1">
|
|
125
|
-
<div class="text-xs uppercase tracking-wide text-destructive">{t('task.errorLabel')}</div>
|
|
128
|
+
<div class="text-xs uppercase tracking-wide text-destructive">{i18n.t('task.errorLabel')}</div>
|
|
126
129
|
<pre class="overflow-auto rounded-md border border-destructive/20 bg-destructive/5 p-3 text-xs text-destructive">{toPrettyJson(resolveTaskError(resolvedTask))}</pre>
|
|
127
130
|
</div>
|
|
128
131
|
{/if}
|
|
129
132
|
|
|
130
133
|
{#if resolveTaskResult(resolvedTask) !== undefined}
|
|
131
134
|
<div class="space-y-1">
|
|
132
|
-
<div class="text-xs uppercase tracking-wide text-muted-foreground">{t('task.resultLabel')}</div>
|
|
135
|
+
<div class="text-xs uppercase tracking-wide text-muted-foreground">{i18n.t('task.resultLabel')}</div>
|
|
133
136
|
<pre class="overflow-auto rounded-md border border-border/60 bg-muted/20 p-3 text-xs">{toPrettyJson(resolveTaskResult(resolvedTask))}</pre>
|
|
134
137
|
</div>
|
|
135
138
|
{/if}
|
|
136
139
|
|
|
137
140
|
<div class="space-y-1">
|
|
138
|
-
<div class="text-xs uppercase tracking-wide text-muted-foreground">{t('task.payloadLabel')}</div>
|
|
141
|
+
<div class="text-xs uppercase tracking-wide text-muted-foreground">{i18n.t('task.payloadLabel')}</div>
|
|
139
142
|
<pre class="overflow-auto rounded-md border border-border/60 bg-muted/20 p-3 text-xs">{toPrettyJson(resolvedTask.payload ?? resolvedTask)}</pre>
|
|
140
143
|
</div>
|
|
141
144
|
|
|
@@ -151,7 +154,7 @@
|
|
|
151
154
|
{/if}
|
|
152
155
|
{:else}
|
|
153
156
|
<div class="flex h-32 items-center justify-center text-sm text-muted-foreground">
|
|
154
|
-
{t('task.noSelection')}
|
|
157
|
+
{i18n.t('task.noSelection')}
|
|
155
158
|
</div>
|
|
156
159
|
{/if}
|
|
157
160
|
</Card.Content>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { useTaskList, getTaskProvider } from '@svadmin/core';
|
|
3
|
-
import {
|
|
3
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
4
|
+
|
|
4
5
|
import type { TaskProvider, TaskRecord } from '@svadmin/core';
|
|
5
6
|
import { Loader2 } from '@lucide/svelte';
|
|
6
7
|
import * as Card from './ui/card/index.js';
|
|
@@ -19,6 +20,8 @@
|
|
|
19
20
|
resolveTaskUpdatedAt,
|
|
20
21
|
} from './task-utils.js';
|
|
21
22
|
|
|
23
|
+
const i18n = useTranslation();
|
|
24
|
+
|
|
22
25
|
let {
|
|
23
26
|
tasks,
|
|
24
27
|
taskProvider = getTaskProvider({ optional: true }) as TaskProvider<TaskRecord> | undefined,
|
|
@@ -68,8 +71,8 @@
|
|
|
68
71
|
});
|
|
69
72
|
|
|
70
73
|
const resolvedTasks = $derived(tasks ?? query.data?.data ?? []);
|
|
71
|
-
const resolvedTitle = $derived(title ?? (dlq ? t('task.dlqTitle') : t('task.listTitle')));
|
|
72
|
-
const resolvedEmptyText = $derived(emptyText ?? (dlq ? t('task.noDlq') : t('task.noTasks')));
|
|
74
|
+
const resolvedTitle = $derived(title ?? (dlq ? i18n.t('task.dlqTitle') : i18n.t('task.listTitle')));
|
|
75
|
+
const resolvedEmptyText = $derived(emptyText ?? (dlq ? i18n.t('task.noDlq') : i18n.t('task.noTasks')));
|
|
73
76
|
|
|
74
77
|
function formatDate(value: unknown) {
|
|
75
78
|
if (!value) return '—';
|
|
@@ -84,9 +87,9 @@
|
|
|
84
87
|
<Card.Title class="text-base">{resolvedTitle}</Card.Title>
|
|
85
88
|
<Card.Description>
|
|
86
89
|
{#if useProviderData && taskProvider}
|
|
87
|
-
{t('task.count', { count: (query.data?.total ?? resolvedTasks.length) || 0 })}
|
|
90
|
+
{i18n.t('task.count', { count: (query.data?.total ?? resolvedTasks.length) || 0 })}
|
|
88
91
|
{:else}
|
|
89
|
-
{t('task.count', { count: resolvedTasks.length })}
|
|
92
|
+
{i18n.t('task.count', { count: resolvedTasks.length })}
|
|
90
93
|
{/if}
|
|
91
94
|
</Card.Description>
|
|
92
95
|
</Card.Header>
|
|
@@ -94,18 +97,18 @@
|
|
|
94
97
|
{#if useProviderData && taskProvider && query.isLoading}
|
|
95
98
|
<div class="flex h-40 items-center justify-center text-muted-foreground">
|
|
96
99
|
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
|
|
97
|
-
{t('task.loadingList')}
|
|
100
|
+
{i18n.t('task.loadingList')}
|
|
98
101
|
</div>
|
|
99
102
|
{:else}
|
|
100
103
|
<div class="overflow-auto">
|
|
101
104
|
<Table.Root>
|
|
102
105
|
<Table.Header>
|
|
103
106
|
<Table.Row>
|
|
104
|
-
<Table.Head>{t('task.taskColumn')}</Table.Head>
|
|
105
|
-
<Table.Head>{t('task.statusColumn')}</Table.Head>
|
|
106
|
-
<Table.Head>{t('task.updatedColumn')}</Table.Head>
|
|
107
|
+
<Table.Head>{i18n.t('task.taskColumn')}</Table.Head>
|
|
108
|
+
<Table.Head>{i18n.t('task.statusColumn')}</Table.Head>
|
|
109
|
+
<Table.Head>{i18n.t('task.updatedColumn')}</Table.Head>
|
|
107
110
|
{#if showActions}
|
|
108
|
-
<Table.Head class="text-right">{t('task.actionsColumn')}</Table.Head>
|
|
111
|
+
<Table.Head class="text-right">{i18n.t('task.actionsColumn')}</Table.Head>
|
|
109
112
|
{/if}
|
|
110
113
|
</Table.Row>
|
|
111
114
|
</Table.Header>
|
|
@@ -139,7 +142,7 @@
|
|
|
139
142
|
<CancelTaskButton taskId={task.id} {taskProvider} />
|
|
140
143
|
{/if}
|
|
141
144
|
<Button variant="ghost" size="sm" onclick={(e) => { e.stopPropagation(); onSelect?.(task); }}>
|
|
142
|
-
{t('task.detailsAction')}
|
|
145
|
+
{i18n.t('task.detailsAction')}
|
|
143
146
|
</Button>
|
|
144
147
|
</div>
|
|
145
148
|
</Table.Cell>
|