@cogito.ai/astryx-web 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -2
  3. package/astryx.integration.mjs +15 -0
  4. package/bin/astryx-web.mjs +353 -0
  5. package/docs/dock-accessibility.doc.mjs +24 -0
  6. package/docs/dock-components.doc.mjs +26 -0
  7. package/docs/dock-copy.doc.mjs +23 -0
  8. package/docs/dock-design-base.doc.mjs +35 -0
  9. package/docs/dock-environment.doc.mjs +24 -0
  10. package/docs/dock-layout.doc.mjs +25 -0
  11. package/docs/dock-product-stance.doc.mjs +25 -0
  12. package/docs/dock-refuse-list.doc.mjs +34 -0
  13. package/docs/dock-states.doc.mjs +23 -0
  14. package/docs/dock-style-archetypes.doc.mjs +104 -0
  15. package/docs/dock-touch-mobile.doc.mjs +27 -0
  16. package/docs/dock-visual-acceptance.doc.mjs +23 -0
  17. package/package.json +51 -3
  18. package/skills/astryx-web-design/SKILL.md +21 -0
  19. package/skills/astryx-web-design/references/acceptance.md +12 -0
  20. package/skills/astryx-web-design/references/design-direction.md +52 -0
  21. package/skills/astryx-web-design/references/page-building.md +18 -0
  22. package/templates/dock-editor-frame.doc.mjs +19 -0
  23. package/templates/dock-editor-frame.tsx +229 -0
  24. package/templates/dock-form-flow.doc.mjs +19 -0
  25. package/templates/dock-form-flow.tsx +169 -0
  26. package/templates/dock-landing.doc.mjs +11 -0
  27. package/templates/dock-landing.tsx +104 -0
  28. package/templates/dock-list.doc.mjs +20 -0
  29. package/templates/dock-list.tsx +223 -0
  30. package/templates/dock-settings.doc.mjs +19 -0
  31. package/templates/dock-settings.tsx +272 -0
  32. package/templates/dock-workbench.doc.mjs +11 -0
  33. package/templates/dock-workbench.tsx +193 -0
