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