@astryxdesign/cli 0.1.0-canary.86d9762 → 0.1.0-canary.a95a267

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.
@@ -88,7 +88,7 @@ import {VStack} from '@astryxdesign/core/Layout';
88
88
  export default function Page() {
89
89
  return (
90
90
  <VStack gap={2}>
91
- <Button label="Hello Astryx" onClick={() => alert('Hi!')} />
91
+ <Button label="Hello XDS" onClick={() => alert('Hi!')} />
92
92
  </VStack>
93
93
  );
94
94
  }`,
@@ -96,11 +96,11 @@ export default function Page() {
96
96
  ],
97
97
  },
98
98
  {
99
- title: 'Customize with StyleX',
99
+ title: 'Customize with xstyle',
100
100
  content: [
101
101
  {
102
102
  type: 'prose',
103
- text: 'Astryx components support various styling solutions, from plain CSS and `className` to Tailwind and CSS-in-JS. See the [styling docs](/docs/styling) for the full guide. Astryx also has a deep integration with [StyleX](https://stylexjs.com/), an atomic CSS-in-JS library: create styles with `stylex.create()` and pass them to components with the `xstyle` prop.',
103
+ text: 'Every component accepts an `xstyle` prop for StyleX style overrides created via `stylex.create()`.',
104
104
  },
105
105
  {
106
106
  type: 'code',
@@ -127,19 +127,19 @@ const overrides = stylex.create({
127
127
  type: 'table',
128
128
  headers: ['Example', 'Stack', 'Path'],
129
129
  rows: [
130
- ['Next.js', 'Next.js + theme CSS', '[apps/example-nextjs](https://github.com/facebook/astryx/tree/main/apps/example-nextjs)'],
131
- ['Next.js + StyleX', 'Next.js + StyleX for custom styles', '[apps/example-nextjs-stylex](https://github.com/facebook/astryx/tree/main/apps/example-nextjs-stylex)'],
132
- ['Next.js + Tailwind', 'Next.js + Tailwind bridge', '[apps/example-nextjs-tailwind](https://github.com/facebook/astryx/tree/main/apps/example-nextjs-tailwind)'],
133
- ['Next.js Source', 'Next.js importing from source', '[apps/example-nextjs-source](https://github.com/facebook/astryx/tree/main/apps/example-nextjs-source)'],
134
- ['Vite', 'Vite', '[apps/example-vite](https://github.com/facebook/astryx/tree/main/apps/example-vite)'],
130
+ ['Next.js', 'Next.js + theme CSS', 'apps/example-nextjs'],
131
+ ['Next.js + StyleX', 'Next.js + StyleX for custom styles', 'apps/example-nextjs-stylex'],
132
+ ['Next.js + Tailwind', 'Next.js + Tailwind bridge', 'apps/example-nextjs-tailwind'],
133
+ ['Next.js Source', 'Next.js importing from source', 'apps/example-nextjs-source'],
134
+ ['Vite', 'Vite', 'apps/example-vite'],
135
135
  ],
136
136
  },
137
137
  {
138
138
  type: 'code',
139
139
  lang: 'bash',
140
140
  label: 'Clone and run an example',
141
- code: `git clone https://github.com/facebook/astryx.git
142
- cd astryx/apps/example-nextjs
141
+ code: `git clone https://github.com/facebookexperimental/xds.git
142
+ cd xds/apps/example-nextjs
143
143
  pnpm install
144
144
  pnpm dev`,
145
145
  },