@@ -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
+ }
@@ -0,0 +1,223 @@
1
+ import { Button } from '@astryxdesign/core/Button'
2
+ import { EmptyState } from '@astryxdesign/core/EmptyState'
3
+ import { Heading } from '@astryxdesign/core/Heading'
4
+ import { Icon } from '@astryxdesign/core/Icon'
5
+ import { List, ListItem } from '@astryxdesign/core/List'
6
+ import { MoreMenu } from '@astryxdesign/core/MoreMenu'
7
+ import { SegmentedControl, SegmentedControlItem } from '@astryxdesign/core/SegmentedControl'
8
+ import { Stack } from '@astryxdesign/core/Stack'
9
+ import { Text } from '@astryxdesign/core/Text'
10
+ import { TextInput } from '@astryxdesign/core/TextInput'
11
+ import { Timestamp } from '@astryxdesign/core/Timestamp'
12
+ import { VisuallyHidden } from '@astryxdesign/core/VisuallyHidden'
13
+ import { useTranslator } from '@astryxdesign/core/i18n'
14
+ import { useState } from 'react'
15
+ import { PageShell } from '@/components/layout'
16
+ import { useCurrentLocale } from '@/i18n'
17
+
18
+ const FILTERS = ['recent', 'all', 'archived'] as const
19
+ type Filter = (typeof FILTERS)[number]
20
+
21
+ const SAMPLE_ITEMS = [
22
+ {
23
+ id: 'brief',
24
+ titleKey: 'page.__PAGE__.item.brief.title',
25
+ metaKey: 'page.__PAGE__.item.brief.meta',
26
+ updatedAt: '2026-11-01T09:00:00.000Z',
27
+ },
28
+ {
29
+ id: 'notes',
30
+ titleKey: 'page.__PAGE__.item.notes.title',
31
+ metaKey: 'page.__PAGE__.item.notes.meta',
32
+ updatedAt: '2026-10-28T14:30:00.000Z',
33
+ },
34
+ {
35
+ id: 'archive',
36
+ titleKey: 'page.__PAGE__.item.archive.title',
37
+ metaKey: 'page.__PAGE__.item.archive.meta',
38
+ updatedAt: '2026-10-20T08:15:00.000Z',
39
+ },
40
+ ] as const
41
+ // Replace with feature data
42
+
43
+ function isFilter(value: string): value is Filter {
44
+ return FILTERS.some((filter) => filter === value)
45
+ }
46
+
47
+ export default function DockList() {
48
+ const locale = useCurrentLocale()
49
+ const t = useTranslator()
50
+ const [search, setSearch] = useState('')
51
+ const [filter, setFilter] = useState<Filter>('recent')
52
+ const hasItems: boolean = SAMPLE_ITEMS.length > 0
53
+
54
+ const visibleItems = SAMPLE_ITEMS.filter((item) => {
55
+ const query = search.trim().toLocaleLowerCase()
56
+ if (!query) return true
57
+ return `${t(item.titleKey)} ${t(item.metaKey)}`.toLocaleLowerCase().includes(query)
58
+ })
59
+
60
+ return (
61
+ <PageShell
62
+ title={t('page.__PAGE__.title')}
63
+ backHref={`/${locale}`}
64
+ backLabel={t('page.__PAGE__.back')}
65
+ actions={
66
+ <Button
67
+ label={t('page.__PAGE__.new')}
68
+ size="sm"
69
+ variant="primary"
70
+ onClick={() => undefined}
71
+ />
72
+ }
73
+ >
74
+ <Stack gap={4}>
75
+ <TextInput
76
+ label={t('page.__PAGE__.search.label')}
77
+ isLabelHidden
78
+ value={search}
79
+ onChange={setSearch}
80
+ placeholder={t('page.__PAGE__.search.placeholder')}
81
+ startIcon={<Icon icon="search" size="sm" />}
82
+ hasClear
83
+ />
84
+ <SegmentedControl
85
+ label={t('page.__PAGE__.filter.label')}
86
+ value={filter}
87
+ onChange={(value) => {
88
+ if (isFilter(value)) setFilter(value)
89
+ }}
90
+ layout="fill"
91
+ >
92
+ {FILTERS.map((candidate) => (
93
+ <SegmentedControlItem
94
+ key={candidate}
95
+ value={candidate}
96
+ label={t(`page.__PAGE__.filter.${candidate}`)}
97
+ />
98
+ ))}
99
+ </SegmentedControl>
100
+
101
+ {!hasItems ? (
102
+ <EmptyState
103
+ title={t('page.__PAGE__.empty.title')}
104
+ description={t('page.__PAGE__.empty.description')}
105
+ actions={
106
+ <Button label={t('page.__PAGE__.new')} variant="primary" onClick={() => undefined} />
107
+ }
108
+ />
109
+ ) : visibleItems.length === 0 ? (
110
+ <Text type="body" color="secondary">
111
+ {t('page.__PAGE__.noResults')}
112
+ </Text>
113
+ ) : (
114
+ <List
115
+ density="balanced"
116
+ hasDividers
117
+ header={
118
+ <VisuallyHidden>
119
+ <Heading level={2}>{t('page.__PAGE__.listTitle')}</Heading>
120
+ </VisuallyHidden>
121
+ }
122
+ >
123
+ {visibleItems.map((item) => (
124
+ <ListItem
125
+ key={item.id}
126
+ label={t(item.titleKey)}
127
+ description={
128
+ <Stack direction="horizontal" gap={2} vAlign="center" wrap="wrap">
129
+ <Text type="supporting" color="secondary">
130
+ {t(item.metaKey)}
131
+ </Text>
132
+ <Timestamp
133
+ value={item.updatedAt}
134
+ format="date"
135
+ type="supporting"
136
+ color="secondary"
137
+ />
138
+ </Stack>
139
+ }
140
+ onClick={() => undefined}
141
+ endContent={
142
+ <MoreMenu
143
+ label={t('page.__PAGE__.row.options')}
144
+ size="sm"
145
+ alignment="end"
146
+ presentation="adaptive"
147
+ items={[
148
+ {
149
+ id: 'archive',
150
+ label: t('page.__PAGE__.row.archive'),
151
+ icon: <Icon icon="close" size="sm" />,
152
+ },
153
+ ]}
154
+ />
155
+ }
156
+ />
157
+ ))}
158
+ </List>
159
+ )}
160
+
161
+ {visibleItems.length > 0 ? (
162
+ <Stack direction="horizontal" hAlign="center">
163
+ <Button label={t('page.__PAGE__.loadMore')} variant="ghost" onClick={() => undefined} />
164
+ </Stack>
165
+ ) : null}
166
+ </Stack>
167
+ </PageShell>
168
+ )
169
+ }
170
+
171
+ /*
172
+ astryx-messages
173
+ {
174
+ "en": {
175
+ "page.__PAGE__.title": "Documents",
176
+ "page.__PAGE__.back": "Back",
177
+ "page.__PAGE__.new": "New",
178
+ "page.__PAGE__.search.label": "Search documents",
179
+ "page.__PAGE__.search.placeholder": "Search documents",
180
+ "page.__PAGE__.filter.label": "Document view",
181
+ "page.__PAGE__.filter.recent": "Recent",
182
+ "page.__PAGE__.filter.all": "All",
183
+ "page.__PAGE__.filter.archived": "Archived",
184
+ "page.__PAGE__.empty.title": "No documents yet",
185
+ "page.__PAGE__.empty.description": "Create the first document to start this collection.",
186
+ "page.__PAGE__.noResults": "No documents match this search.",
187
+ "page.__PAGE__.listTitle": "Documents",
188
+ "page.__PAGE__.row.options": "Document actions",
189
+ "page.__PAGE__.row.archive": "Archive",
190
+ "page.__PAGE__.item.brief.title": "Project brief",
191
+ "page.__PAGE__.item.brief.meta": "Product",
192
+ "page.__PAGE__.item.notes.title": "Research notes",
193
+ "page.__PAGE__.item.notes.meta": "Research",
194
+ "page.__PAGE__.item.archive.title": "Team guidelines",
195
+ "page.__PAGE__.item.archive.meta": "Operations",
196
+ "page.__PAGE__.loadMore": "Load more"
197
+ },
198
+ "zh-CN": {
199
+ "page.__PAGE__.title": "文档",
200
+ "page.__PAGE__.back": "返回",
201
+ "page.__PAGE__.new": "新建",
202
+ "page.__PAGE__.search.label": "搜索文档",
203
+ "page.__PAGE__.search.placeholder": "搜索文档",
204
+ "page.__PAGE__.filter.label": "文档视图",
205
+ "page.__PAGE__.filter.recent": "最近",
206
+ "page.__PAGE__.filter.all": "全部",
207
+ "page.__PAGE__.filter.archived": "已归档",
208
+ "page.__PAGE__.empty.title": "暂无文档",
209
+ "page.__PAGE__.empty.description": "创建第一份文档来开始这个集合。",
210
+ "page.__PAGE__.noResults": "没有文档符合此搜索。",
211
+ "page.__PAGE__.listTitle": "文档",
212
+ "page.__PAGE__.row.options": "文档操作",
213
+ "page.__PAGE__.row.archive": "归档",
214
+ "page.__PAGE__.item.brief.title": "项目简介",
215
+ "page.__PAGE__.item.brief.meta": "产品",
216
+ "page.__PAGE__.item.notes.title": "研究笔记",
217
+ "page.__PAGE__.item.notes.meta": "研究",
218
+ "page.__PAGE__.item.archive.title": "团队指南",
219
+ "page.__PAGE__.item.archive.meta": "运营",
220
+ "page.__PAGE__.loadMore": "加载更多"
221
+ }
222
+ }
223
+ */
@@ -0,0 +1,19 @@
1
+ /** @type {import('@astryxdesign/cli/authoring').IntegrationTemplateDoc} */
2
+ export default {
3
+ type: 'page',
4
+ name: 'Settings page',
5
+ displayName: 'Settings page',
6
+ description:
7
+ 'A mobile-first settings surface with compact tabs, a wide side navigation, and one scrollable section panel.',
8
+ category: 'Settings - Sections',
9
+ keywords: [
10
+ 'settings page',
11
+ 'preferences',
12
+ 'sections',
13
+ 'mobile',
14
+ 'mobile settings',
15
+ 'account settings',
16
+ ],
17
+ replaces: 'settings',
18
+ isReady: true,
19
+ }