astryx-dracula 0.5.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BRAND.md +3 -3
- package/README.md +7 -4
- package/USAGE.md +49 -49
- package/astryx-dracula.d.ts +2 -2
- package/astryx-dracula.js +25 -9
- package/astryx-dracula.variants.d.ts +2 -2
- package/astryx.integration.mjs +1 -1
- package/icons.mjs +21 -17
- package/icons.tsx +69 -62
- package/package.json +125 -120
- package/shared/auth-chrome-config.ts +6 -6
- package/shared/auth-chrome.tsx +143 -144
- package/shared/auth-copy.ts +14 -14
- package/shared/chaptered-doc-config.ts +48 -51
- package/shared/chaptered-doc.tsx +267 -289
- package/shared/chart-hues.ts +25 -10
- package/shared/chart-labels.tsx +31 -30
- package/shared/chart-legend.tsx +55 -56
- package/shared/chart-panel-style.ts +3 -3
- package/shared/data-bar.tsx +97 -102
- package/shared/format-money.ts +1 -1
- package/shared/gallery-image.ts +6 -6
- package/shared/login-demo.ts +1 -1
- package/shared/metric-card.tsx +101 -105
- package/shared/metric-delta.tsx +28 -27
- package/shared/order-desk.tsx +205 -216
- package/shared/revenue-chart.tsx +145 -165
- package/shared/scene-castle.tsx +206 -291
- package/shared/scene-frame.tsx +33 -32
- package/shared/scene-hues.ts +17 -17
- package/shared/scene-tile.tsx +88 -92
- package/shared/settings-data.ts +119 -125
- package/shared/settings-rows.tsx +122 -159
- package/shared/sparkline.tsx +75 -88
- package/shared/sso-icons.tsx +10 -22
- package/shared/stars.tsx +16 -25
- package/templates/ai-chat-landing.template.mjs +5 -4
- package/templates/ai-chat-landing.tsx +473 -460
- package/templates/ai-chat.template.mjs +5 -4
- package/templates/ai-chat.tsx +543 -612
- package/templates/blank.template.mjs +5 -4
- package/templates/blank.tsx +18 -14
- package/templates/centered-hero.template.mjs +5 -4
- package/templates/centered-hero.tsx +55 -68
- package/templates/classic-gallery.template.mjs +5 -4
- package/templates/classic-gallery.tsx +97 -104
- package/templates/contact-form.template.mjs +5 -4
- package/templates/contact-form.tsx +247 -282
- package/templates/dashboard-portfolio.template.mjs +5 -4
- package/templates/dashboard-portfolio.tsx +717 -548
- package/templates/dashboard.template.mjs +5 -4
- package/templates/dashboard.tsx +596 -567
- package/templates/detail-page.template.mjs +5 -4
- package/templates/detail-page.tsx +546 -603
- package/templates/documentation-design.template.mjs +5 -4
- package/templates/documentation-design.tsx +231 -243
- package/templates/documentation-technical.template.mjs +5 -4
- package/templates/documentation-technical.tsx +236 -239
- package/templates/documentation.template.mjs +5 -4
- package/templates/documentation.tsx +267 -279
- package/templates/editor.template.mjs +5 -4
- package/templates/editor.tsx +844 -877
- package/templates/file-explorer.template.mjs +5 -4
- package/templates/file-explorer.tsx +566 -590
- package/templates/form-two-column.template.mjs +5 -4
- package/templates/form-two-column.tsx +195 -210
- package/templates/gallery-hero.template.mjs +5 -4
- package/templates/gallery-hero.tsx +93 -114
- package/templates/ide.template.mjs +5 -4
- package/templates/ide.tsx +407 -453
- package/templates/incident-console.template.mjs +5 -4
- package/templates/incident-console.tsx +593 -575
- package/templates/kanban-board.template.mjs +5 -4
- package/templates/kanban-board.tsx +665 -683
- package/templates/library.template.mjs +5 -4
- package/templates/library.tsx +409 -430
- package/templates/login-card.template.mjs +5 -4
- package/templates/login-card.tsx +63 -72
- package/templates/login-split.template.mjs +5 -4
- package/templates/login-split.tsx +192 -193
- package/templates/login-sso.template.mjs +5 -4
- package/templates/login-sso.tsx +257 -258
- package/templates/login.template.mjs +5 -4
- package/templates/login.tsx +53 -49
- package/templates/messaging-shell.template.mjs +5 -4
- package/templates/messaging-shell.tsx +556 -574
- package/templates/mixed-gallery.template.mjs +5 -4
- package/templates/mixed-gallery.tsx +60 -58
- package/templates/payment-form.template.mjs +5 -4
- package/templates/payment-form.tsx +882 -991
- package/templates/product-detail.template.mjs +5 -4
- package/templates/product-detail.tsx +261 -272
- package/templates/product-gallery.template.mjs +5 -4
- package/templates/product-gallery.tsx +126 -137
- package/templates/product-tour.template.mjs +5 -4
- package/templates/product-tour.tsx +741 -773
- package/templates/settings-dialog.template.mjs +5 -4
- package/templates/settings-dialog.tsx +688 -717
- package/templates/settings-sidebar.template.mjs +5 -4
- package/templates/settings-sidebar.tsx +762 -807
- package/templates/settings.template.mjs +5 -4
- package/templates/settings.tsx +289 -304
- package/templates/shell-nav.template.mjs +5 -4
- package/templates/shell-nav.tsx +212 -219
- package/templates/shell-side-nav.template.mjs +5 -4
- package/templates/shell-side-nav.tsx +135 -157
- package/templates/shell-top-nav.template.mjs +5 -4
- package/templates/shell-top-nav.tsx +182 -203
- package/templates/side-gallery.template.mjs +5 -4
- package/templates/side-gallery.tsx +85 -90
- package/templates/table-grouped.template.mjs +5 -4
- package/templates/table-grouped.tsx +1000 -1053
- package/templates/table-page-chart.template.mjs +5 -4
- package/templates/table-page-chart.tsx +400 -398
- package/templates/table-page-heatmap-status.template.mjs +5 -4
- package/templates/table-page-heatmap-status.tsx +483 -512
- package/templates/table-page-shoe-store-heatmap.template.mjs +5 -4
- package/templates/table-page-shoe-store-heatmap.tsx +748 -746
- package/templates/table-page.template.mjs +5 -4
- package/templates/table-page.tsx +396 -405
- package/templates/table.template.mjs +5 -4
- package/templates/table.tsx +92 -93
- package/templates/tech-report.template.mjs +5 -4
- package/templates/tech-report.tsx +1316 -1304
- package/templates/theme-showcase.template.mjs +5 -4
- package/templates/theme-showcase.tsx +871 -951
- package/theme.css +35 -77
- package/theme.css.d.ts +9 -0
- package/tokens.css +373 -380
package/shared/chaptered-doc.tsx
CHANGED
|
@@ -5,327 +5,305 @@
|
|
|
5
5
|
// Scene systems stay local too: product-tour keeps BAT_WING/BAT_BODY/FIR +
|
|
6
6
|
// NightScene/PaletteScene/TypeScene/PagesScene, tech-report keeps its own.
|
|
7
7
|
|
|
8
|
+
import { AppShell } from "@astryxdesign/core/AppShell";
|
|
9
|
+
import { AspectRatio } from "@astryxdesign/core/AspectRatio";
|
|
10
|
+
import { Button } from "@astryxdesign/core/Button";
|
|
11
|
+
import { CodeBlock } from "@astryxdesign/core/CodeBlock";
|
|
12
|
+
import { Divider } from "@astryxdesign/core/Divider";
|
|
13
|
+
import { useMediaQuery } from "@astryxdesign/core/hooks";
|
|
14
|
+
import { Icon } from "@astryxdesign/core/Icon";
|
|
8
15
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} from
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
SideNav,
|
|
24
|
-
SideNavHeading,
|
|
25
|
-
SideNavItem,
|
|
26
|
-
SideNavSection,
|
|
27
|
-
} from '@astryxdesign/core/SideNav';
|
|
28
|
-
import {NavIcon} from '@astryxdesign/core/NavIcon';
|
|
16
|
+
HStack,
|
|
17
|
+
Layout,
|
|
18
|
+
LayoutContent,
|
|
19
|
+
LayoutPanel,
|
|
20
|
+
StackItem,
|
|
21
|
+
VStack,
|
|
22
|
+
} from "@astryxdesign/core/Layout";
|
|
23
|
+
import { List, ListItem } from "@astryxdesign/core/List";
|
|
24
|
+
import { MobileNavToggle } from "@astryxdesign/core/MobileNav";
|
|
25
|
+
import { NavIcon } from "@astryxdesign/core/NavIcon";
|
|
26
|
+
import { Outline } from "@astryxdesign/core/Outline";
|
|
27
|
+
import { Selector } from "@astryxdesign/core/Selector";
|
|
28
|
+
import { SideNav, SideNavHeading, SideNavItem, SideNavSection } from "@astryxdesign/core/SideNav";
|
|
29
|
+
import { Heading, Text } from "@astryxdesign/core/Text";
|
|
29
30
|
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
import {
|
|
40
|
-
import type
|
|
41
|
-
import {AspectRatio} from '@astryxdesign/core/AspectRatio';
|
|
42
|
-
import {CodeBlock} from '@astryxdesign/core/CodeBlock';
|
|
43
|
-
import {Divider} from '@astryxdesign/core/Divider';
|
|
44
|
-
import {List, ListItem} from '@astryxdesign/core/List';
|
|
45
|
-
import {Outline} from '@astryxdesign/core/Outline';
|
|
46
|
-
import {Selector} from '@astryxdesign/core/Selector';
|
|
47
|
-
import {useMediaQuery} from '@astryxdesign/core/hooks';
|
|
48
|
-
|
|
49
|
-
import {ChevronLeft, ChevronRight} from 'lucide-react';
|
|
31
|
+
buildOutlineByChapter,
|
|
32
|
+
type ChapterGroup,
|
|
33
|
+
type DocChapter,
|
|
34
|
+
type DocSection,
|
|
35
|
+
outlinePanel,
|
|
36
|
+
sceneClip,
|
|
37
|
+
scrollToSection,
|
|
38
|
+
sectionId,
|
|
39
|
+
} from "astryx-dracula/shared/chaptered-doc-config";
|
|
40
|
+
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
41
|
+
import { type ReactNode, useState } from "react";
|
|
50
42
|
|
|
51
43
|
function ChapterRail({
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
44
|
+
groups,
|
|
45
|
+
activeId,
|
|
46
|
+
onSelect,
|
|
47
|
+
heading,
|
|
48
|
+
subheading,
|
|
49
|
+
headingHref,
|
|
50
|
+
headingIcon,
|
|
59
51
|
}: {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
groups: ChapterGroup[];
|
|
53
|
+
activeId: string;
|
|
54
|
+
onSelect: (id: string) => void;
|
|
55
|
+
heading: string;
|
|
56
|
+
subheading: string;
|
|
57
|
+
headingHref: string;
|
|
58
|
+
headingIcon: ReactNode;
|
|
67
59
|
}) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
60
|
+
// Resizable like the shell-side-nav template: 264 default, 220-400 range.
|
|
61
|
+
// The AppShell drawer owns the rail below 1024px (see MobileNavToggle),
|
|
62
|
+
// so the handle only matters at desktop widths.
|
|
63
|
+
return (
|
|
64
|
+
<SideNav
|
|
65
|
+
collapsible
|
|
66
|
+
resizable={{ defaultWidth: 264, minWidth: 220, maxWidth: 400 }}
|
|
67
|
+
header={
|
|
68
|
+
<SideNavHeading
|
|
69
|
+
icon={<NavIcon icon={headingIcon} />}
|
|
70
|
+
heading={heading}
|
|
71
|
+
subheading={subheading}
|
|
72
|
+
headingHref={headingHref}
|
|
73
|
+
/>
|
|
74
|
+
}
|
|
75
|
+
>
|
|
76
|
+
{groups.map((group) => (
|
|
77
|
+
<SideNavSection key={group.title} title={group.title}>
|
|
78
|
+
{group.chapters.map((chapter) => (
|
|
79
|
+
<SideNavItem
|
|
80
|
+
key={chapter.id}
|
|
81
|
+
label={chapter.title}
|
|
82
|
+
icon={chapter.icon}
|
|
83
|
+
isSelected={chapter.id === activeId}
|
|
84
|
+
onClick={() => onSelect(chapter.id)}
|
|
85
|
+
/>
|
|
86
|
+
))}
|
|
87
|
+
</SideNavSection>
|
|
88
|
+
))}
|
|
89
|
+
</SideNav>
|
|
90
|
+
);
|
|
98
91
|
}
|
|
99
92
|
|
|
100
93
|
// ─── Chapter body ────────────────────────────────────────────────────────────
|
|
101
94
|
|
|
102
|
-
function SectionBlock({
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
title={section.code.title}
|
|
129
|
-
width="100%"
|
|
130
|
-
/>
|
|
131
|
-
)}
|
|
132
|
-
</VStack>
|
|
133
|
-
);
|
|
95
|
+
function SectionBlock({ chapterId, section }: { chapterId: string; section: DocSection }) {
|
|
96
|
+
return (
|
|
97
|
+
<VStack gap={3}>
|
|
98
|
+
<Heading level={2} id={sectionId(chapterId, section.key)}>
|
|
99
|
+
{section.heading}
|
|
100
|
+
</Heading>
|
|
101
|
+
<Text type="body" color="secondary" display="block">
|
|
102
|
+
{section.body}
|
|
103
|
+
</Text>
|
|
104
|
+
{section.bullets != null && (
|
|
105
|
+
<List listStyle="disc">
|
|
106
|
+
{section.bullets.map((bullet) => (
|
|
107
|
+
<ListItem key={bullet} label={bullet} />
|
|
108
|
+
))}
|
|
109
|
+
</List>
|
|
110
|
+
)}
|
|
111
|
+
{section.code != null && (
|
|
112
|
+
<CodeBlock
|
|
113
|
+
code={section.code.source}
|
|
114
|
+
language={section.code.language}
|
|
115
|
+
title={section.code.title}
|
|
116
|
+
width="100%"
|
|
117
|
+
/>
|
|
118
|
+
)}
|
|
119
|
+
</VStack>
|
|
120
|
+
);
|
|
134
121
|
}
|
|
135
122
|
|
|
136
123
|
function ChapterNav({
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
124
|
+
chapters,
|
|
125
|
+
chapter,
|
|
126
|
+
onSelect,
|
|
140
127
|
}: {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
128
|
+
chapters: DocChapter[];
|
|
129
|
+
chapter: DocChapter;
|
|
130
|
+
onSelect: (id: string) => void;
|
|
144
131
|
}) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
132
|
+
const index = chapters.findIndex((entry) => entry.id === chapter.id);
|
|
133
|
+
const previous = index > 0 ? chapters[index - 1] : undefined;
|
|
134
|
+
const next = index < chapters.length - 1 ? chapters[index + 1] : undefined;
|
|
135
|
+
return (
|
|
136
|
+
<HStack gap={3} hAlign="between" vAlign="center">
|
|
137
|
+
{previous != null ? (
|
|
138
|
+
<Button
|
|
139
|
+
label={previous.title}
|
|
140
|
+
variant="secondary"
|
|
141
|
+
icon={<Icon icon={ChevronLeft} size="sm" />}
|
|
142
|
+
onClick={() => onSelect(previous.id)}
|
|
143
|
+
/>
|
|
144
|
+
) : (
|
|
145
|
+
<StackItem size="fill" />
|
|
146
|
+
)}
|
|
147
|
+
{next != null ? (
|
|
148
|
+
<Button
|
|
149
|
+
label={next.title}
|
|
150
|
+
variant="secondary"
|
|
151
|
+
endContent={<Icon icon={ChevronRight} size="sm" />}
|
|
152
|
+
onClick={() => onSelect(next.id)}
|
|
153
|
+
/>
|
|
154
|
+
) : (
|
|
155
|
+
<StackItem size="fill" />
|
|
156
|
+
)}
|
|
157
|
+
</HStack>
|
|
158
|
+
);
|
|
172
159
|
}
|
|
173
160
|
|
|
174
161
|
// ─── Page ────────────────────────────────────────────────────────────────────
|
|
175
162
|
|
|
176
|
-
export function ChapterArtFrame({children}: {children: ReactNode}) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
163
|
+
export function ChapterArtFrame({ children }: { children: ReactNode }) {
|
|
164
|
+
return (
|
|
165
|
+
<AspectRatio ratio={16 / 9} style={sceneClip}>
|
|
166
|
+
{children}
|
|
167
|
+
</AspectRatio>
|
|
168
|
+
);
|
|
182
169
|
}
|
|
183
170
|
|
|
184
171
|
export default function ChapteredDoc({
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
172
|
+
groups,
|
|
173
|
+
defaultChapter,
|
|
174
|
+
railHeading,
|
|
175
|
+
railSubheading,
|
|
176
|
+
railHref,
|
|
177
|
+
railIcon,
|
|
178
|
+
eyebrow,
|
|
179
|
+
badge,
|
|
180
|
+
art,
|
|
181
|
+
footer,
|
|
195
182
|
}: {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
183
|
+
groups: ChapterGroup[];
|
|
184
|
+
defaultChapter: string;
|
|
185
|
+
railHeading: string;
|
|
186
|
+
railSubheading: string;
|
|
187
|
+
railHref: string;
|
|
188
|
+
railIcon: ReactNode;
|
|
189
|
+
eyebrow: string;
|
|
190
|
+
badge: (chapter: DocChapter, index: number, total: number) => ReactNode;
|
|
191
|
+
art: (chapterId: string) => ReactNode;
|
|
192
|
+
footer?: ReactNode;
|
|
206
193
|
}) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
194
|
+
const chapters = groups.flatMap((group) => group.chapters);
|
|
195
|
+
const [outlineByChapter] = useState(() => buildOutlineByChapter(chapters));
|
|
196
|
+
const [chapterId, setChapterId] = useState(defaultChapter);
|
|
197
|
+
const [activeSection, setActiveSection] = useState(
|
|
198
|
+
outlineByChapter[defaultChapter]?.[0]?.id ?? "",
|
|
199
|
+
);
|
|
213
200
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
201
|
+
// Responsive contract: below 1024px the outline stops being a column, since
|
|
202
|
+
// a narrow viewport has nothing to outline against.
|
|
203
|
+
const isNarrow = useMediaQuery("(max-width: 1024px)");
|
|
217
204
|
|
|
218
|
-
|
|
219
|
-
|
|
205
|
+
const chapter = chapters.find((entry) => entry.id === chapterId) ?? chapters[0];
|
|
206
|
+
const outlineItems = outlineByChapter[chapter.id] ?? [];
|
|
220
207
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
208
|
+
const openChapter = (id: string) => {
|
|
209
|
+
setChapterId(id);
|
|
210
|
+
setActiveSection(outlineByChapter[id]?.[0]?.id ?? "");
|
|
211
|
+
// A chapter reads as a new page, so the document goes back to the top
|
|
212
|
+
// instead of keeping the previous chapter's scroll offset.
|
|
213
|
+
window.scrollTo({ top: 0 });
|
|
214
|
+
};
|
|
228
215
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
</VStack>
|
|
216
|
+
return (
|
|
217
|
+
<AppShell
|
|
218
|
+
height="auto"
|
|
219
|
+
contentPadding={0}
|
|
220
|
+
mobileNav={{ hasToggle: false }}
|
|
221
|
+
sideNav={
|
|
222
|
+
<ChapterRail
|
|
223
|
+
groups={groups}
|
|
224
|
+
activeId={chapter.id}
|
|
225
|
+
onSelect={openChapter}
|
|
226
|
+
heading={railHeading}
|
|
227
|
+
subheading={railSubheading}
|
|
228
|
+
headingHref={railHref}
|
|
229
|
+
headingIcon={railIcon}
|
|
230
|
+
/>
|
|
231
|
+
}
|
|
232
|
+
>
|
|
233
|
+
<Layout
|
|
234
|
+
height="auto"
|
|
235
|
+
contentWidth={960}
|
|
236
|
+
end={
|
|
237
|
+
isNarrow ? undefined : (
|
|
238
|
+
<LayoutPanel
|
|
239
|
+
isScrollable={false}
|
|
240
|
+
label="On this page"
|
|
241
|
+
role="complementary"
|
|
242
|
+
style={outlinePanel}
|
|
243
|
+
>
|
|
244
|
+
<Outline items={outlineItems} onActiveIdChange={setActiveSection} />
|
|
245
|
+
</LayoutPanel>
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
content={
|
|
249
|
+
<LayoutContent isScrollable={false} padding={8}>
|
|
250
|
+
<VStack gap={8}>
|
|
251
|
+
<VStack gap={2}>
|
|
252
|
+
<HStack gap={2} vAlign="center">
|
|
253
|
+
<MobileNavToggle />
|
|
254
|
+
<Text type="supporting" color="secondary">
|
|
255
|
+
{eyebrow}
|
|
256
|
+
</Text>
|
|
257
|
+
</HStack>
|
|
258
|
+
<Heading level={1} type="display-2">
|
|
259
|
+
{chapter.title}
|
|
260
|
+
</Heading>
|
|
261
|
+
<Text type="supporting" color="secondary" hasTabularNumbers>
|
|
262
|
+
{badge(
|
|
263
|
+
chapter,
|
|
264
|
+
chapters.findIndex((entry) => entry.id === chapter.id),
|
|
265
|
+
chapters.length,
|
|
266
|
+
)}
|
|
267
|
+
</Text>
|
|
268
|
+
{isNarrow && (
|
|
269
|
+
<Selector
|
|
270
|
+
label="On this page"
|
|
271
|
+
isLabelHidden
|
|
272
|
+
options={outlineItems.map((item) => ({
|
|
273
|
+
value: item.id,
|
|
274
|
+
label: item.label,
|
|
275
|
+
}))}
|
|
276
|
+
value={activeSection}
|
|
277
|
+
onChange={(id: string) => {
|
|
278
|
+
setActiveSection(id);
|
|
279
|
+
scrollToSection(id);
|
|
280
|
+
}}
|
|
281
|
+
width="100%"
|
|
282
|
+
/>
|
|
283
|
+
)}
|
|
284
|
+
</VStack>
|
|
299
285
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
286
|
+
<Text type="large" color="secondary" display="block">
|
|
287
|
+
{chapter.intro}
|
|
288
|
+
</Text>
|
|
303
289
|
|
|
304
|
-
|
|
290
|
+
{art(chapter.id)}
|
|
305
291
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
section={section}
|
|
312
|
-
/>
|
|
313
|
-
))}
|
|
314
|
-
</VStack>
|
|
292
|
+
<VStack gap={8}>
|
|
293
|
+
{chapter.sections.map((section) => (
|
|
294
|
+
<SectionBlock key={section.key} chapterId={chapter.id} section={section} />
|
|
295
|
+
))}
|
|
296
|
+
</VStack>
|
|
315
297
|
|
|
316
|
-
|
|
298
|
+
<Divider />
|
|
317
299
|
|
|
318
|
-
|
|
319
|
-
chapters={chapters}
|
|
320
|
-
chapter={chapter}
|
|
321
|
-
onSelect={openChapter}
|
|
322
|
-
/>
|
|
300
|
+
<ChapterNav chapters={chapters} chapter={chapter} onSelect={openChapter} />
|
|
323
301
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
302
|
+
{footer}
|
|
303
|
+
</VStack>
|
|
304
|
+
</LayoutContent>
|
|
305
|
+
}
|
|
306
|
+
/>
|
|
307
|
+
</AppShell>
|
|
308
|
+
);
|
|
331
309
|
}
|
package/shared/chart-hues.ts
CHANGED
|
@@ -5,18 +5,33 @@
|
|
|
5
5
|
// Purple is deliberately absent: purple means tappable, so it must never encode
|
|
6
6
|
// data. `muted` is a COMMENT-blue grey because it backs the `{label: 'Other'}`
|
|
7
7
|
// legend row (dashboard.tsx:229, :253) -- a labelled data category, not chrome.
|
|
8
|
+
//
|
|
9
|
+
// Every var() carries an explicit fallback equal to the theme's own pin for
|
|
10
|
+
// that token. Core moved the canonical `--color-data-*` defaults out of the
|
|
11
|
+
// generated theme CSS and into its own dataVars group, so a bare
|
|
12
|
+
// `var(--color-data-*)` is no longer guaranteed to resolve: the theme's pin is
|
|
13
|
+
// the only thing painting it. The fallback is the same value, so a theme that
|
|
14
|
+
// drops the token still paints the right colour instead of nothing. The
|
|
15
|
+
// fallback-vs-pin sync is enforced by scripts/check.ts, so the two cannot drift.
|
|
8
16
|
|
|
9
17
|
export const CHART_HUES = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
cyan: "var(--color-data-categorical-cyan, #8BE9FD)",
|
|
19
|
+
orange: "var(--color-data-categorical-orange, #FFB86C)",
|
|
20
|
+
green: "var(--color-data-categorical-green, #50FA7B)",
|
|
21
|
+
pink: "var(--color-data-categorical-pink, #FF79C6)",
|
|
22
|
+
muted: "var(--color-data-categorical-blue, #6272A4)",
|
|
23
|
+
// Added because --color-data-categorical-red exists in the palette
|
|
24
|
+
// (tokens.css:276) and heat maps need a severity colour, but no module
|
|
25
|
+
// exposed it. Without this, a chart could not reach red through the
|
|
26
|
+
// sanctioned source at all.
|
|
27
|
+
red: "var(--color-data-categorical-red, #FF5555)",
|
|
20
28
|
} as const;
|
|
21
29
|
|
|
22
30
|
export type ChartHue = (typeof CHART_HUES)[keyof typeof CHART_HUES];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Any `--color-data-*` colour: a categorical hue, or a step of a sequential
|
|
34
|
+
* ramp. The fallback inside the var() is part of the string, which is why the
|
|
35
|
+
* template-literal type below still admits it.
|
|
36
|
+
*/
|
|
37
|
+
export type DataColor = `var(--color-data-${string})`;
|