@ketvietlab/design-system 0.1.5 → 0.1.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/README.md +111 -11
- package/dist/catalogue/catalogue.css +41 -34
- package/dist/catalogue/index.d.ts.map +1 -1
- package/dist/catalogue/index.js +415 -56
- package/dist/catalogue/index.js.map +1 -1
- package/dist/catalogue/page-surfaces.d.ts.map +1 -1
- package/dist/catalogue/page-surfaces.js +8 -6
- package/dist/catalogue/page-surfaces.js.map +1 -1
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js +4 -0
- package/dist/contract/index.js.map +1 -1
- package/dist/foundations/tokens.css +2 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/layouts/flat.css +74 -0
- package/dist/layouts/grouped.css +126 -0
- package/dist/layouts/index.d.ts +3 -1
- package/dist/layouts/index.d.ts.map +1 -1
- package/dist/layouts/index.js +5 -2
- package/dist/layouts/index.js.map +1 -1
- package/dist/layouts/layouts.css +44 -7
- package/dist/layouts/shell.css +16 -2
- package/dist/layouts/shell.d.ts.map +1 -1
- package/dist/layouts/shell.js +1 -1
- package/dist/layouts/shell.js.map +1 -1
- package/dist/patterns/data-table.d.ts +50 -2
- package/dist/patterns/data-table.d.ts.map +1 -1
- package/dist/patterns/data-table.js +57 -3
- package/dist/patterns/data-table.js.map +1 -1
- package/dist/patterns/list-chrome.d.ts +80 -0
- package/dist/patterns/list-chrome.d.ts.map +1 -0
- package/dist/patterns/list-chrome.js +45 -0
- package/dist/patterns/list-chrome.js.map +1 -0
- package/dist/patterns/modal-sheet.d.ts +6 -1
- package/dist/patterns/modal-sheet.d.ts.map +1 -1
- package/dist/patterns/modal-sheet.js +5 -1
- package/dist/patterns/modal-sheet.js.map +1 -1
- package/dist/patterns/patterns.css +943 -131
- package/dist/patterns/record-page.d.ts +3 -2
- package/dist/patterns/record-page.d.ts.map +1 -1
- package/dist/patterns/record-page.js +2 -2
- package/dist/patterns/record-page.js.map +1 -1
- package/dist/primitives/actions.d.ts +6 -0
- package/dist/primitives/actions.d.ts.map +1 -1
- package/dist/primitives/actions.js +4 -2
- package/dist/primitives/actions.js.map +1 -1
- package/dist/primitives/field.d.ts +16 -3
- package/dist/primitives/field.d.ts.map +1 -1
- package/dist/primitives/field.js +18 -5
- package/dist/primitives/field.js.map +1 -1
- package/dist/primitives/navigation.css +1 -1
- package/dist/primitives/primitives.css +87 -6
- package/dist/primitives/progress.js +1 -1
- package/dist/primitives/progress.js.map +1 -1
- package/dist/styles.css +2 -0
- package/package.json +2 -2
package/dist/catalogue/index.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@ketvietlab/ketjs-view/jsx-runtime";
|
|
2
2
|
import { each, html } from '@ketvietlab/ketjs-view';
|
|
3
|
-
import { ActionGroup, Button, LinkButton } from '../primitives/actions.js';
|
|
3
|
+
import { ActionGroup, Button, IconButton, LinkButton } from '../primitives/actions.js';
|
|
4
4
|
import { Avatar, Badge, Code, CountBadge, Tag } from '../primitives/status.js';
|
|
5
5
|
import { EmptyState, LoadingState, Notice } from '../primitives/feedback.js';
|
|
6
6
|
import { Field } from '../primitives/field.js';
|
|
7
7
|
import { NavList, Tabs } from '../primitives/navigation.js';
|
|
8
8
|
import { Progress } from '../primitives/progress.js';
|
|
9
9
|
import { ContentCard, Disclosure, Grid, Inline, Metric, Section, Stack, Surface } from '../layouts/index.js';
|
|
10
|
-
import { AppShell
|
|
10
|
+
import { AppShell } from '../layouts/shell.js';
|
|
11
11
|
import { DataTable } from '../patterns/data-table.js';
|
|
12
|
+
import { ListChrome } from '../patterns/list-chrome.js';
|
|
12
13
|
import { BoardPage } from '../patterns/board-page.js';
|
|
13
14
|
import { DashboardPage } from '../patterns/dashboard-page.js';
|
|
14
15
|
import { ListPage } from '../patterns/list-page.js';
|
|
15
16
|
import { FormPage } from '../patterns/form-page.js';
|
|
17
|
+
import { RecordPage } from '../patterns/record-page.js';
|
|
18
|
+
import { WorkspacePage } from '../patterns/workspace-page.js';
|
|
16
19
|
import { ModalSheet } from '../patterns/modal-sheet.js';
|
|
17
20
|
import { Pipeline } from '../patterns/pipeline.js';
|
|
18
21
|
import { RecordForm } from '../patterns/record-form.js';
|
|
@@ -23,6 +26,83 @@ const orders = [
|
|
|
23
26
|
{ id: 'SO-1039', customer: 'Nguyễn Minh Châu', total: '2.150.000 ₫', state: 'Blocked' },
|
|
24
27
|
];
|
|
25
28
|
const toneOf = (state) => state === 'Ready' ? 'positive' : state === 'Review' ? 'warning' : 'danger';
|
|
29
|
+
const demoNavItems = (active) => [
|
|
30
|
+
{ label: 'Collection', href: '#app-shell', leading: '≡', active: active === 'collection', count: 148 },
|
|
31
|
+
{ label: 'Record', href: '#record-page', leading: '◇', active: active === 'record' },
|
|
32
|
+
{ label: 'Flow', href: '#workspace-flow', leading: '▦', active: active === 'flow', count: 7 },
|
|
33
|
+
{ label: 'Canvas', href: '#workspace-canvas', leading: '□', active: active === 'canvas' },
|
|
34
|
+
];
|
|
35
|
+
const DemoSidebar = (props) => (_jsxs("div", { "data-ui": "shell-demo-sidebar", children: [_jsx("strong", { children: "K\u00E9tSuite" }), _jsx(NavList, { label: "Workspace layouts", items: demoNavItems(props.active) })] }));
|
|
36
|
+
const DemoRail = (props) => (_jsxs("div", { "data-ui": "shell-demo-rail", children: [_jsx("p", { "data-ui": "catalogue-kicker", children: "Context" }), _jsx("strong", { children: props.title }), _jsx("p", { children: props.detail }), props.progress !== undefined && _jsx(Progress, { label: props.title, value: props.progress }), props.items !== undefined && _jsx(Stack, { gap: "compact", items: props.items })] }));
|
|
37
|
+
const DemoShell = (props) => (_jsx(AppShell, { mode: "embedded", sidebar: _jsx(DemoSidebar, { active: props.active }), main: props.main, rightRail: props.railTitle !== undefined ? (_jsx(DemoRail, { title: props.railTitle, detail: props.railDetail ?? '', progress: props.railProgress, items: props.railItems })) : undefined }));
|
|
38
|
+
const OrdersTable = (props = {}) => (_jsx(DataTable, { title: props.title, rows: props.grouped ? [] : orders, id: (row) => row.id, rowHref: (row) => `#${row.id}`, responsive: "stack", selection: { selectedIds: ['SO-1042'] }, groups: props.grouped
|
|
39
|
+
? [
|
|
40
|
+
{
|
|
41
|
+
id: 'ready',
|
|
42
|
+
label: 'Ready to invoice',
|
|
43
|
+
count: 2,
|
|
44
|
+
rows: orders.slice(0, 2),
|
|
45
|
+
pager: { label: '2 shown in Ready', nextHref: '#data-table' },
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'blocked',
|
|
49
|
+
label: 'Needs decision',
|
|
50
|
+
count: 1,
|
|
51
|
+
rows: orders.slice(2),
|
|
52
|
+
},
|
|
53
|
+
]
|
|
54
|
+
: undefined, columns: [
|
|
55
|
+
{
|
|
56
|
+
key: 'id',
|
|
57
|
+
label: 'Order',
|
|
58
|
+
cell: (row) => row.id,
|
|
59
|
+
priority: 'primary',
|
|
60
|
+
kind: 'identifier',
|
|
61
|
+
sort: { href: '#data-table', direction: 'descending' },
|
|
62
|
+
},
|
|
63
|
+
{ key: 'customer', label: 'Customer', cell: (row) => row.customer },
|
|
64
|
+
{ key: 'total', label: 'Total', cell: (row) => row.total, align: 'end', kind: 'currency' },
|
|
65
|
+
{
|
|
66
|
+
key: 'state',
|
|
67
|
+
label: 'State',
|
|
68
|
+
cell: (row) => _jsx(Badge, { label: row.state, tone: toneOf(row.state) }),
|
|
69
|
+
kind: 'status',
|
|
70
|
+
},
|
|
71
|
+
] }));
|
|
72
|
+
const ListDemoChrome = (props) => (_jsx(ListChrome, { search: {
|
|
73
|
+
id: `${props.id}-query`,
|
|
74
|
+
action: `#${props.id}`,
|
|
75
|
+
value: props.id === 'list-page' ? 'Mùa Hạ' : '',
|
|
76
|
+
placeholder: 'Search records',
|
|
77
|
+
hidden: { view: 'table' },
|
|
78
|
+
}, facets: [
|
|
79
|
+
{ id: 'all', label: 'All', href: `#${props.id}`, active: true, count: 148 },
|
|
80
|
+
{ id: 'ready', label: 'Ready', href: `#${props.id}`, count: 91 },
|
|
81
|
+
{ id: 'review', label: 'Review', href: `#${props.id}`, count: 7 },
|
|
82
|
+
], views: [
|
|
83
|
+
{ id: 'table', label: 'Table', href: `#${props.id}`, active: true },
|
|
84
|
+
{ id: 'kanban', label: 'Kanban', href: `#${props.id}` },
|
|
85
|
+
], sort: {
|
|
86
|
+
id: `${props.id}-sort`,
|
|
87
|
+
action: `#${props.id}`,
|
|
88
|
+
choices: [
|
|
89
|
+
{ value: 'date-desc', label: 'Newest first', selected: true },
|
|
90
|
+
{ value: 'total-desc', label: 'Largest total' },
|
|
91
|
+
],
|
|
92
|
+
}, bulk: {
|
|
93
|
+
selectedCount: props.selected ?? 1,
|
|
94
|
+
summary: `${props.selected ?? 1} selected`,
|
|
95
|
+
clearHref: `#${props.id}`,
|
|
96
|
+
actions: [{ id: 'approve', label: 'Approve', name: 'intent', value: 'approve', variant: 'primary' }],
|
|
97
|
+
}, pager: {
|
|
98
|
+
summary: 'Showing 1-3 of 148',
|
|
99
|
+
previousHref: null,
|
|
100
|
+
nextHref: `#${props.id}`,
|
|
101
|
+
pages: [
|
|
102
|
+
{ label: '1', href: `#${props.id}`, active: true },
|
|
103
|
+
{ label: '2', href: `#${props.id}` },
|
|
104
|
+
],
|
|
105
|
+
} }));
|
|
26
106
|
export const componentGroups = [
|
|
27
107
|
{
|
|
28
108
|
id: 'actions',
|
|
@@ -40,6 +120,8 @@ export const componentGroups = [
|
|
|
40
120
|
_jsx(Button, { label: "Terminate", variant: "destructive" }),
|
|
41
121
|
_jsx(Button, { label: "Saving", loading: true }),
|
|
42
122
|
_jsx(Button, { label: "Unavailable", disabled: true }),
|
|
123
|
+
_jsx(LinkButton, { label: "Opening record", href: "#record-page", loading: true }),
|
|
124
|
+
_jsx(IconButton, { label: "Toggle theme", icon: "\u263E" }),
|
|
43
125
|
] })),
|
|
44
126
|
},
|
|
45
127
|
{
|
|
@@ -50,6 +132,8 @@ export const componentGroups = [
|
|
|
50
132
|
_jsx(Button, { label: "Compact", size: "compact" }),
|
|
51
133
|
_jsx(Button, { label: "Default" }),
|
|
52
134
|
_jsx(Button, { label: "Prominent decision", size: "prominent", variant: "primary" }),
|
|
135
|
+
_jsx(IconButton, { label: "Compact theme toggle", icon: "\u263E", size: "compact" }),
|
|
136
|
+
_jsx(IconButton, { label: "Prominent theme toggle", icon: "\u263E", size: "prominent" }),
|
|
53
137
|
_jsx(LinkButton, { label: "Open record", href: "#data-table", variant: "tertiary", leading: "\u2197" }),
|
|
54
138
|
] })),
|
|
55
139
|
},
|
|
@@ -122,16 +206,115 @@ export const componentGroups = [
|
|
|
122
206
|
id: 'field',
|
|
123
207
|
name: 'Field',
|
|
124
208
|
description: 'Text, select, checkbox and error states without application-owned markup.',
|
|
125
|
-
render: () => (_jsx(Grid, { columns: 2, items: [
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
209
|
+
render: () => (_jsx(Surface, { body: _jsx(Grid, { columns: 2, items: [
|
|
210
|
+
_jsx(Field, { id: "company-name", name: "company", label: "Company name", value: "K\u00E9t Vi\u1EC7t", required: true }),
|
|
211
|
+
_jsx(Field, { id: "deployment", name: "deployment", label: "Deployment", type: "select", value: "commerce", options: [
|
|
212
|
+
{ value: 'commerce', label: 'Commerce' },
|
|
213
|
+
{ value: 'cosmetic', label: 'Cosmetic' },
|
|
214
|
+
{ value: 'hospitality', label: 'Hospitality' },
|
|
215
|
+
], help: "A tenant belongs to exactly one deployment." }),
|
|
216
|
+
_jsx(Field, { id: "database-key", name: "databaseKey", label: "Database key", value: "Invalid Key", error: "Use lowercase letters, numbers and hyphens only." }),
|
|
217
|
+
_jsx(Field, { id: "active", name: "active", label: "Active for new orders", type: "checkbox", value: true, help: "New orders can be assigned to this company." }),
|
|
218
|
+
] }) })),
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
id: 'field-states',
|
|
224
|
+
name: 'Field states',
|
|
225
|
+
description: 'Native input types, validation, read-only values and nested groups.',
|
|
226
|
+
examples: [
|
|
227
|
+
{
|
|
228
|
+
id: 'advanced-fields',
|
|
229
|
+
name: 'Operational fields',
|
|
230
|
+
description: 'Numeric constraints, dates, options and nested validation use the same field contract.',
|
|
231
|
+
render: () => (_jsx(Surface, { title: "Settings", body: _jsx(RecordForm, { action: "#advanced-fields", submitLabel: "Save settings", fields: [
|
|
232
|
+
{
|
|
233
|
+
id: 'settings-reference',
|
|
234
|
+
name: 'reference',
|
|
235
|
+
label: 'Reference',
|
|
236
|
+
value: 'CUS-0042',
|
|
237
|
+
readOnly: true,
|
|
238
|
+
help: 'Assigned when the account was created.',
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
id: 'settings-locked',
|
|
242
|
+
name: 'locked',
|
|
243
|
+
label: 'External reference',
|
|
244
|
+
value: 'Pending verification',
|
|
245
|
+
disabled: true,
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
id: 'settings-limit',
|
|
249
|
+
name: 'limit',
|
|
250
|
+
label: 'Credit limit',
|
|
251
|
+
type: 'decimal',
|
|
252
|
+
value: 80000000,
|
|
253
|
+
min: 0,
|
|
254
|
+
step: '1000',
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
id: 'settings-date',
|
|
258
|
+
name: 'date',
|
|
259
|
+
label: 'Effective date',
|
|
260
|
+
type: 'date',
|
|
261
|
+
value: '2026-09-08',
|
|
262
|
+
},
|
|
263
|
+
{ id: 'settings-time', name: 'time', label: 'Delivery time', type: 'time', value: '09:00' },
|
|
264
|
+
{
|
|
265
|
+
id: 'settings-color',
|
|
266
|
+
name: 'color',
|
|
267
|
+
label: 'Calendar colour',
|
|
268
|
+
type: 'color',
|
|
269
|
+
value: '#5167c4',
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
id: 'settings-billing',
|
|
273
|
+
name: 'billing',
|
|
274
|
+
label: 'Billing frequency',
|
|
275
|
+
type: 'radio',
|
|
276
|
+
value: 'monthly',
|
|
277
|
+
required: true,
|
|
278
|
+
options: [
|
|
279
|
+
{ value: 'monthly', label: 'Monthly' },
|
|
280
|
+
{ value: 'quarterly', label: 'Quarterly' },
|
|
281
|
+
],
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
id: 'settings-channels',
|
|
285
|
+
name: 'channels',
|
|
286
|
+
label: 'Notifications',
|
|
287
|
+
type: 'checkbox-group',
|
|
288
|
+
options: [
|
|
289
|
+
{ value: 'email', label: 'Email', checked: true },
|
|
290
|
+
{ value: 'sms', label: 'SMS' },
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
id: 'settings-address',
|
|
295
|
+
name: 'address',
|
|
296
|
+
label: 'Delivery address',
|
|
297
|
+
error: 'Check the delivery address.',
|
|
298
|
+
fields: [
|
|
299
|
+
{
|
|
300
|
+
id: 'settings-street',
|
|
301
|
+
name: 'street',
|
|
302
|
+
label: 'Street',
|
|
303
|
+
value: '',
|
|
304
|
+
required: true,
|
|
305
|
+
error: 'Enter a street address.',
|
|
306
|
+
span: 'full',
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
id: 'settings-city',
|
|
310
|
+
name: 'city',
|
|
311
|
+
label: 'City',
|
|
312
|
+
value: 'Hồ Chí Minh',
|
|
313
|
+
autocomplete: 'address-level2',
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
},
|
|
317
|
+
] }) })),
|
|
135
318
|
},
|
|
136
319
|
],
|
|
137
320
|
},
|
|
@@ -175,27 +358,111 @@ export const componentGroups = [
|
|
|
175
358
|
{
|
|
176
359
|
id: 'application-structure',
|
|
177
360
|
name: 'Application structure',
|
|
178
|
-
description: '
|
|
361
|
+
description: 'Four practical layouts inside the same shell: collection, record, flow workspace and canvas workspace.',
|
|
179
362
|
examples: [
|
|
180
363
|
{
|
|
181
364
|
id: 'app-shell',
|
|
182
|
-
name: '
|
|
183
|
-
description: '
|
|
184
|
-
render: () => (_jsx(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
] })] }), main: _jsx(Page, { title: "Operations", description: "Today across all active tenants", actions: _jsx(Button, { label: "Create order", variant: "primary" }), body: _jsx(Grid, { columns: 3, items: [
|
|
189
|
-
_jsx(Metric, { label: "Orders", value: "148", detail: "+12 today", tone: "positive" }),
|
|
190
|
-
_jsx(Metric, { label: "Review queue", value: "7", detail: "Oldest 42 min", tone: "warning" }),
|
|
191
|
-
_jsx(Metric, { label: "Blocked", value: "2", detail: "Credential required", tone: "danger" }),
|
|
192
|
-
] }) }), rightRail: _jsxs("div", { "data-ui": "shell-demo-rail", children: [_jsx("p", { "data-ui": "catalogue-kicker", children: "Context" }), _jsx("strong", { children: "Today" }), _jsx("p", { children: "Three items need an operational decision." }), _jsx(Progress, { label: "Daily target", value: 72 })] }) })),
|
|
365
|
+
name: 'Collection shell',
|
|
366
|
+
description: 'A full list workspace with sidebar navigation, URL-owned list chrome, selectable rows and a context rail.',
|
|
367
|
+
render: () => (_jsx(DemoShell, { active: "collection", main: _jsx(ListPage, { variant: "operational", context: "Sales / Sales orders", title: "Sales orders", description: "Review demand, fulfillment and payment state from one operational list.", actions: _jsx(Button, { label: "Create order", variant: "primary" }), controls: _jsx(ListDemoChrome, { id: "app-shell" }), body: _jsx(OrdersTable, { title: "Order list" }) }), railTitle: "List health", railDetail: "Seven orders need a human decision before invoicing.", railProgress: 72, railItems: [
|
|
368
|
+
_jsx(Badge, { label: "91 ready", tone: "positive" }),
|
|
369
|
+
_jsx(Badge, { label: "7 review", tone: "warning" }),
|
|
370
|
+
] })),
|
|
193
371
|
},
|
|
194
372
|
{
|
|
195
373
|
id: 'record-page',
|
|
196
|
-
name: 'Record
|
|
197
|
-
description: '
|
|
198
|
-
render: () => (_jsx(
|
|
374
|
+
name: 'Record shell',
|
|
375
|
+
description: 'A durable subject with record identity, tabs, form content and a right-hand facts rail.',
|
|
376
|
+
render: () => (_jsx(DemoShell, { active: "record", main: _jsx(RecordPage, { variant: "operational", context: "Customers / M\u00F9a H\u1EA1 Riverside", title: "M\u00F9a H\u1EA1 Riverside", description: "Customer \u00B7 CUS-0042", status: _jsx(Badge, { label: "Active", tone: "positive" }), actions: _jsx(ActionGroup, { actions: [
|
|
377
|
+
_jsx(Button, { label: "Save", variant: "primary", size: "compact" }),
|
|
378
|
+
_jsx(Button, { label: "Archive", variant: "tertiary", size: "compact" }),
|
|
379
|
+
] }), navigation: _jsx(Tabs, { label: "Customer record", items: [
|
|
380
|
+
{ id: 'details', label: 'Details', href: '#record-page', active: true },
|
|
381
|
+
{ id: 'orders', label: 'Orders', href: '#record-page', count: 6 },
|
|
382
|
+
{ id: 'activity', label: 'Activity', href: '#record-page', count: 8 },
|
|
383
|
+
] }), body: _jsx(Stack, { items: [
|
|
384
|
+
_jsx(Surface, { title: "Main information", body: _jsx(RecordForm, { action: "#record-page", fields: [
|
|
385
|
+
{
|
|
386
|
+
id: 'layout-partner-name',
|
|
387
|
+
span: 'full',
|
|
388
|
+
name: 'name',
|
|
389
|
+
label: 'Name',
|
|
390
|
+
value: 'Mùa Hạ Riverside',
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
id: 'layout-partner-email',
|
|
394
|
+
span: 'full',
|
|
395
|
+
name: 'email',
|
|
396
|
+
label: 'Email',
|
|
397
|
+
type: 'email',
|
|
398
|
+
value: 'hello@muaha.example',
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
id: 'layout-partner-tags',
|
|
402
|
+
name: 'tags',
|
|
403
|
+
label: 'Tags',
|
|
404
|
+
type: 'checkbox-group',
|
|
405
|
+
span: 'full',
|
|
406
|
+
options: [
|
|
407
|
+
{ value: 'vip', label: 'VIP', checked: true },
|
|
408
|
+
{ value: 'hospitality', label: 'Hospitality', checked: true },
|
|
409
|
+
],
|
|
410
|
+
},
|
|
411
|
+
], submitLabel: "Save" }) }),
|
|
412
|
+
_jsx(OrdersTable, { title: "Recent orders" }),
|
|
413
|
+
] }), aside: _jsx(Stack, { items: [
|
|
414
|
+
_jsx(Metric, { label: "Credit limit", value: "80m \u20AB", detail: "42m \u20AB available" }),
|
|
415
|
+
_jsx(Progress, { label: "Onboarding complete", value: 84, tone: "positive" }),
|
|
416
|
+
] }), asideLabel: "Customer context" }) })),
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
id: 'workspace-flow',
|
|
420
|
+
name: 'Flow workspace',
|
|
421
|
+
description: 'A vertical operations overview where metrics, process state and exception lists sit on one grey canvas.',
|
|
422
|
+
render: () => (_jsx(DemoShell, { active: "flow", main: _jsx(WorkspacePage, { variant: "operational", layout: "flow", context: "Sales / Overview", title: "Revenue operations", description: "Follow confirmed demand, open work and handoffs across the team.", actions: _jsx(Button, { label: "Create quotation", variant: "primary" }), controls: _jsx(ActionGroup, { label: "Flow controls", actions: [
|
|
423
|
+
_jsx(LinkButton, { label: "Today", href: "#workspace-flow", size: "compact" }),
|
|
424
|
+
_jsx(LinkButton, { label: "This week", href: "#workspace-flow", size: "compact", variant: "tertiary" }),
|
|
425
|
+
] }), body: _jsx(Stack, { gap: "loose", items: [
|
|
426
|
+
_jsx(Grid, { columns: 4, items: [
|
|
427
|
+
_jsx(Metric, { label: "Quotations", value: 24, detail: "5 new today" }),
|
|
428
|
+
_jsx(Metric, { label: "Sent", value: 9, detail: "Awaiting reply", tone: "info" }),
|
|
429
|
+
_jsx(Metric, { label: "Confirmed", value: 18, detail: "82,000,000 \u20AB", tone: "positive" }),
|
|
430
|
+
_jsx(Metric, { label: "Blocked", value: 2, detail: "Needs attention", tone: "danger" }),
|
|
431
|
+
] }),
|
|
432
|
+
_jsx(Surface, { title: "Sales flow", body: _jsx(Pipeline, { label: "Sales flow", steps: [
|
|
433
|
+
{ id: 'draft', label: 'Quotation', value: 24 },
|
|
434
|
+
{ id: 'sent', label: 'Sent', value: 9, tone: 'info' },
|
|
435
|
+
{ id: 'confirmed', label: 'Confirmed', value: 18, tone: 'positive' },
|
|
436
|
+
{ id: 'invoice', label: 'To invoice', value: 6, tone: 'warning' },
|
|
437
|
+
] }) }),
|
|
438
|
+
_jsx(OrdersTable, { grouped: true, title: "Exceptions" }),
|
|
439
|
+
] }) }), railTitle: "Daily target", railDetail: "56 of 82 confirmed orders have been invoiced today.", railProgress: 68 })),
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
id: 'workspace-canvas',
|
|
443
|
+
name: 'Canvas workspace',
|
|
444
|
+
description: 'A horizontal board-style surface where the main content can scroll without changing the shell.',
|
|
445
|
+
render: () => (_jsx(DemoShell, { active: "canvas", main: _jsx(WorkspacePage, { variant: "operational", layout: "canvas", context: "CRM / Pipeline", title: "Opportunities board", description: "Move active opportunities through a spatial workflow.", actions: _jsx(Button, { label: "Create opportunity", variant: "primary" }), controls: _jsx(Inline, { items: [
|
|
446
|
+
_jsx(LinkButton, { label: "My pipeline", href: "#workspace-canvas", size: "compact" }),
|
|
447
|
+
_jsx(LinkButton, { label: "All teams", href: "#workspace-canvas", size: "compact", variant: "tertiary" }),
|
|
448
|
+
_jsx(Tag, { label: "High value", removeHref: "#workspace-canvas", removeLabel: "Remove filter" }),
|
|
449
|
+
] }), body: _jsx(Grid, { columns: 3, items: [
|
|
450
|
+
_jsx(Section, { title: "Qualified", body: _jsx(Stack, { gap: "compact", items: [
|
|
451
|
+
_jsx(ContentCard, { title: "M\u00F9a H\u1EA1 Riverside", meta: "42,000,000 \u20AB", body: "Needs proposal" }),
|
|
452
|
+
_jsx(ContentCard, { title: "\u00C1nh D\u01B0\u01A1ng Group", meta: "18,000,000 \u20AB", body: "Demo booked" }),
|
|
453
|
+
] }) }),
|
|
454
|
+
_jsx(Section, { title: "Proposal", body: _jsx(Stack, { gap: "compact", items: [
|
|
455
|
+
_jsx(ContentCard, { title: "Lotus Hotels", meta: "64,000,000 \u20AB", body: "Awaiting CFO" }),
|
|
456
|
+
_jsx(ContentCard, { title: "B\u00ECnh Minh Retail", meta: "30,000,000 \u20AB", body: "Legal review" }),
|
|
457
|
+
] }) }),
|
|
458
|
+
_jsx(Section, { title: "Negotiation", body: _jsx(Stack, { gap: "compact", items: [
|
|
459
|
+
_jsx(ContentCard, { title: "S\u00F4ng Xanh", meta: "52,000,000 \u20AB", body: "Discount requested" }),
|
|
460
|
+
_jsx(ContentCard, { title: "Urban Stay", meta: "40,000,000 \u20AB", body: "Close this week" }),
|
|
461
|
+
] }) }),
|
|
462
|
+
] }) }), railTitle: "Pipeline risk", railDetail: "Three opportunities need owner follow-up before Friday.", railItems: [
|
|
463
|
+
_jsx(Badge, { label: "2 overdue", tone: "danger" }),
|
|
464
|
+
_jsx(Badge, { label: "6 due this week", tone: "warning" }),
|
|
465
|
+
] })),
|
|
199
466
|
},
|
|
200
467
|
],
|
|
201
468
|
},
|
|
@@ -239,21 +506,91 @@ export const componentGroups = [
|
|
|
239
506
|
name: 'Patterns',
|
|
240
507
|
description: 'Generic workflows assembled from the same primitives.',
|
|
241
508
|
examples: [
|
|
509
|
+
{
|
|
510
|
+
id: 'list-chrome',
|
|
511
|
+
name: 'List chrome',
|
|
512
|
+
description: 'Search, filters, view switch, bulk state and paging for URL-driven collection screens.',
|
|
513
|
+
render: () => (_jsx(ListChrome, { search: {
|
|
514
|
+
id: 'customer-query',
|
|
515
|
+
action: '#list-chrome',
|
|
516
|
+
placeholder: 'Search customers',
|
|
517
|
+
}, facets: [
|
|
518
|
+
{ id: 'active', label: 'Active', href: '#list-chrome', active: true, count: 42 },
|
|
519
|
+
{ id: 'draft', label: 'Draft', href: '#list-chrome', count: 6 },
|
|
520
|
+
], views: [
|
|
521
|
+
{ id: 'table', label: 'Table', href: '#list-chrome', active: true },
|
|
522
|
+
{ id: 'cards', label: 'Cards', href: '#list-chrome' },
|
|
523
|
+
], sort: {
|
|
524
|
+
id: 'customer-sort',
|
|
525
|
+
action: '#list-chrome',
|
|
526
|
+
choices: [
|
|
527
|
+
{ value: 'updated-desc', label: 'Recently updated', selected: true },
|
|
528
|
+
{ value: 'name-asc', label: 'Name A-Z' },
|
|
529
|
+
],
|
|
530
|
+
}, status: "48 customers", actions: _jsx(Button, { label: "Create", variant: "primary", size: "compact" }), bulk: {
|
|
531
|
+
selectedCount: 2,
|
|
532
|
+
summary: '2 customers selected',
|
|
533
|
+
clearHref: '#list-chrome',
|
|
534
|
+
actions: [{ id: 'archive', label: 'Archive', name: 'intent', value: 'archive' }],
|
|
535
|
+
}, pager: {
|
|
536
|
+
summary: 'Showing 1-25 of 48',
|
|
537
|
+
nextHref: '#list-chrome',
|
|
538
|
+
pages: [
|
|
539
|
+
{ label: '1', href: '#list-chrome', active: true },
|
|
540
|
+
{ label: '2', href: '#list-chrome' },
|
|
541
|
+
],
|
|
542
|
+
} })),
|
|
543
|
+
},
|
|
242
544
|
{
|
|
243
545
|
id: 'list-page',
|
|
244
546
|
name: 'List page',
|
|
245
547
|
description: 'The canonical collection hierarchy: identity, actions, URL-driven controls, result context and records.',
|
|
246
|
-
render: () => (_jsx(ListPage, { variant: "operational", context: "Sales / Sales orders", eyebrow: "Sales", title: "Sales orders", description: "Review demand, fulfillment and payment state from one operational list.", actions: _jsx(Button, { label: "Create order", variant: "primary" }), controls: _jsx(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
548
|
+
render: () => (_jsx(ListPage, { variant: "operational", context: "Sales / Sales orders", eyebrow: "Sales", title: "Sales orders", description: "Review demand, fulfillment and payment state from one operational list.", actions: _jsx(Button, { label: "Create order", variant: "primary" }), controls: _jsx(ListChrome, { search: {
|
|
549
|
+
id: 'orders-query',
|
|
550
|
+
action: '#list-page',
|
|
551
|
+
value: 'Mùa Hạ',
|
|
552
|
+
placeholder: 'Search orders',
|
|
553
|
+
hidden: { view: 'all' },
|
|
554
|
+
}, facets: [
|
|
555
|
+
{ id: 'all', label: 'All', href: '#list-page', active: true, count: 148 },
|
|
556
|
+
{ id: 'ready', label: 'Ready', href: '#list-page', count: 91 },
|
|
557
|
+
{ id: 'review', label: 'Review', href: '#list-page', count: 7 },
|
|
558
|
+
], views: [
|
|
559
|
+
{ id: 'table', label: 'Table', href: '#list-page', active: true },
|
|
560
|
+
{ id: 'kanban', label: 'Kanban', href: '#list-page' },
|
|
561
|
+
], sort: {
|
|
562
|
+
id: 'orders-sort',
|
|
563
|
+
action: '#list-page',
|
|
564
|
+
choices: [
|
|
565
|
+
{ value: 'date-desc', label: 'Newest first', selected: true },
|
|
566
|
+
{ value: 'total-desc', label: 'Largest total' },
|
|
567
|
+
{ value: 'customer-asc', label: 'Customer A-Z' },
|
|
568
|
+
],
|
|
569
|
+
}, bulk: {
|
|
570
|
+
selectedCount: 1,
|
|
571
|
+
summary: '1 order selected',
|
|
572
|
+
clearHref: '#list-page',
|
|
573
|
+
actions: [
|
|
574
|
+
{ id: 'approve', label: 'Approve', name: 'intent', value: 'approve', variant: 'primary' },
|
|
575
|
+
{ id: 'export', label: 'Export', name: 'intent', value: 'export' },
|
|
576
|
+
],
|
|
577
|
+
}, pager: {
|
|
578
|
+
summary: 'Showing 1-3 of 148',
|
|
579
|
+
previousHref: null,
|
|
580
|
+
nextHref: '#list-page',
|
|
581
|
+
pages: [
|
|
582
|
+
{ label: '1', href: '#list-page', active: true },
|
|
583
|
+
{ label: '2', href: '#list-page' },
|
|
584
|
+
{ label: '3', href: '#list-page' },
|
|
585
|
+
],
|
|
586
|
+
} }), body: _jsx(DataTable, { title: "Order list", rows: orders, id: (row) => row.id, rowHref: (row) => `#${row.id}`, responsive: "stack", selection: { selectedIds: ['SO-1042'] }, columns: [
|
|
251
587
|
{
|
|
252
588
|
key: 'id',
|
|
253
589
|
label: 'Order',
|
|
254
590
|
cell: (row) => row.id,
|
|
255
591
|
priority: 'primary',
|
|
256
592
|
kind: 'identifier',
|
|
593
|
+
sort: { href: '#list-page', direction: 'descending' },
|
|
257
594
|
},
|
|
258
595
|
{ key: 'customer', label: 'Customer', cell: (row) => row.customer },
|
|
259
596
|
{ key: 'total', label: 'Total', cell: (row) => row.total, align: 'end', kind: 'currency' },
|
|
@@ -276,7 +613,7 @@ export const componentGroups = [
|
|
|
276
613
|
_jsx(Metric, { label: "Confirmed", value: 18, detail: "82,000,000 \u20AB", tone: "positive" }),
|
|
277
614
|
_jsx(Metric, { label: "To invoice", value: 6, detail: "Needs attention", tone: "warning" }),
|
|
278
615
|
] }),
|
|
279
|
-
_jsx(
|
|
616
|
+
_jsx(Surface, { title: "Sales flow", body: _jsx(Pipeline, { label: "Sales flow", steps: [
|
|
280
617
|
{ id: 'draft', label: 'Quotation', value: 24 },
|
|
281
618
|
{ id: 'sent', label: 'Sent', value: 9, tone: 'info' },
|
|
282
619
|
{ id: 'confirmed', label: 'Confirmed', value: 18, tone: 'positive' },
|
|
@@ -312,8 +649,30 @@ export const componentGroups = [
|
|
|
312
649
|
id: 'data-table',
|
|
313
650
|
name: 'Data table',
|
|
314
651
|
description: 'Columns are data; rows remain semantic and horizontally contained.',
|
|
315
|
-
render: () => (_jsx(DataTable, {
|
|
316
|
-
{
|
|
652
|
+
render: () => (_jsx(DataTable, { title: "Recent sales orders", actions: _jsx(LinkButton, { label: "View all orders", href: "#app-shell", variant: "tertiary" }), rows: [], id: (row) => row.id, rowHref: (row) => `#${row.id}`, responsive: "stack", gutter: "compact", selection: { selectedIds: ['SO-1042'] }, groups: [
|
|
653
|
+
{
|
|
654
|
+
id: 'ready',
|
|
655
|
+
label: 'Ready to invoice',
|
|
656
|
+
count: 2,
|
|
657
|
+
href: '#data-table',
|
|
658
|
+
rows: orders.slice(0, 2),
|
|
659
|
+
pager: { label: '2 shown in Ready', nextHref: '#data-table' },
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
id: 'blocked',
|
|
663
|
+
label: 'Needs decision',
|
|
664
|
+
count: 1,
|
|
665
|
+
rows: orders.slice(2),
|
|
666
|
+
},
|
|
667
|
+
], columns: [
|
|
668
|
+
{
|
|
669
|
+
key: 'id',
|
|
670
|
+
label: 'Order',
|
|
671
|
+
cell: (row) => row.id,
|
|
672
|
+
priority: 'primary',
|
|
673
|
+
kind: 'identifier',
|
|
674
|
+
sort: { href: '#data-table', direction: 'descending' },
|
|
675
|
+
},
|
|
317
676
|
{ key: 'customer', label: 'Customer', cell: (row) => row.customer },
|
|
318
677
|
{ key: 'total', label: 'Total', cell: (row) => row.total, align: 'end', kind: 'currency' },
|
|
319
678
|
{
|
|
@@ -328,30 +687,30 @@ export const componentGroups = [
|
|
|
328
687
|
id: 'form-page',
|
|
329
688
|
name: 'Form page',
|
|
330
689
|
description: 'The canonical form hierarchy: record identity and decision first, a stable form column, then durable context.',
|
|
331
|
-
render: () => (_jsx(FormPage, { variant: "operational", context: "Customers / M\u00F9a H\u1EA1 Riverside", title: "M\u00F9a H\u1EA1 Riverside", description: "Customer \u00B7 CUS-0042", status: _jsx(Badge, { label: "Active", tone: "positive" }), actions: _jsx(Button, { label: "Save partner", variant: "primary" }), body: _jsx(
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
690
|
+
render: () => (_jsx(FormPage, { variant: "operational", context: "Customers / M\u00F9a H\u1EA1 Riverside", title: "M\u00F9a H\u1EA1 Riverside", description: "Customer \u00B7 CUS-0042", status: _jsx(Badge, { label: "Active", tone: "positive" }), actions: _jsx(Button, { label: "Save partner", variant: "primary" }), body: _jsx(Surface, { title: "Main information", body: _jsx(RecordForm, { action: "#form-page", fields: [
|
|
691
|
+
{ id: 'partner-name', name: 'name', label: 'Name', value: 'Mùa Hạ Riverside' },
|
|
692
|
+
{ id: 'partner-ref', name: 'ref', label: 'Reference', value: 'CUS-0042' },
|
|
693
|
+
{
|
|
694
|
+
id: 'partner-email',
|
|
695
|
+
name: 'email',
|
|
696
|
+
label: 'Email',
|
|
697
|
+
type: 'email',
|
|
698
|
+
value: 'hello@muaha.example',
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
id: 'partner-phone',
|
|
702
|
+
name: 'phone',
|
|
703
|
+
label: 'Phone',
|
|
704
|
+
type: 'tel',
|
|
705
|
+
value: '+84 28 3822 0042',
|
|
706
|
+
},
|
|
707
|
+
], submitLabel: "Save partner" }) }), aside: _jsx(Section, { title: "Record context", body: _jsx(Stack, { gap: "compact", items: ['Customer since 2023', '6 delivery addresses'] }) }), asideLabel: "Partner context" })),
|
|
349
708
|
},
|
|
350
709
|
{
|
|
351
710
|
id: 'record-form',
|
|
352
711
|
name: 'Record form',
|
|
353
712
|
description: 'Application supplies translated labels and values, not form markup.',
|
|
354
|
-
render: () => (_jsx(Surface, { body: _jsx(RecordForm, { action: "#record-form", fields: [
|
|
713
|
+
render: () => (_jsx(Surface, { title: "Main information", body: _jsx(RecordForm, { action: "#record-form", fields: [
|
|
355
714
|
{ id: 'record-name', name: 'name', label: 'Display name', value: 'Mùa Hạ Riverside' },
|
|
356
715
|
{
|
|
357
716
|
id: 'record-status',
|
|
@@ -416,6 +775,6 @@ export const CataloguePage = (props = {}) => {
|
|
|
416
775
|
const theme = props.theme ?? 'system';
|
|
417
776
|
const density = props.density ?? 'default';
|
|
418
777
|
const count = componentGroups.reduce((total, group) => total + group.examples.length, 0);
|
|
419
|
-
return (_jsxs("main", { "data-kv-design-system": true, "data-ui": "catalogue", "data-theme": theme === 'system' ? null : theme, "data-density": density, children: [_jsxs("aside", { "data-ui": "catalogue-rail", children: [_jsxs("a", { "data-ui": "catalogue-brand", href: "#top", children: [_jsx("span", { "aria-hidden": "true", children: "K" }), _jsx("strong", { children: "K\u00E9t Vi\u1EC7t" })] }), _jsx("p", { "data-ui": "catalogue-kicker", children: "Design system \u00B7 0.1.
|
|
778
|
+
return (_jsxs("main", { "data-kv-design-system": true, "data-ui": "catalogue", "data-theme": theme === 'system' ? null : theme, "data-density": density, children: [_jsxs("aside", { "data-ui": "catalogue-rail", children: [_jsxs("a", { "data-ui": "catalogue-brand", href: "#top", children: [_jsx("span", { "aria-hidden": "true", children: "K" }), _jsx("strong", { children: "K\u00E9t Vi\u1EC7t" })] }), _jsx("p", { "data-ui": "catalogue-kicker", children: "Design system \u00B7 0.1.7" }), _jsx("nav", { "data-ui": "catalogue-nav", "aria-label": "Component groups", children: each(componentGroups, (group) => group.id, (group) => (_jsxs("a", { "data-ui": "catalogue-nav-group", href: `#${group.id}`, children: [_jsx("span", { children: group.name }), _jsx("span", { "data-ui": "catalogue-nav-count", children: String(group.examples.length) })] }))) })] }), _jsxs("div", { "data-ui": "catalogue-main", id: "top", children: [_jsxs("header", { "data-ui": "catalogue-hero", children: [_jsxs("div", { children: [_jsx("p", { "data-ui": "catalogue-kicker", children: "Public components \u00B7 server rendered" }), _jsx("h1", { "data-ui": "catalogue-title", children: "K\u00E9t Vi\u1EC7t Design System" }), _jsxs("p", { "data-ui": "catalogue-intro", children: [String(count), " specimens from one markup, token and state contract. Dense enough for daily work; quiet enough for decisions."] }), _jsx(LinkButton, { label: "Review page surfaces", href: "/surfaces?kind=record&theme=light", variant: "secondary" })] }), _jsxs("div", { "data-ui": "catalogue-controls", role: "group", "aria-label": "Catalogue preferences", children: [_jsx("span", { children: "Theme" }), _jsx("a", { href: `/?theme=light&density=${density}`, "aria-current": theme === 'light' ? 'page' : null, children: "Light" }), _jsx("a", { href: `/?theme=dark&density=${density}`, "aria-current": theme === 'dark' ? 'page' : null, children: "Dark" }), _jsx("a", { href: `/?theme=system&density=${density}`, "aria-current": theme === 'system' ? 'page' : null, children: "System" }), _jsx("span", { children: "Density" }), _jsx("a", { href: `/?theme=${theme}&density=compact`, "aria-current": density === 'compact' ? 'page' : null, children: "Compact" }), _jsx("a", { href: `/?theme=${theme}&density=default`, "aria-current": density === 'default' ? 'page' : null, children: "Default" }), _jsx("a", { href: `/?theme=${theme}&density=comfortable`, "aria-current": density === 'comfortable' ? 'page' : null, children: "Comfort" })] })] }), each(componentGroups, (group) => group.id, (group) => (_jsxs("section", { "data-ui": "catalogue-group", id: group.id, children: [_jsxs("header", { "data-ui": "catalogue-group-head", children: [_jsxs("div", { children: [_jsxs("p", { "data-ui": "catalogue-kicker", children: [String(group.examples.length).padStart(2, '0'), " components"] }), _jsx("h2", { children: group.name })] }), _jsx("p", { children: group.description })] }), each(group.examples, (example) => example.id, (example) => (_jsxs("article", { "data-ui": "catalogue-specimen", id: example.id, children: [_jsxs("header", { "data-ui": "catalogue-specimen-head", children: [_jsxs("div", { children: [_jsx("h3", { "data-ui": "catalogue-specimen-name", children: example.name }), _jsx("p", { "data-ui": "catalogue-specimen-description", children: example.description })] }), _jsx(Code, { value: "@ketvietlab/design-system", context: "package" })] }), _jsx("div", { "data-ui": "catalogue-stage", children: example.render() })] })))] })))] })] }));
|
|
420
779
|
};
|
|
421
780
|
//# sourceMappingURL=index.js.map
|