astryx-dracula 0.5.0 → 0.5.1

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 (121) hide show
  1. package/astryx.integration.mjs +1 -1
  2. package/icons.mjs +17 -17
  3. package/icons.tsx +61 -62
  4. package/package.json +120 -120
  5. package/shared/auth-chrome-config.ts +6 -6
  6. package/shared/auth-chrome.tsx +143 -144
  7. package/shared/auth-copy.ts +14 -14
  8. package/shared/chaptered-doc-config.ts +48 -51
  9. package/shared/chaptered-doc.tsx +268 -289
  10. package/shared/chart-hues.ts +10 -10
  11. package/shared/chart-labels.tsx +31 -30
  12. package/shared/chart-legend.tsx +55 -56
  13. package/shared/chart-panel-style.ts +3 -3
  14. package/shared/data-bar.tsx +97 -102
  15. package/shared/format-money.ts +1 -1
  16. package/shared/gallery-image.ts +6 -6
  17. package/shared/login-demo.ts +1 -1
  18. package/shared/metric-card.tsx +101 -105
  19. package/shared/metric-delta.tsx +28 -27
  20. package/shared/order-desk.tsx +205 -216
  21. package/shared/revenue-chart.tsx +145 -165
  22. package/shared/scene-castle.tsx +206 -291
  23. package/shared/scene-frame.tsx +33 -32
  24. package/shared/scene-hues.ts +17 -17
  25. package/shared/scene-tile.tsx +88 -92
  26. package/shared/settings-data.ts +125 -125
  27. package/shared/settings-rows.tsx +142 -157
  28. package/shared/sparkline.tsx +75 -88
  29. package/shared/sso-icons.tsx +10 -22
  30. package/shared/stars.tsx +16 -25
  31. package/templates/ai-chat-landing.template.mjs +4 -4
  32. package/templates/ai-chat-landing.tsx +449 -458
  33. package/templates/ai-chat.template.mjs +4 -4
  34. package/templates/ai-chat.tsx +538 -609
  35. package/templates/blank.template.mjs +4 -4
  36. package/templates/blank.tsx +14 -12
  37. package/templates/centered-hero.template.mjs +4 -4
  38. package/templates/centered-hero.tsx +52 -67
  39. package/templates/classic-gallery.template.mjs +4 -4
  40. package/templates/classic-gallery.tsx +92 -101
  41. package/templates/contact-form.template.mjs +4 -4
  42. package/templates/contact-form.tsx +243 -280
  43. package/templates/dashboard-portfolio.template.mjs +4 -4
  44. package/templates/dashboard-portfolio.tsx +713 -546
  45. package/templates/dashboard.template.mjs +4 -4
  46. package/templates/dashboard.tsx +592 -565
  47. package/templates/detail-page.template.mjs +4 -4
  48. package/templates/detail-page.tsx +537 -594
  49. package/templates/documentation-design.template.mjs +4 -4
  50. package/templates/documentation-design.tsx +227 -241
  51. package/templates/documentation-technical.template.mjs +4 -4
  52. package/templates/documentation-technical.tsx +232 -237
  53. package/templates/documentation.template.mjs +4 -4
  54. package/templates/documentation.tsx +263 -277
  55. package/templates/editor.template.mjs +4 -4
  56. package/templates/editor.tsx +839 -874
  57. package/templates/file-explorer.template.mjs +4 -4
  58. package/templates/file-explorer.tsx +562 -588
  59. package/templates/form-two-column.template.mjs +4 -4
  60. package/templates/form-two-column.tsx +187 -208
  61. package/templates/gallery-hero.template.mjs +4 -4
  62. package/templates/gallery-hero.tsx +89 -112
  63. package/templates/ide.template.mjs +4 -4
  64. package/templates/ide.tsx +400 -451
  65. package/templates/incident-console.template.mjs +4 -4
  66. package/templates/incident-console.tsx +549 -573
  67. package/templates/kanban-board.template.mjs +4 -4
  68. package/templates/kanban-board.tsx +660 -680
  69. package/templates/library.template.mjs +4 -4
  70. package/templates/library.tsx +405 -428
  71. package/templates/login-card.template.mjs +4 -4
  72. package/templates/login-card.tsx +59 -70
  73. package/templates/login-split.template.mjs +4 -4
  74. package/templates/login-split.tsx +188 -192
  75. package/templates/login-sso.template.mjs +4 -4
  76. package/templates/login-sso.tsx +253 -256
  77. package/templates/login.template.mjs +4 -4
  78. package/templates/login.tsx +49 -47
  79. package/templates/messaging-shell.template.mjs +4 -4
  80. package/templates/messaging-shell.tsx +550 -572
  81. package/templates/mixed-gallery.template.mjs +4 -4
  82. package/templates/mixed-gallery.tsx +56 -56
  83. package/templates/payment-form.template.mjs +4 -4
  84. package/templates/payment-form.tsx +877 -988
  85. package/templates/product-detail.template.mjs +4 -4
  86. package/templates/product-detail.tsx +252 -270
  87. package/templates/product-gallery.template.mjs +4 -4
  88. package/templates/product-gallery.tsx +122 -135
  89. package/templates/product-tour.template.mjs +4 -4
  90. package/templates/product-tour.tsx +733 -768
  91. package/templates/settings-dialog.template.mjs +4 -4
  92. package/templates/settings-dialog.tsx +684 -715
  93. package/templates/settings-sidebar.template.mjs +4 -4
  94. package/templates/settings-sidebar.tsx +758 -805
  95. package/templates/settings.template.mjs +4 -4
  96. package/templates/settings.tsx +291 -302
  97. package/templates/shell-nav.template.mjs +4 -4
  98. package/templates/shell-nav.tsx +212 -217
  99. package/templates/shell-side-nav.template.mjs +4 -4
  100. package/templates/shell-side-nav.tsx +128 -155
  101. package/templates/shell-top-nav.template.mjs +4 -4
  102. package/templates/shell-top-nav.tsx +178 -201
  103. package/templates/side-gallery.template.mjs +4 -4
  104. package/templates/side-gallery.tsx +81 -88
  105. package/templates/table-grouped.template.mjs +4 -4
  106. package/templates/table-grouped.tsx +996 -1051
  107. package/templates/table-page-chart.template.mjs +4 -4
  108. package/templates/table-page-chart.tsx +396 -396
  109. package/templates/table-page-heatmap-status.template.mjs +4 -4
  110. package/templates/table-page-heatmap-status.tsx +479 -510
  111. package/templates/table-page-shoe-store-heatmap.template.mjs +4 -4
  112. package/templates/table-page-shoe-store-heatmap.tsx +744 -744
  113. package/templates/table-page.template.mjs +4 -4
  114. package/templates/table-page.tsx +392 -403
  115. package/templates/table.template.mjs +4 -4
  116. package/templates/table.tsx +88 -91
  117. package/templates/tech-report.template.mjs +4 -4
  118. package/templates/tech-report.tsx +1312 -1302
  119. package/templates/theme-showcase.template.mjs +4 -4
  120. package/templates/theme-showcase.tsx +863 -949
  121. package/tokens.css +340 -343
