@svadmin/ui 0.85.0 → 0.88.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.
Files changed (89) hide show
  1. package/README.md +31 -0
  2. package/dist/app-shell.css +216 -0
  3. package/dist/app.css +659 -165
  4. package/dist/app.theme.css +659 -165
  5. package/dist/component-registry.d.ts +7292 -529
  6. package/dist/component-registry.js +32 -3
  7. package/dist/components/AppShellPage.svelte +172 -0
  8. package/dist/components/AppShellPage.svelte.d.ts +30 -0
  9. package/dist/components/ApprovalActionCard.svelte +54 -31
  10. package/dist/components/ApprovalCenter.svelte +73 -31
  11. package/dist/components/AuthPageShell.svelte +13 -2
  12. package/dist/components/AutoForm.svelte +7 -12
  13. package/dist/components/AutoForm.svelte.d.ts +0 -1
  14. package/dist/components/AutoTable.svelte +15 -3
  15. package/dist/components/AutoTable.svelte.d.ts +2 -0
  16. package/dist/components/ConfigurationPage.svelte +0 -3
  17. package/dist/components/ConfigurationPage.svelte.d.ts +0 -1
  18. package/dist/components/CreatePage.svelte +22 -19
  19. package/dist/components/CreatePage.svelte.d.ts +4 -1
  20. package/dist/components/EditPage.svelte +23 -20
  21. package/dist/components/EditPage.svelte.d.ts +4 -1
  22. package/dist/components/FieldRenderer.svelte +2 -10
  23. package/dist/components/FieldRenderer.svelte.d.ts +0 -1
  24. package/dist/components/ListPage.svelte +21 -18
  25. package/dist/components/ListPage.svelte.d.ts +2 -1
  26. package/dist/components/LoginPage.svelte +27 -11
  27. package/dist/components/LoginPage.svelte.d.ts +4 -0
  28. package/dist/components/NotificationsSettings.svelte +16 -8
  29. package/dist/components/PageHeader.svelte +1 -3
  30. package/dist/components/PageHeader.svelte.d.ts +0 -1
  31. package/dist/components/PagePattern.svelte +36 -13
  32. package/dist/components/PagePattern.svelte.d.ts +7 -0
  33. package/dist/components/PasswordInput.svelte +36 -17
  34. package/dist/components/PasswordInput.svelte.d.ts +3 -0
  35. package/dist/components/QuickEditDrawer.svelte +0 -1
  36. package/dist/components/ShowPage.svelte +24 -29
  37. package/dist/components/ShowPage.svelte.d.ts +0 -1
  38. package/dist/components/SvarAutoTable.svelte +2 -1
  39. package/dist/components/SvarDataGrid.svelte +8 -4
  40. package/dist/components/SvarDataGrid.svelte.d.ts +3 -0
  41. package/dist/components/SvarResourceTable.svelte +0 -1
  42. package/dist/components/SvarResourceTable.svelte.d.ts +0 -1
  43. package/dist/components/SvarResourceTableView.svelte +2 -2
  44. package/dist/components/account/MemberDirectory.svelte +17 -4
  45. package/dist/components/account/SecurityLogPage.svelte +8 -1
  46. package/dist/components/auto-table-grid.d.ts +1 -0
  47. package/dist/components/content/AuditTimeline.svelte +32 -4
  48. package/dist/components/content/AuditTimeline.svelte.d.ts +9 -0
  49. package/dist/components/content/ContentPageHeader.svelte +2 -1
  50. package/dist/components/content/ContentPageHeader.svelte.d.ts +1 -0
  51. package/dist/components/content/ContentPageShell.svelte +1 -1
  52. package/dist/components/content/ContentPageShell.svelte.d.ts +1 -0
  53. package/dist/components/content/DataPanel.svelte +58 -0
  54. package/dist/components/content/DataPanel.svelte.d.ts +16 -0
  55. package/dist/components/content/DataState.svelte +5 -4
  56. package/dist/components/content/DataState.svelte.d.ts +1 -1
  57. package/dist/components/content/DescriptionList.svelte +5 -8
  58. package/dist/components/content/DescriptionList.svelte.d.ts +0 -1
  59. package/dist/components/content/FilterToolbar.svelte +9 -6
  60. package/dist/components/content/FilterToolbar.svelte.d.ts +0 -1
  61. package/dist/components/content/NetworkTable.svelte +3 -3
  62. package/dist/components/content/NetworkTable.svelte.d.ts +0 -1
  63. package/dist/components/content/PageSection.svelte +1 -1
  64. package/dist/components/content/StatusTabs.svelte +2 -7
  65. package/dist/components/content/StatusTabs.svelte.d.ts +0 -1
  66. package/dist/components/content/WorkspaceLayout.svelte +3 -1
  67. package/dist/components/content/WorkspaceLayout.svelte.d.ts +1 -0
  68. package/dist/components/content/index.d.ts +1 -0
  69. package/dist/components/content/index.js +1 -0
  70. package/dist/components/network/TeamCrewTablePage.svelte +8 -1
  71. package/dist/components/network/UserCardsNFTPage.svelte +3 -1
  72. package/dist/components/profile/ProjectsGrid.svelte +1 -1
  73. package/dist/components/profile/TeamsShowcase.svelte +1 -1
  74. package/dist/components/ui/table/index.d.ts +0 -1
  75. package/dist/components/ui/table/table.svelte +1 -0
  76. package/dist/components/ui/table/table.svelte.d.ts +1 -0
  77. package/dist/components.css +1 -11
  78. package/dist/data-panel.css +88 -0
  79. package/dist/design-contract.d.ts +11 -0
  80. package/dist/design-contract.js +8 -0
  81. package/dist/design-system.d.ts +3 -2
  82. package/dist/design-system.js +3 -2
  83. package/dist/index.d.ts +4 -2
  84. package/dist/index.js +2 -0
  85. package/dist/page-chrome.css +42 -64
  86. package/dist/recipes.d.ts +12 -66
  87. package/dist/recipes.js +52 -50
  88. package/dist/styles/recipes.css +15 -48
  89. package/package.json +4 -4
