@ketvietlab/design-system 0.1.6 → 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 +413 -55
- 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 +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- 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 +937 -131
- package/dist/patterns/record-page.d.ts +2 -2
- package/dist/patterns/record-page.d.ts.map +1 -1
- package/dist/patterns/record-page.js +1 -1
- package/dist/patterns/record-page.js.map +1 -1
- package/dist/primitives/actions.d.ts.map +1 -1
- package/dist/primitives/actions.js +1 -1
- 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 +82 -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,4 +1,4 @@
|
|
|
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
3
|
import { ActionGroup, Button, IconButton, LinkButton } from '../primitives/actions.js';
|
|
4
4
|
import { Avatar, Badge, Code, CountBadge, Tag } from '../primitives/status.js';
|
|
@@ -7,12 +7,15 @@ 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,7 @@ 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 }),
|
|
43
124
|
_jsx(IconButton, { label: "Toggle theme", icon: "\u263E" }),
|
|
44
125
|
] })),
|
|
45
126
|
},
|
|
@@ -51,6 +132,8 @@ export const componentGroups = [
|
|
|
51
132
|
_jsx(Button, { label: "Compact", size: "compact" }),
|
|
52
133
|
_jsx(Button, { label: "Default" }),
|
|
53
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" }),
|
|
54
137
|
_jsx(LinkButton, { label: "Open record", href: "#data-table", variant: "tertiary", leading: "\u2197" }),
|
|
55
138
|
] })),
|
|
56
139
|
},
|
|
@@ -123,16 +206,115 @@ export const componentGroups = [
|
|
|
123
206
|
id: 'field',
|
|
124
207
|
name: 'Field',
|
|
125
208
|
description: 'Text, select, checkbox and error states without application-owned markup.',
|
|
126
|
-
render: () => (_jsx(Grid, { columns: 2, items: [
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
+
] }) })),
|
|
136
318
|
},
|
|
137
319
|
],
|
|
138
320
|
},
|
|
@@ -176,27 +358,111 @@ export const componentGroups = [
|
|
|
176
358
|
{
|
|
177
359
|
id: 'application-structure',
|
|
178
360
|
name: 'Application structure',
|
|
179
|
-
description: '
|
|
361
|
+
description: 'Four practical layouts inside the same shell: collection, record, flow workspace and canvas workspace.',
|
|
180
362
|
examples: [
|
|
181
363
|
{
|
|
182
364
|
id: 'app-shell',
|
|
183
|
-
name: '
|
|
184
|
-
description: '
|
|
185
|
-
render: () => (_jsx(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
] })] }), 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: [
|
|
190
|
-
_jsx(Metric, { label: "Orders", value: "148", detail: "+12 today", tone: "positive" }),
|
|
191
|
-
_jsx(Metric, { label: "Review queue", value: "7", detail: "Oldest 42 min", tone: "warning" }),
|
|
192
|
-
_jsx(Metric, { label: "Blocked", value: "2", detail: "Credential required", tone: "danger" }),
|
|
193
|
-
] }) }), 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
|
+
] })),
|
|
194
371
|
},
|
|
195
372
|
{
|
|
196
373
|
id: 'record-page',
|
|
197
|
-
name: 'Record
|
|
198
|
-
description: '
|
|
199
|
-
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
|
+
] })),
|
|
200
466
|
},
|
|
201
467
|
],
|
|
202
468
|
},
|
|
@@ -240,21 +506,91 @@ export const componentGroups = [
|
|
|
240
506
|
name: 'Patterns',
|
|
241
507
|
description: 'Generic workflows assembled from the same primitives.',
|
|
242
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
|
+
},
|
|
243
544
|
{
|
|
244
545
|
id: 'list-page',
|
|
245
546
|
name: 'List page',
|
|
246
547
|
description: 'The canonical collection hierarchy: identity, actions, URL-driven controls, result context and records.',
|
|
247
|
-
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(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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: [
|
|
252
587
|
{
|
|
253
588
|
key: 'id',
|
|
254
589
|
label: 'Order',
|
|
255
590
|
cell: (row) => row.id,
|
|
256
591
|
priority: 'primary',
|
|
257
592
|
kind: 'identifier',
|
|
593
|
+
sort: { href: '#list-page', direction: 'descending' },
|
|
258
594
|
},
|
|
259
595
|
{ key: 'customer', label: 'Customer', cell: (row) => row.customer },
|
|
260
596
|
{ key: 'total', label: 'Total', cell: (row) => row.total, align: 'end', kind: 'currency' },
|
|
@@ -277,7 +613,7 @@ export const componentGroups = [
|
|
|
277
613
|
_jsx(Metric, { label: "Confirmed", value: 18, detail: "82,000,000 \u20AB", tone: "positive" }),
|
|
278
614
|
_jsx(Metric, { label: "To invoice", value: 6, detail: "Needs attention", tone: "warning" }),
|
|
279
615
|
] }),
|
|
280
|
-
_jsx(
|
|
616
|
+
_jsx(Surface, { title: "Sales flow", body: _jsx(Pipeline, { label: "Sales flow", steps: [
|
|
281
617
|
{ id: 'draft', label: 'Quotation', value: 24 },
|
|
282
618
|
{ id: 'sent', label: 'Sent', value: 9, tone: 'info' },
|
|
283
619
|
{ id: 'confirmed', label: 'Confirmed', value: 18, tone: 'positive' },
|
|
@@ -313,8 +649,30 @@ export const componentGroups = [
|
|
|
313
649
|
id: 'data-table',
|
|
314
650
|
name: 'Data table',
|
|
315
651
|
description: 'Columns are data; rows remain semantic and horizontally contained.',
|
|
316
|
-
render: () => (_jsx(DataTable, {
|
|
317
|
-
{
|
|
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
|
+
},
|
|
318
676
|
{ key: 'customer', label: 'Customer', cell: (row) => row.customer },
|
|
319
677
|
{ key: 'total', label: 'Total', cell: (row) => row.total, align: 'end', kind: 'currency' },
|
|
320
678
|
{
|
|
@@ -329,30 +687,30 @@ export const componentGroups = [
|
|
|
329
687
|
id: 'form-page',
|
|
330
688
|
name: 'Form page',
|
|
331
689
|
description: 'The canonical form hierarchy: record identity and decision first, a stable form column, then durable context.',
|
|
332
|
-
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(
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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" })),
|
|
350
708
|
},
|
|
351
709
|
{
|
|
352
710
|
id: 'record-form',
|
|
353
711
|
name: 'Record form',
|
|
354
712
|
description: 'Application supplies translated labels and values, not form markup.',
|
|
355
|
-
render: () => (_jsx(Surface, { body: _jsx(RecordForm, { action: "#record-form", fields: [
|
|
713
|
+
render: () => (_jsx(Surface, { title: "Main information", body: _jsx(RecordForm, { action: "#record-form", fields: [
|
|
356
714
|
{ id: 'record-name', name: 'name', label: 'Display name', value: 'Mùa Hạ Riverside' },
|
|
357
715
|
{
|
|
358
716
|
id: 'record-status',
|
|
@@ -417,6 +775,6 @@ export const CataloguePage = (props = {}) => {
|
|
|
417
775
|
const theme = props.theme ?? 'system';
|
|
418
776
|
const density = props.density ?? 'default';
|
|
419
777
|
const count = componentGroups.reduce((total, group) => total + group.examples.length, 0);
|
|
420
|
-
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() })] })))] })))] })] }));
|
|
421
779
|
};
|
|
422
780
|
//# sourceMappingURL=index.js.map
|