@@ -1,41 +1,40 @@
1
1
  // Shared login chrome: page wash + 400px column + Moon brand row + the
2
2
  // autocomplete widen-record TextInput needs (prop type omits input attrs).
3
- import type {ReactNode} from 'react';
4
- import {Moon} from 'lucide-react';
5
- import {VStack} from '@astryxdesign/core/Layout';
6
- import {Text} from '@astryxdesign/core/Text';
7
- import {Icon} from '@astryxdesign/core/Icon';
8
- import {Card} from '@astryxdesign/core/Card';
9
- import {Link} from '@astryxdesign/core/Link';
10
- import {TextInput} from '@astryxdesign/core/TextInput';
11
- import {Button} from '@astryxdesign/core/Button';
12
- import {Heading} from '@astryxdesign/core/Text';
13
- import {
14
- AUTH_BRAND_NAME,
15
- AUTH_HEADING,
16
- AUTH_SUBTITLE,
17
- AUTH_PRIMARY_CTA,
18
- AUTH_SIGNUP_PROMPT,
19
- AUTH_SIGNUP_LINK,
20
- AUTH_FORGOT_PASSWORD,
21
- AUTH_EMAIL_PLACEHOLDER,
22
- AUTH_PASSWORD_PLACEHOLDER,
23
- AUTH_TERMS_PREFIX,
24
- AUTH_TERMS_SERVICE,
25
- AUTH_TERMS_PRIVACY,
26
- } from 'astryx-dracula/shared/auth-copy';
27
- import {inputAutoComplete} from 'astryx-dracula/shared/auth-chrome-config';
28
3
 