@@ -10,7 +10,6 @@ interface Props {
10
10
  columns?: 1 | 2 | 3 | 4;
11
11
  layout?: 'vertical' | 'horizontal';
12
12
  bordered?: boolean;
13
- density?: 'compact' | 'comfortable';
14
13
  class?: string;
15
14
  }
16
15
  declare const DescriptionList: import("svelte").Component<Props, {}, "">;
@@ -16,7 +16,6 @@
16
16
  clearLabel?: string;
17
17
  advancedLabel?: string;
18
18
  showSearch?: boolean;
19
- density?: 'compact' | 'comfortable';
20
19
  activeFilterCount?: number;
21
20
  advancedOpen?: boolean;
22
21
  filters?: Snippet;
@@ -31,7 +30,6 @@
31
30
  clearLabel = 'Clear search',
32
31
  advancedLabel = 'Filters',
33
32
  showSearch = true,
34
- density = 'compact',
35
33
  activeFilterCount = 0,
36
34
  advancedOpen = $bindable(false),
37
35
  filters,
@@ -40,10 +38,14 @@
40
38
  class: className = '',
41
39
  }: Props = $props();
42
40
 
43
- const isCompact = $derived(density === 'compact');
41
+ let searchInput = $state<HTMLInputElement | null>(null);
44
42
  const advancedPanelId = `svadmin-filter-toolbar-advanced-${uid}`;
45
43
  const i18n = useTranslation();
46
44
  let mobile = $state(false);
45
+ function clearSearch(): void {
46
+ query = '';
47
+ searchInput?.focus();
48
+ }
47
49
  onMount(() => {
48
50
  const media = window.matchMedia('(max-width: 767px)');
49
51
  const update = () => { mobile = media.matches; };
@@ -53,13 +55,14 @@
53
55
  });
54
56
  </script>
55
57
 
56
- <div class={cn('svadmin-filter-toolbar', className)} data-density={density} data-svadmin-filter-toolbar data-advanced-open={advanced && advancedOpen ? 'true' : 'false'}>
58
+ <div class={cn('svadmin-filter-toolbar', className)} data-svadmin-filter-toolbar data-advanced-open={advanced && advancedOpen ? 'true' : 'false'}>
57
59
  <div class="svadmin-filter-toolbar__row">
