@cogito.ai/astryx-web 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +34 -2
- package/astryx.integration.mjs +15 -0
- package/bin/astryx-web.mjs +350 -0
- package/docs/dock-accessibility.doc.mjs +24 -0
- package/docs/dock-components.doc.mjs +26 -0
- package/docs/dock-copy.doc.mjs +23 -0
- package/docs/dock-design-base.doc.mjs +35 -0
- package/docs/dock-environment.doc.mjs +24 -0
- package/docs/dock-layout.doc.mjs +25 -0
- package/docs/dock-product-stance.doc.mjs +25 -0
- package/docs/dock-refuse-list.doc.mjs +34 -0
- package/docs/dock-states.doc.mjs +23 -0
- package/docs/dock-touch-mobile.doc.mjs +27 -0
- package/docs/dock-visual-acceptance.doc.mjs +23 -0
- package/package.json +51 -3
- package/templates/dock-editor-frame.doc.mjs +19 -0
- package/templates/dock-editor-frame.tsx +229 -0
- package/templates/dock-form-flow.doc.mjs +19 -0
- package/templates/dock-form-flow.tsx +169 -0
- package/templates/dock-landing.doc.mjs +11 -0
- package/templates/dock-landing.tsx +104 -0
- package/templates/dock-list.doc.mjs +20 -0
- package/templates/dock-list.tsx +223 -0
- package/templates/dock-settings.doc.mjs +19 -0
- package/templates/dock-settings.tsx +272 -0
- package/templates/dock-workbench.doc.mjs +11 -0
- package/templates/dock-workbench.tsx +193 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** @type {import('@astryxdesign/cli/authoring').ReferenceDoc} */
|
|
2
|
+
export default {
|
|
3
|
+
type: 'generic',
|
|
4
|
+
name: 'dock-touch-mobile',
|
|
5
|
+
title: 'Dock Touch Mobile',
|
|
6
|
+
description: 'Touch targets, safe areas, compact navigation, and mobile interaction rules.',
|
|
7
|
+
sections: [
|
|
8
|
+
{
|
|
9
|
+
title: 'Touch and mobile',
|
|
10
|
+
content: [
|
|
11
|
+
{
|
|
12
|
+
type: 'list',
|
|
13
|
+
style: 'unordered',
|
|
14
|
+
items: [
|
|
15
|
+
'Touch targets are at least 44×44px. 32px is allowed only in dense toolbars that never appear on touch screens.',
|
|
16
|
+
'On compact containers, first-level destinations live in the bottom navigation, and the primary action of a flow sits in a bottom bar within thumb reach.',
|
|
17
|
+
'Respect safe areas: `viewport-fit=cover` and `env(safe-area-inset-*)` padding on fixed bars.',
|
|
18
|
+
'Use `100dvh`, not `100vh`.',
|
|
19
|
+
'Inputs use at least a 16px font so iOS does not zoom.',
|
|
20
|
+
'Anything revealed on hover must also work by tap; gate hover styles with `@media (hover: hover)`.',
|
|
21
|
+
'Secondary choices on compact containers open as bottom sheets, not floating menus.',
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** @type {import('@astryxdesign/cli/authoring').ReferenceDoc} */
|
|
2
|
+
export default {
|
|
3
|
+
type: 'generic',
|
|
4
|
+
name: 'dock-visual-acceptance',
|
|
5
|
+
title: 'Dock Visual Acceptance',
|
|
6
|
+
description: 'The render matrix and visual review rules for UI work.',
|
|
7
|
+
sections: [
|
|
8
|
+
{
|
|
9
|
+
title: 'Visual acceptance',
|
|
10
|
+
content: [
|
|
11
|
+
{
|
|
12
|
+
type: 'list',
|
|
13
|
+
style: 'unordered',
|
|
14
|
+
items: [
|
|
15
|
+
'Render the changed pages at 390×844 and 1440×900, in light and dark.',
|
|
16
|
+
'Check them against A1–A9. Fix everything you find in one batch. At most two rounds, then hand over.',
|
|
17
|
+
'Screenshots are for judging what the user sees. Never use them to watch CI, pipelines, or progress; read the API.',
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cogito.ai/astryx-web",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Mobile-first page archetypes and design guidance for AgentDock web projects",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"astryx-web": "./bin/astryx-web.mjs"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
"./templates/dock-landing": "./templates/dock-landing.tsx",
|
|
14
|
+
"./templates/dock-workbench": "./templates/dock-workbench.tsx",
|
|
15
|
+
"./templates/dock-list": "./templates/dock-list.tsx",
|
|
16
|
+
"./templates/dock-form-flow": "./templates/dock-form-flow.tsx",
|
|
17
|
+
"./templates/dock-settings": "./templates/dock-settings.tsx",
|
|
18
|
+
"./templates/dock-editor-frame": "./templates/dock-editor-frame.tsx"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"astryx.integration.mjs",
|
|
22
|
+
"templates/",
|
|
23
|
+
"docs/",
|
|
24
|
+
"skills/",
|
|
25
|
+
"bin/",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22.13.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@astryxdesign/cli": ">=0.7.0",
|
|
34
|
+
"@astryxdesign/core": "^0.7.5"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"@astryxdesign/cli": {
|
|
38
|
+
"optional": true
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@astryxdesign/cli": "0.7.5",
|
|
43
|
+
"@astryxdesign/core": "0.7.5",
|
|
44
|
+
"typescript": "6.0.3"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"check": "pnpm test && pnpm run check:integration && pnpm run check:templates && pnpm run check:intents",
|
|
48
|
+
"check:integration": "astryx integration check --strict && astryx integration verify",
|
|
49
|
+
"check:templates": "node scripts/check-templates.mjs",
|
|
50
|
+
"check:intents": "node scripts/golden-intents.mjs",
|
|
51
|
+
"check-types": "pnpm run check",
|
|
52
|
+
"test": "node --test test/*.test.mjs"
|
|
53
|
+
}
|
|
6
54
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** @type {import('@astryxdesign/cli/authoring').IntegrationTemplateDoc} */
|
|
2
|
+
export default {
|
|
3
|
+
type: 'page',
|
|
4
|
+
name: 'Editor frame',
|
|
5
|
+
displayName: 'Editor frame',
|
|
6
|
+
description:
|
|
7
|
+
'A full-bleed editor workspace with a named content slot, floating tools, an overflow menu, and compact bottom navigation.',
|
|
8
|
+
category: 'Editor - Canvas',
|
|
9
|
+
keywords: [
|
|
10
|
+
'canvas editor',
|
|
11
|
+
'diagram editor',
|
|
12
|
+
'workspace',
|
|
13
|
+
'editor frame',
|
|
14
|
+
'floating toolbar',
|
|
15
|
+
'mobile',
|
|
16
|
+
],
|
|
17
|
+
replaces: 'canvas-editor',
|
|
18
|
+
isReady: true,
|
|
19
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { DropdownMenu } from '@astryxdesign/core/DropdownMenu'
|
|
2
|
+
import { Icon } from '@astryxdesign/core/Icon'
|
|
3
|
+
import { IconButton } from '@astryxdesign/core/IconButton'
|
|
4
|
+
import { MoreMenu } from '@astryxdesign/core/MoreMenu'
|
|
5
|
+
import { Stack } from '@astryxdesign/core/Stack'
|
|
6
|
+
import { Text } from '@astryxdesign/core/Text'
|
|
7
|
+
import { useTranslator } from '@astryxdesign/core/i18n'
|
|
8
|
+
import * as stylex from '@stylexjs/stylex'
|
|
9
|
+
|
|
10
|
+
const styles = stylex.create({
|
|
11
|
+
frame: {
|
|
12
|
+
position: 'relative',
|
|
13
|
+
flex: 1,
|
|
14
|
+
minHeight: 0,
|
|
15
|
+
width: 'calc(100% + 1.5rem)',
|
|
16
|
+
marginInline: '-0.75rem',
|
|
17
|
+
marginBlock: '-0.75rem',
|
|
18
|
+
overflow: 'hidden',
|
|
19
|
+
backgroundColor: 'var(--color-background-muted)',
|
|
20
|
+
'@container (min-width: 420px)': {
|
|
21
|
+
width: 'calc(100% + 2.5rem)',
|
|
22
|
+
marginInline: '-1.25rem',
|
|
23
|
+
marginBlock: '-1.25rem',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
tools: {
|
|
27
|
+
position: 'absolute',
|
|
28
|
+
top: 'max(0.75rem, env(safe-area-inset-top))',
|
|
29
|
+
left: 'max(0.75rem, env(safe-area-inset-left))',
|
|
30
|
+
zIndex: 2,
|
|
31
|
+
padding: '0.25rem',
|
|
32
|
+
borderRadius: 'var(--radius-element)',
|
|
33
|
+
backgroundColor: 'var(--color-background-card)',
|
|
34
|
+
boxShadow: 'var(--shadow-med)',
|
|
35
|
+
'@container (min-width: 640px)': {
|
|
36
|
+
top: 'max(1.5rem, env(safe-area-inset-top))',
|
|
37
|
+
left: 'max(1.5rem, env(safe-area-inset-left))',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
menu: {
|
|
41
|
+
position: 'absolute',
|
|
42
|
+
top: 'max(0.75rem, env(safe-area-inset-top))',
|
|
43
|
+
right: 'max(0.75rem, env(safe-area-inset-right))',
|
|
44
|
+
zIndex: 2,
|
|
45
|
+
'@container (min-width: 640px)': {
|
|
46
|
+
top: 'max(1.5rem, env(safe-area-inset-top))',
|
|
47
|
+
right: 'max(1.5rem, env(safe-area-inset-right))',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
bottomNav: {
|
|
51
|
+
position: 'absolute',
|
|
52
|
+
left: '50%',
|
|
53
|
+
bottom: 'max(0.75rem, env(safe-area-inset-bottom))',
|
|
54
|
+
transform: 'translateX(-50%)',
|
|
55
|
+
zIndex: 2,
|
|
56
|
+
padding: '0.25rem',
|
|
57
|
+
borderRadius: 'var(--radius-full)',
|
|
58
|
+
backgroundColor: 'var(--color-background-card)',
|
|
59
|
+
boxShadow: 'var(--shadow-med)',
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
function EditorSlot() {
|
|
64
|
+
const t = useTranslator()
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Stack
|
|
68
|
+
aria-label={t('page.__PAGE__.slot.label')}
|
|
69
|
+
height="100%"
|
|
70
|
+
hAlign="center"
|
|
71
|
+
vAlign="center"
|
|
72
|
+
gap={2}
|
|
73
|
+
>
|
|
74
|
+
<Text type="body" weight="semibold">
|
|
75
|
+
{t('page.__PAGE__.slot.title')}
|
|
76
|
+
</Text>
|
|
77
|
+
<Text type="supporting" color="secondary">
|
|
78
|
+
{t('page.__PAGE__.slot.description')}
|
|
79
|
+
</Text>
|
|
80
|
+
</Stack>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export default function DockEditorFrame() {
|
|
85
|
+
const t = useTranslator()
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<Stack width="100%" xstyle={styles.frame}>
|
|
89
|
+
<EditorSlot />
|
|
90
|
+
|
|
91
|
+
<Stack direction="horizontal" gap={1} xstyle={styles.tools}>
|
|
92
|
+
<IconButton
|
|
93
|
+
label={t('page.__PAGE__.tool.select')}
|
|
94
|
+
icon={<Icon icon="arrowUp" size="sm" />}
|
|
95
|
+
variant="ghost"
|
|
96
|
+
size="sm"
|
|
97
|
+
/>
|
|
98
|
+
<IconButton
|
|
99
|
+
label={t('page.__PAGE__.tool.move')}
|
|
100
|
+
icon={<Icon icon="arrowDown" size="sm" />}
|
|
101
|
+
variant="ghost"
|
|
102
|
+
size="sm"
|
|
103
|
+
/>
|
|
104
|
+
<IconButton
|
|
105
|
+
label={t('page.__PAGE__.tool.find')}
|
|
106
|
+
icon={<Icon icon="search" size="sm" />}
|
|
107
|
+
variant="ghost"
|
|
108
|
+
size="sm"
|
|
109
|
+
/>
|
|
110
|
+
<IconButton
|
|
111
|
+
label={t('page.__PAGE__.tool.layers')}
|
|
112
|
+
icon={<Icon icon="viewColumns" size="sm" />}
|
|
113
|
+
variant="ghost"
|
|
114
|
+
size="sm"
|
|
115
|
+
/>
|
|
116
|
+
<IconButton
|
|
117
|
+
label={t('page.__PAGE__.tool.adjust')}
|
|
118
|
+
icon={<Icon icon="wrench" size="sm" />}
|
|
119
|
+
variant="ghost"
|
|
120
|
+
size="sm"
|
|
121
|
+
/>
|
|
122
|
+
<MoreMenu
|
|
123
|
+
label={t('page.__PAGE__.tool.more')}
|
|
124
|
+
size="sm"
|
|
125
|
+
presentation="adaptive"
|
|
126
|
+
items={[
|
|
127
|
+
{
|
|
128
|
+
id: 'duplicate',
|
|
129
|
+
label: t('page.__PAGE__.action.duplicate'),
|
|
130
|
+
icon: <Icon icon="copy" size="sm" />,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: 'delete',
|
|
134
|
+
label: t('page.__PAGE__.action.delete'),
|
|
135
|
+
variant: 'destructive',
|
|
136
|
+
icon: <Icon icon="close" size="sm" />,
|
|
137
|
+
},
|
|
138
|
+
]}
|
|
139
|
+
/>
|
|
140
|
+
</Stack>
|
|
141
|
+
|
|
142
|
+
<DropdownMenu
|
|
143
|
+
xstyle={styles.menu}
|
|
144
|
+
hasChevron={false}
|
|
145
|
+
button={{
|
|
146
|
+
label: t('page.__PAGE__.menu'),
|
|
147
|
+
icon: <Icon icon="menu" size="sm" />,
|
|
148
|
+
variant: 'secondary',
|
|
149
|
+
size: 'sm',
|
|
150
|
+
}}
|
|
151
|
+
items={[
|
|
152
|
+
{
|
|
153
|
+
id: 'rename',
|
|
154
|
+
label: t('page.__PAGE__.action.rename'),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: 'export',
|
|
158
|
+
label: t('page.__PAGE__.action.export'),
|
|
159
|
+
},
|
|
160
|
+
]}
|
|
161
|
+
/>
|
|
162
|
+
|
|
163
|
+
<Stack direction="horizontal" gap={1} xstyle={styles.bottomNav}>
|
|
164
|
+
<IconButton
|
|
165
|
+
label={t('page.__PAGE__.nav.back')}
|
|
166
|
+
icon={<Icon icon="chevronLeft" size="sm" />}
|
|
167
|
+
variant="ghost"
|
|
168
|
+
size="sm"
|
|
169
|
+
/>
|
|
170
|
+
<IconButton
|
|
171
|
+
label={t('page.__PAGE__.nav.history')}
|
|
172
|
+
icon={<Icon icon="clock" size="sm" />}
|
|
173
|
+
variant="ghost"
|
|
174
|
+
size="sm"
|
|
175
|
+
/>
|
|
176
|
+
<IconButton
|
|
177
|
+
label={t('page.__PAGE__.nav.done')}
|
|
178
|
+
icon={<Icon icon="check" size="sm" />}
|
|
179
|
+
variant="primary"
|
|
180
|
+
size="sm"
|
|
181
|
+
/>
|
|
182
|
+
</Stack>
|
|
183
|
+
</Stack>
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/*
|
|
188
|
+
astryx-messages
|
|
189
|
+
{
|
|
190
|
+
"en": {
|
|
191
|
+
"page.__PAGE__.slot.label": "Editor content",
|
|
192
|
+
"page.__PAGE__.slot.title": "Editor canvas",
|
|
193
|
+
"page.__PAGE__.slot.description": "Put the domain editor in this slot.",
|
|
194
|
+
"page.__PAGE__.tool.select": "Select",
|
|
195
|
+
"page.__PAGE__.tool.move": "Move",
|
|
196
|
+
"page.__PAGE__.tool.find": "Find",
|
|
197
|
+
"page.__PAGE__.tool.layers": "Layers",
|
|
198
|
+
"page.__PAGE__.tool.adjust": "Adjust",
|
|
199
|
+
"page.__PAGE__.tool.more": "More tools",
|
|
200
|
+
"page.__PAGE__.menu": "Editor menu",
|
|
201
|
+
"page.__PAGE__.action.duplicate": "Duplicate",
|
|
202
|
+
"page.__PAGE__.action.delete": "Delete",
|
|
203
|
+
"page.__PAGE__.action.rename": "Rename",
|
|
204
|
+
"page.__PAGE__.action.export": "Export",
|
|
205
|
+
"page.__PAGE__.nav.back": "Back",
|
|
206
|
+
"page.__PAGE__.nav.history": "History",
|
|
207
|
+
"page.__PAGE__.nav.done": "Done"
|
|
208
|
+
},
|
|
209
|
+
"zh-CN": {
|
|
210
|
+
"page.__PAGE__.slot.label": "编辑器内容",
|
|
211
|
+
"page.__PAGE__.slot.title": "编辑器画布",
|
|
212
|
+
"page.__PAGE__.slot.description": "在此插槽中放入领域编辑器。",
|
|
213
|
+
"page.__PAGE__.tool.select": "选择",
|
|
214
|
+
"page.__PAGE__.tool.move": "移动",
|
|
215
|
+
"page.__PAGE__.tool.find": "查找",
|
|
216
|
+
"page.__PAGE__.tool.layers": "图层",
|
|
217
|
+
"page.__PAGE__.tool.adjust": "调整",
|
|
218
|
+
"page.__PAGE__.tool.more": "更多工具",
|
|
219
|
+
"page.__PAGE__.menu": "编辑器菜单",
|
|
220
|
+
"page.__PAGE__.action.duplicate": "复制",
|
|
221
|
+
"page.__PAGE__.action.delete": "删除",
|
|
222
|
+
"page.__PAGE__.action.rename": "重命名",
|
|
223
|
+
"page.__PAGE__.action.export": "导出",
|
|
224
|
+
"page.__PAGE__.nav.back": "返回",
|
|
225
|
+
"page.__PAGE__.nav.history": "历史",
|
|
226
|
+
"page.__PAGE__.nav.done": "完成"
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
*/
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** @type {import('@astryxdesign/cli/authoring').IntegrationTemplateDoc} */
|
|
2
|
+
export default {
|
|
3
|
+
type: 'page',
|
|
4
|
+
name: 'Form flow',
|
|
5
|
+
displayName: 'Form flow',
|
|
6
|
+
description:
|
|
7
|
+
'A mobile-first creation form or wizard with one step per screen, inline validation, and actions within thumb reach.',
|
|
8
|
+
category: 'Form - Flow',
|
|
9
|
+
keywords: [
|
|
10
|
+
'creation form',
|
|
11
|
+
'multi-step form',
|
|
12
|
+
'wizard form',
|
|
13
|
+
'mobile form',
|
|
14
|
+
'mobile',
|
|
15
|
+
'several steps',
|
|
16
|
+
],
|
|
17
|
+
replaces: 'form-wizard',
|
|
18
|
+
isReady: true,
|
|
19
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Button } from '@astryxdesign/core/Button'
|
|
2
|
+
import { FormLayout } from '@astryxdesign/core/FormLayout'
|
|
3
|
+
import { Heading } from '@astryxdesign/core/Heading'
|
|
4
|
+
import { Stack } from '@astryxdesign/core/Stack'
|
|
5
|
+
import { Text } from '@astryxdesign/core/Text'
|
|
6
|
+
import { TextArea } from '@astryxdesign/core/TextArea'
|
|
7
|
+
import { TextInput } from '@astryxdesign/core/TextInput'
|
|
8
|
+
import { useTranslator } from '@astryxdesign/core/i18n'
|
|
9
|
+
import * as stylex from '@stylexjs/stylex'
|
|
10
|
+
import { useState } from 'react'
|
|
11
|
+
import { PageShell } from '@/components/layout'
|
|
12
|
+
import { useCurrentLocale } from '@/i18n'
|
|
13
|
+
|
|
14
|
+
const styles = stylex.create({
|
|
15
|
+
fields: {
|
|
16
|
+
display: 'grid',
|
|
17
|
+
gridTemplateColumns: 'minmax(0, 1fr)',
|
|
18
|
+
gap: '0.75rem',
|
|
19
|
+
'@container (min-width: 640px)': {
|
|
20
|
+
gridTemplateColumns: 'auto minmax(0, 1fr)',
|
|
21
|
+
gap: '0.75rem 1rem',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
actions: {
|
|
25
|
+
position: 'sticky',
|
|
26
|
+
bottom: 0,
|
|
27
|
+
marginBlockStart: 'auto',
|
|
28
|
+
paddingBlock: '0.75rem',
|
|
29
|
+
paddingBlockEnd: 'max(0.75rem, env(safe-area-inset-bottom))',
|
|
30
|
+
backgroundColor: 'var(--color-background-surface)',
|
|
31
|
+
'@container (min-width: 640px)': {
|
|
32
|
+
position: 'static',
|
|
33
|
+
justifyContent: 'flex-end',
|
|
34
|
+
marginBlockStart: 0,
|
|
35
|
+
paddingBlock: 0,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
type Step = 0 | 1
|
|
41
|
+
|
|
42
|
+
export default function DockFormFlow() {
|
|
43
|
+
const locale = useCurrentLocale()
|
|
44
|
+
const t = useTranslator()
|
|
45
|
+
const [step, setStep] = useState<Step>(0)
|
|
46
|
+
const [name, setName] = useState('')
|
|
47
|
+
const [details, setDetails] = useState('')
|
|
48
|
+
const [error, setError] = useState<string | null>(null)
|
|
49
|
+
|
|
50
|
+
function goNext() {
|
|
51
|
+
if (!name.trim()) {
|
|
52
|
+
setError(t('page.__PAGE__.error.name'))
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
setError(null)
|
|
56
|
+
setStep(1)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<PageShell
|
|
61
|
+
title={t('page.__PAGE__.title')}
|
|
62
|
+
backHref={`/${locale}`}
|
|
63
|
+
backLabel={t('page.__PAGE__.back')}
|
|
64
|
+
>
|
|
65
|
+
<Stack gap={4} minHeight="100%">
|
|
66
|
+
<Text type="supporting" color="secondary">
|
|
67
|
+
{t('page.__PAGE__.step', { current: step + 1, total: 2 })}
|
|
68
|
+
</Text>
|
|
69
|
+
<Stack gap={1}>
|
|
70
|
+
<Heading level={2}>
|
|
71
|
+
{step === 0 ? t('page.__PAGE__.step.details') : t('page.__PAGE__.step.review')}
|
|
72
|
+
</Heading>
|
|
73
|
+
<Text type="supporting" color="secondary">
|
|
74
|
+
{step === 0
|
|
75
|
+
? t('page.__PAGE__.step.details.description')
|
|
76
|
+
: t('page.__PAGE__.step.review.description')}
|
|
77
|
+
</Text>
|
|
78
|
+
</Stack>
|
|
79
|
+
|
|
80
|
+
{step === 0 ? (
|
|
81
|
+
<Stack gap={4}>
|
|
82
|
+
<FormLayout direction="horizontal-labels" xstyle={styles.fields}>
|
|
83
|
+
<TextInput
|
|
84
|
+
label={t('page.__PAGE__.field.name')}
|
|
85
|
+
value={name}
|
|
86
|
+
onChange={(value) => {
|
|
87
|
+
setName(value)
|
|
88
|
+
if (error) setError(null)
|
|
89
|
+
}}
|
|
90
|
+
placeholder={t('page.__PAGE__.field.name.placeholder')}
|
|
91
|
+
isRequired
|
|
92
|
+
status={error ? { type: 'error', message: error } : undefined}
|
|
93
|
+
/>
|
|
94
|
+
</FormLayout>
|
|
95
|
+
<TextArea
|
|
96
|
+
label={t('page.__PAGE__.field.details')}
|
|
97
|
+
value={details}
|
|
98
|
+
onChange={setDetails}
|
|
99
|
+
placeholder={t('page.__PAGE__.field.details.placeholder')}
|
|
100
|
+
/>
|
|
101
|
+
</Stack>
|
|
102
|
+
) : (
|
|
103
|
+
<Stack gap={2}>
|
|
104
|
+
<Text type="body">{name}</Text>
|
|
105
|
+
<Text type="supporting" color="secondary">
|
|
106
|
+
{details || t('page.__PAGE__.review.noDetails')}
|
|
107
|
+
</Text>
|
|
108
|
+
</Stack>
|
|
109
|
+
)}
|
|
110
|
+
|
|
111
|
+
<Stack direction="horizontal" hAlign="between" gap={2} width="100%" xstyle={styles.actions}>
|
|
112
|
+
<Button
|
|
113
|
+
label={t('page.__PAGE__.backStep')}
|
|
114
|
+
variant="secondary"
|
|
115
|
+
isDisabled={step === 0}
|
|
116
|
+
onClick={() => setStep(0)}
|
|
117
|
+
/>
|
|
118
|
+
<Button
|
|
119
|
+
label={step === 0 ? t('page.__PAGE__.next') : t('page.__PAGE__.create')}
|
|
120
|
+
variant="primary"
|
|
121
|
+
onClick={step === 0 ? goNext : () => undefined}
|
|
122
|
+
/>
|
|
123
|
+
</Stack>
|
|
124
|
+
</Stack>
|
|
125
|
+
</PageShell>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/*
|
|
130
|
+
astryx-messages
|
|
131
|
+
{
|
|
132
|
+
"en": {
|
|
133
|
+
"page.__PAGE__.title": "Create item",
|
|
134
|
+
"page.__PAGE__.back": "Back",
|
|
135
|
+
"page.__PAGE__.step": "Step {current} of {total}",
|
|
136
|
+
"page.__PAGE__.step.details": "Details",
|
|
137
|
+
"page.__PAGE__.step.review": "Review",
|
|
138
|
+
"page.__PAGE__.step.details.description": "Add the information needed for this item.",
|
|
139
|
+
"page.__PAGE__.step.review.description": "Check the information before creating the item.",
|
|
140
|
+
"page.__PAGE__.field.name": "Name",
|
|
141
|
+
"page.__PAGE__.field.name.placeholder": "Name this item",
|
|
142
|
+
"page.__PAGE__.field.details": "Details",
|
|
143
|
+
"page.__PAGE__.field.details.placeholder": "Add anything the next person should know",
|
|
144
|
+
"page.__PAGE__.error.name": "Enter a name to continue.",
|
|
145
|
+
"page.__PAGE__.review.noDetails": "No details added.",
|
|
146
|
+
"page.__PAGE__.backStep": "Back",
|
|
147
|
+
"page.__PAGE__.next": "Next",
|
|
148
|
+
"page.__PAGE__.create": "Create"
|
|
149
|
+
},
|
|
150
|
+
"zh-CN": {
|
|
151
|
+
"page.__PAGE__.title": "创建事项",
|
|
152
|
+
"page.__PAGE__.back": "返回",
|
|
153
|
+
"page.__PAGE__.step": "第 {current} 步,共 {total} 步",
|
|
154
|
+
"page.__PAGE__.step.details": "详细信息",
|
|
155
|
+
"page.__PAGE__.step.review": "检查",
|
|
156
|
+
"page.__PAGE__.step.details.description": "添加此事项所需的信息。",
|
|
157
|
+
"page.__PAGE__.step.review.description": "创建前检查这些信息。",
|
|
158
|
+
"page.__PAGE__.field.name": "名称",
|
|
159
|
+
"page.__PAGE__.field.name.placeholder": "为此事项命名",
|
|
160
|
+
"page.__PAGE__.field.details": "详细信息",
|
|
161
|
+
"page.__PAGE__.field.details.placeholder": "添加下一位处理者需要了解的内容",
|
|
162
|
+
"page.__PAGE__.error.name": "请输入名称后继续。",
|
|
163
|
+
"page.__PAGE__.review.noDetails": "尚未添加详细信息。",
|
|
164
|
+
"page.__PAGE__.backStep": "上一步",
|
|
165
|
+
"page.__PAGE__.next": "下一步",
|
|
166
|
+
"page.__PAGE__.create": "创建"
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
*/
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** @type {import('@astryxdesign/cli/authoring').IntegrationTemplateDoc} */
|
|
2
|
+
export default {
|
|
3
|
+
type: 'page',
|
|
4
|
+
name: 'Landing page',
|
|
5
|
+
displayName: 'Landing page',
|
|
6
|
+
description:
|
|
7
|
+
'A first-level landing page with a short orientation line and module entries that lead one route deeper.',
|
|
8
|
+
category: 'Landing - Modules',
|
|
9
|
+
keywords: ['landing page', 'home', 'index', 'module entries', 'mobile', 'mobile landing'],
|
|
10
|
+
isReady: true,
|
|
11
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Blockquote } from '@astryxdesign/core/Blockquote'
|
|
2
|
+
import { ClickableCard } from '@astryxdesign/core/ClickableCard'
|
|
3
|
+
import { Grid } from '@astryxdesign/core/Grid'
|
|
4
|
+
import { Heading } from '@astryxdesign/core/Heading'
|
|
5
|
+
import { Stack } from '@astryxdesign/core/Stack'
|
|
6
|
+
import { Text } from '@astryxdesign/core/Text'
|
|
7
|
+
import { VisuallyHidden } from '@astryxdesign/core/VisuallyHidden'
|
|
8
|
+
import { useTranslator } from '@astryxdesign/core/i18n'
|
|
9
|
+
import * as stylex from '@stylexjs/stylex'
|
|
10
|
+
import { PageContainer } from '@/components/layout'
|
|
11
|
+
import { useCurrentLocale } from '@/i18n'
|
|
12
|
+
|
|
13
|
+
const styles = stylex.create({
|
|
14
|
+
entries: {
|
|
15
|
+
gridTemplateColumns: 'minmax(0, 1fr)',
|
|
16
|
+
'@container (min-width: 600px)': {
|
|
17
|
+
gridTemplateColumns: 'repeat(3, minmax(0, 1fr))',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const SAMPLE_MODULES = [
|
|
23
|
+
{
|
|
24
|
+
id: 'primary',
|
|
25
|
+
path: 'primary',
|
|
26
|
+
titleKey: 'page.__PAGE__.module.primary.title',
|
|
27
|
+
descriptionKey: 'page.__PAGE__.module.primary.description',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: 'secondary',
|
|
31
|
+
path: 'secondary',
|
|
32
|
+
titleKey: 'page.__PAGE__.module.secondary.title',
|
|
33
|
+
descriptionKey: 'page.__PAGE__.module.secondary.description',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'settings',
|
|
37
|
+
path: 'settings',
|
|
38
|
+
titleKey: 'page.__PAGE__.module.settings.title',
|
|
39
|
+
descriptionKey: 'page.__PAGE__.module.settings.description',
|
|
40
|
+
},
|
|
41
|
+
] as const
|
|
42
|
+
// Replace with feature data
|
|
43
|
+
|
|
44
|
+
export default function DockLanding() {
|
|
45
|
+
const locale = useCurrentLocale()
|
|
46
|
+
const t = useTranslator()
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<PageContainer>
|
|
50
|
+
<VisuallyHidden>
|
|
51
|
+
<Heading level={1}>{t('page.__PAGE__.title')}</Heading>
|
|
52
|
+
</VisuallyHidden>
|
|
53
|
+
<Blockquote>{t('page.__PAGE__.orientation')}</Blockquote>
|
|
54
|
+
<Grid columns={3} gap={3} xstyle={styles.entries}>
|
|
55
|
+
{SAMPLE_MODULES.map((module) => {
|
|
56
|
+
const title = t(module.titleKey)
|
|
57
|
+
return (
|
|
58
|
+
<ClickableCard
|
|
59
|
+
key={module.id}
|
|
60
|
+
label={title}
|
|
61
|
+
href={`/${locale}/${module.path}`}
|
|
62
|
+
padding={3}
|
|
63
|
+
>
|
|
64
|
+
<Stack gap={1}>
|
|
65
|
+
<Text type="body" weight="semibold">
|
|
66
|
+
{title}
|
|
67
|
+
</Text>
|
|
68
|
+
<Text type="supporting" color="secondary">
|
|
69
|
+
{t(module.descriptionKey)}
|
|
70
|
+
</Text>
|
|
71
|
+
</Stack>
|
|
72
|
+
</ClickableCard>
|
|
73
|
+
)
|
|
74
|
+
})}
|
|
75
|
+
</Grid>
|
|
76
|
+
</PageContainer>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
astryx-messages
|
|
82
|
+
{
|
|
83
|
+
"en": {
|
|
84
|
+
"page.__PAGE__.title": "Overview",
|
|
85
|
+
"page.__PAGE__.orientation": "Choose a module to continue.",
|
|
86
|
+
"page.__PAGE__.module.primary.title": "Primary workspace",
|
|
87
|
+
"page.__PAGE__.module.primary.description": "Open the main work for this page.",
|
|
88
|
+
"page.__PAGE__.module.secondary.title": "Recent activity",
|
|
89
|
+
"page.__PAGE__.module.secondary.description": "Review the latest changes and decisions.",
|
|
90
|
+
"page.__PAGE__.module.settings.title": "Settings",
|
|
91
|
+
"page.__PAGE__.module.settings.description": "Adjust preferences for this workspace."
|
|
92
|
+
},
|
|
93
|
+
"zh-CN": {
|
|
94
|
+
"page.__PAGE__.title": "概览",
|
|
95
|
+
"page.__PAGE__.orientation": "选择一个模块继续。",
|
|
96
|
+
"page.__PAGE__.module.primary.title": "主工作区",
|
|
97
|
+
"page.__PAGE__.module.primary.description": "打开此页面的主要工作。",
|
|
98
|
+
"page.__PAGE__.module.secondary.title": "最近活动",
|
|
99
|
+
"page.__PAGE__.module.secondary.description": "查看最近的更改与决定。",
|
|
100
|
+
"page.__PAGE__.module.settings.title": "设置",
|
|
101
|
+
"page.__PAGE__.module.settings.description": "调整此工作区的偏好。"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
*/
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** @type {import('@astryxdesign/cli/authoring').IntegrationTemplateDoc} */
|
|
2
|
+
export default {
|
|
3
|
+
type: 'page',
|
|
4
|
+
name: 'List page',
|
|
5
|
+
displayName: 'List page',
|
|
6
|
+
description:
|
|
7
|
+
'A searchable collection with a primary action, a compact filter, list rows, an empty state, and load-more pagination.',
|
|
8
|
+
category: 'List - Collection',
|
|
9
|
+
keywords: [
|
|
10
|
+
'list page',
|
|
11
|
+
'library',
|
|
12
|
+
'collection',
|
|
13
|
+
'search',
|
|
14
|
+
'recent items',
|
|
15
|
+
'mobile',
|
|
16
|
+
'mobile list',
|
|
17
|
+
],
|
|
18
|
+
replaces: 'library',
|
|
19
|
+
isReady: true,
|
|
20
|
+
}
|