@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { getResource } from '@svadmin/core';
|
|
3
|
-
import {
|
|
4
|
-
|
|
2
|
+
import { captureAdminContext, getResource } from '@svadmin/core';
|
|
3
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
4
|
+
|
|
5
5
|
import type { Snippet } from 'svelte';
|
|
6
6
|
import PageHeader from './PageHeader.svelte';
|
|
7
7
|
import AutoForm from './AutoForm.svelte';
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
import RefreshButton from './buttons/RefreshButton.svelte';
|
|
11
11
|
import DeleteButton from './buttons/DeleteButton.svelte';
|
|
12
12
|
|
|
13
|
+
const i18n = useTranslation();
|
|
14
|
+
|
|
13
15
|
interface Props {
|
|
14
16
|
resourceName: string;
|
|
15
17
|
id: string | number;
|
|
@@ -27,9 +29,10 @@
|
|
|
27
29
|
headerActions,
|
|
28
30
|
class: className = '',
|
|
29
31
|
}: Props = $props();
|
|
32
|
+
const adminContext = captureAdminContext();
|
|
30
33
|
|
|
31
34
|
const resource = $derived(getResource(resourceName));
|
|
32
|
-
const pageTitle = $derived(title ?? `${t('common.edit')} ${resource.label} #${id}`);
|
|
35
|
+
const pageTitle = $derived(title ?? `${i18n.t('common.edit')} ${resource.label} #${id}`);
|
|
33
36
|
const showDelete = $derived(canDelete ?? resource.canDelete !== false);
|
|
34
37
|
</script>
|
|
35
38
|
|
|
@@ -40,7 +43,7 @@
|
|
|
40
43
|
<ShowButton resource={resourceName} recordItemId={id} hideText />
|
|
41
44
|
<RefreshButton resource={resourceName} hideText />
|
|
42
45
|
{#if showDelete !== false}
|
|
43
|
-
<DeleteButton resource={resourceName} recordItemId={id} hideText onSuccess={() => navigate(`/${resourceName}`)} />
|
|
46
|
+
<DeleteButton resource={resourceName} recordItemId={id} hideText onSuccess={() => adminContext.navigate(`/${resourceName}`)} />
|
|
44
47
|
{/if}
|
|
45
48
|
{#if headerActions}
|
|
46
49
|
{@render headerActions()}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { scale } from 'svelte/transition';
|
|
3
3
|
import { PackageOpen } from '@lucide/svelte';
|
|
4
|
-
import {
|
|
4
|
+
import { useTranslation } from '@svadmin/core';
|
|
5
|
+
|
|
6
|
+
const i18n = useTranslation();
|
|
5
7
|
|
|
6
8
|
let {
|
|
7
|
-
title = t('empty.title'),
|
|
8
|
-
description = t('empty.description'),
|
|
9
|
+
title = i18n.t('empty.title'),
|
|
10
|
+
description = i18n.t('empty.description'),
|
|
9
11
|
children,
|
|
10
12
|
} = $props<{
|
|
11
13
|
title?: string;
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
import { AlertTriangle } from '@lucide/svelte';
|
|
4
4
|
import { Button } from './ui/button/index.js';
|
|
5
5
|
import * as Alert from './ui/alert/index.js';
|
|
6
|
-
import {
|
|
6
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
7
|
+
|
|
8
|
+
const i18n = useTranslation();
|
|
7
9
|
|
|
8
10
|
let {
|
|
9
11
|
children,
|
|
@@ -32,14 +34,14 @@
|
|
|
32
34
|
<div class="flex items-start gap-3">
|
|
33
35
|
<AlertTriangle class="h-5 w-5 mt-0.5 shrink-0" />
|
|
34
36
|
<div class="space-y-2">
|
|
35
|
-
<Alert.Title>{t('common.error')}</Alert.Title>
|
|
37
|
+
<Alert.Title>{i18n.t('common.error')}</Alert.Title>
|
|
36
38
|
<Alert.Description class="text-sm">
|
|
37
39
|
{error instanceof Error ? error.message : String(error)}
|
|
38
40
|
</Alert.Description>
|
|
39
41
|
</div>
|
|
40
42
|
</div>
|
|
41
43
|
<Button variant="outline" size="sm" onclick={reset} class="w-full">
|
|
42
|
-
{t('common.retry')}
|
|
44
|
+
{i18n.t('common.retry')}
|
|
43
45
|
</Button>
|
|
44
46
|
</Alert.Root>
|
|
45
47
|
</div>
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { AlertTriangle, RefreshCw } from '@lucide/svelte';
|
|
3
|
-
import {
|
|
3
|
+
import { useTranslation } from '@svadmin/core';
|
|
4
4
|
import { Button } from './ui/button';
|
|
5
5
|
import * as Alert from './ui/alert/index.js';
|
|
6
6
|
|
|
7
|
+
const i18n = useTranslation();
|
|
8
|
+
|
|
7
9
|
let {
|
|
8
10
|
error,
|
|
9
|
-
title = t('error.title'),
|
|
10
|
-
description = t('error.description'),
|
|
11
|
+
title = i18n.t('error.title'),
|
|
12
|
+
description = i18n.t('error.description'),
|
|
11
13
|
retry,
|
|
12
14
|
} = $props<{
|
|
13
15
|
error?: Error | null;
|
|
@@ -28,7 +30,7 @@
|
|
|
28
30
|
<div class="mt-4">
|
|
29
31
|
<Button variant="outline" size="sm" onclick={retry}>
|
|
30
32
|
<RefreshCw class="h-3 w-3" data-icon="inline-start" />
|
|
31
|
-
{t('buttons.retry')}
|
|
33
|
+
{i18n.t('buttons.retry')}
|
|
32
34
|
</Button>
|
|
33
35
|
</div>
|
|
34
36
|
{/if}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { captureAdminContext } from '@svadmin/core';
|
|
3
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
4
|
+
|
|
4
5
|
import { AlertTriangle, ArrowLeft, FileQuestion, Home } from '@lucide/svelte';
|
|
5
6
|
import { Button } from './ui/button/index.js';
|
|
6
7
|
import * as Card from './ui/card/index.js';
|
|
7
8
|
|
|
9
|
+
const i18n = useTranslation();
|
|
10
|
+
|
|
8
11
|
interface Props {
|
|
9
12
|
status?: '404' | '500';
|
|
10
13
|
title?: string;
|
|
@@ -12,17 +15,16 @@
|
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
let { status = '404', title, description }: Props = $props();
|
|
18
|
+
const adminContext = captureAdminContext();
|
|
15
19
|
|
|
16
20
|
function goBack() {
|
|
17
|
-
|
|
18
|
-
window.history.back();
|
|
19
|
-
}
|
|
21
|
+
adminContext.back();
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
const isNotFound = $derived(status === '404');
|
|
23
|
-
const resolvedTitle = $derived(title ?? (isNotFound ? t('common.pageNotFound') : t('common.error')));
|
|
25
|
+
const resolvedTitle = $derived(title ?? (isNotFound ? i18n.t('common.pageNotFound') : i18n.t('common.error')));
|
|
24
26
|
const resolvedDescription = $derived(
|
|
25
|
-
description ?? (isNotFound ? t('error.pageNotFoundDescription') : t('error.internalServerErrorDescription')),
|
|
27
|
+
description ?? (isNotFound ? i18n.t('error.pageNotFoundDescription') : i18n.t('error.internalServerErrorDescription')),
|
|
26
28
|
);
|
|
27
29
|
</script>
|
|
28
30
|
|
|
@@ -46,11 +48,11 @@
|
|
|
46
48
|
<div class="flex flex-col justify-center gap-2 sm:flex-row">
|
|
47
49
|
<Button variant="outline" onclick={goBack}>
|
|
48
50
|
<ArrowLeft class="h-4 w-4" />
|
|
49
|
-
{t('common.back')}
|
|
51
|
+
{i18n.t('common.back')}
|
|
50
52
|
</Button>
|
|
51
|
-
<Button onclick={() => navigate('/')}>
|
|
53
|
+
<Button onclick={() => adminContext.navigate('/')}>
|
|
52
54
|
<Home class="h-4 w-4" />
|
|
53
|
-
{t('common.returnHome')}
|
|
55
|
+
{i18n.t('common.returnHome')}
|
|
54
56
|
</Button>
|
|
55
57
|
</div>
|
|
56
58
|
</Card.CardContent>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
<script lang="ts">
|
|
7
7
|
import type { FieldDefinition } from '@svadmin/core';
|
|
8
|
-
import {
|
|
8
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
9
9
|
import { Input } from './ui/input/index.js';
|
|
10
10
|
import { Textarea } from './ui/textarea/index.js';
|
|
11
11
|
import { Switch } from './ui/switch/index.js';
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
import type { Snippet } from 'svelte';
|
|
22
22
|
import { getRichTextEditor } from '../editor-config.svelte.js';
|
|
23
23
|
|
|
24
|
+
const i18n = useTranslation();
|
|
25
|
+
|
|
24
26
|
let { field, value, onchange, disabled, children } = $props<{
|
|
25
27
|
field: FieldDefinition;
|
|
26
28
|
value: unknown;
|
|
@@ -107,7 +109,7 @@
|
|
|
107
109
|
oninput={(e) => onchange((e.target as HTMLInputElement).value)}
|
|
108
110
|
required={field.required}
|
|
109
111
|
{disabled}
|
|
110
|
-
placeholder={t('field.enterValue', { label: field.label })}
|
|
112
|
+
placeholder={i18n.t('field.enterValue', { label: field.label })}
|
|
111
113
|
/>
|
|
112
114
|
|
|
113
115
|
{:else if field.type === 'email'}
|
|
@@ -188,7 +190,7 @@
|
|
|
188
190
|
<EditorComp
|
|
189
191
|
id={field.key}
|
|
190
192
|
value={strVal}
|
|
191
|
-
placeholder={t('field.enterValue', { label: field.label })}
|
|
193
|
+
placeholder={i18n.t('field.enterValue', { label: field.label })}
|
|
192
194
|
preset="full"
|
|
193
195
|
onchange={(html: string) => onchange(html)}
|
|
194
196
|
{disabled}
|
|
@@ -201,7 +203,7 @@
|
|
|
201
203
|
required={field.required}
|
|
202
204
|
{disabled}
|
|
203
205
|
rows={10}
|
|
204
|
-
placeholder={t('field.enterValue', { label: field.label })}
|
|
206
|
+
placeholder={i18n.t('field.enterValue', { label: field.label })}
|
|
205
207
|
class="resize-y"
|
|
206
208
|
/>
|
|
207
209
|
{/if}
|
|
@@ -214,7 +216,7 @@
|
|
|
214
216
|
required={field.required}
|
|
215
217
|
{disabled}
|
|
216
218
|
rows={4}
|
|
217
|
-
placeholder={t('field.enterValue', { label: field.label })}
|
|
219
|
+
placeholder={i18n.t('field.enterValue', { label: field.label })}
|
|
218
220
|
class="resize-y"
|
|
219
221
|
/>
|
|
220
222
|
|
|
@@ -226,7 +228,7 @@
|
|
|
226
228
|
onchange={(v) => onchange(v)}
|
|
227
229
|
optionLabel={field.optionLabel ?? 'title'}
|
|
228
230
|
optionValue={field.optionValue ?? 'id'}
|
|
229
|
-
placeholder={t('field.selectPlaceholder')}
|
|
231
|
+
placeholder={i18n.t('field.selectPlaceholder')}
|
|
230
232
|
{disabled}
|
|
231
233
|
/>
|
|
232
234
|
|
|
@@ -240,7 +242,7 @@
|
|
|
240
242
|
required={field.required}
|
|
241
243
|
disabled={disabled}
|
|
242
244
|
>
|
|
243
|
-
<option value="">{t('field.selectPlaceholder')}</option>
|
|
245
|
+
<option value="">{i18n.t('field.selectPlaceholder')}</option>
|
|
244
246
|
{#each field.options ?? [] as opt, _i (_i)}
|
|
245
247
|
<option value={opt.value}>{opt.label}</option>
|
|
246
248
|
{/each}
|
|
@@ -252,7 +254,7 @@
|
|
|
252
254
|
onchange={(e) => onchange((e.target as HTMLSelectElement).value)}
|
|
253
255
|
required={field.required}
|
|
254
256
|
{disabled}
|
|
255
|
-
placeholder={t('field.selectPlaceholder')}
|
|
257
|
+
placeholder={i18n.t('field.selectPlaceholder')}
|
|
256
258
|
>
|
|
257
259
|
{#each field.options ?? [] as opt, _i (_i)}
|
|
258
260
|
<option value={opt.value}>{opt.label}</option>
|
|
@@ -278,7 +280,7 @@
|
|
|
278
280
|
</label>
|
|
279
281
|
{/each}
|
|
280
282
|
{#if !(field.options?.length)}
|
|
281
|
-
<p class="text-xs text-muted-foreground">{t('field.noOptions')}</p>
|
|
283
|
+
<p class="text-xs text-muted-foreground">{i18n.t('field.noOptions')}</p>
|
|
282
284
|
{/if}
|
|
283
285
|
</div>
|
|
284
286
|
{#if multiVal.length > 0}
|
|
@@ -287,7 +289,7 @@
|
|
|
287
289
|
{@const label = field.options?.find((o: { label: string; value: string | number }) => o.value === v)?.label ?? String(v)}
|
|
288
290
|
<Badge variant="secondary" class="gap-1">
|
|
289
291
|
{label}
|
|
290
|
-
<button type="button" onclick={() => toggleMulti(v)} class="ml-0.5 rounded-sm hover:text-destructive hover:bg-destructive/10 transition-colors" aria-label={t('common.clear')}>×</button>
|
|
292
|
+
<button type="button" onclick={() => toggleMulti(v)} class="ml-0.5 rounded-sm hover:text-destructive hover:bg-destructive/10 transition-colors" aria-label={i18n.t('common.clear')}>×</button>
|
|
291
293
|
</Badge>
|
|
292
294
|
{/each}
|
|
293
295
|
</div>
|
|
@@ -301,7 +303,7 @@
|
|
|
301
303
|
onCheckedChange={(v) => onchange(v)}
|
|
302
304
|
disabled={disabled}
|
|
303
305
|
/>
|
|
304
|
-
<span class="text-sm text-muted-foreground">{boolVal ? t('common.yes') : t('common.no')}</span>
|
|
306
|
+
<span class="text-sm text-muted-foreground">{boolVal ? i18n.t('common.yes') : i18n.t('common.no')}</span>
|
|
305
307
|
</div>
|
|
306
308
|
|
|
307
309
|
{:else if field.type === 'tags'}
|
|
@@ -314,7 +316,7 @@
|
|
|
314
316
|
type="button"
|
|
315
317
|
onclick={() => removeTag(i)}
|
|
316
318
|
class="ml-0.5 rounded-sm hover:text-destructive hover:bg-destructive/10 transition-colors"
|
|
317
|
-
aria-label={t('common.clear')}
|
|
319
|
+
aria-label={i18n.t('common.clear')}
|
|
318
320
|
>×</button>
|
|
319
321
|
</Badge>
|
|
320
322
|
{/each}
|
|
@@ -322,7 +324,7 @@
|
|
|
322
324
|
<Input
|
|
323
325
|
id={field.key}
|
|
324
326
|
type="text"
|
|
325
|
-
placeholder={t('field.tagsPlaceholder')}
|
|
327
|
+
placeholder={i18n.t('field.tagsPlaceholder')}
|
|
326
328
|
onkeydown={handleTagKeydown}
|
|
327
329
|
{disabled}
|
|
328
330
|
/>
|
|
@@ -354,13 +356,13 @@
|
|
|
354
356
|
{#if url}
|
|
355
357
|
<img src={url} alt="preview" class="h-9 w-9 rounded object-cover border" />
|
|
356
358
|
{/if}
|
|
357
|
-
<TooltipButton tooltip={t('common.removeImage')} variant="ghost" size="icon" class="h-8 w-8 shrink-0" onclick={() => removeImage(i)}>
|
|
359
|
+
<TooltipButton tooltip={i18n.t('common.removeImage')} variant="ghost" size="icon" class="h-8 w-8 shrink-0" onclick={() => removeImage(i)}>
|
|
358
360
|
<X class="h-3.5 w-3.5" />
|
|
359
361
|
</TooltipButton>
|
|
360
362
|
</div>
|
|
361
363
|
{/each}
|
|
362
364
|
<Button variant="outline" size="sm" type="button" onclick={addImage}>
|
|
363
|
-
<Plus class="h-3.5 w-3.5 mr-1" /> {t('field.addImage')}
|
|
365
|
+
<Plus class="h-3.5 w-3.5 mr-1" /> {i18n.t('field.addImage')}
|
|
364
366
|
</Button>
|
|
365
367
|
</div>
|
|
366
368
|
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { useForgotPassword } from '@svadmin/core';
|
|
3
|
-
import {
|
|
4
|
-
|
|
2
|
+
import { captureAdminContext, useForgotPassword } from '@svadmin/core';
|
|
3
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
4
|
+
|
|
5
5
|
import { Button } from './ui/button/index.js';
|
|
6
6
|
import { Input } from './ui/input/index.js';
|
|
7
7
|
import { Label } from './ui/label/index.js';
|
|
8
8
|
import * as Alert from './ui/alert/index.js';
|
|
9
9
|
import { User, ArrowLeft, CheckCircle, Loader2, AlertCircle, Shield } from '@lucide/svelte';
|
|
10
10
|
|
|
11
|
+
const i18n = useTranslation();
|
|
12
|
+
|
|
11
13
|
let { title = 'Admin' } = $props<{
|
|
12
14
|
title?: string;
|
|
13
15
|
}>();
|
|
14
16
|
|
|
17
|
+
const adminContext = captureAdminContext();
|
|
15
18
|
const forgot = useForgotPassword();
|
|
16
19
|
|
|
17
20
|
let identifier = $state('');
|
|
@@ -22,13 +25,13 @@
|
|
|
22
25
|
e.preventDefault();
|
|
23
26
|
error = '';
|
|
24
27
|
|
|
25
|
-
if (!identifier) { error = t('auth.usernameOrEmailRequired'); return; }
|
|
28
|
+
if (!identifier) { error = i18n.t('auth.usernameOrEmailRequired'); return; }
|
|
26
29
|
|
|
27
30
|
const result = await forgot.mutate({ email: identifier, username: identifier });
|
|
28
31
|
if (result.success) {
|
|
29
32
|
sent = true;
|
|
30
33
|
} else {
|
|
31
|
-
error = result.error?.message ?? t('common.operationFailed');
|
|
34
|
+
error = result.error?.message ?? i18n.t('common.operationFailed');
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
37
|
</script>
|
|
@@ -54,10 +57,10 @@
|
|
|
54
57
|
|
|
55
58
|
<div class="space-y-4">
|
|
56
59
|
<h2 class="text-3xl xl:text-4xl font-bold text-white leading-tight">
|
|
57
|
-
{t('auth.forgotPassword')}
|
|
60
|
+
{i18n.t('auth.forgotPassword')}
|
|
58
61
|
</h2>
|
|
59
62
|
<p class="text-base text-white/70 leading-relaxed max-w-[320px]">
|
|
60
|
-
{t('auth.forgotPasswordDescription')}
|
|
63
|
+
{i18n.t('auth.forgotPasswordDescription')}
|
|
61
64
|
</p>
|
|
62
65
|
</div>
|
|
63
66
|
|
|
@@ -82,16 +85,16 @@
|
|
|
82
85
|
<div class="space-y-1 mb-8">
|
|
83
86
|
<h1 class="text-2xl font-semibold tracking-tight">
|
|
84
87
|
{#if sent}
|
|
85
|
-
{t('auth.resetLinkSent')}
|
|
88
|
+
{i18n.t('auth.resetLinkSent')}
|
|
86
89
|
{:else}
|
|
87
|
-
{t('auth.forgotPassword')}
|
|
90
|
+
{i18n.t('auth.forgotPassword')}
|
|
88
91
|
{/if}
|
|
89
92
|
</h1>
|
|
90
93
|
<p class="text-sm text-muted-foreground">
|
|
91
94
|
{#if sent}
|
|
92
|
-
{t('auth.resetLinkSent')}
|
|
95
|
+
{i18n.t('auth.resetLinkSent')}
|
|
93
96
|
{:else}
|
|
94
|
-
{t('auth.forgotPasswordDescription')}
|
|
97
|
+
{i18n.t('auth.forgotPasswordDescription')}
|
|
95
98
|
{/if}
|
|
96
99
|
</p>
|
|
97
100
|
</div>
|
|
@@ -100,11 +103,11 @@
|
|
|
100
103
|
<div class="space-y-4">
|
|
101
104
|
<div class="flex items-center gap-3 rounded-lg border bg-muted/50 p-4">
|
|
102
105
|
<CheckCircle class="h-5 w-5 text-primary shrink-0" />
|
|
103
|
-
<p class="text-sm text-muted-foreground">{t('auth.resetLinkSent')}</p>
|
|
106
|
+
<p class="text-sm text-muted-foreground">{i18n.t('auth.resetLinkSent')}</p>
|
|
104
107
|
</div>
|
|
105
|
-
<Button variant="outline" class="w-full" onclick={() => navigate('/login')}>
|
|
108
|
+
<Button variant="outline" class="w-full" onclick={() => adminContext.navigate('/login')}>
|
|
106
109
|
<ArrowLeft class="h-4 w-4 mr-2" />
|
|
107
|
-
{t('auth.backToLogin')}
|
|
110
|
+
{i18n.t('auth.backToLogin')}
|
|
108
111
|
</Button>
|
|
109
112
|
</div>
|
|
110
113
|
{:else}
|
|
@@ -117,13 +120,13 @@
|
|
|
117
120
|
{/if}
|
|
118
121
|
|
|
119
122
|
<div class="space-y-2">
|
|
120
|
-
<Label for="forgot-identifier">{t('auth.usernameOrEmail')}</Label>
|
|
123
|
+
<Label for="forgot-identifier">{i18n.t('auth.usernameOrEmail')}</Label>
|
|
121
124
|
<div class="relative">
|
|
122
125
|
<User class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none z-[1]" />
|
|
123
126
|
<Input
|
|
124
127
|
id="forgot-identifier"
|
|
125
128
|
type="text"
|
|
126
|
-
placeholder={t('auth.identifierPlaceholder')}
|
|
129
|
+
placeholder={i18n.t('auth.identifierPlaceholder')}
|
|
127
130
|
bind:value={identifier}
|
|
128
131
|
class="pl-9"
|
|
129
132
|
autocomplete="username"
|
|
@@ -135,14 +138,14 @@
|
|
|
135
138
|
{#if forgot.isLoading}
|
|
136
139
|
<Loader2 class="h-4 w-4 animate-spin mr-2" />
|
|
137
140
|
{/if}
|
|
138
|
-
{t('auth.sendResetLink')}
|
|
141
|
+
{i18n.t('auth.sendResetLink')}
|
|
139
142
|
</Button>
|
|
140
143
|
</form>
|
|
141
144
|
|
|
142
145
|
<div class="flex items-center justify-center mt-8 pt-6 border-t">
|
|
143
|
-
<Button variant="link" class="text-sm h-auto p-0 font-medium inline-flex items-center gap-1" onclick={() => navigate('/login')}>
|
|
146
|
+
<Button variant="link" class="text-sm h-auto p-0 font-medium inline-flex items-center gap-1" onclick={() => adminContext.navigate('/login')}>
|
|
144
147
|
<ArrowLeft class="h-3 w-3" />
|
|
145
|
-
{t('auth.backToLogin')}
|
|
148
|
+
{i18n.t('auth.backToLogin')}
|
|
146
149
|
</Button>
|
|
147
150
|
</div>
|
|
148
151
|
{/if}
|
|
@@ -5,9 +5,12 @@
|
|
|
5
5
|
import TooltipButton from './TooltipButton.svelte';
|
|
6
6
|
import { getResolvedTheme, toggleTheme } from '@svadmin/core';
|
|
7
7
|
import Breadcrumbs from './Breadcrumbs.svelte';
|
|
8
|
-
import {
|
|
8
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
9
|
+
|
|
9
10
|
import { getComponentRegistry } from '../component-registry.svelte.js';
|
|
10
11
|
|
|
12
|
+
const i18n = useTranslation();
|
|
13
|
+
|
|
11
14
|
let {
|
|
12
15
|
showThemeToggle = false,
|
|
13
16
|
showBreadcrumbs = true,
|
|
@@ -54,7 +57,7 @@
|
|
|
54
57
|
{/if}
|
|
55
58
|
|
|
56
59
|
{#if siteUrl}
|
|
57
|
-
<TooltipButton tooltip={t('common.goToSite') || 'Site'} href={siteUrl} target="_blank" rel="noopener noreferrer" class="rounded-full flex items-center justify-center">
|
|
60
|
+
<TooltipButton tooltip={i18n.t('common.goToSite') || 'Site'} href={siteUrl} target="_blank" rel="noopener noreferrer" class="rounded-full flex items-center justify-center">
|
|
58
61
|
<MonitorUp class="h-4 w-4 text-muted-foreground transition-colors hover:text-foreground" />
|
|
59
62
|
</TooltipButton>
|
|
60
63
|
{/if}
|
|
@@ -66,7 +69,7 @@
|
|
|
66
69
|
{#if showSearch && onSearchClick}
|
|
67
70
|
<Button variant="outline" size="sm" onclick={onSearchClick} class="gap-2 text-muted-foreground h-9 px-3 rounded-lg border-border/60">
|
|
68
71
|
<Search class="h-3.5 w-3.5" />
|
|
69
|
-
<span class="hidden sm:inline text-xs">{t('common.search')}...</span>
|
|
72
|
+
<span class="hidden sm:inline text-xs">{i18n.t('common.search')}...</span>
|
|
70
73
|
<kbd class="hidden sm:inline-flex items-center gap-0.5 rounded border bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium font-mono text-muted-foreground">
|
|
71
74
|
<span class="text-xs">⌘</span>K
|
|
72
75
|
</kbd>
|
|
@@ -77,7 +80,7 @@
|
|
|
77
80
|
{#if CustomThemeToggle}
|
|
78
81
|
<CustomThemeToggle />
|
|
79
82
|
{:else}
|
|
80
|
-
<TooltipButton tooltip={t('common.toggleTheme')} onclick={() => toggleTheme()} class="rounded-full">
|
|
83
|
+
<TooltipButton tooltip={i18n.t('common.toggleTheme')} onclick={() => toggleTheme()} class="rounded-full">
|
|
81
84
|
{#if getResolvedTheme() === 'dark'}
|
|
82
85
|
<Moon class="h-4 w-4 transition-all" />
|
|
83
86
|
{:else}
|
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
import { useInfiniteList } from '@svadmin/core';
|
|
4
4
|
import type { BaseRecord, Sort, Filter } from '@svadmin/core';
|
|
5
5
|
import type { Snippet } from 'svelte';
|
|
6
|
-
import {
|
|
6
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
7
|
+
|
|
7
8
|
import { Skeleton } from './ui/skeleton/index.js';
|
|
8
9
|
import { Loader2 } from '@lucide/svelte';
|
|
9
10
|
import { intersect } from '../actions.js';
|
|
10
11
|
|
|
12
|
+
const i18n = useTranslation();
|
|
13
|
+
|
|
11
14
|
interface Props<T extends BaseRecord = BaseRecord> {
|
|
12
15
|
resource: string;
|
|
13
16
|
pageSize?: number;
|
|
@@ -67,7 +70,7 @@
|
|
|
67
70
|
{#if empty}
|
|
68
71
|
{@render empty()}
|
|
69
72
|
{:else}
|
|
70
|
-
<p class="text-center text-sm text-muted-foreground py-8">{t('empty.title')}</p>
|
|
73
|
+
<p class="text-center text-sm text-muted-foreground py-8">{i18n.t('empty.title')}</p>
|
|
71
74
|
{/if}
|
|
72
75
|
{:else}
|
|
73
76
|
{#each allItems as item, index (index)}
|
|
@@ -86,7 +89,7 @@
|
|
|
86
89
|
<!-- Sentinel for infinite scroll -->
|
|
87
90
|
<div use:intersect={loadMore} class="h-1"></div>
|
|
88
91
|
{:else}
|
|
89
|
-
<p class="text-center text-xs text-muted-foreground py-2">{t('empty.noMore')}</p>
|
|
92
|
+
<p class="text-center text-xs text-muted-foreground py-2">{i18n.t('empty.noMore')}</p>
|
|
90
93
|
{/if}
|
|
91
94
|
{/if}
|
|
92
95
|
</div>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
3
|
+
|
|
3
4
|
import { AlertCircle, Cloud, FolderGit, MessageCircle, Plug } from '@lucide/svelte';
|
|
4
5
|
import type { Component } from 'svelte';
|
|
5
6
|
import * as Card from './ui/card/index.js';
|
|
6
7
|
import { Switch } from './ui/switch/index.js';
|
|
7
8
|
|
|
9
|
+
const i18n = useTranslation();
|
|
10
|
+
|
|
8
11
|
interface Integration {
|
|
9
12
|
id: string;
|
|
10
13
|
name: string;
|
|
@@ -28,8 +31,8 @@
|
|
|
28
31
|
|
|
29
32
|
<div class="space-y-6">
|
|
30
33
|
<div>
|
|
31
|
-
<h2 class="text-xl font-semibold text-foreground">{t('settings.integrations')}</h2>
|
|
32
|
-
<p class="mt-1 text-sm text-muted-foreground">{t('settings.integrationsDescription')}</p>
|
|
34
|
+
<h2 class="text-xl font-semibold text-foreground">{i18n.t('settings.integrations')}</h2>
|
|
35
|
+
<p class="mt-1 text-sm text-muted-foreground">{i18n.t('settings.integrationsDescription')}</p>
|
|
33
36
|
</div>
|
|
34
37
|
|
|
35
38
|
<div class="grid gap-4">
|
|
@@ -45,14 +48,14 @@
|
|
|
45
48
|
<div class="flex flex-wrap items-center gap-2">
|
|
46
49
|
<span class="font-semibold text-foreground">{integration.name}</span>
|
|
47
50
|
<span class="rounded-full px-2 py-0.5 text-[10px] font-semibold {integration.connected ? 'bg-green-500/10 text-green-600' : 'bg-muted text-muted-foreground'}">
|
|
48
|
-
{integration.connected ? t('integrations.statusConnected') : t('integrations.statusDisconnected')}
|
|
51
|
+
{integration.connected ? i18n.t('integrations.statusConnected') : i18n.t('integrations.statusDisconnected')}
|
|
49
52
|
</span>
|
|
50
53
|
</div>
|
|
51
54
|
<p class="text-sm text-muted-foreground">{integration.description}</p>
|
|
52
55
|
</div>
|
|
53
56
|
</div>
|
|
54
57
|
<div class="flex items-center gap-3">
|
|
55
|
-
<span class="text-xs text-muted-foreground">{integration.connected ? t('integrations.enabled') : t('integrations.disabled')}</span>
|
|
58
|
+
<span class="text-xs text-muted-foreground">{integration.connected ? i18n.t('integrations.enabled') : i18n.t('integrations.disabled')}</span>
|
|
56
59
|
<Switch checked={integration.connected} onCheckedChange={(checked) => toggleConnection(integration.id, checked)} />
|
|
57
60
|
</div>
|
|
58
61
|
</div>
|
|
@@ -64,7 +67,7 @@
|
|
|
64
67
|
<Card.Card class="border-dashed bg-muted/20">
|
|
65
68
|
<Card.CardContent class="flex items-center gap-3 p-5 text-sm text-muted-foreground">
|
|
66
69
|
<AlertCircle class="h-4 w-4 shrink-0" />
|
|
67
|
-
<span>{t('integrations.addMoreHint')}</span>
|
|
70
|
+
<span>{i18n.t('integrations.addMoreHint')}</span>
|
|
68
71
|
</Card.CardContent>
|
|
69
72
|
</Card.Card>
|
|
70
73
|
</div>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
3
3
|
import * as Dialog from './ui/dialog/index.js';
|
|
4
4
|
|
|
5
|
+
const i18n = useTranslation();
|
|
6
|
+
|
|
5
7
|
let { open = $bindable(false) }: { open?: boolean } = $props();
|
|
6
8
|
|
|
7
9
|
interface Shortcut {
|
|
@@ -36,7 +38,7 @@
|
|
|
36
38
|
<Dialog.Root bind:open>
|
|
37
39
|
<Dialog.Content class="max-w-md">
|
|
38
40
|
<Dialog.Header>
|
|
39
|
-
<Dialog.Title>{t('common.keyboardShortcuts') || 'Keyboard Shortcuts'}</Dialog.Title>
|
|
41
|
+
<Dialog.Title>{i18n.t('common.keyboardShortcuts') || 'Keyboard Shortcuts'}</Dialog.Title>
|
|
40
42
|
</Dialog.Header>
|
|
41
43
|
<div class="space-y-4 py-2">
|
|
42
44
|
{#each shortcuts as group, _i (_i)}
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
import CommandPalette from './CommandPalette.svelte';
|
|
8
8
|
import KeyboardShortcuts from './KeyboardShortcuts.svelte';
|
|
9
9
|
import ChatDialog from './ChatDialog.svelte';
|
|
10
|
-
import {
|
|
11
|
-
|
|
10
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
11
|
+
|
|
12
|
+
import { captureAdminContext, getAuthProvider, getTaskProvider } from '@svadmin/core';
|
|
12
13
|
import type { Identity, MenuItem, TaskProvider, TaskRecord } from '@svadmin/core';
|
|
13
|
-
import { navigate } from '@svadmin/core/router';
|
|
14
14
|
import { getPath } from '../router-state.svelte.js';
|
|
15
15
|
import { Skeleton } from './ui/skeleton/index.js';
|
|
16
16
|
import * as Sheet from './ui/sheet/index.js';
|
|
@@ -18,24 +18,23 @@
|
|
|
18
18
|
import { getComponentRegistry } from '../component-registry.svelte.js';
|
|
19
19
|
import { Button } from './ui/button/index.js';
|
|
20
20
|
|
|
21
|
+
const i18n = useTranslation();
|
|
22
|
+
|
|
21
23
|
let commandOpen = $state(false);
|
|
22
24
|
let shortcutsOpen = $state(false);
|
|
23
25
|
let mobileMenuOpen = $state(false);
|
|
24
26
|
|
|
25
27
|
let { children, title = 'Admin', menu, siteUrl, routeMode = 'auto' }: { children: Snippet; title?: string; menu?: MenuItem[]; siteUrl?: string; routeMode?: 'hash' | 'path' | 'auto' } = $props();
|
|
28
|
+
const adminContext = captureAdminContext();
|
|
26
29
|
|
|
27
|
-
let _hasAuth = true;
|
|
28
30
|
let auth: ReturnType<typeof getAuthProvider> | null = null;
|
|
29
31
|
try {
|
|
30
32
|
auth = getAuthProvider();
|
|
31
|
-
} catch {
|
|
32
|
-
_hasAuth = false;
|
|
33
|
-
}
|
|
33
|
+
} catch { /* Auth is optional for public layouts. */ }
|
|
34
34
|
let loading = $state(true);
|
|
35
35
|
let identity = $state<Identity | null>(null);
|
|
36
36
|
const taskProvider = getTaskProvider({ optional: true }) as TaskProvider<TaskRecord> | undefined;
|
|
37
|
-
const
|
|
38
|
-
const TaskQueueComponent = registry.TaskQueueDrawer;
|
|
37
|
+
const TaskQueueComponent = getComponentRegistry()?.TaskQueueDrawer;
|
|
39
38
|
|
|
40
39
|
$effect(() => {
|
|
41
40
|
let cancelled = false;
|
|
@@ -59,10 +58,10 @@
|
|
|
59
58
|
try {
|
|
60
59
|
const result = await auth.logout();
|
|
61
60
|
if (result.success) {
|
|
62
|
-
navigate(result.redirectTo ?? '/login');
|
|
61
|
+
await adminContext.navigate(result.redirectTo ?? '/login');
|
|
63
62
|
}
|
|
64
63
|
} catch {
|
|
65
|
-
navigate('/login');
|
|
64
|
+
await adminContext.navigate('/login');
|
|
66
65
|
}
|
|
67
66
|
}
|
|
68
67
|
|
|
@@ -156,11 +155,11 @@
|
|
|
156
155
|
variant="outline"
|
|
157
156
|
size="sm"
|
|
158
157
|
class="md:hidden gap-1.5 px-2.5"
|
|
159
|
-
aria-label={t('common.menu')}
|
|
158
|
+
aria-label={i18n.t('common.menu')}
|
|
160
159
|
onclick={() => { mobileMenuOpen = true; }}
|
|
161
160
|
>
|
|
162
161
|
<Menu class="h-5 w-5" />
|
|
163
|
-
<span class="text-xs">{t('common.menu')}</span>
|
|
162
|
+
<span class="text-xs">{i18n.t('common.menu')}</span>
|
|
164
163
|
</Button>
|
|
165
164
|
{/snippet}
|
|
166
165
|
{#snippet rightActions()}
|