58
60
  {#if showSearch}
59
61
  <div class="svadmin-filter-toolbar__search">
60
62
  <Search class="svadmin-filter-toolbar__search-icon" aria-hidden="true" />
61
63
  <Input
62
64
  bind:value={query}
65
+ bind:ref={searchInput}
63
66
  {placeholder}
64
67
  class="svadmin-filter-toolbar__input"
65
68
  aria-label={placeholder}
@@ -71,7 +74,7 @@
71
74
  class="svadmin-filter-toolbar__clear"
72
75
  aria-label={clearLabel}
73
76
  title={clearLabel}
74
- onclick={() => query = ''}
77
+ onclick={clearSearch}
75
78
  >
76
79
  <X class="svadmin-filter-toolbar__control-icon" aria-hidden="true" />
77
80
  </Button>
@@ -86,7 +89,7 @@
86
89
  {#if advanced || (mobile && filters)}
87
90
  <Button
88
91
  variant={advancedOpen ? 'secondary' : 'outline'}
89
- size={isCompact ? 'sm' : 'default'}
92
+ size="default"
90
93
  class="svadmin-filter-toolbar__toggle"
91
94
  onclick={() => advancedOpen = !advancedOpen}
92
95
  aria-expanded={advancedOpen}
@@ -5,7 +5,6 @@ interface Props {
5
5
  clearLabel?: string;
6
6
  advancedLabel?: string;
7
7
  showSearch?: boolean;
8
- density?: 'compact' | 'comfortable';
9
8
  activeFilterCount?: number;
10
9
  advancedOpen?: boolean;
11
10
  filters?: Snippet;
@@ -6,15 +6,15 @@
6
6
  import DataState from './DataState.svelte';
7
7
  import type { DataStateKind } from './DataState.svelte';
8
8
  import type { NetworkColumn } from './NetworkTable.types.js';
9
- interface Props { rows?: T[]; columns: NetworkColumn<T>[]; row?: Snippet<[T]>; state?: DataStateKind; stateTitle?: string; stateDescription?: string; emptyTitle?: string; emptyDescription?: string; retry?: () => void; retryLabel?: string; loadingLabel?: string; class?: string; density?: 'comfortable' | 'compact'; }
10
- let { rows = [], columns, row, state, stateTitle, stateDescription, emptyTitle, emptyDescription, retry, retryLabel, loadingLabel, class: className = '', density = 'comfortable' }: Props = $props();
9
+ interface Props { rows?: T[]; columns: NetworkColumn<T>[]; row?: Snippet<[T]>; state?: DataStateKind; stateTitle?: string; stateDescription?: string; emptyTitle?: string; emptyDescription?: string; retry?: () => void; retryLabel?: string; loadingLabel?: string; class?: string; }
10
+ let { rows = [], columns, row, state, stateTitle, stateDescription, emptyTitle, emptyDescription, retry, retryLabel, loadingLabel, class: className = '' }: Props = $props();
11
11
  const resolvedState = $derived(state ?? (rows.length === 0 ? 'empty' : undefined));
12
12
  </script>
13
13
  {#if resolvedState}
14
14
  <DataState state={resolvedState} {...definedOptions({ title: stateTitle ?? emptyTitle, description: stateDescription ?? emptyDescription, retry, retryLabel, loadingLabel })} class={className} />
15
15
  {:else}
16
16
  <div class={'svadmin-u-1384f66f41d0 svadmin-u-5f22e64f2282 svadmin-u-ca6bcd4b6f3f svadmin-u-18049387f0af svadmin-u-cd0ad9a56558 ' + className}>
17
- <Table.Root {density} data-svadmin-datatable>
17
+ <Table.Root data-svadmin-datatable>
18
18
  <Table.Header data-svadmin-table-head><Table.Row>{#each columns as column (String(column.key))}<Table.Head>{column.label}</Table.Head>{/each}</Table.Row></Table.Header>
19
19
  <Table.Body>
20
20
  {#each rows as item, index (String('id' in item ? item.id : index))}
@@ -15,7 +15,6 @@ declare function $$render<T extends object>(): {
15
15
  retryLabel?: string;
16
16
  loadingLabel?: string;
17
17
  class?: string;
18
- density?: "comfortable" | "compact";
19
18
  };
20
19
  exports: {};
21
20
  bindings: "";
@@ -22,7 +22,7 @@
22
22
  display: grid;
23
23
  grid-template-columns: minmax(0, 1fr);
24
24
  align-content: start;
25
- gap: 1rem;
25
+ gap: var(--svadmin-space-4);
26
26
  min-width: 0;
27
27
  }
28
28
  </style>
@@ -12,7 +12,6 @@
12
12
  interface Props {
13
13
  items: StatusTabItem[];
14
14
  value?: string;
15
- density?: 'compact' | 'comfortable';
16
15
  variant?: 'pills' | 'underline' | 'segmented';
17
16
  onchange?: (key: string) => void;
18
17
  class?: string;
@@ -21,7 +20,6 @@
21
20
  let {
22
21
  items = [],
23
22
  value = $bindable(items[0]?.key ?? ''),
24
- density = 'compact',
25
23
  variant = 'pills',
26
24
  onchange,
27
25
  class: className = '',
@@ -61,8 +59,6 @@
61
59
  tabs[nextIndex]?.click();
62
60
  }
63
61
 
64
- const isCompact = $derived(density === 'compact');
65
-
66
62
  const toneClasses: Record<NonNullable<StatusTabItem['tone']>, { activeBadge: string; inactiveBadge: string }> = {
67
63
  default: {
68
64
  activeBadge: 'svadmin-u-6a1572b6bf5a svadmin-u-20aaf08a7ed1',
@@ -95,7 +91,6 @@
95
91
  role="tablist"
96
92
  aria-orientation="horizontal"
97
93
  data-svadmin-status-tabs
98
- data-density={density}
99
94
  data-variant={variant}
100
95
  class={cn(
101
96
  'svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-44ee8ba0a421 svadmin-u-1384f66f41d0',
@@ -118,7 +113,7 @@
118
113
  onkeydown={handleKeydown}
119
114
  class={cn(
120
115
  'svadmin-u-52083e7da442 svadmin-u-3960ffc248d9 svadmin-u-58284b4ea568 svadmin-u-e82ae8be04aa svadmin-u-2689f3958069 svadmin-u-ceb69a6b0e5f svadmin-u-34516836730d svadmin-u-df37b1fd9495 svadmin-u-793c80e97ffb svadmin-u-ddac70ae5d29 svadmin-u-49330148794a svadmin-u-b29d8adbad2e',
121
- isCompact ? 'svadmin-u-359090c2d529 svadmin-u-0b91436debbd svadmin-u-660d2effb880' : 'svadmin-u-fc7473ca09eb svadmin-u-0e17f2bd9074 svadmin-u-ec0091ee009b',
116
+ 'svadmin-u-fc7473ca09eb svadmin-u-0e17f2bd9074 svadmin-u-ec0091ee009b',
122
117
  variant === 'pills' && [
123
118
  'svadmin-u-421ac2be5045 svadmin-u-ca6bcd4b6f3f',
124
119
  active
@@ -144,7 +139,7 @@
144
139
  <span
145
140
  class={cn(
146
141
  'svadmin-u-52083e7da442 svadmin-u-3960ffc248d9 svadmin-u-86843cf1e227 svadmin-u-ac204c108886 svadmin-u-e83a7042bc91 svadmin-u-3032cae0badb svadmin-u-c2385a463da8',
147
- isCompact ? 'svadmin-u-69aaf7265e58 svadmin-u-d8e0e382c67b svadmin-u-465609a240a8 svadmin-u-1dc571a3609f' : 'svadmin-u-f8516763aedd svadmin-u-45d828117213 svadmin-u-465609a240a8 svadmin-u-359090c2d529',
142
+ 'svadmin-u-f8516763aedd svadmin-u-45d828117213 svadmin-u-465609a240a8 svadmin-u-359090c2d529',
148
143
  active ? badgeTone.activeBadge : badgeTone.inactiveBadge
149
144
  )}
150
145
  >
@@ -8,7 +8,6 @@ export interface StatusTabItem {
8
8
  interface Props {
9
9
  items: StatusTabItem[];
10
10
  value?: string;
11
- density?: 'compact' | 'comfortable';
12
11
  variant?: 'pills' | 'underline' | 'segmented';
13
12
  onchange?: (key: string) => void;
14
13
  class?: string;
@@ -10,6 +10,7 @@
10
10
  secondaryCollapsed?: boolean;
11
11
  secondaryCollapsedWidth?: string;
12
12
  mobileOrder?: 'primary-first' | 'secondary-first';
13
+ label?: string;
13
14
  class?: string;
14
15
  }
15
16
 
@@ -21,6 +22,7 @@
21
22
  secondaryCollapsed = false,
22
23
  secondaryCollapsedWidth = '3rem',
23
24
  mobileOrder = 'primary-first',
25
+ label,
24
26
  class: className = '',
25
27
  }: Props = $props();
26
28
 
@@ -28,7 +30,7 @@
28
30
  const resolvedSecondaryWidth = $derived(secondaryCollapsed ? secondaryCollapsedWidth : secondaryWidth);
29
31
  </script>
30
32
 
31
- <div class={styles.root + ' ' + className} data-svadmin-workspace-layout data-secondary-collapsed={secondaryCollapsed} style:--workspace-secondary-width={resolvedSecondaryWidth}>
33
+ <div class={styles.root + ' ' + className} data-svadmin-workspace-layout data-workspace-order={mobileOrder} data-secondary-collapsed={secondaryCollapsed} {...(label ? { 'aria-label': label, role: 'region' } : {})} style:--workspace-secondary-width={resolvedSecondaryWidth}>
32
34
  {#if summary}<div class={styles.summary} data-svadmin-workspace-summary>{@render summary()}</div>{/if}
33
35
  <div class={styles.columns}>
34
36
  {#if mobileOrder === 'secondary-first' && secondary}<aside class={styles.secondary} data-svadmin-workspace-secondary>{@render secondary()}</aside>{/if}
@@ -7,6 +7,7 @@ interface Props {
7
7
  secondaryCollapsed?: boolean;
8
8
  secondaryCollapsedWidth?: string;
9
9
  mobileOrder?: 'primary-first' | 'secondary-first';
10
+ label?: string;
10
11
  class?: string;
11
12
  }
12
13
  declare const WorkspaceLayout: import("svelte").Component<Props, {}, "">;
@@ -1,6 +1,7 @@
1
1
  export { default as ContentPageShell } from './ContentPageShell.svelte';
2
2
  export { default as DashboardPage } from './DashboardPage.svelte';
3
3
  export { default as PageSection } from './PageSection.svelte';
4
+ export { default as DataPanel } from './DataPanel.svelte';
4
5
  export { default as ContentPageHeader } from './ContentPageHeader.svelte';
5
6
  export { default as SectionHeader } from './SectionHeader.svelte';
6
7
  export { default as PageToolbar } from './PageToolbar.svelte';
@@ -1,6 +1,7 @@
1
1
  export { default as ContentPageShell } from './ContentPageShell.svelte';
2
2
  export { default as DashboardPage } from './DashboardPage.svelte';
3
3
  export { default as PageSection } from './PageSection.svelte';
4
+ export { default as DataPanel } from './DataPanel.svelte';
4
5
  export { default as ContentPageHeader } from './ContentPageHeader.svelte';
5
6
  export { default as SectionHeader } from './SectionHeader.svelte';
6
7
  export { default as PageToolbar } from './PageToolbar.svelte';
@@ -5,6 +5,7 @@
5
5
  import ContentPageShell from '../content/ContentPageShell.svelte';
6
6
  import ContentPageHeader from '../content/ContentPageHeader.svelte';
7
7
  import FilterToolbar from '../content/FilterToolbar.svelte';
8
+ import DataState from '../content/DataState.svelte';
8
9
  import NetworkTable from '../content/NetworkTable.svelte';
9
10
  import type { NetworkColumn } from '../content/NetworkTable.types.js';
10
11
  import { Avatar } from '../ui/avatar/index.js';
@@ -38,5 +39,11 @@
38
39
  <ReferenceNotice />
39
40
  <div class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed svadmin-u-1004c0c3954c svadmin-u-020ba687fa12 svadmin-u-64cac80d2e9a svadmin-u-3b9871a0bf93"><ContentPageHeader title={i18n.t('network.teamCrew')} description={i18n.t('network.teamCrewDescription')} /><div class="svadmin-u-60fbb7713999 svadmin-u-1eb5c6df38c1 svadmin-u-77a2a20e90d4"><Button variant="outline" size="sm" onclick={() => downloadRows('sample-team.json', filtered)}><Download class="svadmin-u-783b0d9d1e2c" />{i18n.t('common.export')}</Button><Button size="sm" onclick={() => context.navigate('/account/members/team-members')}><UserPlus class="svadmin-u-783b0d9d1e2c" />{i18n.t('account.inviteMember')}</Button></div></div>
40
41
  <FilterToolbar bind:query placeholder={i18n.t('common.search')} />
41
- <NetworkTable rows={filtered} {columns} {row} />
42
+ {#if rows.length === 0}
43
+ <DataState state="empty" title={i18n.t('account.member')} />
44
+ {:else if filtered.length === 0}
45
+ <DataState state="filtered-empty" title={i18n.t('account.member')} description={i18n.t('common.search')} />
46
+ {:else}
47
+ <NetworkTable rows={filtered} {columns} {row} />
48
+ {/if}
42
49
  </ContentPageShell>
@@ -28,8 +28,10 @@
28
28
  <ReferenceNotice />
29
29
  <ContentPageHeader title={i18n.t('network.userCards')} description={i18n.t('network.userCardsDescription')} />
30
30
  <FilterToolbar bind:query placeholder={i18n.t('common.search')} clearLabel={i18n.locale === 'zh-CN' ? '清除搜索' : 'Clear search'} />
31
- {#if filtered.length === 0}
31
+ {#if users.length === 0}
32
32
  <DataState state="empty" title={i18n.t('network.userCards')} />
33
+ {:else if filtered.length === 0}
34
+ <DataState state="filtered-empty" title={i18n.t('network.userCards')} description={i18n.t('common.search')} />
33
35
  {:else}
34
36
  <div class="svadmin-u-f3c543ad5fe9 svadmin-u-0c3bc98565dd svadmin-u-e4d6f343b9ff svadmin-u-b86f7f946cd8">
35
37
  {#each filtered as user (user.id)}
@@ -34,7 +34,7 @@
34
34
  {#if projects.length === 0}
35
35
  <DataState state="empty" title={i18n.t('publicProfile.noProjects')} />
36
36
  {:else if filtered.length === 0}
37
- <DataState state="empty" title={i18n.t('publicProfile.noProjects')} description={i18n.t('publicProfile.searchProjects')} />
37
+ <DataState state="filtered-empty" title={i18n.t('publicProfile.noProjects')} description={i18n.t('publicProfile.searchProjects')} />
38
38
  {:else}
39
39
  <div class={'svadmin-u-f3c543ad5fe9 svadmin-u-0c3bc98565dd ' + gridClass}>
40
40
  {#each filtered as project (project.id)}
@@ -13,5 +13,5 @@
13
13
  <section class="svadmin-u-3e7ce58d64fa">
14
14
  <div class="svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed svadmin-u-1004c0c3954c svadmin-u-020ba687fa12 svadmin-u-9f76a62f4f44 svadmin-u-3b9871a0bf93"><div><h2 class="svadmin-u-4ee734926ff6 svadmin-u-e83a7042bc91 svadmin-u-d4108abe6359">{i18n.t('publicProfile.teamsCount', { count: filtered.length })}</h2><p class="svadmin-u-b6b02c0ebef6 svadmin-u-fc7473ca09eb svadmin-u-bfa603190748">{i18n.t('publicProfile.searchTeams')}</p></div></div>
15
15
  <FilterToolbar bind:query placeholder={i18n.t('publicProfile.searchTeams')} />
16
- {#if filtered.length === 0}<DataState state="empty" title={i18n.t('publicProfile.noTeams')} />{:else}<div class="svadmin-u-f3c543ad5fe9 svadmin-u-0c3bc98565dd svadmin-u-e4d6f343b9ff svadmin-u-b86f7f946cd8">{#each filtered as team (team.id)}<TeamCard {team} />{/each}</div>{/if}
16
+ {#if teams.length === 0}<DataState state="empty" title={i18n.t('publicProfile.noTeams')} />{:else if filtered.length === 0}<DataState state="filtered-empty" title={i18n.t('publicProfile.noTeams')} description={i18n.t('publicProfile.searchTeams')} />{:else}<div class="svadmin-u-f3c543ad5fe9 svadmin-u-0c3bc98565dd svadmin-u-e4d6f343b9ff svadmin-u-b86f7f946cd8">{#each filtered as team (team.id)}<TeamCard {team} />{/each}</div>{/if}
17
17
  </section>
@@ -6,5 +6,4 @@ import Footer from "./table-footer.svelte";
6
6
  import Head from "./table-head.svelte";
7
7
  import Header from "./table-header.svelte";
8
8
  import Row from "./table-row.svelte";
9
- export type { TableDensity } from "./table.svelte";
10
9
  export { Root, Body, Caption, Cell, Footer, Head, Header, Row, Root as Table, Body as TableBody, Caption as TableCaption, Cell as TableCell, Footer as TableFooter, Head as TableHead, Header as TableHeader, Row as TableRow, };
@@ -6,6 +6,7 @@
6
6
  export type TableDensity = "compact" | "comfortable";
7
7
 
8
8
  type Props = WithElementRef<HTMLTableAttributes, HTMLTableElement> & {
9
+ /** @deprecated Retained for compatibility; comfortable is the shared default. */
9
10
  density?: TableDensity;
10
11
  };
11
12
 
@@ -2,6 +2,7 @@ import type { HTMLTableAttributes } from "svelte/elements";
2
2
  import { type WithElementRef } from "../../../utils.js";
3
3
  export type TableDensity = "compact" | "comfortable";
4
4
  type Props = WithElementRef<HTMLTableAttributes, HTMLTableElement> & {
5
+ /** @deprecated Retained for compatibility; comfortable is the shared default. */
5
6
  density?: TableDensity;
6
7
  };
7
8
  declare const Table: import("svelte").Component<Props, {}, "ref">;
@@ -889,11 +889,6 @@ main {
889
889
  vertical-align: middle;
890
890
  white-space: nowrap;
891
891
  }
892
- .svadmin-table-cell[data-density="compact"] {
893
- height: 2rem;
894
- padding: 0.25rem 0.5rem;
895
- font-size: 0.75rem;
896
- }
897
892
  .svadmin-table-cell[data-sticky="right"], .svadmin-table-cell[data-sticky="left"] {
898
893
  position: sticky;
899
894
  z-index: 10;
@@ -2041,11 +2036,6 @@ main {
2041
2036
  font-weight: 500;
2042
2037
  white-space: nowrap;
2043
2038
  }
2044
- .svadmin-table-head[data-density="compact"] {
2045
- height: 2rem;
2046
- padding: 0.25rem 0.5rem;
2047
- font-size: 0.75rem;
2048
- }
2049
2039
  .svadmin-table-head[data-sticky="right"], .svadmin-table-head[data-sticky="left"] {
2050
2040
  position: sticky;
2051
2041
  z-index: 20;
@@ -2218,7 +2208,7 @@ details[data-svadmin-filter][open] > :not(summary),
2218
2208
 
2219
2209
  /* --- Admin UI layout preset (clean-flat) --- */
2220
2210
  /* Keep this public class for layoutPreset API compatibility. The preset only
2221
- * adjusts density and composition; color, focus, and elevation stay semantic. */
2211
+ * adjusts composition; color, focus, and elevation stay semantic. */
2222
2212
  .layout-clean-flat {
2223
2213
  --radius: 0.5rem;
2224
2214
  --svadmin-content-width: 74rem;
@@ -0,0 +1,88 @@
1
+ /* Data panel: the recurring "titled surface with a body" container.
2
+ *
3
+ * Hosts previously hand-rolled this block per page, which is how a project ends
4
+ * up with three panel paddings and two radii. Every length here is a token. */
5
+ @layer components {
6
+ .svadmin-data-panel {
7
+ --svadmin-panel-padding: var(--svadmin-space-5);
8
+ display: grid;
9
+ grid-template-columns: minmax(0, 1fr);
10
+ align-content: start;
11
+ min-width: 0;
12
+ border: 1px solid var(--border);
13
+ border-radius: var(--radius-lg);
14
+ background: var(--card);
15
+ color: var(--card-foreground);
16
+ overflow: hidden;
17
+ }
18
+ .svadmin-data-panel[data-padding="compact"] {
19
+ --svadmin-panel-padding: var(--svadmin-space-4);
20
+ }
21
+ .svadmin-data-panel[data-padding="none"] {
22
+ --svadmin-panel-padding: 0;
23
+ }
24
+
25
+ .svadmin-data-panel__header {
26
+ display: flex;
27
+ flex-wrap: wrap;
28
+ align-items: flex-start;
29
+ justify-content: space-between;
30
+ gap: var(--svadmin-space-3);
31
+ min-width: 0;
32
+ padding: var(--svadmin-panel-padding);
33
+ padding-block-end: 0;
34
+ }
35
+ .svadmin-data-panel[data-padding="none"] .svadmin-data-panel__header {
36
+ padding: var(--svadmin-space-4) var(--svadmin-space-5);
37
+ border-bottom: 1px solid var(--border);
38
+ }
39
+ .svadmin-data-panel__heading {
40
+ display: grid;
41
+ gap: var(--svadmin-space-1);
42
+ min-width: 0;
43
+ flex: 1 1 0;
44
+ }
45
+ .svadmin-data-panel__title {
46
+ margin: 0;
47
+ color: var(--foreground);
48
+ font-size: var(--svadmin-text-section);
49
+ font-weight: 600;
50
+ line-height: var(--svadmin-leading-tight);
51
+ overflow-wrap: anywhere;
52
+ }
53
+ .svadmin-data-panel__description {
54
+ max-width: var(--svadmin-measure);
55
+ margin: 0;
56
+ color: var(--muted-foreground);
57
+ font-size: var(--svadmin-text-body);
58
+ line-height: var(--svadmin-leading-body);
59
+ overflow-wrap: anywhere;
60
+ }
61
+ .svadmin-data-panel__actions {
62
+ display: flex;
63
+ flex-wrap: wrap;
64
+ align-items: center;
65
+ gap: var(--svadmin-space-2);
66
+ flex: 0 0 auto;
67
+ }
68
+ .svadmin-data-panel__body {
69
+ display: grid;
70
+ gap: var(--svadmin-space-4);
71
+ min-width: 0;
72
+ padding: var(--svadmin-panel-padding);
73
+ }
74
+ .svadmin-data-panel[data-padding="none"] .svadmin-data-panel__body {
75
+ gap: 0;
76
+ }
77
+ .svadmin-data-panel__footer {
78
+ display: flex;
79
+ flex-wrap: wrap;
80
+ align-items: center;
81
+ justify-content: flex-end;
82
+ gap: var(--svadmin-space-2);
83
+ padding: var(--svadmin-space-3) var(--svadmin-space-5);
84
+ border-top: 1px solid var(--border);
85
+ color: var(--muted-foreground);
86
+ font-size: var(--svadmin-text-caption);
87
+ }
88
+ }
@@ -8,6 +8,17 @@ export declare const surfaceDesignContract: {
8
8
  readonly table: {
9
9
  readonly density: readonly ["comfortable", "compact"];
10
10
  };
11
+ readonly pageFamilies: readonly ["list", "form", "detail", "workspace", "dashboard"];
12
+ readonly pageStates: readonly ["ready", "loading", "empty", "filtered-empty", "error", "forbidden"];
13
+ readonly composition: {
14
+ readonly maxPrimaryActions: 1;
15
+ readonly secondaryActions: "overflow";
16
+ readonly destructiveActions: "confirm";
17
+ readonly modalNesting: 0;
18
+ };
11
19
  };
12
20
  export type SurfaceTone = typeof surfaceDesignContract.metric.tone[number];
21
+ /** @deprecated Kept for source compatibility; product pages use one baseline rhythm. */
13
22
  export type SurfaceDensity = typeof surfaceDesignContract.metric.density[number];
23
+ export type AdminPageFamily = typeof surfaceDesignContract.pageFamilies[number];
24
+ export type AdminPageState = typeof surfaceDesignContract.pageStates[number];
@@ -8,4 +8,12 @@ export const surfaceDesignContract = {
8
8
  table: {
9
9
  density: ['comfortable', 'compact'],
10
10
  },
11
+ pageFamilies: ['list', 'form', 'detail', 'workspace', 'dashboard'],
12
+ pageStates: ['ready', 'loading', 'empty', 'filtered-empty', 'error', 'forbidden'],
13
+ composition: {
14
+ maxPrimaryActions: 1,
15
+ secondaryActions: 'overflow',
16
+ destructiveActions: 'confirm',
17
+ modalNesting: 0,
18
+ },
11
19
  };
@@ -1,11 +1,12 @@
1
- import type { SurfaceTone, SurfaceDensity } from "./design-contract.js";
1
+ import type { SurfaceDensity, SurfaceTone } from "./design-contract.js";
2
2
  export declare function metricSurfaceClasses(tone?: SurfaceTone): {
3
3
  state: string;
4
4
  description: string;
5
5
  root: string;
6
6
  card: string;
7
7
  };
8
- export declare function tableSurfaceClasses(density?: SurfaceDensity): {
8
+ /** @deprecated The argument is accepted for compatibility and uses the shared baseline. */
9
+ export declare function tableSurfaceClasses(_density?: SurfaceDensity): {
9
10
  state: string;
10
11
  content: string;
11
12
  head: string;
@@ -2,6 +2,7 @@ import { surfaceMetricRecipe as surfaceMetric, surfaceTableRecipe as surfaceTabl
2
2
  export function metricSurfaceClasses(tone = "neutral") {
3
3
  return surfaceMetric({ tone });
4
4
  }
5
- export function tableSurfaceClasses(density = "comfortable") {
6
- return surfaceTable({ density });
5
+ /** @deprecated The argument is accepted for compatibility and uses the shared baseline. */
6
+ export function tableSurfaceClasses(_density = "comfortable") {
7
+ return surfaceTable();
7
8
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { surfaceDesignContract } from "./design-contract.js";
2
- export type { SurfaceTone, SurfaceDensity } from "./design-contract.js";
2
+ export type { AdminPageFamily, AdminPageState, SurfaceDensity, SurfaceTone } from "./design-contract.js";
3
3
  export { designSystemComponents, type DesignComponentContract, type DesignComponentId, type DesignComponentState, } from "./design-system-components.js";
4
4
  export { metricSurfaceClasses, tableSurfaceClasses } from "./design-system.js";
5
5
  export { default as AdminApp } from './components/AdminApp.svelte';
@@ -38,7 +38,8 @@ export { default as MetricStrip } from './components/MetricStrip.svelte';
38
38
  export type { MetricStripItem, MetricTone } from './components/MetricStrip.svelte';
39
39
  export { default as PageHeader } from './components/PageHeader.svelte';
40
40
  export { default as PagePattern } from './components/PagePattern.svelte';
41
- export type { PagePatternKind } from './components/PagePattern.svelte';
41
+ export type { PagePatternKind, PagePatternState } from './components/PagePattern.svelte';
42
+ export { default as AppShellPage } from './components/AppShellPage.svelte';
42
43
  export { default as ResourceOperationsPage } from './components/ResourceOperationsPage.svelte';
43
44
  export { default as RecordDetailDrawer } from './components/RecordDetailDrawer.svelte';
44
45
  export { default as ResourceAccessGuard } from './components/ResourceAccessGuard.svelte';
@@ -278,6 +279,7 @@ export { default as TwoFactorAuthPage } from './components/TwoFactorAuthPage.sve
278
279
  export { default as ContentPageShell } from './components/content/ContentPageShell.svelte';
279
280
  export { default as DashboardPage } from './components/content/DashboardPage.svelte';
280
281
  export { default as PageSection } from './components/content/PageSection.svelte';
282
+ export { default as DataPanel } from './components/content/DataPanel.svelte';
281
283
  export { default as ContentPageHeader } from './components/content/ContentPageHeader.svelte';
282
284
  export { default as ConfigurationPage } from './components/ConfigurationPage.svelte';
283
285
  export { default as SectionHeader } from './components/content/SectionHeader.svelte';
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ export { default as StatsCard } from './components/StatsCard.svelte';
31
31
  export { default as MetricStrip } from './components/MetricStrip.svelte';
32
32
  export { default as PageHeader } from './components/PageHeader.svelte';
33
33
  export { default as PagePattern } from './components/PagePattern.svelte';
34
+ export { default as AppShellPage } from './components/AppShellPage.svelte';
34
35
  export { default as ResourceOperationsPage } from './components/ResourceOperationsPage.svelte';
35
36
  export { default as RecordDetailDrawer } from './components/RecordDetailDrawer.svelte';
36
37
  export { default as ResourceAccessGuard } from './components/ResourceAccessGuard.svelte';
@@ -245,6 +246,7 @@ export { default as TwoFactorAuthPage } from './components/TwoFactorAuthPage.sve
245
246
  export { default as ContentPageShell } from './components/content/ContentPageShell.svelte';
246
247
  export { default as DashboardPage } from './components/content/DashboardPage.svelte';
247
248
  export { default as PageSection } from './components/content/PageSection.svelte';
249
+ export { default as DataPanel } from './components/content/DataPanel.svelte';
248
250
  export { default as ContentPageHeader } from './components/content/ContentPageHeader.svelte';
249
251
  export { default as ConfigurationPage } from './components/ConfigurationPage.svelte';
250
252
  export { default as SectionHeader } from './components/content/SectionHeader.svelte';