@astryxdesign/cli 0.1.2-canary.609e358 → 0.1.2-canary.b712653

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/cli",
3
- "version": "0.1.2-canary.609e358",
3
+ "version": "0.1.2-canary.b712653",
4
4
  "displayName": "CLI",
5
5
  "description": "Scaffold projects, browse templates, generate themes, and get agent-ready docs from the command line.",
6
6
  "author": "Meta Open Source",
@@ -63,9 +63,9 @@
63
63
  "zod": "^4.4.3"
64
64
  },
65
65
  "peerDependencies": {
66
- "@astryxdesign/core": "0.1.2-canary.609e358",
67
- "@astryxdesign/lab": "0.1.2-canary.609e358",
68
- "@astryxdesign/theme-neutral": "0.1.2-canary.609e358",
66
+ "@astryxdesign/core": "0.1.2-canary.b712653",
67
+ "@astryxdesign/lab": "0.1.2-canary.b712653",
68
+ "@astryxdesign/theme-neutral": "0.1.2-canary.b712653",
69
69
  "gpt-tokenizer": "^2.0.0"
70
70
  },
71
71
  "peerDependenciesMeta": {
@@ -80,9 +80,9 @@
80
80
  }
81
81
  },
82
82
  "devDependencies": {
83
- "@astryxdesign/core": "0.1.2-canary.609e358",
84
- "@astryxdesign/lab": "0.1.2-canary.609e358",
85
- "@astryxdesign/theme-neutral": "0.1.2-canary.609e358",
83
+ "@astryxdesign/core": "0.1.2-canary.b712653",
84
+ "@astryxdesign/lab": "0.1.2-canary.b712653",
85
+ "@astryxdesign/theme-neutral": "0.1.2-canary.b712653",
86
86
  "gpt-tokenizer": "^2.0.0"
87
87
  },