4
+ import { Button } from "@astryxdesign/core/Button";
5
+ import { Card } from "@astryxdesign/core/Card";
6
+ import { Icon } from "@astryxdesign/core/Icon";
7
+ import { VStack } from "@astryxdesign/core/Layout";
8
+ import { Link } from "@astryxdesign/core/Link";
9
+ import { Heading, Text } from "@astryxdesign/core/Text";
10
+ import { TextInput } from "@astryxdesign/core/TextInput";
11
+ import { inputAutoComplete } from "astryx-dracula/shared/auth-chrome-config";
12
+ import {
13
+ AUTH_BRAND_NAME,
14
+ AUTH_EMAIL_PLACEHOLDER,
15
+ AUTH_FORGOT_PASSWORD,
16
+ AUTH_HEADING,
17
+ AUTH_PASSWORD_PLACEHOLDER,
18
+ AUTH_PRIMARY_CTA,
19
+ AUTH_SIGNUP_LINK,
20
+ AUTH_SIGNUP_PROMPT,
21
+ AUTH_SUBTITLE,
22
+ AUTH_TERMS_PREFIX,
23
+ AUTH_TERMS_PRIVACY,
24
+ AUTH_TERMS_SERVICE,
25
+ } from "astryx-dracula/shared/auth-copy";
26
+ import { Moon } from "lucide-react";
27
+ import type { ReactNode } from "react";
29
28
 
30
29
  export function LoginBrand() {
31
- return (
32
- <VStack gap={2} hAlign="center">
33
- <Icon icon={Moon} size="lg" color="secondary" />
34
- <Text type="body" weight="semibold" size="lg">
35
- {AUTH_BRAND_NAME}
36
- </Text>
37
- </VStack>
38
- );
30
+ return (
31
+ <VStack gap={2} hAlign="center">
32
+ <Icon icon={Moon} size="lg" color="secondary" />
33
+ <Text type="body" weight="semibold" size="lg">
34
+ {AUTH_BRAND_NAME}
35
+ </Text>
36
+ </VStack>
37
+ );
39
38
  }
40
39
 
41
40
  // Shared password-login core: the centered header, credential fields, primary