@@ -157,7 +157,7 @@ pnpm dev`,
157
157
  lang: 'json',
158
158
  label: 'package.json',
159
159
  code: `"scripts": {
160
- "astryx": "node node_modules/@astryxdesign/cli/bin/astryx.mjs"
160
+ "xds": "node node_modules/@astryxdesign/cli/bin/astryx.mjs"
161
161
  }`,
162
162
  },
163
163
  {
@@ -22,8 +22,9 @@ export const docs = {
22
22
  type: 'table',
23
23
  headers: ['Approach', 'Use for', 'Example'],
24
24
  rows: [
25
- ['StyleX', 'Component-specific overrides, reusable styles, pseudo-classes, and typed tokens', 'const styles = stylex.create(...); <Button xstyle={styles.save} />'],
25
+ ['xstyle prop', 'Overriding a specific component', 'xstyle={styles.override}'],
26
26
  ['Tailwind utilities', 'Layout, wrappers, and utility styling', 'className="flex gap-3 p-4"'],
27
+ ['stylex.create', 'Reusable styles, pseudo-classes, typed tokens', 'stylex.create({ card: { ... } })'],
27
28
  ['className', 'Integrating with external CSS or Tailwind on components', 'className="my-card shadow-lg"'],
28
29
  ['Styling-library token aliases', 'Keeping Panda, Chakra, MUI, Emotion, styled-components, UnoCSS, CSS Modules, or Sass in sync with the system', "colors.surface = 'var(--color-background-surface)'"],
29
30
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/cli",
3
- "version": "0.1.0-canary.86d9762",
3
+ "version": "0.1.0-canary.a95a267",
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",
@@ -54,9 +54,9 @@
54
54
  "jscodeshift": "^17.3.0"
55
55
  },
56
56
  "peerDependencies": {
57
- "@astryxdesign/core": "0.1.0-canary.86d9762",
58
- "@astryxdesign/lab": "0.1.0-canary.86d9762",
59
- "@astryxdesign/theme-neutral": "0.1.0-canary.86d9762"
57
+ "@astryxdesign/core": "0.1.0-canary.a95a267",
58
+ "@astryxdesign/lab": "0.1.0-canary.a95a267",
59
+ "@astryxdesign/theme-neutral": "0.1.0-canary.a95a267"
60
60
  },
61
61
  "peerDependenciesMeta": {
62
62
  "@astryxdesign/core": {
@@ -70,9 +70,9 @@
70
70
  }
71
71
  },
72
72
  "devDependencies": {
73
- "@astryxdesign/core": "0.1.0-canary.86d9762",
74
- "@astryxdesign/lab": "0.1.0-canary.86d9762",
75
- "@astryxdesign/theme-neutral": "0.1.0-canary.86d9762"
73
+ "@astryxdesign/core": "0.1.0-canary.a95a267",
74
+ "@astryxdesign/lab": "0.1.0-canary.a95a267",
75
+ "@astryxdesign/theme-neutral": "0.1.0-canary.a95a267"
76
76
  },
77
77
  "scripts": {
78
78
  "astryx": "node bin/astryx.mjs",
@@ -355,8 +355,8 @@ export function checkAgentDocs(ctx) {
355
355
  try {
356
356
  const content = fs.readFileSync(path.join(ctx.cwd, rel), 'utf-8');
357
357
  return (
358
- (content.includes('<!-- ASTRYX:START -->') || content.includes('<!-- XDS:START -->')) &&
359
- (content.includes('<!-- ASTRYX:END -->') || content.includes('<!-- XDS:END -->'))
358
+ content.includes('<!-- XDS:START -->') &&
359
+ content.includes('<!-- XDS:END -->')
360
360
  );
361
361
  } catch {
362
362
  return false;
@@ -368,7 +368,7 @@ export function checkAgentDocs(ctx) {
368
368
  id: 'agent-docs',
369
369
  label: 'AI agent docs',
370
370
  status: 'warn',
371
- message: `Agent docs present (${present.join(', ')}) but no Astryx section markers found.`,
371
+ message: `Agent docs present (${present.join(', ')}) but no XDS section markers found.`,
372
372
  fix: 'Add the XDS section to your agent docs with `astryx init --features agents`.',
373
373
  };
374
374
  }
@@ -31,11 +31,8 @@ const AGENTS_MD = 'AGENTS.md';
31
31
  const CLAUDE_MD = 'CLAUDE.md';
32
32
  const CLAUDE_DIR_MD = path.join('.claude', 'CLAUDE.md');
33
33
 
34
- const MARKER_START = '<!-- ASTRYX:START -->';
35
- const MARKER_END = '<!-- ASTRYX:END -->';
36
- // Legacy markers — read during migration so the script finds existing XDS blocks
37
- const LEGACY_MARKER_START = '<!-- XDS:START -->';
38
- const LEGACY_MARKER_END = '<!-- XDS:END -->';
34
+ const XDS_MARKER_START = '<!-- XDS:START -->';
35
+ const XDS_MARKER_END = '<!-- XDS:END -->';
39
36
 
40
37
  /**
41
38
  * Agent tool presets — maps tool names to their file search paths.
@@ -102,7 +99,7 @@ export function resolveAgentPaths(targetDir, agent) {
102
99
  */
103
100
  export function generateCompressedIndex(version, {coreDir, runPrefix = getRunPrefix()} = {}) {
104
101
  const run = `${runPrefix} astryx`;
105
- const lines = [MARKER_START];
102
+ const lines = [XDS_MARKER_START];
106
103
 
107
104
  // Component count from live discovery
108
105
  let componentCount = '90+';
@@ -180,7 +177,7 @@ export function generateCompressedIndex(version, {coreDir, runPrefix = getRunPre
180
177
  lines.push(`${run} swizzle <Name> eject source (--gap to report why)`);
181
178
  lines.push(`${run} upgrade --apply codemods after version bump`);
182
179
  lines.push(`after @astryxdesign/core bump, always run ${run} upgrade --apply`);
183
- lines.push(MARKER_END);
180
+ lines.push(XDS_MARKER_END);
184
181
 
185
182
  return lines.join('\n');
186
183
  }
@@ -221,21 +218,14 @@ export function injectXdsBlock(filePath, compressedIndex, {createIfMissing = fal
221
218
  if (fs.existsSync(filePath)) {
222
219
  content = fs.readFileSync(filePath, 'utf-8');
223
220
 
224
- // Find existing section — try new markers first, fall back to legacy XDS markers
225
- let startIdx = content.indexOf(MARKER_START);
226
- let endIdx = content.indexOf(MARKER_END);
227
- let markerEndLength = MARKER_END.length;
228
- if (startIdx === -1) {
229
- startIdx = content.indexOf(LEGACY_MARKER_START);
230
- endIdx = content.indexOf(LEGACY_MARKER_END);
231
- markerEndLength = LEGACY_MARKER_END.length;
232
- }
221
+ const startIdx = content.indexOf(XDS_MARKER_START);
222
+ const endIdx = content.indexOf(XDS_MARKER_END);
233
223
 
234
224
  if (startIdx !== -1 && endIdx !== -1) {
235
225
  content =
236
226
  content.slice(0, startIdx) +
237
227
  compressedIndex +
238
- content.slice(endIdx + markerEndLength);
228
+ content.slice(endIdx + XDS_MARKER_END.length);
239
229
  } else if (onlyReplace) {
240
230
  // File exists but has no Astryx markers — skip it
241
231
  return false;
@@ -287,20 +277,13 @@ export function removeXdsBlock(filePath, {deleteIfEmpty = false} = {}) {
287
277
  if (!fs.existsSync(filePath)) return false;
288
278
 
289
279
  let content = fs.readFileSync(filePath, 'utf-8');
290
- // Find existing section — try new markers first, fall back to legacy
291
- let startIdx = content.indexOf(MARKER_START);
292
- let endIdx = content.indexOf(MARKER_END);
293
- let markerEndLen = MARKER_END.length;
294
- if (startIdx === -1) {
295
- startIdx = content.indexOf(LEGACY_MARKER_START);
296
- endIdx = content.indexOf(LEGACY_MARKER_END);
297
- markerEndLen = LEGACY_MARKER_END.length;
298
- }
280
+ const startIdx = content.indexOf(XDS_MARKER_START);
281
+ const endIdx = content.indexOf(XDS_MARKER_END);
299
282
 
300
283
  if (startIdx === -1 || endIdx === -1) return false;
301
284
 
302
285
  const before = content.slice(0, startIdx).trimEnd();
303
- const after = content.slice(endIdx + markerEndLen).trimStart();
286
+ const after = content.slice(endIdx + XDS_MARKER_END.length).trimStart();
304
287
  content = before + (after ? '\n\n' + after : '') + '\n';
305
288
 
306
289
  if (deleteIfEmpty) {
@@ -32,8 +32,8 @@ describe('generateCompressedIndex', () => {
32
32
  it('includes the version number', () => {
33
33
  const result = generateCompressedIndex('1.2.3');
34
34
  expect(result).toContain('Astryx v1.2.3');
35
- expect(result).toContain('<!-- ASTRYX:START -->');
36
- expect(result).toContain('<!-- ASTRYX:END -->');
35
+ expect(result).toContain('<!-- XDS:START -->');
36
+ expect(result).toContain('<!-- XDS:END -->');
37
37
  });
38
38
 
39
39
  it('includes theme nudge rule', () => {
@@ -82,19 +82,19 @@ describe('injectXdsBlock', () => {
82
82
  const filePath = path.join(tmpDir, 'test.md');
83
83
  fs.writeFileSync(filePath, '# Existing content\n');
84
84
 
85
- const result = injectXdsBlock(filePath, '<!-- ASTRYX:START -->\nnew\n<!-- ASTRYX:END -->');
85
+ const result = injectXdsBlock(filePath, '<!-- XDS:START -->\nnew\n<!-- XDS:END -->');
86
86
 
87
87
  expect(result).toBe(true);
88
88
  const content = fs.readFileSync(filePath, 'utf-8');
89
89
  expect(content).toContain('# Existing content');
90
- expect(content).toContain('<!-- ASTRYX:START -->');
90
+ expect(content).toContain('<!-- XDS:START -->');
91
91
  });
92
92
 
93
93
  it('replaces existing markers', () => {
94
94
  const filePath = path.join(tmpDir, 'test.md');
95
95
  fs.writeFileSync(filePath, 'before\n<!-- XDS:START -->\nold\n<!-- XDS:END -->\nafter\n');
96
96
 
97
- injectXdsBlock(filePath, '<!-- ASTRYX:START -->\nnew\n<!-- ASTRYX:END -->');
97
+ injectXdsBlock(filePath, '<!-- XDS:START -->\nnew\n<!-- XDS:END -->');
98
98
 
99
99
  const content = fs.readFileSync(filePath, 'utf-8');
100
100
  expect(content).toContain('new');
@@ -106,7 +106,7 @@ describe('injectXdsBlock', () => {
106
106
  it('returns false and does not create file when createIfMissing is false', () => {
107
107
  const filePath = path.join(tmpDir, 'nonexistent.md');
108
108
 
109
- const result = injectXdsBlock(filePath, '<!-- ASTRYX:START -->\ncontent\n<!-- ASTRYX:END -->');
109
+ const result = injectXdsBlock(filePath, '<!-- XDS:START -->\ncontent\n<!-- XDS:END -->');
110
110
 
111
111
  expect(result).toBe(false);
112
112
  expect(fs.existsSync(filePath)).toBe(false);
@@ -116,11 +116,11 @@ describe('injectXdsBlock', () => {
116
116
  const filePath = path.join(tmpDir, 'test.md');
117
117
  fs.writeFileSync(filePath, '# Existing content\n\nNo XDS markers here.\n');
118
118
 
119
- const result = injectXdsBlock(filePath, '<!-- ASTRYX:START -->\nnew\n<!-- ASTRYX:END -->', {onlyReplace: true});
119
+ const result = injectXdsBlock(filePath, '<!-- XDS:START -->\nnew\n<!-- XDS:END -->', {onlyReplace: true});
120
120
 
121
121
  expect(result).toBe(false);
122
122
  const content = fs.readFileSync(filePath, 'utf-8');
123
- expect(content).not.toContain('<!-- ASTRYX:START -->');
123
+ expect(content).not.toContain('<!-- XDS:START -->');
124
124
  expect(content).toBe('# Existing content\n\nNo XDS markers here.\n');
125
125
  });
126
126
 
@@ -128,7 +128,7 @@ describe('injectXdsBlock', () => {
128
128
  const filePath = path.join(tmpDir, 'test.md');
129
129
  fs.writeFileSync(filePath, 'before\n<!-- XDS:START -->\nold\n<!-- XDS:END -->\nafter\n');
130
130
 
131
- const result = injectXdsBlock(filePath, '<!-- ASTRYX:START -->\nnew\n<!-- ASTRYX:END -->', {onlyReplace: true});
131
+ const result = injectXdsBlock(filePath, '<!-- XDS:START -->\nnew\n<!-- XDS:END -->', {onlyReplace: true});
132
132
 
133
133
  expect(result).toBe(true);
134
134
  const content = fs.readFileSync(filePath, 'utf-8');
@@ -139,7 +139,7 @@ describe('injectXdsBlock', () => {
139
139
  it('creates file when createIfMissing is true', () => {
140
140
  const filePath = path.join(tmpDir, 'new.md');
141
141
 
142
- const result = injectXdsBlock(filePath, '<!-- ASTRYX:START -->\ncontent\n<!-- ASTRYX:END -->', {
142
+ const result = injectXdsBlock(filePath, '<!-- XDS:START -->\ncontent\n<!-- XDS:END -->', {
143
143
  createIfMissing: true,
144
144
  header: '# Header',
145
145
  });
@@ -147,7 +147,7 @@ describe('injectXdsBlock', () => {
147
147
  expect(result).toBe(true);
148
148
  const content = fs.readFileSync(filePath, 'utf-8');
149
149
  expect(content).toContain('# Header');
150
- expect(content).toContain('<!-- ASTRYX:START -->');
150
+ expect(content).toContain('<!-- XDS:START -->');
151
151
  });
152
152
  });
153
153
 
@@ -157,9 +157,9 @@ describe('injectAgentsMd', () => {
157
157
 
158
158
  const content = fs.readFileSync(path.join(tmpDir, 'AGENTS.md'), 'utf-8');
159
159
  expect(content).toContain('# AGENTS.md');
160
- expect(content).toContain('<!-- ASTRYX:START -->');
160
+ expect(content).toContain('<!-- XDS:START -->');
161
161
  expect(content).toContain('Astryx v1.0.0');
162
- expect(content).toContain('<!-- ASTRYX:END -->');
162
+ expect(content).toContain('<!-- XDS:END -->');
163
163
  });
164
164
 
165
165
  it('updates existing AGENTS.md by replacing XDS markers', () => {
@@ -195,7 +195,7 @@ Existing agent docs.
195
195
 
196
196
  const content = fs.readFileSync(path.join(tmpDir, 'AGENTS.md'), 'utf-8');
197
197
  expect(content).toContain('Existing agent docs.');
198
- expect(content).toContain('<!-- ASTRYX:START -->');
198
+ expect(content).toContain('<!-- XDS:START -->');
199
199
  expect(content).toContain('Astryx v1.0.0');
200
200
  });
201
201
  });
@@ -210,7 +210,7 @@ describe('injectClaudeMd', () => {
210
210
  const content = fs.readFileSync(path.join(tmpDir, 'CLAUDE.md'), 'utf-8');
211
211
  expect(content).toContain('# Claude Config');
212
212
  expect(content).toContain('Existing rules.');
213
- expect(content).toContain('<!-- ASTRYX:START -->');
213
+ expect(content).toContain('<!-- XDS:START -->');
214
214
  expect(content).toContain('Astryx v1.0.0');
215
215
  });
216
216
 
@@ -322,7 +322,7 @@ describe('installAgentDocs', () => {
322
322
  expect(fs.existsSync(path.join(tmpDir, '.claude', 'CLAUDE.md'))).toBe(true);
323
323
  expect(fs.existsSync(path.join(tmpDir, 'AGENTS.md'))).toBe(false);
324
324
  const content = fs.readFileSync(path.join(tmpDir, '.claude', 'CLAUDE.md'), 'utf-8');
325
- expect(content).toContain('<!-- ASTRYX:START -->');
325
+ expect(content).toContain('<!-- XDS:START -->');
326
326
  });
327
327
 
328
328
  it('injects into CLAUDE.md at root when it exists', () => {
@@ -334,7 +334,7 @@ describe('installAgentDocs', () => {
334
334
  expect(written).toEqual(['CLAUDE.md']);
335
335
  expect(fs.existsSync(path.join(tmpDir, 'AGENTS.md'))).toBe(false);
336
336
  const claudeContent = fs.readFileSync(path.join(tmpDir, 'CLAUDE.md'), 'utf-8');
337
- expect(claudeContent).toContain('<!-- ASTRYX:START -->');
337
+ expect(claudeContent).toContain('<!-- XDS:START -->');
338
338
  expect(claudeContent).toContain('Project rules.');
339
339
  });
340
340
 
@@ -349,8 +349,8 @@ describe('installAgentDocs', () => {
349
349
  expect(written).toContain('CLAUDE.md');
350
350
  const agentsContent = fs.readFileSync(path.join(tmpDir, 'AGENTS.md'), 'utf-8');
351
351
  const claudeContent = fs.readFileSync(path.join(tmpDir, 'CLAUDE.md'), 'utf-8');
352
- expect(agentsContent).toContain('<!-- ASTRYX:START -->');
353
- expect(claudeContent).toContain('<!-- ASTRYX:START -->');
352
+ expect(agentsContent).toContain('<!-- XDS:START -->');
353
+ expect(claudeContent).toContain('<!-- XDS:START -->');
354
354
  });
355
355
 
356
356
  it('updates existing .claude/CLAUDE.md', () => {
@@ -363,7 +363,7 @@ describe('installAgentDocs', () => {
363
363
  expect(written).toEqual(['.claude/CLAUDE.md']);
364
364
  const content = fs.readFileSync(path.join(tmpDir, '.claude', 'CLAUDE.md'), 'utf-8');
365
365
  expect(content).toContain('Existing content.');
366
- expect(content).toContain('<!-- ASTRYX:START -->');
366
+ expect(content).toContain('<!-- XDS:START -->');
367
367
  });
368
368
 
369
369
  it('respects --agent claude preset: finds existing CLAUDE.md', () => {
@@ -410,7 +410,7 @@ describe('installAgentDocs', () => {
410
410
 
411
411
  expect(written).toEqual([]);
412
412
  const content = fs.readFileSync(path.join(tmpDir, 'CLAUDE.md'), 'utf-8');
413
- expect(content).not.toContain('<!-- ASTRYX:START -->');
413
+ expect(content).not.toContain('<!-- XDS:START -->');
414
414
  expect(content).toBe('# Claude\n\nProject rules only.\n');
415
415
  });
416
416
 
@@ -248,7 +248,7 @@ export function registerInit(program) {
248
248
  humanLog(' 2. Optionally add a theme:');
249
249
  humanLog(" import { neutralTheme } from '@astryxdesign/theme-neutral'");
250
250
  humanLog(' <Theme theme={neutralTheme}>...</Theme>');
251
- humanLog(` 3. ${run} astryx --help for all commands`);
251
+ humanLog(` 3. ${run} xds --help for all commands`);
252
252
  humanLog('');
253
253
  });
254
254
  }
@@ -4,7 +4,7 @@
4
4
  * @file Detect the project's package manager from lockfiles.
5
5
  *
6
6
  * Returns the correct command prefix for running package binaries
7
- * (e.g. 'npx astryx', 'yarn astryx', 'pnpm exec astryx').
7
+ * (e.g. 'npx xds', 'yarn xds', 'pnpm exec xds').
8
8
  */
9
9
 
10
10
  import * as fs from 'node:fs';
@@ -3,23 +3,24 @@
3
3
  'use client';
4
4
 
5
5
  import * as stylex from '@stylexjs/stylex';
6
- import {Heading, Text} from '@astryxdesign/core/Text';
6
+ import {
7
+ SideNav,
8
+ SideNavHeading,
9
+ SideNavItem,
10
+ SideNavSection,
11
+ } from '@astryxdesign/core/SideNav';
12
+ import {Text} from '@astryxdesign/core/Text';
7
13
  import {Button} from '@astryxdesign/core/Button';
8
14
  import {Card} from '@astryxdesign/core/Card';
9
- import {ClickableCard} from '@astryxdesign/core/ClickableCard';
10
15
  import {HStack, VStack, StackItem} from '@astryxdesign/core/Stack';
11
- import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
16
+ import {Layout, LayoutContent, LayoutPanel} from '@astryxdesign/core/Layout';
12
17
  import {Grid} from '@astryxdesign/core/Grid';
13
18
  import {radiusVars} from '@astryxdesign/core/theme/tokens.stylex';
14
19
 
15
20
  const styles = stylex.create({
16
21
  previewCard: {
17
- borderRadius: radiusVars['--radius-element'],
18
- },
19
- // Negative margin offsets each card's 8px padding so the grid content stays
20
- // visually aligned while giving every card a padded hover/click target.
21
- cardGrid: {
22
- margin: -8,
22
+ borderRadius: radiusVars['--radius-container'],
23
+ cursor: 'pointer',
23
24
  },
24
25
  });
25
26
 
@@ -212,12 +213,30 @@ const COMPONENT_CATEGORIES = [
212
213
  export default function DocumentationOverviewPage() {
213
214
  return (
214
215
  <Layout
215
- height="auto"
216
+ height="fill"
216
217
  contentWidth={1200}
218
+ start={
219
+ <LayoutPanel hasDivider padding={0}>
220
+ <SideNav header={<SideNavHeading heading="Product Name" />}>
221
+ <SideNavSection title="Navigation" isHeaderHidden>
222
+ <SideNavItem label="Home" isSelected />
223
+ <SideNavItem label="Getting started" />
224
+ </SideNavSection>
225
+
226
+ {COMPONENT_CATEGORIES.map(category => (
227
+ <SideNavSection key={category.label} title={category.label}>
228
+ {category.items.map(item => (
229
+ <SideNavItem key={item.key} label={item.name} />
230
+ ))}
231
+ </SideNavSection>
232
+ ))}
233
+ </SideNav>
234
+ </LayoutPanel>
235
+ }
217
236
  content={
218
237
  <LayoutContent padding={8}>
219
238
  <VStack gap={10}>
220
- <Card variant="gray" padding={10}>
239
+ <Card variant="cyan" padding={10}>
221
240
  <HStack gap={8} vAlign="center">
222
241
  <StackItem size="fill">
223
242
  <VStack gap={4}>
@@ -227,7 +246,11 @@ export default function DocumentationOverviewPage() {
227
246
  beautiful, accessible products.
228
247
  </Text>
229
248
  <HStack>
230
- <Button label="Get started" variant="primary" size="lg" />
249
+ <Button
250
+ label="Get started"
251
+ variant="primary"
252
+ size="lg"
253
+ />
231
254
  </HStack>
232
255
  </VStack>
233
256
  </StackItem>
@@ -237,35 +260,25 @@ export default function DocumentationOverviewPage() {
237
260
 
238
261
  {COMPONENT_CATEGORIES.map(category => (
239
262
  <VStack key={category.label} gap={4}>
240
- <Heading level={2}>{category.label}</Heading>
241
- <Grid
242
- columns={{minWidth: 260}}
243
- gap={2}
244
- xstyle={styles.cardGrid}>
263
+ <Text type="display-2">{category.label}</Text>
264
+ <Grid columns={{minWidth: 260}} gap={8}>
245
265
  {category.items.map(item => (
246
- <ClickableCard
247
- key={item.key}
248
- label={`Open ${item.name}`}
249
- onClick={() => {}}
250
- variant="transparent"
251
- padding={2}>
252
- <VStack gap={3}>
253
- <Card
254
- variant="muted"
255
- padding={0}
256
- minHeight={160}
257
- xstyle={styles.previewCard}
258
- />
259
- <VStack gap={0.5}>
260
- <Text type="body" weight="bold">
261
- {item.name}
262
- </Text>
263
- <Text type="body" color="secondary" maxLines={3}>
264
- {item.desc}
265
- </Text>
266
- </VStack>
266
+ <VStack key={item.key} gap={3}>
267
+ <Card
268
+ variant="muted"
269
+ padding={0}
270
+ minHeight={160}
271
+ xstyle={styles.previewCard}
272
+ />
273
+ <VStack gap={0.5}>
274
+ <Text type="body" weight="bold">
275
+ {item.name}
276
+ </Text>
277
+ <Text type="body" color="secondary">
278
+ {item.desc}
279
+ </Text>
267
280
  </VStack>
268
- </ClickableCard>
281
+ </VStack>
269
282
  ))}
270
283
  </Grid>
271
284
  </VStack>