88
88
  "scripts": {
@@ -0,0 +1,321 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {Fragment, useState, useMemo, useEffect} from 'react';
6
+ import {AppShell} from '@astryxdesign/core/AppShell';
7
+ import {Layout, LayoutHeader, LayoutContent} from '@astryxdesign/core/Layout';
8
+ import {TopNav} from '@astryxdesign/core/TopNav';
9
+ import {DropdownMenu, DropdownMenuItem} from '@astryxdesign/core/DropdownMenu';
10
+ import {CommandPalette} from '@astryxdesign/core/CommandPalette';
11
+ import {createStaticSource} from '@astryxdesign/core/Typeahead';
12
+ import {Divider} from '@astryxdesign/core/Divider';
13
+ import {Kbd} from '@astryxdesign/core/Kbd';
14
+ import {SideNav} from '@astryxdesign/core/SideNav';
15
+ import {TreeList} from '@astryxdesign/core/TreeList';
16
+ import type {TreeListItemData} from '@astryxdesign/core/TreeList';
17
+ import {Icon} from '@astryxdesign/core/Icon';
18
+ import {Text} from '@astryxdesign/core/Text';
19
+ import {IconButton} from '@astryxdesign/core/IconButton';
20
+ import {Button} from '@astryxdesign/core/Button';
21
+ import {TextInput} from '@astryxdesign/core/TextInput';
22
+ import {Card} from '@astryxdesign/core/Card';
23
+ import {Stack, VStack, HStack} from '@astryxdesign/core/Stack';
24
+ import {
25
+ PlayIcon,
26
+ MagnifyingGlassIcon,
27
+ FolderIcon,
28
+ DocumentTextIcon,
29
+ } from '@heroicons/react/24/outline';
30
+
31
+ const noop = () => {};
32
+
33
+ const folder = (
34
+ id: string,
35
+ children: TreeListItemData[],
36
+ isExpanded = true,
37
+ ): TreeListItemData => ({
38
+ id,
39
+ label: <Text maxLines={1}>{id}</Text>,
40
+ startContent: <Icon icon={FolderIcon} size="xsm" />,
41
+ isExpanded,
42
+ children,
43
+ });
44
+
45
+ const file = (id: string, isSelected = false): TreeListItemData => ({
46
+ id,
47
+ label: <Text maxLines={1}>{id}</Text>,
48
+ startContent: <Icon icon={DocumentTextIcon} size="xsm" />,
49
+ isSelected,
50
+ });
51
+
52
+ const FILE_TREE: TreeListItemData[] = [
53
+ folder('src', [
54
+ folder('components', [
55
+ file('AppShell.tsx', true),
56
+ file('TopNav.tsx'),
57
+ file('SideNav.tsx'),
58
+ ]),
59
+ folder('hooks', [file('useTheme.ts'), file('useResizable.ts')]),
60
+ file('index.tsx'),
61
+ file('App.tsx'),
62
+ ]),
63
+ folder('public', [file('favicon.ico'), file('robots.txt')], false),
64
+ file('package.json'),
65
+ file('tsconfig.json'),
66
+ file('README.md'),
67
+ ];
68
+
69
+ // Each menu is split into groups; groups are separated by a divider.
70
+ // `[label, shortcut]` — the shortcut renders as a single combined Kbd
71
+ // (e.g. ⌘N); an empty shortcut renders no Kbd.
72
+ type MenuEntry = [label: string, shortcut: string];
73
+
74
+ const MENU_WIDTH = 280;
75
+
76
+ const MENUS: {label: string; groups: MenuEntry[][]}[] = [
77
+ {
78
+ label: 'File',
79
+ groups: [
80
+ [
81
+ ['New File', '⌘N'],
82
+ ['New Window', '⇧⌘N'],
83
+ ],
84
+ [
85
+ ['Open...', '⌘O'],
86
+ ['Save', '⌘S'],
87
+ ['Save As...', '⇧⌘S'],
88
+ ],
89
+ [['Close Editor', '⌘W']],
90
+ ],
91
+ },
92
+ {
93
+ label: 'Edit',
94
+ groups: [
95
+ [
96
+ ['Undo', '⌘Z'],
97
+ ['Redo', '⇧⌘Z'],
98
+ ],
99
+ [
100
+ ['Cut', '⌘X'],
101
+ ['Copy', '⌘C'],
102
+ ['Paste', '⌘V'],
103
+ ],
104
+ [['Find', '⌘F']],
105
+ ],
106
+ },
107
+ {
108
+ label: 'View',
109
+ groups: [
110
+ [['Command Palette', '⇧⌘P']],
111
+ [
112
+ ['Explorer', '⇧⌘E'],
113
+ ['Search', '⇧⌘F'],
114
+ ],
115
+ [
116
+ ['Toggle Terminal', '⌃`'],
117
+ ['Zen Mode', '⌘K'],
118
+ ],
119
+ ],
120
+ },
121
+ {
122
+ label: 'Window',
123
+ groups: [
124
+ [
125
+ ['Minimize', '⌘M'],
126
+ ['Zoom', ''],
127
+ ],
128
+ [
129
+ ['Next Tab', '⌃⇥'],
130
+ ['Previous Tab', '⌃⇧⇥'],
131
+ ],
132
+ [['Bring All to Front', '']],
133
+ ],
134
+ },
135
+ {
136
+ label: 'Help',
137
+ groups: [
138
+ [
139
+ ['Documentation', ''],
140
+ ['Release Notes', ''],
141
+ ['Report Issue', ''],
142
+ ['About', ''],
143
+ ],
144
+ ],
145
+ },
146
+ ];
147
+
148
+ const CODE_LINES = [
149
+ '38%',
150
+ '62%',
151
+ '54%',
152
+ '0%',
153
+ '46%',
154
+ '70%',
155
+ '58%',
156
+ '34%',
157
+ '0%',
158
+ '50%',
159
+ '66%',
160
+ '42%',
161
+ '60%',
162
+ '28%',
163
+ ];
164
+
165
+ const EDITOR_TABS = ['AppShell.tsx', 'TopNav.tsx', 'theme.ts'];
166
+
167
+ const COMMANDS = [
168
+ {id: 'new-file', label: 'New File'},
169
+ {id: 'open-file', label: 'Open File…'},
170
+ {id: 'save-all', label: 'Save All'},
171
+ {id: 'find-in-files', label: 'Find in Files'},
172
+ {id: 'toggle-terminal', label: 'Toggle Terminal'},
173
+ {id: 'go-to-symbol', label: 'Go to Symbol…'},
174
+ {id: 'appshell', label: 'AppShell.tsx'},
175
+ {id: 'topnav', label: 'TopNav.tsx'},
176
+ {id: 'sidenav', label: 'SideNav.tsx'},
177
+ {id: 'use-theme', label: 'useTheme.ts'},
178
+ {id: 'theme', label: 'theme.ts'},
179
+ ];
180
+
181
+ export default function ShellNav() {
182
+ const [isPaletteOpen, setIsPaletteOpen] = useState(false);
183
+ const searchSource = useMemo(() => createStaticSource(COMMANDS), []);
184
+
185
+ useEffect(() => {
186
+ const handleKeyDown = (e: KeyboardEvent) => {
187
+ if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
188
+ e.preventDefault();
189
+ setIsPaletteOpen(true);
190
+ }
191
+ };
192
+ window.addEventListener('keydown', handleKeyDown);
193
+ return () => window.removeEventListener('keydown', handleKeyDown);
194
+ }, []);
195
+
196
+ return (
197
+ <>
198
+ <AppShell
199
+ contentPadding={0}
200
+ topNav={
201
+ <TopNav
202
+ label="Astryx Studio menu bar"
203
+ startContent={
204
+ <>
205
+ {MENUS.map(menu => (
206
+ <DropdownMenu
207
+ key={menu.label}
208
+ button={{label: menu.label, variant: 'ghost', size: 'sm'}}
209
+ hasChevron={false}
210
+ menuWidth={MENU_WIDTH}>
211
+ {menu.groups.map((group, gi) => (
212
+ <Fragment key={gi}>
213
+ {gi > 0 && <Divider />}
214
+ {group.map(([label, shortcut]) => (
215
+ <DropdownMenuItem
216
+ key={label}
217
+ label={label}
218
+ onClick={noop}
219
+ endContent={
220
+ shortcut ? <Kbd keys={shortcut} /> : undefined
221
+ }
222
+ />
223
+ ))}
224
+ </Fragment>
225
+ ))}
226
+ </DropdownMenu>
227
+ ))}
228
+ </>
229
+ }
230
+ endContent={
231
+ <>
232
+ <Stack onClick={() => setIsPaletteOpen(true)}>
233
+ <TextInput
234
+ label="Search files and commands"
235
+ isLabelHidden
236
+ size="sm"
237
+ width={240}
238
+ startIcon={MagnifyingGlassIcon}
239
+ placeholder="Search files and commands…"
240
+ value=""
241
+ onChange={() => {}}
242
+ />
243
+ </Stack>
244
+ <IconButton
245
+ label="Run project"
246
+ tooltip="Run"
247
+ variant="ghost"
248
+ icon={<Icon icon={PlayIcon} size="sm" />}
249
+ />
250
+ <Button label="Share" variant="secondary" />
251
+ </>
252
+ }
253
+ />
254
+ }
255
+ sideNav={
256
+ <SideNav
257
+ resizable={{defaultWidth: 240, minWidth: 180, maxWidth: 400}}>
258
+ <TreeList items={FILE_TREE} density="compact" />
259
+ </SideNav>
260
+ }>
261
+ <Layout
262
+ height="fill"
263
+ header={
264
+ <LayoutHeader hasDivider padding={6}>
265
+ <HStack gap={2}>
266
+ {EDITOR_TABS.map(tab => (
267
+ <Card
268
+ key={tab}
269
+ variant="muted"
270
+ padding={0}
271
+ width={132}
272
+ height={36}
273
+ />
274
+ ))}
275
+ </HStack>
276
+ </LayoutHeader>
277
+ }
278
+ content={
279
+ <LayoutContent padding={6}>
280
+ <VStack gap={2}>
281
+ {CODE_LINES.map((width, i) =>
282
+ width === '0%' ? (
283
+ <Card
284
+ key={i}
285
+ variant="muted"
286
+ padding={0}
287
+ width={1}
288
+ height={14}
289
+ />
290
+ ) : (
291
+ <HStack key={i} gap={3} vAlign="center">
292
+ <Card
293
+ variant="muted"
294
+ padding={0}
295
+ width={20}
296
+ height={14}
297
+ />
298
+ <Card
299
+ variant="muted"
300
+ padding={0}
301
+ width={width}
302
+ height={14}
303
+ />
304
+ </HStack>
305
+ ),
306
+ )}
307
+ </VStack>
308
+ </LayoutContent>
309
+ }
310
+ />
311
+ </AppShell>
312
+ <CommandPalette
313
+ isOpen={isPaletteOpen}
314
+ onOpenChange={setIsPaletteOpen}
315
+ searchSource={searchSource}
316
+ label="Search files and commands"
317
+ onValueChange={() => setIsPaletteOpen(false)}
318
+ />
319
+ </>
320
+ );
321
+ }
@@ -0,0 +1,12 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('../../../../core/src/docs-types').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'page',
6
+ name: 'Shell Nav',
7
+ displayName: 'Shell Nav',
8
+ description:
9
+ 'A top + side nav app shell with a File/Edit/View/Window/Help menu bar plus command-palette search, a resizable file-tree SideNav, and a static grey-card tabbed code editor.',
10
+ isReady: true,
11
+ category: 'Shell - Top Nav + Left Sidebar',
12
+ };