@@ -45,43 +44,43 @@ export function LoginBrand() {
45
44
  // shell — login-split's two-column grid and login-sso's step machine keep
46
45
  // their own markup and take the pieces below instead of this whole card.
47
46
  export function AuthCard({
48
- selfHash,
49
- signupLink = AUTH_SIGNUP_LINK,
50
- children,
47
+ selfHash,
48
+ signupLink = AUTH_SIGNUP_LINK,
49
+ children,
51
50
  }: {
52
- selfHash: string;
53
- signupLink?: string;
54
- children: ReactNode;
51
+ selfHash: string;
52
+ signupLink?: string;
53
+ children: ReactNode;
55
54
  }) {
56
- return (
57
- <>
58
- <Card padding={4} width="100%">
59
- <VStack gap={4} hAlign="stretch">
60
- <VStack gap={1} hAlign="center">
61
- <Heading level={1} type="display-2" justify="center">
62
- {AUTH_HEADING}
63
- </Heading>
64
- <Text type="body" color="secondary">
65
- {AUTH_SUBTITLE}
66
- </Text>
67
- </VStack>
68
- {children}
69
- {/* Prose link: colour alone is not a cue inside a sentence
55
+ return (
56
+ <>
57
+ <Card padding={4} width="100%">
58
+ <VStack gap={4} hAlign="stretch">
59
+ <VStack gap={1} hAlign="center">
60
+ <Heading level={1} type="display-2" justify="center">
61
+ {AUTH_HEADING}
62
+ </Heading>
63
+ <Text type="body" color="secondary">
64
+ {AUTH_SUBTITLE}
65
+ </Text>
66
+ </VStack>
67
+ {children}
68
+ {/* Prose link: colour alone is not a cue inside a sentence
70
69
  (WCAG 1.4.1 / F73), so it asks for the underline the kit
71
70
  only gives on hover. */}
72
- <VStack hAlign="center">
73
- <Text type="supporting" color="secondary">
74
- {AUTH_SIGNUP_PROMPT}{' '}
75
- <Link href={selfHash} type="supporting" hasUnderline>
76
- {signupLink}
77
- </Link>
78
- </Text>
79
- </VStack>
80
- </VStack>
81
- </Card>
82
- <AuthTerms selfHash={selfHash} />
83
- </>
84
- );
71
+ <VStack hAlign="center">
72
+ <Text type="supporting" color="secondary">
73
+ {AUTH_SIGNUP_PROMPT}{" "}
74
+ <Link href={selfHash} type="supporting" hasUnderline>
75
+ {signupLink}
76
+ </Link>
77
+ </Text>
78
+ </VStack>
79
+ </VStack>
80
+ </Card>
81
+ <AuthTerms selfHash={selfHash} />
82
+ </>
83
+ );
85
84
  }
86
85
 
87
86
  // Email + password fields with the shared error/forgot-password rhythm, plus
