@svadmin/create 0.41.2 → 0.43.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.
@@ -16,7 +16,7 @@ bun run dev
16
16
 
17
17
  在编码助手中提出需求即可,例如:
18
18
 
19
- > 基于当前客户工作台,把全站调整为高密度运营,保留客户 CRUD 和跟进流程。
19
+ > 基于当前客户工作台,把全站调整为宽屏运营布局,保留客户 CRUD 和跟进流程。
20
20
  > 先读取 svadmin.vibe.json 和设计规范,修改后运行检查并查看移动端截图。
21
21
 
22
22
  `AGENTS.md` 提供通用规则,`.agents/skills/svadmin-vibe/SKILL.md` 提供生成与
@@ -3,7 +3,6 @@ import { initialPreset } from './design-selection';
3
3
 
4
4
  interface DesignPreset {
5
5
  label: string;
6
- density: 'compact' | 'comfortable';
7
6
  width: 'wide' | 'default';
8
7
  formColumns: 1 | 2;
9
8
  detailLayout: 'list' | 'grid';
@@ -12,17 +11,17 @@ interface DesignPreset {
12
11
 
13
12
  export const designPresets = {
14
13
  operations: {
15
- label: '高密度运营', density: 'compact', width: 'wide',
14
+ label: '宽屏运营', width: 'wide',
16
15
  formColumns: 2, detailLayout: 'list',
17
16
  theme: { colorPreset: 'neutral', layoutPreset: 'clean-flat' },
18
17
  },
19
18
  enterprise: {
20
- label: '标准企业', density: 'comfortable', width: 'wide',
19
+ label: '标准企业', width: 'wide',
21
20
  formColumns: 2, detailLayout: 'grid',
22
21
  theme: { colorPreset: 'stripe', layoutPreset: 'clean-flat' },
23
22
  },
24
23
  collaboration: {
25
- label: '轻量协作', density: 'comfortable', width: 'default',
24
+ label: '轻量协作', width: 'default',
26
25
  formColumns: 1, detailLayout: 'list',
27
26
  theme: { colorPreset: 'green', layoutPreset: 'clean-flat' },
28
27
  },
@@ -2,8 +2,6 @@
2
2
  import { useList, useCan } from '@svadmin/core';
3
3
  import { AutoTable, Button, DashboardPage, DataState, MetricBlock, PageSection } from '@svadmin/ui';
4
4
  import { customers, followups, approvals } from './contracts';
5
- import { getDesign } from '../../design.svelte';
6
- const design = $derived(getDesign());
7
5
  const access = useCan(() => ({ resource: 'customers', action: 'list' }));
8
6
  const followupAccess = useCan(() => ({ resource: 'followups', action: 'list' }));
9
7
  const approvalAccess = useCan(() => ({ resource: 'approvals', action: 'list' }));
@@ -37,7 +35,7 @@
37
35
  {/if}
38
36
  <PageSection title="客户">
39
37
  <AutoTable resourceName="customers" showHeader={false} selectable={false}
40
- syncWithLocation={false} density={design.density} />
38
+ syncWithLocation={false} />
41
39
  </PageSection>
42
40
  {#snippet secondary()}
43
41
  <PageSection title="待办">
@@ -15,9 +15,9 @@
15
15
  }));
16
16
  </script>
17
17
 
18
- <ContentPageShell pageId="customer-detail" width={design.width} density={design.density}>
18
+ <ContentPageShell pageId="customer-detail" width={design.width}>
19
19
  {#if id !== undefined}
20
- <ShowPage {resourceName} {id} layout={design.detailLayout} density={design.density}>
20
+ <ShowPage {resourceName} {id} layout={design.detailLayout}>
21
21
  <PageSection title="最近跟进">
22
22
  {#snippet actions()}<Button variant="ghost" href="#/followups">全部记录</Button>{/snippet}
23
23
  {#if permission.isLoading || records.isLoading}
@@ -7,7 +7,7 @@
7
7
  const design = $derived(getDesign());
8
8
  </script>
9
9
 
10
- <ContentPageShell pageId="customer-form" width={design.width} density={design.density}>
10
+ <ContentPageShell pageId="customer-form" width={design.width}>
11
11
  <AutoForm {resourceName} {mode} {...(id === undefined ? {} : { id })}
12
- columns={design.formColumns} density={design.density} />
12
+ columns={design.formColumns} />
13
13
  </ContentPageShell>
@@ -5,6 +5,6 @@
5
5
  const design = $derived(getDesign());
6
6
  </script>
7
7
 
8
- <ContentPageShell pageId="customer-list" width={design.width} density={design.density}>
9
- <AutoTable {resourceName} density={design.density} />
8
+ <ContentPageShell pageId="customer-list" width={design.width}>
9
+ <AutoTable {resourceName} />
10
10
  </ContentPageShell>
@@ -1,13 +1,11 @@
1
1
  <script lang="ts">
2
2
  import { AutoForm, ContentPageShell, DataState, PageSection, ShowPage } from '@svadmin/ui';
3
- import { getDesign } from '../../design.svelte';
4
3
  let { resourceName, id }: { resourceName: string; id?: string | number } = $props();
5
- const design = $derived(getDesign());
6
4
  </script>
7
5
 
8
- <ContentPageShell pageId="approval-review" width="default" density={design.density}>
6
+ <ContentPageShell pageId="approval-review" width="default">
9
7
  {#if id !== undefined}
10
- <ShowPage {resourceName} {id} density={design.density}>
8
+ <ShowPage {resourceName} {id}>
11
9
  <PageSection title="审批决定">
12
10
  <AutoForm {resourceName} {id} mode="edit" showHeader={false} columns={1} />
13
11
  </PageSection>
@@ -70,7 +70,6 @@ test('global design preset changes without losing customer data', async ({ page
70
70
  await page.goto('/#/workspace_settings');
71
71
  await page.getByRole('combobox', { name: '设计预设', exact: true }).selectOption('operations');
72
72
  await page.evaluate(() => { location.hash = '/customers'; });
73
- await expect(page.locator('[data-svadmin-content-page="customer-list"]')).toHaveAttribute('data-density', 'compact');
74
73
  await expect(visibleText(page, '澄川科技')).toBeVisible();
75
74
  await page.evaluate(() => { location.hash = '/workspace_settings'; });
76
75
  await page.getByRole('combobox', { name: '设计预设', exact: true }).selectOption('collaboration');
@@ -84,7 +83,6 @@ for (const preset of catalog.presets) {
84
83
  await page.getByRole('combobox', { name: '设计预设', exact: true }).selectOption(preset);
85
84
  await page.evaluate(() => { location.hash = '/customers'; });
86
85
  await expect(visibleText(page, '澄川科技')).toBeVisible();
87
- await expect(page.locator('[data-svadmin-content-page="customer-list"]')).toHaveAttribute('data-density', preset === 'operations' ? 'compact' : 'comfortable');
88
86
  await page.screenshot({ path: testInfo.outputPath(`${preset}.png`), fullPage: true, animations: 'disabled' });
89
87
  });
90
88
  }
@@ -36,7 +36,7 @@ The CLI commands remain the fallback when no MCP client is configured.
36
36
  internal/example-only imports.
37
37
  - Translate "compact", "standard", or "lightweight" requests into the existing
38
38
  application-wide presets in `src/design.svelte.ts`. Keep layout, form columns,
39
- table density, and detail layout consistent. Change `src/design-selection.ts`
39
+ and detail layout consistent. Change `src/design-selection.ts`
40
40
  for the initial preset. Do not silently reset a user's saved preferences.
41
41
  - Preserve resource contracts, providers, permissions, routes, and active form
42
42
  values when making visual-only changes. Keep metric values provider-backed.
@@ -115,6 +115,12 @@ feedback for repeated operational work. The interface should feel like a real
115
115
  administrative product with trustworthy states, not a collection of dashboard
116
116
  templates.
117
117
 
118
+ For business workflow, page selection, list density, operation ownership, and
119
+ acceptance gates, read `docs/ENTERPRISE_PRODUCT_SYSTEM.md`. This document is
120
+ the product-usage layer above the visual system: it explains how to use the
121
+ published components to build useful enterprise workflows instead of treating
122
+ the component catalog as a page design.
123
+
118
124
  Metronic is a capability reference only. Its page families, information
119
125
  architecture, and scenario coverage may expose missing components or examples,
120
126
  but its palette, decoration, card treatment, typography, and branding are not
@@ -131,7 +137,7 @@ not become a mixed visual theme:
131
137
  | --- | --- | --- |
132
138
  | Stripe style prompt | theme-menu chip `#635bff`, painted `--primary: oklch(0.54 0.24 293)`, technical grid, hairline borders, layered elevation, lift/depress feedback | Stripe brand assets, marketing gradients, oversized hero treatment |
133
139
  | Corporate-clean prompt | neutral enterprise surfaces, readable hierarchy, generous spacing, focus-ring offset, motion capped at 200ms | blue-only palette, rigid utility-class recipes, decorative cards |
134
- | Fuse / Midone / Skote | navigation anatomy, page-family coverage, toolbar/table/form composition, density observations | vendor palette, logos, fonts, CSS, copied markup or component chrome |
140
+ | Fuse / Midone / Skote | navigation anatomy, page-family coverage, toolbar/table/form composition, layout observations | vendor palette, logos, fonts, CSS, copied markup or component chrome |
135
141
  | svadmin | semantic tokens, component API, state ownership, accessibility, responsive contracts | no second visual authority |
136
142
 
137
143
  When references conflict, svadmin semantics and accessibility win first, the
@@ -170,7 +176,7 @@ The same contract is used at every delivery surface:
170
176
  remains the preset chip `#635bff`, not the oklch `--primary` used by
171
177
  `@svadmin/ui`.
172
178
 
173
- Theme refinements must preserve component density, invalid and selected states.
179
+ Theme refinements must preserve component geometry, invalid and selected states.
174
180
  Focus belongs to the active control, not every enclosing card. Search icons and
175
181
  clear actions use logical positioning so the same layout works in RTL.
176
182
 
@@ -205,7 +211,7 @@ and documentation:
205
211
  move the primary action or force an unnecessary page transition.
206
212
  3. **Consistent by contract:** semantic tokens, component variants, state names,
207
213
  page skeletons, and feedback lifecycles remain stable across products. Layout
208
- presets may change density and composition, not interaction meaning.
214
+ presets may change composition, not interaction meaning.
209
215
  4. **Trustworthy in every state:** loading, empty, partial, error, forbidden,
210
216
  destructive, reversible, and completed states expose their scope and next
211
217
  step. Data freshness, permission boundaries, and action consequences must be
@@ -298,18 +304,20 @@ unframed layouts with a stable content width. Cards represent individual
298
304
  objects or bounded tools; page sections are not decorative floating cards and
299
305
  cards are not nested for visual effect.
300
306
 
301
- ### Visual Density Dials
307
+ ### Spacing Rhythm
308
+
309
+ svadmin components ship one comfortable baseline rhythm so pages scan
310
+ consistently and generated output matches hand-built pages:
302
311
 
303
- svadmin components support systematic density levels to balance scanning speed
304
- and operational throughput:
312
+ - **Components**: 4px/8px/16px rhythm with 40px–44px control heights and
313
+ 40px–44px table row heights, used across `AutoTable`, `FilterToolbar`,
314
+ `RecordDetailDrawer`, forms, and operations work areas.
315
+ - **Spacious onboarding or marketing surfaces** may widen vertical padding with
316
+ page-local layout choices, but must not fork component recipes.
305
317
 
306
- - **Density 8–10 (Dense / Dashboard)**: 2px/4px/8px rhythm with 28px–32px row
307
- heights. Used for `AutoTable`, `FilterToolbar`, `RecordDetailDrawer`, and
308
- operations work areas.
309
- - **Density 4–6 (Comfortable / Standard)**: 4px/8px/16px rhythm with 40px–44px
310
- control heights. Used for settings forms, account profiles, and overview cards.
311
- - **Density 1–3 (Spacious / Onboarding)**: 16px/24px/32px rhythm for public
312
- portals and introductory workflows.
318
+ Density is not a component or page-pattern option; there is no compact or
319
+ comfortable modifier to coordinate across `AutoTable`, `ContentPageShell`, or
320
+ Surface widgets.
313
321
 
314
322
  ## Elevation & Depth
315
323
 
@@ -339,7 +347,9 @@ another titled page shell. Keep `DashboardPage` for existing dashboards.
339
347
 
340
348
  Use `PagePattern` for custom business compositions that do not fit those
341
349
  resource routes. It supplies layout only, not querying, permissions, form
342
- submission, or loading/error handling:
350
+ submission, or business data fetching. It owns the default page-state
351
+ presentation so custom pages do not need to recreate loading/error/empty
352
+ layouts:
343
353
 
344
354
  - `list`: comfortable title, toolbar, table/list content, and list empty states.
345
355
  - `form`: narrow reading width, comfortable grouped fields and a single save area.
@@ -347,6 +357,13 @@ submission, or loading/error handling:
347
357
  - `workspace`: comfortable primary work area plus an optional secondary panel.
348
358
  - `dashboard`: wide layout with optional metrics and secondary context.
349
359
 
360
+ Set `state` to `loading`, `empty`, `filtered-empty`, `error`, or `forbidden`
361
+ while the page is not ready. Use `empty` only when the underlying collection is
362
+ empty; use `filtered-empty` when filters excluded all records. Page content is
363
+ hidden during those states, and the shared `DataState` component supplies the
364
+ accessible default. Use `retry` only for `error`; use `stateAction` for an
365
+ explicitly permitted next step. `ready` is the default.
366
+
350
367
  Optional `secondary` content renders beside the primary content for every kind.
351
368
  For advanced resizable, collapsible, or independently scrolling work areas,
352
369
  compose `WorkspaceLayout` or `MasterDetailView` directly. The pattern does not
@@ -398,10 +415,8 @@ cards, repeated title bars, or unrestricted two-column fields.
398
415
  persistence request succeeds; preserve edits after failure.
399
416
  - Separate initial-empty content from filtered-no-results content. Offer
400
417
  creation only when permitted, and clearing filters only when filters exist.
401
- - Page patterns default to comfortable density so generated and custom pages
402
- have a consistent baseline. Use compact density explicitly for operational
403
- work that prioritizes scanning speed; use comfortable density for forms and
404
- general-purpose pages.
418
+ - Page patterns use a single comfortable baseline so generated and custom pages
419
+ share the same rhythm across forms, detail, list, and workspace families.
405
420
  - Reference `packages/ui/stories/ConfigurationExample.svelte` in the SVAdmin
406
421
  source for a working composition; its save action is in-memory demo state,
407
422
  not a persistence implementation.
@@ -414,7 +429,7 @@ passing component tests alone does not establish visual acceptance.
414
429
 
415
430
  Buttons, fields, tabs, tables, badges, empty states, skeletons, alerts, and
416
431
  feedback use shared components and semantic tokens. Layout presets may adjust
417
- density and composition, but they must not replace component color, typography,
432
+ composition, but they must not replace component color, typography,
418
433
  focus, or elevation with hard-coded values.
419
434
 
420
435
  ### Shell anatomy
@@ -462,11 +477,11 @@ Transitions provide clear state confirmation without delaying user action:
462
477
  The reference stack is layered. It is not a visual mixture:
463
478
 
464
479
  - **svadmin owns its visual principles:** hierarchy, restraint, neutral surfaces,
465
- typography, density, and interaction tone.
480
+ typography, spacing, and interaction tone.
466
481
  - **Refine is an application-model reference:** resource routing, CRUD flows,
467
482
  provider state, access control, and mutation ownership.
468
483
  - **Ant Design is a behavior reference:** field validation, alerts, messages,
469
- notifications, results, empty states, loading, and high-density data tasks.
484
+ notifications, results, empty states, loading, and data-heavy tasks.
470
485
  - **shadcn/ui is a composition reference:** accessible primitives, source-owned
471
486
  components, semantic tokens, variants, and AI-readable assembly patterns.
472
487
  - **Carbon and PatternFly are enterprise-pattern references:** notification
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svadmin/create",
3
- "version": "0.41.2",
3
+ "version": "0.43.0",
4
4
  "description": "Scaffolding tool for svadmin projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -30,7 +30,7 @@
30
30
  "@types/node": "^26.4.0",
31
31
  "@types/prompts": "^2.4.9",
32
32
  "typescript": "^7.0.2",
33
- "@svadmin/core": "^0.61.1"
33
+ "@svadmin/core": "^0.62.0"
34
34
  },
35
35
  "keywords": [
36
36
  "svadmin",
@@ -10,10 +10,10 @@
10
10
  "check": "svelte-check --tsconfig ./tsconfig.json"
11
11
  },
12
12
  "dependencies": {
13
- "@svadmin/core": "^0.61.1",
14
- "@svadmin/app": "^0.2.5",
15
- "@svadmin/ai-elements": "^0.11.3",
16
- "@svadmin/ui": "^0.85.0",
13
+ "@svadmin/core": "^0.62.0",
14
+ "@svadmin/app": "^0.2.6",
15
+ "@svadmin/ai-elements": "^0.12.0",
16
+ "@svadmin/ui": "^0.88.0",
17
17
  "typebox": "^1.3.34",
18
18
  "@tanstack/svelte-query": "^6.1.48",
19
19
  "@lucide/svelte": "^1.35.0"
@@ -42,76 +42,76 @@
42
42
  "graphql": "^16.8.0"
43
43
  },
44
44
  "simple-rest": {
45
- "@svadmin/simple-rest": "^0.12.6",
45
+ "@svadmin/simple-rest": "^0.12.7",
46
46
  "@refinedev/simple-rest": "^6.0.1"
47
47
  },
48
48
  "supabase": {
49
- "@svadmin/supabase": "^0.19.3",
49
+ "@svadmin/supabase": "^0.19.4",
50
50
  "@supabase/supabase-js": "^2.112.4",
51
51
  "@refinedev/supabase": "^6.0.2"
52
52
  },
53
53
  "graphql": {
54
- "@svadmin/graphql": "^0.12.6",
54
+ "@svadmin/graphql": "^0.12.7",
55
55
  "@refinedev/graphql": "^8.0.1",
56
56
  "graphql-request": "^7.4.0",
57
57
  "graphql": "^16.8.0"
58
58
  },
59
59
  "rest": {
60
- "@svadmin/rest": "^0.2.5",
60
+ "@svadmin/rest": "^0.2.6",
61
61
  "@refinedev/rest": "^2.1.1",
62
62
  "@nestjsx/crud-request": "^5.0.0-alpha.3"
63
63
  },
64
64
  "airtable": {
65
- "@svadmin/airtable": "^0.12.6",
65
+ "@svadmin/airtable": "^0.12.7",
66
66
  "@refinedev/airtable": "^5.0.1"
67
67
  },
68
68
  "appwrite": {
69
- "@svadmin/appwrite": "^0.11.6",
69
+ "@svadmin/appwrite": "^0.11.7",
70
70
  "appwrite": ">=26.2.0",
71
71
  "@refinedev/appwrite": "^8.0.1"
72
72
  },
73
73
  "directus": {
74
- "@svadmin/directus": "^0.11.6"
74
+ "@svadmin/directus": "^0.11.7"
75
75
  },
76
76
  "drizzle": {
77
- "@svadmin/drizzle": "^0.14.3",
77
+ "@svadmin/drizzle": "^0.14.4",
78
78
  "drizzle-orm": "^1.0.0-rc.1",
79
79
  "refine-sqlx": "^0.10.3"
80
80
  },
81
81
  "elysia": {
82
- "@svadmin/elysia": "^0.14.6",
82
+ "@svadmin/elysia": "^0.14.7",
83
83
  "elysia": ">=1.4.30",
84
84
  "@elysiajs/eden": ">=1.4.9"
85
85
  },
86
86
  "firebase": {
87
- "@svadmin/firebase": "^0.12.6"
87
+ "@svadmin/firebase": "^0.12.7"
88
88
  },
89
89
  "hasura": {
90
- "@svadmin/hasura": "^0.12.6",
90
+ "@svadmin/hasura": "^0.12.7",
91
91
  "@refinedev/hasura": "^7.0.1",
92
92
  "graphql-request": "^7.4.0"
93
93
  },
94
94
  "medusa": {
95
- "@svadmin/medusa": "^0.12.6",
95
+ "@svadmin/medusa": "^0.12.7",
96
96
  "@refinedev/medusa": "^5.0.0"
97
97
  },
98
98
  "nestjs-query": {
99
- "@svadmin/nestjs-query": "^0.12.6",
99
+ "@svadmin/nestjs-query": "^0.12.7",
100
100
  "@refinedev/nestjs-query": "^5.0.0"
101
101
  },
102
102
  "nestjsx-crud": {
103
- "@svadmin/nestjsx-crud": "^0.12.6",
103
+ "@svadmin/nestjsx-crud": "^0.12.7",
104
104
  "@refinedev/nestjsx-crud": "^6.0.1"
105
105
  },
106
106
  "pocketbase": {
107
- "@svadmin/pocketbase": "^0.13.3",
107
+ "@svadmin/pocketbase": "^0.13.4",
108
108
  "pocketbase": ">=0.28.0"
109
109
  },
110
110
  "sanity": {
111
- "@svadmin/sanity": "^0.11.6"
111
+ "@svadmin/sanity": "^0.11.7"
112
112
  },
113
113
  "strapi": {
114
- "@svadmin/strapi": "^0.12.6",
114
+ "@svadmin/strapi": "^0.12.7",
115
115
  "@refinedev/strapi-v4": "^7.0.1"
116
116
  }
117
117
  },