astryx-dracula 0.2.1 → 0.3.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 (83) hide show
  1. package/BRAND.md +30 -18
  2. package/README.md +17 -12
  3. package/USAGE.md +29 -10
  4. package/astryx-dracula.js +19 -13
  5. package/astryx-dracula.variants.d.ts +15 -0
  6. package/package.json +59 -17
  7. package/shared/auth-chrome-config.ts +18 -0
  8. package/shared/auth-chrome.tsx +25 -0
  9. package/shared/auth-copy.ts +22 -0
  10. package/shared/chaptered-doc-config.ts +92 -0
  11. package/shared/chaptered-doc.tsx +332 -0
  12. package/shared/chart-hues.ts +27 -0
  13. package/shared/chart-labels.tsx +44 -0
  14. package/shared/chart-legend.tsx +100 -0
  15. package/shared/chart-panel-style.ts +13 -0
  16. package/shared/data-bar.tsx +160 -0
  17. package/shared/gallery-image.ts +20 -0
  18. package/shared/login-demo.ts +7 -0
  19. package/shared/metric-delta.tsx +36 -0
  20. package/shared/order-desk.tsx +273 -0
  21. package/shared/revenue-chart.tsx +174 -0
  22. package/shared/scene-castle.tsx +322 -0
  23. package/shared/scene-frame.tsx +88 -0
  24. package/shared/scene-hues.ts +49 -0
  25. package/shared/scene-tile.tsx +128 -0
  26. package/shared/settings-data.ts +125 -0
  27. package/shared/settings-rows.tsx +179 -0
  28. package/shared/sparkline.tsx +94 -0
  29. package/shared/sso-icons.tsx +30 -0
  30. package/templates/ai-chat-landing.tsx +66 -33
  31. package/templates/ai-chat.tsx +36 -19
  32. package/templates/blank.tsx +4 -3
  33. package/templates/centered-hero.tsx +14 -125
  34. package/templates/classic-gallery.tsx +20 -66
  35. package/templates/contact-form.tsx +59 -39
  36. package/templates/dashboard-portfolio.tsx +143 -226
  37. package/templates/dashboard.tsx +122 -122
  38. package/templates/detail-page.tsx +95 -91
  39. package/templates/documentation-design.template.mjs +1 -1
  40. package/templates/documentation-design.tsx +83 -96
  41. package/templates/documentation-technical.template.mjs +1 -1
  42. package/templates/documentation-technical.tsx +29 -19
  43. package/templates/documentation.template.mjs +1 -1
  44. package/templates/documentation.tsx +52 -74
  45. package/templates/editor.tsx +112 -84
  46. package/templates/file-explorer.tsx +131 -84
  47. package/templates/form-two-column.tsx +61 -125
  48. package/templates/gallery-hero.tsx +15 -171
  49. package/templates/ide.tsx +22 -20
  50. package/templates/incident-console.tsx +104 -70
  51. package/templates/kanban-board.tsx +99 -42
  52. package/templates/library.template.mjs +2 -2
  53. package/templates/library.tsx +37 -42
  54. package/templates/login-card.tsx +58 -87
  55. package/templates/login-split.tsx +88 -126
  56. package/templates/login-sso.tsx +105 -64
  57. package/templates/login.tsx +107 -53
  58. package/templates/messaging-shell.tsx +171 -144
  59. package/templates/mixed-gallery.tsx +29 -130
  60. package/templates/payment-form.tsx +368 -290
  61. package/templates/product-detail.tsx +39 -58
  62. package/templates/product-gallery.tsx +30 -41
  63. package/templates/product-tour.template.mjs +6 -0
  64. package/templates/product-tour.tsx +916 -0
  65. package/templates/settings-dialog.tsx +135 -282
  66. package/templates/settings-sidebar.tsx +178 -268
  67. package/templates/settings.tsx +41 -14
  68. package/templates/shell-nav.tsx +31 -24
  69. package/templates/shell-side-nav.tsx +29 -20
  70. package/templates/shell-top-nav.tsx +80 -44
  71. package/templates/side-gallery.tsx +38 -94
  72. package/templates/table-grouped.tsx +62 -34
  73. package/templates/table-page-chart.tsx +23 -302
  74. package/templates/table-page-heatmap-status.tsx +156 -92
  75. package/templates/table-page-shoe-store-heatmap.tsx +18 -293
  76. package/templates/table-page.tsx +23 -7
  77. package/templates/table.tsx +23 -8
  78. package/templates/tech-report.template.mjs +6 -0
  79. package/templates/tech-report.tsx +1486 -0
  80. package/templates/theme-showcase.template.mjs +1 -1
  81. package/templates/theme-showcase.tsx +299 -237
  82. package/theme.css +76 -14
  83. package/tokens.css +425 -30
@@ -1,8 +1,12 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
  // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > (LP > V[g=4] > Hd"Account settings"[level=2] + (UL > LI*8) + D + LI) + (LC[p=4] > V[g=6] > Hd"Personal info"[level=2] + (V > (H[j=between a=center] > (V > Tx"Legal name" + Tx"Vlad Dracul"[t=supporting]) + Lk"Edit")*7) + (C.muted > V[g=4] > (H[g=3 a=start] > Ic + (V[g=1] > Tx"Why is info hidden" + Tx[t=supporting]))*3))