@@ -89,87 +88,87 @@ export function AuthCard({
89
88
  // not the outer 16px: without the group the two inputs sat twice as far
90
89
  // apart as the fields below them.
91
90
  export function AuthLoginFields({
92
- email,
93
- password,
94
- error,
95
- selfHash,
96
- isLoading,
97
- onEmailChange,
98
- onPasswordChange,
99
- onSubmit,
91
+ email,
92
+ password,
93
+ error,
94
+ selfHash,
95
+ isLoading,
96
+ onEmailChange,
97
+ onPasswordChange,
98
+ onSubmit,
100
99
  }: {
101
- email: string;
102
- password: string;
103
- error: string | null;
104
- selfHash: string;
105
- isLoading: boolean;
106
- onEmailChange: (value: string) => void;
107
- onPasswordChange: (value: string) => void;
108
- onSubmit: () => void;
100
+ email: string;
101
+ password: string;
102
+ error: string | null;
103
+ selfHash: string;
104
+ isLoading: boolean;
105
+ onEmailChange: (value: string) => void;
106
+ onPasswordChange: (value: string) => void;
107
+ onSubmit: () => void;
109
108
  }) {
110
- return (
111
- <>
112
- <VStack gap={2}>
113
- <TextInput
114
- label="Email"
115
- isLabelHidden
116
- value={email}
117
- onChange={onEmailChange}
118
- placeholder={AUTH_EMAIL_PLACEHOLDER}
119
- type="email"
120
- {...inputAutoComplete('email')}
121
- size="lg"
122
- onEnter={onSubmit}
123
- status={error ? {type: 'error', message: error} : undefined}
124
- />
125
- <VStack gap={1}>
126
- <TextInput
127
- label="Password"
128
- isLabelHidden
129
- value={password}
130
- onChange={onPasswordChange}
131
- placeholder={AUTH_PASSWORD_PLACEHOLDER}
132
- type="password"
133
- {...inputAutoComplete('current-password')}
134
- size="lg"
135
- onEnter={onSubmit}
136
- status={error ? {type: 'error', message: error} : undefined}
137
- />
138
- {error && (
139
- <VStack hAlign="end">
140
- <Link href={selfHash} color="secondary" isStandalone>
141
- {AUTH_FORGOT_PASSWORD}
142
- </Link>
143
- </VStack>
144
- )}
145
- </VStack>
146
- </VStack>
147
- <Button
148
- label={AUTH_PRIMARY_CTA}
149
- variant="primary"
150
- size="lg"
151
- isLoading={isLoading}
152
- onClick={onSubmit}
153
- />
154
- </>
155
- );
109
+ return (
110
+ <>
111
+ <VStack gap={2}>
112
+ <TextInput
113
+ label="Email"
114
+ isLabelHidden
115
+ value={email}
116
+ onChange={onEmailChange}
117
+ placeholder={AUTH_EMAIL_PLACEHOLDER}
118
+ type="email"
119
+ {...inputAutoComplete("email")}
120
+ size="lg"
121
+ onEnter={onSubmit}
122
+ status={error ? { type: "error", message: error } : undefined}
123
+ />
124
+ <VStack gap={1}>
125
+ <TextInput
126
+ label="Password"
127
+ isLabelHidden
128
+ value={password}
129
+ onChange={onPasswordChange}
130
+ placeholder={AUTH_PASSWORD_PLACEHOLDER}
131
+ type="password"
132
+ {...inputAutoComplete("current-password")}
133
+ size="lg"
134
+ onEnter={onSubmit}
135
+ status={error ? { type: "error", message: error } : undefined}
136
+ />
137
+ {error && (
138
+ <VStack hAlign="end">
139
+ <Link href={selfHash} color="secondary" isStandalone>
140
+ {AUTH_FORGOT_PASSWORD}
141
+ </Link>
142
+ </VStack>
143
+ )}
144
+ </VStack>
145
+ </VStack>
146
+ <Button
147
+ label={AUTH_PRIMARY_CTA}
148
+ variant="primary"
149
+ size="lg"
150
+ isLoading={isLoading}
151
+ onClick={onSubmit}
152
+ />
153
+ </>
154
+ );
156
155
  }
157
156
 
158
157
  // The family terms line, rendered below the card in the page column.
159
- export function AuthTerms({selfHash}: {selfHash: string}) {
160
- return (
161
- <VStack hAlign="center" width="100%">
162
- <Text type="supporting" color="secondary" justify="center">
163
- {AUTH_TERMS_PREFIX}{' '}
164
- <Link href={selfHash} type="supporting" hasUnderline>
165
- {AUTH_TERMS_SERVICE}
166
- </Link>{' '}
167
- and{' '}
168
- <Link href={selfHash} type="supporting" hasUnderline>
169
- {AUTH_TERMS_PRIVACY}
170
- </Link>
171
- .
172
- </Text>
173
- </VStack>
174
- );
158
+ export function AuthTerms({ selfHash }: { selfHash: string }) {
159
+ return (
160
+ <VStack hAlign="center" width="100%">
161
+ <Text type="supporting" color="secondary" justify="center">
162
+ {AUTH_TERMS_PREFIX}{" "}
163
+ <Link href={selfHash} type="supporting" hasUnderline>
164
+ {AUTH_TERMS_SERVICE}
165
+ </Link>{" "}
166
+ and{" "}
167
+ <Link href={selfHash} type="supporting" hasUnderline>
168
+ {AUTH_TERMS_PRIVACY}
169
+ </Link>
170
+ .
171
+ </Text>
172
+ </VStack>
173
+ );
175
174
  }
@@ -1,22 +1,22 @@
1
1
  // Auth copy shared by the four login templates. Single-sourced so the family
2
2
  // line cannot drift again. SSO-specific strings (Work email, Whisper your
3
3
  // details, Continue with SSO, provider names) stay per-template in login-sso.
4
- export const AUTH_HEADING = 'Welcome back to the night';
5
- export const AUTH_SUBTITLE = 'Sign in to your crypt';
6
- export const AUTH_PRIMARY_CTA = 'Sign in';
7
- export const AUTH_SIGNUP_PROMPT = 'New to the castle?';
8
- export const AUTH_SIGNUP_LINK = 'Sign up';
9
- export const AUTH_SSO_DIVIDER = 'Or continue with';
10
- export const AUTH_FORGOT_PASSWORD = 'Forgot password?';
4
+ export const AUTH_HEADING = "Welcome back to the night";
5
+ export const AUTH_SUBTITLE = "Sign in to your crypt";
6
+ export const AUTH_PRIMARY_CTA = "Sign in";
7
+ export const AUTH_SIGNUP_PROMPT = "New to the castle?";
8
+ export const AUTH_SIGNUP_LINK = "Sign up";
9
+ export const AUTH_SSO_DIVIDER = "Or continue with";
10
+ export const AUTH_FORGOT_PASSWORD = "Forgot password?";
11
11
  // Names the problem without apologising, and does not blame one field: a
12
12
  // mistyped email used to be reported as a wrong password, because this string
13
13
  // was attached to the password input only.
14
- export const AUTH_ERROR_MESSAGE = 'Email or password is wrong. Try again.';
15
- export const AUTH_EMAIL_PLACEHOLDER = 'you@castle.dracula';
14
+ export const AUTH_ERROR_MESSAGE = "Email or password is wrong. Try again.";
15
+ export const AUTH_EMAIL_PLACEHOLDER = "you@castle.dracula";
16
16
  // The placeholder is the only visible name on the credential inputs, so it has
17
17
  // to actually name the field. "Whisper your password" named nothing.
18
- export const AUTH_PASSWORD_PLACEHOLDER = 'Your password';
19
- export const AUTH_BRAND_NAME = 'Castle Dracula';
20
- export const AUTH_TERMS_PREFIX = 'By clicking continue, you agree to our';
21
- export const AUTH_TERMS_SERVICE = 'Terms of service';
22
- export const AUTH_TERMS_PRIVACY = 'Privacy policy';
18
+ export const AUTH_PASSWORD_PLACEHOLDER = "Your password";
19
+ export const AUTH_BRAND_NAME = "Castle Dracula";
20
+ export const AUTH_TERMS_PREFIX = "By clicking continue, you agree to our";
21
+ export const AUTH_TERMS_SERVICE = "Terms of service";
22
+ export const AUTH_TERMS_PRIVACY = "Privacy policy";
@@ -9,84 +9,81 @@
9
9
  // documentation-technical, product-tour, tech-report) share lives here; the
10
10
  // outline-building and scroll helpers that only chaptered-doc itself calls stay
11
11
  // unexported in that file.
12
- import type {CSSProperties} from 'react';
13
- import type {IconType} from '@astryxdesign/core/Icon';
14
- import type {OutlineItem} from '@astryxdesign/core/Outline';
12
+
13
+ import type { IconType } from "@astryxdesign/core/Icon";
14
+ import type { OutlineItem } from "@astryxdesign/core/Outline";
15
+ import type { CSSProperties } from "react";
15
16
 
16
17
  // ─── Types ───────────────────────────────────────────────────────────────────
17
18
 
18
19
  export interface DocSection {
19
- // Unique within the chapter; the DOM id is derived from it so the outline
20
- // links and the headings can never drift apart.
21
- key: string;
22
- heading: string;
23
- body: string;
24
- bullets?: string[];
25
- code?: {language: string; title: string; source: string};
20
+ // Unique within the chapter; the DOM id is derived from it so the outline
21
+ // links and the headings can never drift apart.
22
+ key: string;
23
+ heading: string;
24
+ body: string;
25
+ bullets?: string[];
26
+ code?: { language: string; title: string; source: string };
26
27
  }
27
28
 
28
29
  export interface DocChapter {
29
- id: string;
30
- title: string;
31
- icon: IconType;
32
- intro: string;
33
- hasArt?: boolean;
34
- sections: DocSection[];
30
+ id: string;
31
+ title: string;
32
+ icon: IconType;
33
+ intro: string;
34
+ hasArt?: boolean;
35
+ sections: DocSection[];
35
36
  }
36
37
 
37
- export type ChapterGroup = {title: string; chapters: DocChapter[]};
38
+ export type ChapterGroup = { title: string; chapters: DocChapter[] };
38
39
 
39
- export const sectionId = (chapterId: string, key: string) =>
40
- `${chapterId}--${key}`;
40
+ export const sectionId = (chapterId: string, key: string) => `${chapterId}--${key}`;
41
41
 
42
42
  // Astryx has no image primitive: AspectRatio exposes no objectFit or radius
43
43
  // props, so the scene fill and the corner clip live in these two styles.
44
44
  export const sceneFill: CSSProperties = {
45
- width: '100%',
46
- height: '100%',
47
- display: 'block',
45
+ width: "100%",
46
+ height: "100%",
47
+ display: "block",
48
48
  };
49
49
  export const sceneClip: CSSProperties = {
50
- borderRadius: 'var(--radius-container)',
51
- overflow: 'clip',
50
+ borderRadius: "var(--radius-container)",
51
+ overflow: "clip",
52
52
  };
53
53
 
54
54
  // The outline is sticky so it tracks the chapter as the document scrolls.
55
55
  export const outlinePanel: CSSProperties = {
56
- position: 'sticky',
57
- top: 'var(--spacing-6)',
58
- alignSelf: 'start',
59
- // No paddingBlockStart. This object is applied via `style=` to the outline
60
- // LayoutPanels (chaptered-doc.tsx:316, documentation-design.tsx:592,
61
- // documentation-technical.tsx:82), and an inline style prop BEATS the stylex
62
- // class -- so this 8px silently overrode the panel's own 16px block padding
63
- // at the top edge only, leaving every "On this page" rail in the kit
64
- // asymmetric by 8px. The panel already owns its block padding.
56
+ position: "sticky",
57
+ top: "var(--spacing-6)",
58
+ alignSelf: "start",
59
+ // No paddingBlockStart. This object is applied via `style=` to the outline
60
+ // LayoutPanels (chaptered-doc.tsx:316, documentation-design.tsx:592,
61
+ // documentation-technical.tsx:82), and an inline style prop BEATS the stylex
62
+ // class -- so this 8px silently overrode the panel's own 16px block padding
63
+ // at the top edge only, leaving every "On this page" rail in the kit
64
+ // asymmetric by 8px. The panel already owns its block padding.
65
65
  };
66
66
 
67
67
  // Derived once per page so the Outline receives a stable array identity
68
68
  // and does not re-register its scroll spy on every render.
69
- export function buildOutlineByChapter(
70
- chapters: DocChapter[],
71
- ): Record<string, OutlineItem[]> {
72
- return Object.fromEntries(
73
- chapters.map(chapter => [
74
- chapter.id,
75
- chapter.sections.map(section => ({
76
- id: sectionId(chapter.id, section.key),
77
- label: section.heading,
78
- level: 2,
79
- })),
80
- ]),
81
- );
69
+ export function buildOutlineByChapter(chapters: DocChapter[]): Record<string, OutlineItem[]> {
70
+ return Object.fromEntries(
71
+ chapters.map((chapter) => [
72
+ chapter.id,
73
+ chapter.sections.map((section) => ({
74
+ id: sectionId(chapter.id, section.key),
75
+ label: section.heading,
76
+ level: 2,
77
+ })),
78
+ ]),
79
+ );
82
80
  }
83
81
 
84
82
  export function scrollToSection(id: string) {
85
- const target = document.getElementById(id);
86
- if (target != null) {
87
- target.scrollIntoView({behavior: 'smooth', block: 'start'});
88
- }
83
+ const target = document.getElementById(id);
84
+ if (target != null) {
85
+ target.scrollIntoView({ behavior: "smooth", block: "start" });
86
+ }
89
87
  }
90
88
 
91
89
  // ─── Rail ────────────────────────────────────────────────────────────────────
92
-