@svadmin/ui 0.85.0 → 0.86.0
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/README.md +29 -0
- package/dist/app-shell.css +216 -0
- package/dist/app.css +483 -172
- package/dist/app.theme.css +483 -172
- package/dist/component-registry.d.ts +7292 -529
- package/dist/component-registry.js +32 -3
- package/dist/components/AppShellPage.svelte +172 -0
- package/dist/components/AppShellPage.svelte.d.ts +30 -0
- package/dist/components/AutoForm.svelte +7 -12
- package/dist/components/AutoForm.svelte.d.ts +0 -1
- package/dist/components/AutoTable.svelte +2 -0
- package/dist/components/AutoTable.svelte.d.ts +2 -0
- package/dist/components/ConfigurationPage.svelte +0 -3
- package/dist/components/ConfigurationPage.svelte.d.ts +0 -1
- package/dist/components/CreatePage.svelte +1 -5
- package/dist/components/CreatePage.svelte.d.ts +0 -1
- package/dist/components/EditPage.svelte +1 -5
- package/dist/components/EditPage.svelte.d.ts +0 -1
- package/dist/components/FieldRenderer.svelte +2 -10
- package/dist/components/FieldRenderer.svelte.d.ts +0 -1
- package/dist/components/ListPage.svelte +2 -5
- package/dist/components/ListPage.svelte.d.ts +0 -1
- package/dist/components/PageHeader.svelte +1 -3
- package/dist/components/PageHeader.svelte.d.ts +0 -1
- package/dist/components/PagePattern.svelte +36 -13
- package/dist/components/PagePattern.svelte.d.ts +7 -0
- package/dist/components/QuickEditDrawer.svelte +0 -1
- package/dist/components/ShowPage.svelte +5 -9
- package/dist/components/ShowPage.svelte.d.ts +0 -1
- package/dist/components/SvarAutoTable.svelte +2 -1
- package/dist/components/SvarDataGrid.svelte +8 -4
- package/dist/components/SvarDataGrid.svelte.d.ts +3 -0
- package/dist/components/SvarResourceTable.svelte +0 -1
- package/dist/components/SvarResourceTable.svelte.d.ts +0 -1
- package/dist/components/SvarResourceTableView.svelte +2 -2
- package/dist/components/auto-table-grid.d.ts +1 -0
- package/dist/components/content/ContentPageHeader.svelte +2 -1
- package/dist/components/content/ContentPageHeader.svelte.d.ts +1 -0
- package/dist/components/content/ContentPageShell.svelte +1 -1
- package/dist/components/content/ContentPageShell.svelte.d.ts +1 -0
- package/dist/components/content/DataPanel.svelte +58 -0
- package/dist/components/content/DataPanel.svelte.d.ts +16 -0
- package/dist/components/content/DescriptionList.svelte +5 -8
- package/dist/components/content/DescriptionList.svelte.d.ts +0 -1
- package/dist/components/content/FilterToolbar.svelte +2 -5
- package/dist/components/content/FilterToolbar.svelte.d.ts +0 -1
- package/dist/components/content/NetworkTable.svelte +3 -3
- package/dist/components/content/NetworkTable.svelte.d.ts +0 -1
- package/dist/components/content/PageSection.svelte +1 -1
- package/dist/components/content/StatusTabs.svelte +2 -7
- package/dist/components/content/StatusTabs.svelte.d.ts +0 -1
- package/dist/components/content/index.d.ts +1 -0
- package/dist/components/content/index.js +1 -0
- package/dist/components/ui/table/index.d.ts +0 -1
- package/dist/components/ui/table/table.svelte +1 -0
- package/dist/components/ui/table/table.svelte.d.ts +1 -0
- package/dist/components.css +1 -11
- package/dist/data-panel.css +88 -0
- package/dist/design-contract.d.ts +11 -0
- package/dist/design-contract.js +8 -0
- package/dist/design-system.d.ts +3 -2
- package/dist/design-system.js +3 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -0
- package/dist/page-chrome.css +40 -62
- package/dist/recipes.d.ts +67 -154
- package/dist/recipes.js +32 -68
- package/dist/styles/recipes.css +15 -48
- package/package.json +4 -4
|
@@ -12,6 +12,36 @@ function variant(recipe, name) {
|
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
const registryEntries = [
|
|
15
|
+
{
|
|
16
|
+
id: "page-pattern",
|
|
17
|
+
component: "@svadmin/ui/components/PagePattern.svelte",
|
|
18
|
+
recipe: "contentPageRecipe",
|
|
19
|
+
props: {
|
|
20
|
+
kind: { kind: "enum", values: ["list", "form", "detail", "workspace", "dashboard"], required: true },
|
|
21
|
+
title: { kind: "string", required: true },
|
|
22
|
+
description: { kind: "string" },
|
|
23
|
+
eyebrow: { kind: "string" },
|
|
24
|
+
pageId: { kind: "string" },
|
|
25
|
+
width: variant("contentPageRecipe", "width"),
|
|
26
|
+
density: { kind: "enum", values: ["comfortable", "compact"], default: "comfortable", description: "Deprecated compatibility prop; use the shared baseline." },
|
|
27
|
+
state: { kind: "enum", values: ["ready", "loading", "empty", "error", "forbidden"], default: "ready" },
|
|
28
|
+
stateTitle: { kind: "string" },
|
|
29
|
+
stateDescription: { kind: "string" },
|
|
30
|
+
retry: { kind: "callback", description: "Use an error-state retry callback." },
|
|
31
|
+
class: { kind: "string" },
|
|
32
|
+
},
|
|
33
|
+
slots: {
|
|
34
|
+
children: { kind: "snippet", required: true },
|
|
35
|
+
actions: { kind: "snippet" },
|
|
36
|
+
toolbar: { kind: "snippet" },
|
|
37
|
+
metrics: { kind: "snippet" },
|
|
38
|
+
secondary: { kind: "snippet" },
|
|
39
|
+
footer: { kind: "snippet" },
|
|
40
|
+
stateAction: { kind: "snippet" },
|
|
41
|
+
},
|
|
42
|
+
tokens: semanticTokens,
|
|
43
|
+
states: ["ready", "loading", "empty", "error", "forbidden"],
|
|
44
|
+
},
|
|
15
45
|
{
|
|
16
46
|
id: "content-page-shell",
|
|
17
47
|
component: "@svadmin/ui/components/content/ContentPageShell.svelte",
|
|
@@ -22,7 +52,7 @@ const registryEntries = [
|
|
|
22
52
|
description: { kind: "string" },
|
|
23
53
|
pageId: { kind: "string" },
|
|
24
54
|
width: variant("contentPageRecipe", "width"),
|
|
25
|
-
density:
|
|
55
|
+
density: { kind: "enum", values: ["comfortable", "compact"], default: "comfortable", description: "Deprecated compatibility prop; use the shared baseline." },
|
|
26
56
|
class: { kind: "string" },
|
|
27
57
|
},
|
|
28
58
|
slots: { children: { kind: "snippet", required: true }, actions: { kind: "snippet" } },
|
|
@@ -38,7 +68,6 @@ const registryEntries = [
|
|
|
38
68
|
eyebrow: { kind: "string" },
|
|
39
69
|
description: { kind: "string" },
|
|
40
70
|
breadcrumbs: { kind: "string[]" },
|
|
41
|
-
density: variant("contentHeaderRecipe", "density"),
|
|
42
71
|
class: { kind: "string" },
|
|
43
72
|
},
|
|
44
73
|
slots: { actions: { kind: "snippet" } },
|
|
@@ -208,7 +237,7 @@ export function createComponentRegistryManifest() {
|
|
|
208
237
|
return {
|
|
209
238
|
version: "svadmin/component-registry-v1",
|
|
210
239
|
purpose: "authoring-only",
|
|
211
|
-
coverage: "
|
|
240
|
+
coverage: "page-pattern-and-semantic-ui-components",
|
|
212
241
|
runtimeCatalog: "@svadmin/surface: createSurfaceCatalogManifest",
|
|
213
242
|
designContract: surfaceDesignContract,
|
|
214
243
|
recipes: Object.fromEntries(Object.keys(allRecipes)
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { Menu, X } from '@lucide/svelte';
|
|
4
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
5
|
+
import { cn } from '../utils.js';
|
|
6
|
+
|
|
7
|
+
type Width = 'narrow' | 'default' | 'wide' | 'full';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
/** Page content; typically a `PagePattern` or `ContentPageShell`. */
|
|
11
|
+
children: Snippet;
|
|
12
|
+
/** Navigation region. The host owns links and routing; the shell owns layout. */
|
|
13
|
+
sidebar?: Snippet;
|
|
14
|
+
/** Leading topbar region, rendered before the mobile navigation trigger. */
|
|
15
|
+
topbarStart?: Snippet;
|
|
16
|
+
/** Topbar region between the leading and trailing slots (search, breadcrumbs…). */
|
|
17
|
+
topbar?: Snippet;
|
|
18
|
+
/** Trailing topbar actions (account menu, notifications…). */
|
|
19
|
+
topbarEnd?: Snippet;
|
|
20
|
+
/** Optional secondary column for detail/workspace pages. */
|
|
21
|
+
aside?: Snippet;
|
|
22
|
+
footer?: Snippet;
|
|
23
|
+
width?: Width;
|
|
24
|
+
/** Collapses the navigation rail to icons. Host-controlled, presentation only. */
|
|
25
|
+
collapsed?: boolean;
|
|
26
|
+
/** Open state of the below-breakpoint navigation drawer. */
|
|
27
|
+
mobileOpen?: boolean;
|
|
28
|
+
/** Accessible name for the primary landmark. */
|
|
29
|
+
label?: string;
|
|
30
|
+
skipLabel?: string;
|
|
31
|
+
contentId?: string;
|
|
32
|
+
class?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let {
|
|
36
|
+
children,
|
|
37
|
+
sidebar,
|
|
38
|
+
topbarStart,
|
|
39
|
+
topbar,
|
|
40
|
+
topbarEnd,
|
|
41
|
+
aside,
|
|
42
|
+
footer,
|
|
43
|
+
width = 'default',
|
|
44
|
+
collapsed = false,
|
|
45
|
+
mobileOpen = $bindable(false),
|
|
46
|
+
label,
|
|
47
|
+
skipLabel,
|
|
48
|
+
contentId,
|
|
49
|
+
class: className = '',
|
|
50
|
+
}: Props = $props();
|
|
51
|
+
|
|
52
|
+
const generatedId = $props.id();
|
|
53
|
+
const i18n = useTranslation();
|
|
54
|
+
const mainId = $derived(contentId ?? generatedId);
|
|
55
|
+
const sidebarId = $derived(`${generatedId}-sidebar`);
|
|
56
|
+
// 未提供可读名称时退回通用文案,避免出现没有可访问名的 <main>。
|
|
57
|
+
const resolvedLabel = $derived(label ?? i18n.t('common.mainNavigation'));
|
|
58
|
+
const resolvedSkipLabel = $derived(skipLabel ?? i18n.t('common.skipToMainContent'));
|
|
59
|
+
|
|
60
|
+
function closeMobileNav() {
|
|
61
|
+
mobileOpen = false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function onKeydown(event: KeyboardEvent) {
|
|
65
|
+
if (event.key === 'Escape' && mobileOpen) closeMobileNav();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 宿主常用 hash 路由,不能让跳转链接把 #main 当成一次路由跳转。
|
|
69
|
+
function focusMain(event: MouseEvent) {
|
|
70
|
+
const target = document.getElementById(mainId);
|
|
71
|
+
if (!target) return;
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
target.focus();
|
|
74
|
+
target.scrollIntoView?.({ block: 'start' });
|
|
75
|
+
}
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<svelte:window onkeydown={onKeydown} />
|
|
79
|
+
|
|
80
|
+
<a class="svadmin-app-shell__skip" href="#{mainId}" onclick={focusMain}>{resolvedSkipLabel}</a>
|
|
81
|
+
|
|
82
|
+
<div
|
|
83
|
+
class={cn('svadmin-app-shell', className)}
|
|
84
|
+
data-sidebar={sidebar ? 'true' : undefined}
|
|
85
|
+
data-aside={aside ? 'true' : undefined}
|
|
86
|
+
data-collapsed={collapsed ? 'true' : undefined}
|
|
87
|
+
data-mobile-open={mobileOpen ? 'true' : undefined}
|
|
88
|
+
data-width={width}
|
|
89
|
+
>
|
|
90
|
+
<header class="svadmin-app-shell__topbar" data-slot="app-shell-topbar">
|
|
91
|
+
{#if sidebar}
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
class="svadmin-app-shell__mobile-toggle"
|
|
95
|
+
data-slot="app-shell-mobile-toggle"
|
|
96
|
+
aria-controls={sidebarId}
|
|
97
|
+
aria-expanded={mobileOpen ? 'true' : 'false'}
|
|
98
|
+
aria-label={mobileOpen ? i18n.t('common.close') : i18n.t('common.menu')}
|
|
99
|
+
onclick={() => (mobileOpen = !mobileOpen)}
|
|
100
|
+
>
|
|
101
|
+
{#if mobileOpen}
|
|
102
|
+
<X aria-hidden="true" size={18} />
|
|
103
|
+
{:else}
|
|
104
|
+
<Menu aria-hidden="true" size={18} />
|
|
105
|
+
{/if}
|
|
106
|
+
</button>
|
|
107
|
+
{/if}
|
|
108
|
+
{#if topbarStart}
|
|
109
|
+
<div class="svadmin-app-shell__topbar-start">{@render topbarStart()}</div>
|
|
110
|
+
{/if}
|
|
111
|
+
<div class="svadmin-app-shell__topbar-main">{@render topbar?.()}</div>
|
|
112
|
+
{#if topbarEnd}
|
|
113
|
+
<div class="svadmin-app-shell__topbar-end">{@render topbarEnd()}</div>
|
|
114
|
+
{/if}
|
|
115
|
+
</header>
|
|
116
|
+
|
|
117
|
+
{#if sidebar}
|
|
118
|
+
<nav id={sidebarId} class="svadmin-app-shell__sidebar" aria-label={resolvedLabel} data-slot="app-shell-sidebar">
|
|
119
|
+
<div class="svadmin-app-shell__sidebar-inner">{@render sidebar()}</div>
|
|
120
|
+
</nav>
|
|
121
|
+
<button
|
|
122
|
+
type="button"
|
|
123
|
+
class="svadmin-app-shell__scrim"
|
|
124
|
+
tabindex="-1"
|
|
125
|
+
aria-hidden="true"
|
|
126
|
+
data-slot="app-shell-scrim"
|
|
127
|
+
onclick={closeMobileNav}
|
|
128
|
+
></button>
|
|
129
|
+
{/if}
|
|
130
|
+
|
|
131
|
+
<main id={mainId} class="svadmin-app-shell__main" tabindex="-1">
|
|
132
|
+
<div class="svadmin-app-shell__body" data-slot="app-shell-body">
|
|
133
|
+
<div class="svadmin-app-shell__content" data-slot="app-shell-content">
|
|
134
|
+
{@render children()}
|
|
135
|
+
</div>
|
|
136
|
+
{#if aside}
|
|
137
|
+
<aside class="svadmin-app-shell__aside" data-slot="app-shell-aside">{@render aside()}</aside>
|
|
138
|
+
{/if}
|
|
139
|
+
</div>
|
|
140
|
+
</main>
|
|
141
|
+
|
|
142
|
+
{#if footer}
|
|
143
|
+
<footer class="svadmin-app-shell__footer" data-slot="app-shell-footer">{@render footer()}</footer>
|
|
144
|
+
{/if}
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<style>
|
|
148
|
+
/* Layout-only overrides. Sizes, colors and radii stay in app-shell.css so a
|
|
149
|
+
* host override of the token layer reaches this component too. */
|
|
150
|
+
.svadmin-app-shell__mobile-toggle {
|
|
151
|
+
align-items: center;
|
|
152
|
+
justify-content: center;
|
|
153
|
+
flex: 0 0 auto;
|
|
154
|
+
height: var(--svadmin-control-h);
|
|
155
|
+
width: var(--svadmin-control-h);
|
|
156
|
+
border: 1px solid var(--border);
|
|
157
|
+
border-radius: var(--radius-md);
|
|
158
|
+
background: var(--background);
|
|
159
|
+
color: var(--foreground);
|
|
160
|
+
cursor: pointer;
|
|
161
|
+
}
|
|
162
|
+
.svadmin-app-shell__mobile-toggle:hover {
|
|
163
|
+
background: var(--muted);
|
|
164
|
+
}
|
|
165
|
+
.svadmin-app-shell__mobile-toggle:focus-visible {
|
|
166
|
+
outline: var(--svadmin-focus-width) solid var(--ring);
|
|
167
|
+
outline-offset: var(--svadmin-focus-offset);
|
|
168
|
+
}
|
|
169
|
+
.svadmin-app-shell__main:focus-visible {
|
|
170
|
+
outline: none;
|
|
171
|
+
}
|
|
172
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type Width = 'narrow' | 'default' | 'wide' | 'full';
|
|
3
|
+
interface Props {
|
|
4
|
+
/** Page content; typically a `PagePattern` or `ContentPageShell`. */
|
|
5
|
+
children: Snippet;
|
|
6
|
+
/** Navigation region. The host owns links and routing; the shell owns layout. */
|
|
7
|
+
sidebar?: Snippet;
|
|
8
|
+
/** Leading topbar region, rendered before the mobile navigation trigger. */
|
|
9
|
+
topbarStart?: Snippet;
|
|
10
|
+
/** Topbar region between the leading and trailing slots (search, breadcrumbs…). */
|
|
11
|
+
topbar?: Snippet;
|
|
12
|
+
/** Trailing topbar actions (account menu, notifications…). */
|
|
13
|
+
topbarEnd?: Snippet;
|
|
14
|
+
/** Optional secondary column for detail/workspace pages. */
|
|
15
|
+
aside?: Snippet;
|
|
16
|
+
footer?: Snippet;
|
|
17
|
+
width?: Width;
|
|
18
|
+
/** Collapses the navigation rail to icons. Host-controlled, presentation only. */
|
|
19
|
+
collapsed?: boolean;
|
|
20
|
+
/** Open state of the below-breakpoint navigation drawer. */
|
|
21
|
+
mobileOpen?: boolean;
|
|
22
|
+
/** Accessible name for the primary landmark. */
|
|
23
|
+
label?: string;
|
|
24
|
+
skipLabel?: string;
|
|
25
|
+
contentId?: string;
|
|
26
|
+
class?: string;
|
|
27
|
+
}
|
|
28
|
+
declare const AppShellPage: import("svelte").Component<Props, {}, "mobileOpen">;
|
|
29
|
+
type AppShellPage = ReturnType<typeof AppShellPage>;
|
|
30
|
+
export default AppShellPage;
|
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
rendering?: ResourceRendering | undefined;
|
|
30
30
|
id?: string | number;
|
|
31
31
|
mode?: 'create' | 'edit' | 'clone' | 'show';
|
|
32
|
-
density?: 'compact' | 'comfortable';
|
|
33
32
|
columns?: 1 | 2 | 3 | 4;
|
|
34
33
|
showHeader?: boolean;
|
|
35
34
|
fieldRenderer?: Snippet<[{ field: FieldDefinition; value: unknown; onchange: (v: unknown) => void }]>;
|
|
@@ -47,7 +46,6 @@
|
|
|
47
46
|
rendering,
|
|
48
47
|
id,
|
|
49
48
|
mode = 'create',
|
|
50
|
-
density = 'comfortable',
|
|
51
49
|
columns = 1,
|
|
52
50
|
showHeader = true,
|
|
53
51
|
fieldRenderer,
|
|
@@ -64,7 +62,6 @@
|
|
|
64
62
|
const binding = useResourceContract(() => resourceName);
|
|
65
63
|
const activeRendering = $derived(bindResourceRendering(rendering, binding.resource));
|
|
66
64
|
const isReadonly = $derived(mode === 'show');
|
|
67
|
-
const isCompact = $derived(density === 'compact');
|
|
68
65
|
const instanceId = $props.id();
|
|
69
66
|
|
|
70
67
|
// ─── Resource metadata ────────────────────────────────────────────
|
|
@@ -315,7 +312,7 @@
|
|
|
315
312
|
});
|
|
316
313
|
</script>
|
|
317
314
|
|
|
318
|
-
<div class=
|
|
315
|
+
<div class="svadmin-u-b3542e058833" data-svadmin-rendering-resource={activeRendering?.resource.name} data-svadmin-rendering-kind={activeRendering ? 'form' : undefined}>
|
|
319
316
|
{#if showHeader}
|
|
320
317
|
<div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-0c3bc98565dd">
|
|
321
318
|
<TooltipButton
|
|
@@ -378,11 +375,11 @@
|
|
|
378
375
|
{#each groups as group, _i (_i)}
|
|
379
376
|
<Card.Root class="svadmin-u-6ee2d41e2d2d svadmin-u-438b2237b8d6">
|
|
380
377
|
{#if group.name}
|
|
381
|
-
<Card.Header
|
|
378
|
+
<Card.Header>
|
|
382
379
|
<Card.Title class="svadmin-u-42536e69e639">{group.name}</Card.Title>
|
|
383
380
|
</Card.Header>
|
|
384
381
|
{/if}
|
|
385
|
-
<Card.Content class=
|
|
382
|
+
<Card.Content class="svadmin-u-f0faeb26d656 svadmin-u-7a9aabfcd059 svadmin-u-9fcd8a13827e svadmin-u-050494726fba svadmin-u-9335c39f6eff">
|
|
386
383
|
<div class={gridClass}>
|
|
387
384
|
{#each group.fields as field (field.key)}
|
|
388
385
|
<div data-svadmin-field-key={field.key} class={cn(columns > 1 && isFullWidthField(field) && 'svadmin-u-2c955d1b45df', !!form.errors[field.key] && 'svadmin-u-ee1a5af3aa10')}>
|
|
@@ -393,7 +390,6 @@
|
|
|
393
390
|
{field}
|
|
394
391
|
value={renderedDraft.values[field.key]}
|
|
395
392
|
onchange={fieldChange(field.key)}
|
|
396
|
-
{density}
|
|
397
393
|
invalid={!!form.errors[field.key]}
|
|
398
394
|
{...definedOptions({ "errorId": form.errors[field.key] ? fieldErrorId(field.key) : undefined })}
|
|
399
395
|
disabled={isReadonly}
|
|
@@ -410,8 +406,8 @@
|
|
|
410
406
|
{/each}
|
|
411
407
|
{:else}
|
|
412
408
|
<Card.Root class="svadmin-u-6ee2d41e2d2d svadmin-u-438b2237b8d6">
|
|
413
|
-
<Card.Content class=
|
|
414
|
-
<div class={gridClass} data-svadmin-form-grid data-columns={columns}
|
|
409
|
+
<Card.Content class="svadmin-u-f0faeb26d656 svadmin-u-52be28846b5f svadmin-u-9fcd8a13827e svadmin-u-7a9aabfcd059 svadmin-u-0a58453f3755 svadmin-u-050494726fba">
|
|
410
|
+
<div class={gridClass} data-svadmin-form-grid data-columns={columns}>
|
|
415
411
|
{#each formFields as field (field.key)}
|
|
416
412
|
<div data-svadmin-field-key={field.key} class={cn(columns > 1 && isFullWidthField(field) && 'svadmin-u-2c955d1b45df', !!form.errors[field.key] && 'svadmin-u-ee1a5af3aa10')}>
|
|
417
413
|
{#if fieldRenderer}
|
|
@@ -421,7 +417,6 @@
|
|
|
421
417
|
{field}
|
|
422
418
|
value={renderedDraft.values[field.key]}
|
|
423
419
|
onchange={fieldChange(field.key)}
|
|
424
|
-
{density}
|
|
425
420
|
invalid={!!form.errors[field.key]}
|
|
426
421
|
{...definedOptions({ "errorId": form.errors[field.key] ? fieldErrorId(field.key) : undefined })}
|
|
427
422
|
disabled={isReadonly}
|
|
@@ -441,7 +436,7 @@
|
|
|
441
436
|
{#if formActions && !isReadonly}
|
|
442
437
|
{@render formActions({ isLoading: form.submitting, onSubmit: handleSubmit })}
|
|
443
438
|
{:else if !isReadonly}
|
|
444
|
-
<Button type="submit" size=
|
|
439
|
+
<Button type="submit" size="default" disabled={form.submitting}>
|
|
445
440
|
{#if form.submitting}
|
|
446
441
|
<Loader2 class="svadmin-u-11e59c6d5f6b svadmin-u-dc7972ebf3f3 svadmin-u-afbdd13a380e" data-icon="inline-start" aria-hidden="true" />
|
|
447
442
|
{:else}
|
|
@@ -452,7 +447,7 @@
|
|
|
452
447
|
<Button
|
|
453
448
|
type="button"
|
|
454
449
|
variant="outline"
|
|
455
|
-
size=
|
|
450
|
+
size="default"
|
|
456
451
|
onclick={back}
|
|
457
452
|
>
|
|
458
453
|
{i18n.t('common.cancel')}
|
|
@@ -112,10 +112,12 @@
|
|
|
112
112
|
selectable?: boolean;
|
|
113
113
|
/** 仅在业务回调支持按查询执行服务端命令时启用。 */
|
|
114
114
|
allowSelectAllMatching?: boolean;
|
|
115
|
+
/** @deprecated Retained for compatibility; comfortable is the shared default. */
|
|
115
116
|
density?: 'compact' | 'comfortable';
|
|
116
117
|
showHeader?: boolean;
|
|
117
118
|
title?: string;
|
|
118
119
|
showFilterTags?: boolean;
|
|
120
|
+
/** @deprecated Retained for compatibility; use the shared appearance baseline. */
|
|
119
121
|
showDensitySwitcher?: boolean;
|
|
120
122
|
showRefresh?: boolean;
|
|
121
123
|
/** Custom header actions (right side) */
|
|
@@ -15,10 +15,12 @@ interface Props {
|
|
|
15
15
|
selectable?: boolean;
|
|
16
16
|
/** 仅在业务回调支持按查询执行服务端命令时启用。 */
|
|
17
17
|
allowSelectAllMatching?: boolean;
|
|
18
|
+
/** @deprecated Retained for compatibility; comfortable is the shared default. */
|
|
18
19
|
density?: 'compact' | 'comfortable';
|
|
19
20
|
showHeader?: boolean;
|
|
20
21
|
title?: string;
|
|
21
22
|
showFilterTags?: boolean;
|
|
23
|
+
/** @deprecated Retained for compatibility; use the shared appearance baseline. */
|
|
22
24
|
showDensitySwitcher?: boolean;
|
|
23
25
|
showRefresh?: boolean;
|
|
24
26
|
/** Custom header actions (right side) */
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
footer?: Snippet;
|
|
12
12
|
children: Snippet;
|
|
13
13
|
width?: 'narrow' | 'default' | 'wide';
|
|
14
|
-
density?: 'compact' | 'comfortable';
|
|
15
14
|
class?: string;
|
|
16
15
|
}
|
|
17
16
|
|
|
@@ -23,7 +22,6 @@
|
|
|
23
22
|
footer,
|
|
24
23
|
children,
|
|
25
24
|
width = 'default',
|
|
26
|
-
density = 'comfortable',
|
|
27
25
|
class: className = '',
|
|
28
26
|
}: Props = $props();
|
|
29
27
|
</script>
|
|
@@ -32,7 +30,6 @@
|
|
|
32
30
|
{title}
|
|
33
31
|
{...definedOptions({ description, eyebrow, actions })}
|
|
34
32
|
{width}
|
|
35
|
-
{density}
|
|
36
33
|
class={className}
|
|
37
34
|
>
|
|
38
35
|
<div class="configuration-page__content">
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
resourceName: string;
|
|
16
16
|
rendering?: ResourceRendering | undefined;
|
|
17
17
|
title?: string;
|
|
18
|
-
density?: 'compact' | 'comfortable';
|
|
19
18
|
columns?: 1 | 2 | 3 | 4;
|
|
20
19
|
headerActions?: Snippet;
|
|
21
20
|
onSuccess?: () => void;
|
|
@@ -26,7 +25,6 @@
|
|
|
26
25
|
resourceName,
|
|
27
26
|
rendering,
|
|
28
27
|
title,
|
|
29
|
-
density = 'comfortable',
|
|
30
28
|
columns = 1,
|
|
31
29
|
headerActions,
|
|
32
30
|
onSuccess,
|
|
@@ -39,10 +37,9 @@
|
|
|
39
37
|
const pageTitle = $derived(title ?? `${i18n.t('common.create')}${resource.label}`);
|
|
40
38
|
</script>
|
|
41
39
|
|
|
42
|
-
<div class="
|
|
40
|
+
<div class="svadmin-u-b3542e058833 {className}">
|
|
43
41
|
<PageHeader
|
|
44
42
|
title={pageTitle}
|
|
45
|
-
{density}
|
|
46
43
|
onBack={() => navigateGuard(() => adminContext.navigate(`/${resourceName}`))}
|
|
47
44
|
>
|
|
48
45
|
{#snippet actions()}
|
|
@@ -57,7 +54,6 @@
|
|
|
57
54
|
{rendering}
|
|
58
55
|
{resourceName}
|
|
59
56
|
mode="create"
|
|
60
|
-
{density}
|
|
61
57
|
{columns}
|
|
62
58
|
showHeader={false}
|
|
63
59
|
onNavigationGuardReady={(guard) => navigateGuard = guard}
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
rendering?: ResourceRendering | undefined;
|
|
21
21
|
id: string | number;
|
|
22
22
|
title?: string;
|
|
23
|
-
density?: 'compact' | 'comfortable';
|
|
24
23
|
columns?: 1 | 2 | 3 | 4;
|
|
25
24
|
canDelete?: boolean;
|
|
26
25
|
headerActions?: Snippet;
|
|
@@ -33,7 +32,6 @@
|
|
|
33
32
|
rendering,
|
|
34
33
|
id,
|
|
35
34
|
title,
|
|
36
|
-
density = 'comfortable',
|
|
37
35
|
columns = 1,
|
|
38
36
|
canDelete,
|
|
39
37
|
headerActions,
|
|
@@ -48,10 +46,9 @@
|
|
|
48
46
|
const showDelete = $derived(canDelete ?? resource.canDelete !== false);
|
|
49
47
|
</script>
|
|
50
48
|
|
|
51
|
-
<div class="
|
|
49
|
+
<div class="svadmin-u-b3542e058833 {className}">
|
|
52
50
|
<PageHeader
|
|
53
51
|
title={pageTitle}
|
|
54
|
-
{density}
|
|
55
52
|
onBack={() => navigateGuard(() => navigation.list(resourceName))}
|
|
56
53
|
>
|
|
57
54
|
{#snippet actions()}
|
|
@@ -72,7 +69,6 @@
|
|
|
72
69
|
{resourceName}
|
|
73
70
|
mode="edit"
|
|
74
71
|
{id}
|
|
75
|
-
{density}
|
|
76
72
|
{columns}
|
|
77
73
|
showHeader={false}
|
|
78
74
|
onNavigationGuardReady={(guard) => navigateGuard = guard}
|
|
@@ -35,25 +35,21 @@
|
|
|
35
35
|
import { Plus, X } from '@lucide/svelte';
|
|
36
36
|
import type { Snippet } from 'svelte';
|
|
37
37
|
import { getRichTextEditor } from '../editor-config.svelte.js';
|
|
38
|
-
import { cn } from '../utils.js';
|
|
39
38
|
import { numericInputValue } from '../numeric-input.js';
|
|
40
39
|
|
|
41
40
|
type FieldOption = NonNullable<FieldDefinition['options']>[number];
|
|
42
41
|
const i18n = useTranslation();
|
|
43
42
|
|
|
44
|
-
let { field, value, onchange, disabled, invalid = false, errorId,
|
|
43
|
+
let { field, value, onchange, disabled, invalid = false, errorId, children } = $props<{
|
|
45
44
|
field: FieldDefinition;
|
|
46
45
|
value: unknown;
|
|
47
46
|
onchange: (val: unknown) => void;
|
|
48
47
|
disabled?: boolean;
|
|
49
48
|
invalid?: boolean;
|
|
50
49
|
errorId?: string;
|
|
51
|
-
density?: 'compact' | 'comfortable';
|
|
52
50
|
children?: Snippet;
|
|
53
51
|
}>();
|
|
54
52
|
|
|
55
|
-
const isCompact = $derived(density === 'compact');
|
|
56
|
-
|
|
57
53
|
// Typed accessors
|
|
58
54
|
const strVal = $derived((value as string) ?? '');
|
|
59
55
|
const numVal = $derived(numericInputValue(value));
|
|
@@ -111,13 +107,9 @@
|
|
|
111
107
|
</script>
|
|
112
108
|
|
|
113
109
|
<div
|
|
114
|
-
class=
|
|
115
|
-
'svadmin-u-5a2508227c6a',
|
|
116
|
-
isCompact && 'svadmin-u-da7c36cd8867 svadmin-u-01e043b9ca05 svadmin-u-5e375759a547 svadmin-u-0144d38a6921 svadmin-u-910198b850a8 svadmin-u-220cd47c030c svadmin-u-84a68a4bfa38 svadmin-u-2b201b2c12c7 svadmin-u-334c9da7fe2b svadmin-u-f7194f86de09 svadmin-u-a281d7e98ab9 svadmin-u-6cddb40447d9 svadmin-u-150c3670da1d svadmin-u-f01a063e8052 svadmin-u-3e2aa4ec6454'
|
|
117
|
-
)}
|
|
110
|
+
class="svadmin-u-5a2508227c6a"
|
|
118
111
|
data-svadmin-field
|
|
119
112
|
data-svadmin-field-key={field.key}
|
|
120
|
-
data-density={density}
|
|
121
113
|
>
|
|
122
114
|
<Label for={field.key} id="label-{field.key}" data-svadmin-field-label>
|
|
123
115
|
{field.label}
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
rendering?: ResourceRendering | undefined;
|
|
17
17
|
title?: string;
|
|
18
18
|
canCreate?: boolean;
|
|
19
|
-
density?: 'compact' | 'comfortable';
|
|
20
19
|
/** Passthrough: enable row selection checkboxes */
|
|
21
20
|
selectable?: boolean;
|
|
22
21
|
allowSelectAllMatching?: boolean;
|
|
@@ -44,7 +43,6 @@
|
|
|
44
43
|
rendering,
|
|
45
44
|
title,
|
|
46
45
|
canCreate,
|
|
47
|
-
density = 'comfortable',
|
|
48
46
|
selectable,
|
|
49
47
|
allowSelectAllMatching,
|
|
50
48
|
headerActions,
|
|
@@ -62,8 +60,8 @@
|
|
|
62
60
|
const showCreate = $derived(canCreate ?? resource.canCreate !== false);
|
|
63
61
|
</script>
|
|
64
62
|
|
|
65
|
-
<div class="
|
|
66
|
-
<PageHeader title={pageTitle}
|
|
63
|
+
<div class="svadmin-u-3e7ce58d64fa {className}">
|
|
64
|
+
<PageHeader title={pageTitle}>
|
|
67
65
|
{#snippet actions()}
|
|
68
66
|
{#if showCreate}
|
|
69
67
|
<CreateButton resource={resourceName} />
|
|
@@ -90,7 +88,6 @@
|
|
|
90
88
|
{rendering}
|
|
91
89
|
{resourceName}
|
|
92
90
|
showHeader={false}
|
|
93
|
-
{density}
|
|
94
91
|
{...definedOptions({ "selectable": selectable })}
|
|
95
92
|
{...definedOptions({ allowSelectAllMatching })}
|
|
96
93
|
{...definedOptions({ batchActions })}
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
onBack?: () => void;
|
|
16
16
|
backLabel?: string;
|
|
17
17
|
showBreadcrumbs?: boolean;
|
|
18
|
-
density?: 'compact' | 'comfortable';
|
|
19
18
|
class?: string;
|
|
20
19
|
}
|
|
21
20
|
|
|
@@ -29,13 +28,12 @@
|
|
|
29
28
|
onBack,
|
|
30
29
|
backLabel = 'Back',
|
|
31
30
|
showBreadcrumbs = true,
|
|
32
|
-
density = 'comfortable',
|
|
33
31
|
class: className = '',
|
|
34
32
|
}: Props = $props();
|
|
35
33
|
|
|
36
34
|
</script>
|
|
37
35
|
|
|
38
|
-
<div class={cn('svadmin-page-header', className)}
|
|
36
|
+
<div class={cn('svadmin-page-header', className)}>
|
|
39
37
|
{#if showBreadcrumbs}
|
|
40
38
|
<Breadcrumbs class="svadmin-page-header__breadcrumbs" />
|
|
41
39
|
{/if}
|