3
+ // L > (LP[p=0] > V[g=4] > Tx"Account settings"[t=label] + (UL > LI*8) + D + LI"Professional hosting tools") + (LC[p=6] > V[g=0] > (Tbar > B.ghost + Hd"Personal info"[level=1]) + Hd"Personal info"[level=1] + (V[g=0] > (H[j=between a=start] > (V[g=0] > Tx"Legal name"[weight=semibold] + Tx"Vlad Dracul"[t=supporting]) + Lk"Edit")*7) + (C.muted > V[g=4] > (H[g=3 a=start] > Ic + (V[g=1] > Tx"Why is info hidden?"[weight=semibold] + Tx[t=supporting]))*3))
4
4
 
5
- import {useState, type CSSProperties} from 'react';
5
+ /**
6
+ * Settings Panels — account sections with a nav panel and divided rows. Frame: Layout nav panel (fill) | content column of section views. One (Frame/responsive/container: see XLE header above.)
7
+ */
8
+
9
+ import {Fragment, useState, type CSSProperties} from 'react';
6
10
  import {useMediaQuery} from '@astryxdesign/core/hooks';
7
11
  import {
8
12
  VStack,
@@ -23,18 +27,12 @@ import {Card} from '@astryxdesign/core/Card';
23
27
  import {Switch} from '@astryxdesign/core/Switch';
24
28
  import {Divider} from '@astryxdesign/core/Divider';
25
29
  import {TabList, Tab} from '@astryxdesign/core/TabList';
26
- import {Badge} from '@astryxdesign/core/Badge';
30
+ import {StatusDot} from '@astryxdesign/core/StatusDot';
27
31
  import {Icon} from '@astryxdesign/core/Icon';
28
32
  import {Center} from '@astryxdesign/core/Center';
29
33
  import {
30
- User,
31
34
  Lock,
32
35
  ShieldCheck,
33
- Bell,
34
- FileText,
35
- CreditCard,
36
- Globe,
37
- Briefcase,
38
36
  Wrench,
39
37
  Monitor,
40
38
  SquarePen,
@@ -42,6 +40,9 @@ import {
42
40
  ArrowLeft,
43
41
  ChevronRight,
44
42
  } from 'lucide-react';
43
+ import {NAV_ITEMS, LOGIN_ROWS, SOCIAL_ROWS, DEVICE_ROWS, INFO_TILES, iconBox, actionNoWrap, sideNavHeading} from 'astryx-dracula/shared/settings-data';
44
+ import {InfoRowItem, ExpandableRow} from 'astryx-dracula/shared/settings-rows';
45
+ import type {InfoRow} from 'astryx-dracula/shared/settings-data';
45
46
 
46
47
  // Anchor the page to the viewport height so the sidebar + content fill the
47
48
  // screen. Layout height="fill" is min-height:100% which collapses when the
@@ -49,11 +50,6 @@ import {
49
50
  const fillViewport: CSSProperties = {
50
51
  minHeight: '100dvh',
51
52
  };
52
- const iconBox: CSSProperties = {
53
- borderRadius: 'var(--radius-container)',
54
- backgroundColor: 'var(--color-background-surface)',
55
- flexShrink: 0,
56
- };
57
53
  const rowPadding: CSSProperties = {
58
54
  paddingBlock: 'var(--spacing-4)',
59
55
  };
@@ -61,25 +57,15 @@ const sideNavPadding: CSSProperties = {
61
57
  paddingBlock: 'var(--spacing-4)',
62
58
  paddingInline: 'var(--spacing-3)',
63
59
  };
64
- const sideNavHeading: CSSProperties = {
65
- marginInline: 'var(--spacing-4)',
66
- };
67
60
 
68
- const NAV_ITEMS = [
69
- {label: 'Personal information', icon: User},
70
- {label: 'Login & security', icon: Lock},
71
- {label: 'Privacy', icon: ShieldCheck},
72
- {label: 'Notifications', icon: Bell},
73
- {label: 'Taxes', icon: FileText},
74
- {label: 'Payments', icon: CreditCard},
75
- {label: 'Languages & currency', icon: Globe},
76
- {label: 'Travel for work', icon: Briefcase},
77
- ];
61
+ // Same-route hash: demo links stay focusable anchors without escaping the
62
+ // template through the hash router (bare "#" would drop back to the home page).
63
+ const SELF_HASH = '#/templates/settings-sidebar';
78
64
 
79
65
  // Section title shown beside the mobile back button (matches each section's
80
66
  // in-content heading, which is hidden on mobile to avoid a duplicate).
81
67
  const SECTION_TITLES: Record<string, string> = {
82
- 'Personal information': 'Personal info',
68
+ 'Personal information': 'Personal information',
83
69
  'Login & security': 'Login & security',
84
70
  Privacy: 'Privacy',
85
71
  Notifications: 'Notifications',
@@ -90,124 +76,16 @@ const SECTION_TITLES: Record<string, string> = {
90
76
  'Professional hosting tools': 'Hosting tools',
91
77
  };
92
78
 
93
- interface InfoRow {
94
- label: string;
95
- value: string;
96
- action: string;
97
- }
98
-
99
- const LOGIN_ROWS: InfoRow[] = [
100
- {label: 'Password', value: 'Not created', action: 'Create'},
101
- ];
102
-
103
- const SOCIAL_ROWS: InfoRow[] = [
104
- {label: 'Google', value: 'Connected', action: 'Disconnect'},
105
- ];
106
-
107
79
  const TAX_ROWS: InfoRow[] = [
108
- {label: 'Taxpayer information', value: 'Not provided', action: 'Add'},
109
- {label: 'Tax documents', value: 'No documents yet', action: 'View'},
80
+ {label: 'Tax scrolls', value: 'Not provided', action: 'Add'},
81
+ {label: 'Past scrolls', value: 'No scrolls yet', action: 'View'},
110
82
  ];
111
83
 
112
84
  const PAYOUT_ROWS: InfoRow[] = [
113
- {label: 'Payout method', value: 'Not set up', action: 'Add'},
114
- {label: 'Past payments', value: 'No payments yet', action: 'View'},
115
- ];
116
-
117
- const DEVICE_ROWS: {
118
- label: string;
119
- badge?: string;
120
- location: string;
121
- action?: string;
122
- }[] = [
123
- {
124
- label: 'OS X 10.15.7 · Chrome',
125
- badge: 'CURRENT SESSION',
126
- location: 'Brașov, Transylvania · March 30, 2026 at 19:31',
127
- },
128
- {label: 'Session', location: 'August 9, 2023 at 04:19', action: 'Log out'},
129
- {
130
- label: 'OS X 10.15.7 · unknown',
131
- location: 'Whitby, England · April 14, 2023 at 17:47',
132
- action: 'Log out',
133
- },
85
+ {label: 'Payout crypt', value: 'Not set up', action: 'Add'},
86
+ {label: 'Past payouts', value: 'No tributes yet', action: 'View'},
134
87
  ];
135
88
 
136
- function InfoRowItem({label, value, action}: InfoRow) {
137
- return (
138
- <>
139
- <HStack hAlign="between" vAlign="start" style={rowPadding}>
140
- <VStack gap={0}>
141
- <Text type="body" weight="semibold" display="block">
142
- {label}
143
- </Text>
144
- <Text type="supporting" color="secondary" display="block">
145
- {value}
146
- </Text>
147
- </VStack>
148
- {action && <Link href="#/templates/settings-sidebar">{action}</Link>}
149
- </HStack>
150
- <Divider />
151
- </>
152
- );
153
- }
154
-
155
- interface ExpandableRowProps {
156
- label: string;
157
- value: string;
158
- children: React.ReactNode;
159
- isExpanded: boolean;
160
- onEdit: () => void;
161
- onCancel: () => void;
162
- onSave: () => void;
163
- }
164
-
165
- function ExpandableRow({
166
- label,
167
- value,
168
- children,
169
- isExpanded,
170
- onEdit,
171
- onCancel,
172
- onSave,
173
- }: ExpandableRowProps) {
174
- return (
175
- <>
176
- {isExpanded ? (
177
- <VStack gap={4} style={rowPadding}>
178
- <Text type="body" weight="semibold" display="block">
179
- {label}
180
- </Text>
181
- {children}
182
- <HStack gap={2}>
183
- <Button label="Save" variant="primary" onClick={onSave} />
184
- <Button label="Cancel" variant="ghost" onClick={onCancel} />
185
- </HStack>
186
- </VStack>
187
- ) : (
188
- <HStack hAlign="between" vAlign="start" style={rowPadding}>
189
- <VStack gap={0}>
190
- <Text type="body" weight="semibold" display="block">
191
- {label}
192
- </Text>
193
- <Text type="supporting" color="secondary" display="block">
194
- {value}
195
- </Text>
196
- </VStack>
197
- <Link
198
- href="#/templates/settings-sidebar"
199
- onClick={(e: React.MouseEvent) => {
200
- e.preventDefault();
201
- onEdit();
202
- }}>
203
- Edit
204
- </Link>
205
- </HStack>
206
- )}
207
- <Divider />
208
- </>
209
- );
210
- }
211
89
 
212
90
  const LANGUAGES = [
213
91
  {label: 'English (Canada)', value: 'en-CA'},
@@ -274,9 +152,9 @@ export default function SettingsSidebar() {
274
152
 
275
153
  const navList = (
276
154
  <VStack gap={4} style={sideNavPadding}>
277
- <Heading level={2} style={sideNavHeading}>
155
+ <Text type="label" style={sideNavHeading}>
278
156
  Account settings
279
- </Heading>
157
+ </Text>
280
158
  <List density="spacious">
281
159
  {NAV_ITEMS.map(item => (
282
160
  <ListItem
@@ -298,7 +176,6 @@ export default function SettingsSidebar() {
298
176
  <ListItem
299
177
  label="Professional hosting tools"
300
178
  startContent={<Icon icon={Wrench} />}
301
- onClick={() => {}}
302
179
  />
303
180
  </List>
304
181
  </VStack>
@@ -310,7 +187,14 @@ export default function SettingsSidebar() {
310
187
  <Layout
311
188
  height="fill"
312
189
  style={fillViewport}
313
- content={<LayoutContent padding={2}>{navList}</LayoutContent>}
190
+ // padding={0}, not padding={2}. This wraps the SAME navList element
191
+ // the desktop LayoutPanel renders with padding={0}, and sideNavPadding
192
+ // already supplies the list's 12px inline inset. The extra 8px here is
193
+ // what made the same nav list measure 20px on mobile against 12px on
194
+ // desktop -- and against 24px further down, so the two mobile states
195
+ // disagreed with each other too. The container owns no gutter; the
196
+ // list owns its own.
197
+ content={<LayoutContent padding={0}>{navList}</LayoutContent>}
314
198
  />
315
199
  );
316
200
  }
@@ -328,7 +212,7 @@ export default function SettingsSidebar() {
328
212
  )
329
213
  }
330
214
  content={
331
- <LayoutContent padding={4}>
215
+ <LayoutContent padding={6}>
332
216
  <VStack gap={0}>
333
217
  {/* Mobile detail view: a back button sits beside the section title
334
218
  (the per-section headings below are hidden on mobile). Toolbar's
@@ -336,7 +220,7 @@ export default function SettingsSidebar() {
336
220
  flush with the content edge. */}
337
221
  {isNarrow && (
338
222
  <Toolbar
339
- label={`Back to Account settings — ${SECTION_TITLES[activeNav]}`}
223
+ label={`Back to Account settings: ${SECTION_TITLES[activeNav]}`}
340
224
  gap={2}
341
225
  startContent={
342
226
  <>
@@ -348,14 +232,14 @@ export default function SettingsSidebar() {
348
232
  icon={<Icon icon={ArrowLeft} size="sm" />}
349
233
  onClick={() => setMobileView('nav')}
350
234
  />
351
- <Heading level={2}>{SECTION_TITLES[activeNav]}</Heading>
235
+ <Heading level={1}>{SECTION_TITLES[activeNav]}</Heading>
352
236
  </>
353
237
  }
354
238
  />
355
239
  )}
356
240
  {activeNav === 'Login & security' && (
357
241
  <VStack gap={6}>
358
- {!isNarrow && <Heading level={2}>Login &amp; security</Heading>}
242
+ {!isNarrow && <Heading level={1}>Login &amp; security</Heading>}
359
243
 
360
244
  <TabList value={activeTab} onChange={setActiveTab} hasDivider>
361
245
  <Tab value="login" label="Login" />
@@ -365,38 +249,60 @@ export default function SettingsSidebar() {
365
249
  {activeTab === 'login' && (
366
250
  <VStack gap={8}>
367
251
  <VStack gap={0}>
368
- <Heading level={3}>Login</Heading>
252
+ <Heading level={2}>Login</Heading>
369
253
  <Divider />
370
254
  {LOGIN_ROWS.map(row => (
371
- <InfoRowItem key={row.label} {...row} />
255
+ <InfoRowItem
256
+ key={row.label}
257
+ {...row}
258
+ href={SELF_HASH}
259
+ style={rowPadding}
260
+ />
372
261
  ))}
373
262
  </VStack>
374
263
 
375
264
  <VStack gap={0}>
376
- <Heading level={3}>Social accounts</Heading>
265
+ <Heading level={2}>Social accounts</Heading>
377
266
  <Divider />
378
267
  {SOCIAL_ROWS.map(row => (
379
- <InfoRowItem key={row.label} {...row} />
268
+ <InfoRowItem
269
+ key={row.label}
270
+ {...row}
271
+ href={SELF_HASH}
272
+ style={rowPadding}
273
+ />
380
274
  ))}
381
275
  </VStack>
382
276
 
383
277
  <VStack gap={0}>
384
- <Heading level={3}>Device history</Heading>
278
+ <Heading level={2}>Device history</Heading>
385
279
  <Divider />
386
- {DEVICE_ROWS.map((device, i) => (
280
+ {DEVICE_ROWS.map((device) => (
387
281
  <HStack
388
- key={i}
282
+ key={device.location}
389
283
  gap={3}
390
284
  vAlign="start"
391
285
  style={rowPadding}>
392
286
  <Icon icon={Monitor} />
393
287
  <StackItem size="fill">
394
288
  <VStack gap={0}>
395
- <HStack gap={2} vAlign="center">
289
+ {/* wrap: the label plus the session status
290
+ exceed the content width on a phone. */}
291
+ <HStack gap={2} vAlign="center" wrap="wrap">
396
292
  <Text type="body" weight="semibold">
397
293
  {device.label}
398
294
  </Text>
399
- {device.badge && <Badge label={device.badge} />}
295
+ {device.isCurrent && (
296
+ <HStack gap={1} vAlign="center">
297
+ <StatusDot
298
+ variant="success"
299
+ label="Current session"
300
+ />
301
+ <Text type="supporting" color="secondary">
302
+ Current session
303
+ </Text>
304
+ </HStack>
305
+ )}
400
306
  </HStack>
401
307
  <Text
402
308
  type="supporting"
@@ -408,7 +314,9 @@ export default function SettingsSidebar() {
408
314
  </VStack>
409
315
  </StackItem>
410
316
  {device.action && (
411
- <Link href="#/templates/settings-sidebar">{device.action}</Link>
317
+ <Link href={SELF_HASH} style={actionNoWrap}>
318
+ {device.action}
319
+ </Link>
412
320
  )}
413
321
  </HStack>
414
322
  ))}
@@ -416,7 +324,7 @@ export default function SettingsSidebar() {
416
324
  </VStack>
417
325
 
418
326
  <VStack gap={0}>
419
- <Heading level={3}>Account</Heading>
327
+ <Heading level={2}>Account</Heading>
420
328
  <Divider />
421
329
  <HStack
422
330
  hAlign="between"
@@ -433,7 +341,9 @@ export default function SettingsSidebar() {
433
341
  This action cannot be undone
434
342
  </Text>
435
343
  </VStack>
436
- <Link href="#/templates/settings-sidebar">Deactivate</Link>
344
+ <Link href={SELF_HASH} style={actionNoWrap}>
345
+ Deactivate
346
+ </Link>
437
347
  </HStack>
438
348
  <Divider />
439
349
  </VStack>
@@ -443,12 +353,12 @@ export default function SettingsSidebar() {
443
353
  {activeTab === 'shared' && (
444
354
  <VStack gap={8}>
445
355
  <VStack gap={2}>
446
- <Heading level={3}>Shared access</Heading>
356
+ <Heading level={2}>Shared access</Heading>
447
357
  <Divider />
448
358
  <Text type="body" color="secondary">
449
359
  Review each request carefully before approving access.
450
- We&apos;ll email your employee or co-worker a 4-digit
451
- code that lets them log into your account with their
360
+ We&apos;ll email your kin or coven-mate a 4-digit
361
+ code that lets them enter your crypt from their
452
362
  trusted device.
453
363
  </Text>
454
364
  </VStack>
@@ -459,7 +369,7 @@ export default function SettingsSidebar() {
459
369
  <Icon icon={Lock} />
460
370
  </Center>
461
371
  <VStack gap={1}>
462
- <Text type="body" weight="bold">
372
+ <Text type="body">
463
373
  Adding devices from people you trust
464
374
  </Text>
465
375
  <Text type="body" color="secondary">
@@ -479,7 +389,7 @@ export default function SettingsSidebar() {
479
389
  {activeNav === 'Languages & currency' && (
480
390
  <VStack gap={6}>
481
391
  {!isNarrow && (
482
- <Heading level={2}>Languages &amp; currency</Heading>
392
+ <Heading level={1}>Languages &amp; currency</Heading>
483
393
  )}
484
394
  <VStack gap={0}>
485
395
  <ExpandableRow
@@ -491,7 +401,9 @@ export default function SettingsSidebar() {
491
401
  isExpanded={expandedRow === 'language'}
492
402
  onEdit={() => setExpandedRow('language')}
493
403
  onCancel={() => setExpandedRow(null)}
494
- onSave={() => setExpandedRow(null)}>
404
+ onSave={() => setExpandedRow(null)}
405
+ href={SELF_HASH}
406
+ style={rowPadding}>
495
407
  <Selector
496
408
  label="Language"
497
409
  isLabelHidden
@@ -510,7 +422,9 @@ export default function SettingsSidebar() {
510
422
  isExpanded={expandedRow === 'currency'}
511
423
  onEdit={() => setExpandedRow('currency')}
512
424
  onCancel={() => setExpandedRow(null)}
513
- onSave={() => setExpandedRow(null)}>
425
+ onSave={() => setExpandedRow(null)}
426
+ href={SELF_HASH}
427
+ style={rowPadding}>
514
428
  <Selector
515
429
  label="Currency"
516
430
  isLabelHidden
@@ -529,7 +443,9 @@ export default function SettingsSidebar() {
529
443
  isExpanded={expandedRow === 'timezone'}
530
444
  onEdit={() => setExpandedRow('timezone')}
531
445
  onCancel={() => setExpandedRow(null)}
532
- onSave={() => setExpandedRow(null)}>
446
+ onSave={() => setExpandedRow(null)}
447
+ href={SELF_HASH}
448
+ style={rowPadding}>
533
449
  <Selector
534
450
  label="Time zone"
535
451
  isLabelHidden
@@ -545,7 +461,9 @@ export default function SettingsSidebar() {
545
461
 
546
462
  {activeNav === 'Personal information' && (
547
463
  <VStack gap={6}>
548
- {!isNarrow && <Heading level={2}>Personal info</Heading>}
464
+ {!isNarrow && (
465
+ <Heading level={1}>Personal information</Heading>
466
+ )}
549
467
  <VStack gap={0}>
550
468
  <ExpandableRow
551
469
  label="Legal name"
@@ -553,7 +471,9 @@ export default function SettingsSidebar() {
553
471
  isExpanded={expandedRow === 'legalName'}
554
472
  onEdit={() => setExpandedRow('legalName')}
555
473
  onCancel={() => setExpandedRow(null)}
556
- onSave={() => setExpandedRow(null)}>
474
+ onSave={() => setExpandedRow(null)}
475
+ href={SELF_HASH}
476
+ style={rowPadding}>
557
477
  <TextInput
558
478
  label="Legal name"
559
479
  isLabelHidden
@@ -567,7 +487,9 @@ export default function SettingsSidebar() {
567
487
  isExpanded={expandedRow === 'preferredName'}
568
488
  onEdit={() => setExpandedRow('preferredName')}
569
489
  onCancel={() => setExpandedRow(null)}
570
- onSave={() => setExpandedRow(null)}>
490
+ onSave={() => setExpandedRow(null)}
491
+ href={SELF_HASH}
492
+ style={rowPadding}>
571
493
  <TextInput
572
494
  label="Preferred first name"
573
495
  isLabelHidden
@@ -581,7 +503,9 @@ export default function SettingsSidebar() {
581
503
  isExpanded={expandedRow === 'email'}
582
504
  onEdit={() => setExpandedRow('email')}
583
505
  onCancel={() => setExpandedRow(null)}
584
- onSave={() => setExpandedRow(null)}>
506
+ onSave={() => setExpandedRow(null)}
507
+ href={SELF_HASH}
508
+ style={rowPadding}>
585
509
  <TextInput
586
510
  label="Email address"
587
511
  isLabelHidden
@@ -595,7 +519,9 @@ export default function SettingsSidebar() {
595
519
  isExpanded={expandedRow === 'phone'}
596
520
  onEdit={() => setExpandedRow('phone')}
597
521
  onCancel={() => setExpandedRow(null)}
598
- onSave={() => setExpandedRow(null)}>
522
+ onSave={() => setExpandedRow(null)}
523
+ href={SELF_HASH}
524
+ style={rowPadding}>
599
525
  <TextInput
600
526
  label="Phone number"
601
527
  isLabelHidden
@@ -607,6 +533,8 @@ export default function SettingsSidebar() {
607
533
  label="Identity verification"
608
534
  value="Verified"
609
535
  action=""
536
+ href={SELF_HASH}
537
+ style={rowPadding}
610
538
  />
611
539
  <ExpandableRow
612
540
  label="Residential address"
@@ -614,7 +542,9 @@ export default function SettingsSidebar() {
614
542
  isExpanded={expandedRow === 'address'}
615
543
  onEdit={() => setExpandedRow('address')}
616
544
  onCancel={() => setExpandedRow(null)}
617
- onSave={() => setExpandedRow(null)}>
545
+ onSave={() => setExpandedRow(null)}
546
+ href={SELF_HASH}
547
+ style={rowPadding}>
618
548
  <TextInput
619
549
  label="Residential address"
620
550
  isLabelHidden
@@ -628,7 +558,9 @@ export default function SettingsSidebar() {
628
558
  isExpanded={expandedRow === 'mailingAddress'}
629
559
  onEdit={() => setExpandedRow('mailingAddress')}
630
560
  onCancel={() => setExpandedRow(null)}
631
- onSave={() => setExpandedRow(null)}>
561
+ onSave={() => setExpandedRow(null)}
562
+ href={SELF_HASH}
563
+ style={rowPadding}>
632
564
  <TextInput
633
565
  label="Mailing address"
634
566
  isLabelHidden
@@ -642,7 +574,9 @@ export default function SettingsSidebar() {
642
574
  isExpanded={expandedRow === 'emergencyContact'}
643
575
  onEdit={() => setExpandedRow('emergencyContact')}
644
576
  onCancel={() => setExpandedRow(null)}
645
- onSave={() => setExpandedRow(null)}>
577
+ onSave={() => setExpandedRow(null)}
578
+ href={SELF_HASH}
579
+ style={rowPadding}>
646
580
  <TextInput
647
581
  label="Emergency contact"
648
582
  isLabelHidden
@@ -654,61 +588,27 @@ export default function SettingsSidebar() {
654
588
 
655
589
  <Card padding={4}>
656
590
  <VStack gap={4}>
657
- <HStack gap={3} vAlign="start">
658
- <Center width={48} height={48} style={iconBox}>
659
- <Icon icon={Lock} />
660
- </Center>
661
- <VStack gap={0}>
662
- <Text type="body" weight="semibold" display="block">
663
- Why isn&apos;t my info shown here?
664
- </Text>
665
- <Text
666
- type="supporting"
667
- color="secondary"
668
- display="block">
669
- We&apos;re hiding some account details to protect your
670
- identity.
671
- </Text>
672
- </VStack>
673
- </HStack>
674
- <Divider />
675
- <HStack gap={3} vAlign="start">
676
- <Center width={48} height={48} style={iconBox}>
677
- <Icon icon={SquarePen} />
678
- </Center>
679
- <VStack gap={0}>
680
- <Text type="body" weight="semibold" display="block">
681
- Which details can be edited?
682
- </Text>
683
- <Text
684
- type="supporting"
685
- color="secondary"
686
- display="block">
687
- Contact info and personal details can be edited. If
688
- this info was used to verify your identity,
689
- you&apos;ll need to get verified again the next time
690
- you book—or to continue hosting.
691
- </Text>
692
- </VStack>
693
- </HStack>
694
- <Divider />
695
- <HStack gap={3} vAlign="start">
696
- <Center width={48} height={48} style={iconBox}>
697
- <Icon icon={Share2} />
698
- </Center>
699
- <VStack gap={0}>
700
- <Text type="body" weight="semibold" display="block">
701
- What info is shared with others?
702
- </Text>
703
- <Text
704
- type="supporting"
705
- color="secondary"
706
- display="block">
707
- We only release contact information after a
708
- reservation is confirmed.
709
- </Text>
710
- </VStack>
711
- </HStack>
591
+ {INFO_TILES.map((tile, i) => (
592
+ <Fragment key={tile.title}>
593
+ {i > 0 && <Divider />}
594
+ <HStack gap={3} vAlign="start">
595
+ <Center width={48} height={48} style={iconBox}>
596
+ <Icon icon={tile.icon} />
597
+ </Center>
598
+ <VStack gap={0}>
599
+ <Text type="body" weight="semibold" display="block">
600
+ {tile.title}
601
+ </Text>
602
+ <Text
603
+ type="body"
604
+ color="secondary"
605
+ display="block">
606
+ {tile.body}
607
+ </Text>
608
+ </VStack>
609
+ </HStack>
610
+ </Fragment>
611
+ ))}
712
612
  </VStack>
713
613
  </Card>
714
614
  </VStack>
@@ -716,11 +616,11 @@ export default function SettingsSidebar() {
716
616
 
717
617
  {activeNav === 'Privacy' && (
718
618
  <VStack gap={6}>
719
- {!isNarrow && <Heading level={2}>Privacy</Heading>}
619
+ {!isNarrow && <Heading level={1}>Privacy</Heading>}
720
620
 
721
621
  <VStack gap={8}>
722
622
  <VStack gap={0}>
723
- <Heading level={3}>Messages</Heading>
623
+ <Heading level={2}>Messages</Heading>
724
624
  <VStack style={rowPadding}>
725
625
  <Switch
726
626
  label="Show people when I've read their messages."
@@ -734,17 +634,17 @@ export default function SettingsSidebar() {
734
634
  <Text type="body" weight="semibold">
735
635
  Blocked people
736
636
  </Text>
737
- <Link href="#/templates/settings-sidebar">View</Link>
637
+ <Link href={SELF_HASH}>View</Link>
738
638
  </HStack>
739
639
  <Divider />
740
640
  </VStack>
741
641
 
742
642
  <VStack gap={0}>
743
- <Heading level={3}>Listings</Heading>
643
+ <Heading level={2}>Listings</Heading>
744
644
  <VStack style={rowPadding}>
745
645
  <Switch
746
- label="Include my listing(s) in search engines"
747
- description="Turning this on means search engines, like Google, will display your listing page(s) in search results."
646
+ label="List my wares in the scrying mirrors"
647
+ description="Turning this on means scrying engines, like Google, will show your wares to seekers."
748
648
  value={searchEngines}
749
649
  onChange={setSearchEngines}
750
650
  labelPosition="start"
@@ -755,16 +655,16 @@ export default function SettingsSidebar() {
755
655
  </VStack>
756
656
 
757
657
  <VStack gap={4}>
758
- <Heading level={3}>Reviews</Heading>
658
+ <Heading level={2}>Reviews</Heading>
759
659
  <Text type="body" color="secondary">
760
660
  Choose what&apos;s shared when you write a review.{' '}
761
- <Link href="#/templates/settings-sidebar" type="supporting">
661
+ <Link href={SELF_HASH} type="body">
762
662
  Learn more
763
663
  </Link>
764
664
  </Text>
765
665
  <VStack gap={4}>
766
666
  <Switch
767
- label="Show my home city and country"
667
+ label="Show my home haunt and country"
768
668
  description="Ex: City and country"
769
669
  value={showCity}
770
670
  onChange={setShowCity}
@@ -772,8 +672,8 @@ export default function SettingsSidebar() {
772
672
  labelSpacing="spread"
773
673
  />
774
674
  <Switch
775
- label="Show my trip type"
776
- description="Ex: Stayed with kids or pets"
675
+ label="Show my journey type"
676
+ description="Ex: Rested with kin or familiars"
777
677
  value={showTripType}
778
678
  onChange={setShowTripType}
779
679
  labelPosition="start"
@@ -788,8 +688,8 @@ export default function SettingsSidebar() {
788
688
  labelSpacing="spread"
789
689
  />
790
690
  <Switch
791
- label="Show my booked services"
792
- description="Ex: Gourmet brunch or tasting menu"
691
+ label="Show my booked revels"
692
+ description="Ex: Midnight feasts and tasting rituals"
793
693
  value={showServices}
794
694
  onChange={setShowServices}
795
695
  labelPosition="start"
@@ -800,11 +700,11 @@ export default function SettingsSidebar() {
800
700
  </VStack>
801
701
 
802
702
  <VStack gap={4}>
803
- <Heading level={3}>Data privacy</Heading>
703
+ <Heading level={2}>Data privacy</Heading>
804
704
  <Card>
805
705
  <HStack hAlign="between" vAlign="center">
806
706
  <Text type="body">Request my personal data</Text>
807
- <Link href="#/templates/settings-sidebar">Request</Link>
707
+ <Link href={SELF_HASH}>Request</Link>
808
708
  </HStack>
809
709
  </Card>
810
710
  <Switch
@@ -818,7 +718,7 @@ export default function SettingsSidebar() {
818
718
  <Card>
819
719
  <HStack hAlign="between" vAlign="center">
820
720
  <Text type="body">Delete my account</Text>
821
- <Link href="#/templates/settings-sidebar">Delete</Link>
721
+ <Link href={SELF_HASH}>Delete</Link>
822
722
  </HStack>
823
723
  </Card>
824
724
  <Card variant="muted">
@@ -827,13 +727,13 @@ export default function SettingsSidebar() {
827
727
  <Icon icon={ShieldCheck} />
828
728
  </Center>
829
729
  <VStack gap={1}>
830
- <Text type="body" weight="bold">
730
+ <Text type="body">
831
731
  Committed to privacy
832
732
  </Text>
833
- <Text type="supporting" color="secondary">
733
+ <Text type="body" color="secondary">
834
734
  We&apos;re committed to keeping your data protected.
835
735
  See details in our{' '}
836
- <Link href="#/templates/settings-sidebar" type="supporting">
736
+ <Link href={SELF_HASH} type="supporting">
837
737
  Privacy Policy
838
738
  </Link>
839
739
  .
@@ -848,13 +748,13 @@ export default function SettingsSidebar() {
848
748
 
849
749
  {activeNav === 'Notifications' && (
850
750
  <VStack gap={6}>
851
- {!isNarrow && <Heading level={2}>Notifications</Heading>}
751
+ {!isNarrow && <Heading level={1}>Notifications</Heading>}
852
752
  <VStack gap={0}>
853
- <Heading level={3}>Messages</Heading>
753
+ <Heading level={2}>Messages</Heading>
854
754
  <VStack style={rowPadding}>
855
755
  <Switch
856
756
  label="Email notifications"
857
- description="Listing updates, trip reminders, and account activity."
757
+ description="Coven updates, journey reminders, and crypt activity."
858
758
  value={emailNotif}
859
759
  onChange={setEmailNotif}
860
760
  labelPosition="start"
@@ -865,7 +765,7 @@ export default function SettingsSidebar() {
865
765
  <VStack style={rowPadding}>
866
766
  <Switch
867
767
  label="Push notifications"
868
- description="Instant alerts for messages and reservation requests."
768
+ description="Swift ravens for messages and booking requests."
869
769
  value={pushNotif}
870
770
  onChange={setPushNotif}
871
771
  labelPosition="start"
@@ -879,12 +779,17 @@ export default function SettingsSidebar() {
879
779
 
880
780
  {activeNav === 'Taxes' && (
881
781
  <VStack gap={6}>
882
- {!isNarrow && <Heading level={2}>Taxes</Heading>}
782
+ {!isNarrow && <Heading level={1}>Taxes</Heading>}
883
783
  <VStack gap={0}>
884
- <Heading level={3}>Tax documents</Heading>
784
+ <Heading level={2}>Tax scrolls</Heading>
885
785
  <Divider />
886
786
  {TAX_ROWS.map(row => (
887
- <InfoRowItem key={row.label} {...row} />
787
+ <InfoRowItem
788
+ key={row.label}
789
+ {...row}
790
+ href={SELF_HASH}
791
+ style={rowPadding}
792
+ />
888
793
  ))}
889
794
  </VStack>
890
795
  </VStack>
@@ -892,12 +797,17 @@ export default function SettingsSidebar() {
892
797
 
893
798
  {activeNav === 'Payments' && (
894
799
  <VStack gap={6}>
895
- {!isNarrow && <Heading level={2}>Payments</Heading>}
800
+ {!isNarrow && <Heading level={1}>Payments</Heading>}
896
801
  <VStack gap={0}>
897
- <Heading level={3}>Payouts</Heading>
802
+ <Heading level={2}>Payout crypt</Heading>
898
803
  <Divider />
899
804
  {PAYOUT_ROWS.map(row => (
900
- <InfoRowItem key={row.label} {...row} />
805
+ <InfoRowItem
806
+ key={row.label}
807
+ {...row}
808
+ href={SELF_HASH}
809
+ style={rowPadding}
810
+ />
901
811
  ))}
902
812
  </VStack>
903
813
  </VStack>
@@ -905,13 +815,13 @@ export default function SettingsSidebar() {
905
815
 
906
816
  {activeNav === 'Travel for work' && (
907
817
  <VStack gap={6}>
908
- {!isNarrow && <Heading level={2}>Travel for work</Heading>}
818
+ {!isNarrow && <Heading level={1}>Travel for work</Heading>}
909
819
  <VStack gap={0}>
910
- <Heading level={3}>Work trips</Heading>
820
+ <Heading level={2}>Work haunts</Heading>
911
821
  <VStack style={rowPadding}>
912
822
  <Switch
913
- label="Show work-trip options at checkout"
914
- description="Add a work email to expense trips and unlock business-ready listings."
823
+ label="Show night-errand options at checkout"
824
+ description="Add a coven address to expense night errands and unlock travel-ready wares."
915
825
  value={workTrips}
916
826
  onChange={setWorkTrips}
917
827
  labelPosition="start"
@@ -926,7 +836,7 @@ export default function SettingsSidebar() {
926
836
  {activeNav === 'Professional hosting tools' && (
927
837
  <VStack gap={6}>
928
838
  {!isNarrow && (
929
- <Heading level={2}>Professional hosting tools</Heading>
839
+ <Heading level={1}>Professional hosting tools</Heading>
930
840
  )}
931
841
  <Card variant="muted">
932
842
  <HStack gap={4} vAlign="start">
@@ -934,10 +844,10 @@ export default function SettingsSidebar() {
934
844
  <Icon icon={Wrench} />
935
845
  </Center>
936
846
  <VStack gap={1}>
937
- <Text type="body" weight="bold">
938
- Tools for professional hosts
847
+ <Text type="body">
848
+ Hosting grimoire
939
849
  </Text>
940
- <Text type="supporting" color="secondary">
850
+ <Text type="body" color="secondary">
941
851
  Manage multiple listings, route tasks to co-hosts, and
942
852
  review consolidated payouts from one place.
943
853
  </Text>