@veluai/velu 0.2.13 → 0.2.15
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/README.md +80 -80
- package/dist/cli.js +37 -37
- package/package.json +64 -64
- package/runtime/velu-ui/base.css +320 -320
- package/runtime/velu-ui/components/Accordion.jsx +64 -64
- package/runtime/velu-ui/components/ApiClient.jsx +207 -207
- package/runtime/velu-ui/components/ApiField.jsx +87 -87
- package/runtime/velu-ui/components/ApiPath.jsx +63 -63
- package/runtime/velu-ui/components/ApiReferencePage.jsx +384 -384
- package/runtime/velu-ui/components/ApiSamples.jsx +36 -36
- package/runtime/velu-ui/components/ApiSidebar.jsx +122 -122
- package/runtime/velu-ui/components/AskBar.jsx +71 -71
- package/runtime/velu-ui/components/Callout.jsx +114 -114
- package/runtime/velu-ui/components/Card.jsx +131 -131
- package/runtime/velu-ui/components/Chatbot.jsx +885 -885
- package/runtime/velu-ui/components/CodeBlock.jsx +375 -375
- package/runtime/velu-ui/components/Columns.jsx +56 -56
- package/runtime/velu-ui/components/ContextMenu.jsx +298 -273
- package/runtime/velu-ui/components/ErrorCard.jsx +138 -138
- package/runtime/velu-ui/components/Field.jsx +81 -81
- package/runtime/velu-ui/components/Image.jsx +163 -163
- package/runtime/velu-ui/components/Logo.jsx +31 -31
- package/runtime/velu-ui/components/MethodBadge.jsx +31 -31
- package/runtime/velu-ui/components/NavSelect.jsx +108 -108
- package/runtime/velu-ui/components/NotFound.jsx +63 -63
- package/runtime/velu-ui/components/PageFeedback.jsx +219 -219
- package/runtime/velu-ui/components/PageFooter.jsx +145 -145
- package/runtime/velu-ui/components/PageHeader.jsx +422 -422
- package/runtime/velu-ui/components/PageNav.jsx +77 -77
- package/runtime/velu-ui/components/PoweredBy.jsx +51 -51
- package/runtime/velu-ui/components/Prompt.jsx +115 -115
- package/runtime/velu-ui/components/Search.jsx +460 -460
- package/runtime/velu-ui/components/Sidebar.jsx +254 -254
- package/runtime/velu-ui/components/SocialLinks.jsx +90 -90
- package/runtime/velu-ui/components/Steps.jsx +65 -65
- package/runtime/velu-ui/components/ThemeToggle.jsx +48 -48
- package/runtime/velu-ui/components/Toc.jsx +537 -537
- package/runtime/velu-ui/components/TocBar.jsx +195 -195
- package/runtime/velu-ui/components/Tree.jsx +87 -87
- package/runtime/velu-ui/components/TryItBar.jsx +102 -102
- package/runtime/velu-ui/components/accordion.css +92 -92
- package/runtime/velu-ui/components/api-page.css +208 -208
- package/runtime/velu-ui/components/api.css +635 -635
- package/runtime/velu-ui/components/ask-bar.css +94 -94
- package/runtime/velu-ui/components/card.css +105 -105
- package/runtime/velu-ui/components/chatbot.css +622 -622
- package/runtime/velu-ui/components/code-block.css +263 -263
- package/runtime/velu-ui/components/context-menu.css +173 -173
- package/runtime/velu-ui/components/docs-layout.css +822 -822
- package/runtime/velu-ui/components/field.css +82 -82
- package/runtime/velu-ui/components/image.css +237 -237
- package/runtime/velu-ui/components/nav-select.css +157 -157
- package/runtime/velu-ui/components/not-found.css +94 -94
- package/runtime/velu-ui/components/page-feedback.css +241 -241
- package/runtime/velu-ui/components/page-footer.css +130 -130
- package/runtime/velu-ui/components/page-header.css +558 -558
- package/runtime/velu-ui/components/page-nav.css +50 -50
- package/runtime/velu-ui/components/powered-by.css +92 -92
- package/runtime/velu-ui/components/prompt.css +99 -99
- package/runtime/velu-ui/components/search.css +307 -307
- package/runtime/velu-ui/components/sidebar.css +205 -205
- package/runtime/velu-ui/components/steps.css +77 -77
- package/runtime/velu-ui/components/theme-toggle.css +102 -102
- package/runtime/velu-ui/components/toc-bar.css +234 -234
- package/runtime/velu-ui/components/tree.css +49 -49
- package/runtime/velu-ui/index.js +54 -54
- package/runtime/velu-ui/lib/api-send.js +92 -92
- package/runtime/velu-ui/lib/brand-icons.jsx +103 -103
- package/runtime/velu-ui/lib/component-schemas.js +100 -100
- package/runtime/velu-ui/lib/copyText.js +64 -64
- package/runtime/velu-ui/lib/docs-assistant.js +250 -250
- package/runtime/velu-ui/lib/lang-icons.jsx +147 -147
- package/runtime/velu-ui/lib/pagefind.js +113 -113
- package/runtime/velu-ui/lib/prism-langs.js +957 -957
- package/runtime/velu-ui/lib/prism-loader.js +74 -74
- package/runtime/velu-ui/lib/resolveIcon.jsx +29 -29
- package/runtime/velu-ui/lib/scrollIntoNearestView.js +66 -66
- package/runtime/velu-ui/mdx-components.jsx +105 -105
- package/runtime/velu-ui/primitives/Cluster.jsx +49 -49
- package/runtime/velu-ui/primitives/Stack.jsx +63 -63
- package/runtime/velu-ui/primitives/Switcher.jsx +57 -57
- package/runtime/velu-ui/primitives/stack.css +3 -3
- package/runtime/velu-ui/primitives/switcher.css +25 -25
- package/runtime/velu-ui/styles.css +46 -46
- package/runtime/velu-ui/tokens.css +4 -4
- package/schema/velu.schema.json +423 -423
- package/src/lib/extract-mdx-error.js +170 -170
- package/src/lib/issues.js +159 -159
- package/src/lib/known-components.js +34 -34
- package/src/navigation.js +443 -443
- package/src/runtime/App.jsx +1669 -1668
- package/src/runtime/ErrorBoundary.jsx +54 -54
- package/src/runtime/client-entry.jsx +22 -22
- package/src/runtime/server-entry.jsx +16 -16
- package/src/template.html +48 -48
- package/templates/starter/ai-tools/claude-code.mdx +26 -26
- package/templates/starter/ai-tools/cursor.mdx +17 -17
- package/templates/starter/api-reference/introduction.mdx +43 -43
- package/templates/starter/development.mdx +19 -19
- package/templates/starter/essentials/code.mdx +29 -29
- package/templates/starter/essentials/images.mdx +29 -29
- package/templates/starter/essentials/markdown.mdx +25 -25
- package/templates/starter/essentials/navigation.mdx +39 -39
- package/templates/starter/essentials/settings.mdx +30 -30
- package/templates/starter/favicon.svg +6 -6
- package/templates/starter/index.mdx +31 -31
- package/templates/starter/openapi.json +160 -160
- package/templates/starter/quickstart.mdx +31 -31
- package/templates/starter/velu.json +41 -41
package/runtime/velu-ui/base.css
CHANGED
|
@@ -1,320 +1,320 @@
|
|
|
1
|
-
/* Fonts are loaded via <link rel="preconnect"/"stylesheet"> in template.html
|
|
2
|
-
(faster than an @import inside critical CSS — non-blocking, parallel). */
|
|
3
|
-
:root {
|
|
4
|
-
--ratio: 1.25;
|
|
5
|
-
--s-6: calc(var(--s-5) / var(--ratio));
|
|
6
|
-
--s-5: calc(var(--s-4) / var(--ratio));
|
|
7
|
-
--s-4: calc(var(--s-3) / var(--ratio));
|
|
8
|
-
--s-3: calc(var(--s-2) / var(--ratio));
|
|
9
|
-
--s-2: calc(var(--s-1) / var(--ratio));
|
|
10
|
-
--s-1: calc(var(--s0) / var(--ratio));
|
|
11
|
-
--s0: 1rem;
|
|
12
|
-
--s1: calc(var(--s0) * var(--ratio));
|
|
13
|
-
--s2: calc(var(--s1) * var(--ratio));
|
|
14
|
-
--s3: calc(var(--s2) * var(--ratio));
|
|
15
|
-
--s4: calc(var(--s3) * var(--ratio));
|
|
16
|
-
--s5: calc(var(--s4) * var(--ratio));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/* Semantic color tokens — verbatim from Figma (1:1 names, no translation).
|
|
20
|
-
Components reference ONLY these (never raw hex), so theme switching =
|
|
21
|
-
swapping this block (zero component changes).
|
|
22
|
-
--page-bg is PROVISIONAL: Figma has no explicit page-background token yet
|
|
23
|
-
(see note to Aravind) — replace once defined. */
|
|
24
|
-
:root {
|
|
25
|
-
--page-bg: #ffffff;
|
|
26
|
-
|
|
27
|
-
--border-color: #dcdcde;
|
|
28
|
-
--text-color: #000000;
|
|
29
|
-
--accent-color: #dc143c;
|
|
30
|
-
--muted-color: #7a7a7a;
|
|
31
|
-
--surface-color: #f2f3f4;
|
|
32
|
-
|
|
33
|
-
--note-bg-color: #f2f3f4;
|
|
34
|
-
--note-stroke-color: #6b7280;
|
|
35
|
-
--warning-bg-color: #fef3e2;
|
|
36
|
-
--warning-stroke-color: #d97706;
|
|
37
|
-
--info-bg-color: #e8f4fd;
|
|
38
|
-
--info-stroke-color: #3b82f6;
|
|
39
|
-
--tip-bg-color: #e8f5e9;
|
|
40
|
-
--tip-stroke-color: #16a34a;
|
|
41
|
-
--check-bg-color: #e6f9ed;
|
|
42
|
-
--check-stroke-color: #22c55e;
|
|
43
|
-
--danger-bg-color: #fde8e8;
|
|
44
|
-
--danger-stroke-color: #dc2626;
|
|
45
|
-
--callout-bg-color: #f3e8fd;
|
|
46
|
-
--callout-stroke-color: #8b5cf6;
|
|
47
|
-
|
|
48
|
-
--post-pill-color: #e8f4fd;
|
|
49
|
-
--post-pill-stroke-color: #91bbf9;
|
|
50
|
-
--post-cta-color: #3064e3;
|
|
51
|
-
--get-pill-color: #e6f9ed;
|
|
52
|
-
--get-pill-stroke-color: #22c55e;
|
|
53
|
-
--get-cta-color: #22c55e;
|
|
54
|
-
--put-pill-color: #fef3e2;
|
|
55
|
-
--put-pill-stroke-color: #d97706;
|
|
56
|
-
--put-cta-color: #d97706;
|
|
57
|
-
--delete-pill-color: #fde8e8;
|
|
58
|
-
--delete-pill-stroke-color: #dc2626;
|
|
59
|
-
--delete-cta-color: #dc2626;
|
|
60
|
-
--patch-pill-color: #f3e8fd;
|
|
61
|
-
--patch-pill-stroke-color: #8b5cf6;
|
|
62
|
-
--patch-cta-color: #8b5cf6;
|
|
63
|
-
}
|
|
64
|
-
:root[data-theme="dark"] {
|
|
65
|
-
--page-bg: #0D0E10;
|
|
66
|
-
|
|
67
|
-
--border-color: #262827;
|
|
68
|
-
--text-color: #eeeff1;
|
|
69
|
-
--accent-color: #dc143c;
|
|
70
|
-
--muted-color: #7a7a7a;
|
|
71
|
-
--surface-color: #323334;
|
|
72
|
-
|
|
73
|
-
--note-bg-color: #1a1a1c;
|
|
74
|
-
--note-stroke-color: #eeeff1;
|
|
75
|
-
--warning-bg-color: #2a1f0d;
|
|
76
|
-
--warning-stroke-color: #7a5a1f;
|
|
77
|
-
--info-bg-color: #0d1f2a;
|
|
78
|
-
--info-stroke-color: #1f5a7a;
|
|
79
|
-
--tip-bg-color: #0d2a1a;
|
|
80
|
-
--tip-stroke-color: #1f7a4a;
|
|
81
|
-
--check-bg-color: #0d2a1a;
|
|
82
|
-
--check-stroke-color: #1f7a4a;
|
|
83
|
-
--danger-bg-color: #2a0d0d;
|
|
84
|
-
--danger-stroke-color: #7a1f1f;
|
|
85
|
-
--callout-bg-color: #1f0d2a;
|
|
86
|
-
--callout-stroke-color: #5a1f7a;
|
|
87
|
-
|
|
88
|
-
--post-pill-color: #1e3a8a;
|
|
89
|
-
--post-pill-stroke-color: #3b82f6;
|
|
90
|
-
--post-cta-color: #2563eb;
|
|
91
|
-
--get-pill-color: #065f46;
|
|
92
|
-
--get-pill-stroke-color: #10b981;
|
|
93
|
-
--get-cta-color: #059669;
|
|
94
|
-
--put-pill-color: #78350f;
|
|
95
|
-
--put-pill-stroke-color: #f59e0b;
|
|
96
|
-
--put-cta-color: #d97706;
|
|
97
|
-
--delete-pill-color: #7f1d1d;
|
|
98
|
-
--delete-pill-stroke-color: #ef4444;
|
|
99
|
-
--delete-cta-color: #dc2626;
|
|
100
|
-
--patch-pill-color: #4c1d95;
|
|
101
|
-
--patch-pill-stroke-color: #8b5cf6;
|
|
102
|
-
--patch-cta-color: #7c3aed;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
:root {
|
|
106
|
-
--measure: 66ch;
|
|
107
|
-
--font-sans: "Google Sans Flex", sans-serif;
|
|
108
|
-
--font-mono: "Google Sans Code", ui-monospace, SFMono-Regular, monospace;
|
|
109
|
-
--font-brand: "Outfit", var(--font-sans);
|
|
110
|
-
font-family: var(--font-sans);
|
|
111
|
-
|
|
112
|
-
/* Approx height of the docs PageHeader (used as the offset for sticky
|
|
113
|
-
sidebars / TOC so they stick BELOW the header, not behind it). */
|
|
114
|
-
--velu-header-height: 7rem;
|
|
115
|
-
|
|
116
|
-
/* Fluid font sizes — 375px → 1440px viewport */
|
|
117
|
-
--f-body: 1rem; /* 16 → 16 */
|
|
118
|
-
--f-h7: calc(var(--f-h6) / var(--ratio)); /* micro UI text — one modular step below h6 (chips, captions, kbd) */
|
|
119
|
-
--f-h6: clamp(0.75rem, 0.188vw + 0.68rem, 0.875rem); /* 12 → 14 (reversed: mobile 14 → desktop 12, see note) */
|
|
120
|
-
--f-h5: 1rem; /* 16 → 16 */
|
|
121
|
-
--f-h4: clamp(1.125rem, 0.235vw + 1.07rem, 1.375rem); /* 18 → 22 */
|
|
122
|
-
--f-h3: clamp(1.3125rem,0.423vw + 1.214rem, 1.75rem); /* 21 → 28 */
|
|
123
|
-
--f-h2: clamp(1.5rem, 0.704vw + 1.335rem, 2.25rem); /* 24 → 36 */
|
|
124
|
-
--f-h1: clamp(1.6875rem,1.972vw + 1.226rem, 3rem); /* 27 → 48 */
|
|
125
|
-
|
|
126
|
-
/* Line-height tokens — unitless (height ÷ font-size from Figma). The
|
|
127
|
-
single source of truth for leading; components reference these, never
|
|
128
|
-
a hardcoded ratio. */
|
|
129
|
-
--lh-body: 1.75;
|
|
130
|
-
--lh-h1: 1.75;
|
|
131
|
-
--lh-h2: 1.78;
|
|
132
|
-
--lh-h3: 1.71;
|
|
133
|
-
--lh-h4: 1.82;
|
|
134
|
-
--lh-h5: 1.75;
|
|
135
|
-
--lh-h6: 1.71;
|
|
136
|
-
--lh-h7: 1.71;
|
|
137
|
-
|
|
138
|
-
/* Hairline width — single source of truth for every box border, divider
|
|
139
|
-
and rail. (Sub-pixel: crisp on hi-dpi; some 1x displays round it.) */
|
|
140
|
-
--border-width: 0.5px;
|
|
141
|
-
|
|
142
|
-
/* Icon stroke weight — single source of truth for every lucide icon. */
|
|
143
|
-
--icon-stroke: 1.5;
|
|
144
|
-
|
|
145
|
-
/* Icon size scale — em-relative so an icon next to text inherits the
|
|
146
|
-
text size automatically. `--icon-size` matches surrounding text;
|
|
147
|
-
`--icon-size-lg` is one modular step larger (for nav lists / trees
|
|
148
|
-
where the icon should slightly outweigh the label). */
|
|
149
|
-
--icon-size: 1em;
|
|
150
|
-
--icon-size-lg: calc(1em * var(--ratio));
|
|
151
|
-
|
|
152
|
-
/* Corner-radius scale, derived from --s0 (16px) — no raw literals.
|
|
153
|
-
sm 8 / md 16 / lg 32. Components pick the right step. */
|
|
154
|
-
--radius-sm: calc(var(--s0) / 2);
|
|
155
|
-
--radius-md: var(--s0);
|
|
156
|
-
--radius-lg: calc(var(--s0) * 2);
|
|
157
|
-
|
|
158
|
-
/* Font-weight scale — single source of truth so components never
|
|
159
|
-
write raw 300/400/500/600/700. Matches Google Sans Flex's
|
|
160
|
-
variable-font axis stops. */
|
|
161
|
-
--weight-light: 300;
|
|
162
|
-
--weight-normal: 400;
|
|
163
|
-
--weight-medium: 500;
|
|
164
|
-
--weight-semibold: 600;
|
|
165
|
-
--weight-bold: 700;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/* lucide-react adds class="lucide …" to every icon svg. This one rule
|
|
169
|
-
tokenizes stroke weight app-wide (CSS overrides the svg's stroke-width
|
|
170
|
-
attribute), so no component sets it per-icon. */
|
|
171
|
-
.lucide {
|
|
172
|
-
stroke-width: var(--icon-stroke);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/* Prose rhythm — wraps MDX content. MDX compiles to a flat list of
|
|
176
|
-
sibling block elements (h1, p, the velu-ui components, etc.).
|
|
177
|
-
Spacing is scaled by HEADING LEVEL so the document's structure is
|
|
178
|
-
readable at a glance:
|
|
179
|
-
- default sibling pair (paragraph rhythm): --s1
|
|
180
|
-
- before any heading (section break): scaled by level
|
|
181
|
-
- after a heading (heading → first child): one step under default
|
|
182
|
-
The rules use adjacent-sibling selectors so every same-level heading
|
|
183
|
-
gets the same lead-in regardless of what came before it (sibling
|
|
184
|
-
equality), and the larger before-heading gap reads as the section
|
|
185
|
-
break in every case. The owl rule sets the default; per-heading
|
|
186
|
-
rules below override it via source order (same specificity). */
|
|
187
|
-
|
|
188
|
-
/* Scroll-anchor offset for in-page links: when a TOC click lands on
|
|
189
|
-
a heading, the browser scrolls so the heading sits at the viewport
|
|
190
|
-
top — which would otherwise put it BEHIND the sticky chrome
|
|
191
|
-
(header + TocBar). `scroll-margin-block-start` tells the scroll
|
|
192
|
-
algorithm to leave that much space above the target.
|
|
193
|
-
|
|
194
|
-
--velu-scroll-offset is published by App.jsx as
|
|
195
|
-
`headerHeight + tocbarHeight + 1rem`, measured live via
|
|
196
|
-
ResizeObserver. The scroll-spy reads the SAME variable as its
|
|
197
|
-
trigger line, so scrollIntoView lands the heading exactly where
|
|
198
|
-
the spy promotes it — no magic numbers, no drift. */
|
|
199
|
-
.velu-hero h1,
|
|
200
|
-
.velu-prose :is(h1, h2, h3, h4, h5, h6) {
|
|
201
|
-
scroll-margin-block-start: var(--velu-scroll-offset, 5rem);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/* Default prose rhythm. */
|
|
205
|
-
.velu-prose > * + * {
|
|
206
|
-
margin-block-start: var(--s1);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/* Before-heading: progressively larger gap above higher-level headings.
|
|
210
|
-
Same level → same gap → siblings read at equal intervals. */
|
|
211
|
-
.velu-prose > * + h2 {
|
|
212
|
-
margin-block-start: var(--s4);
|
|
213
|
-
}
|
|
214
|
-
.velu-prose > * + h3 {
|
|
215
|
-
margin-block-start: var(--s3);
|
|
216
|
-
}
|
|
217
|
-
.velu-prose > * + h4 {
|
|
218
|
-
margin-block-start: var(--s2);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/* After-heading: tighter, so the heading reads as "introducing" what
|
|
222
|
-
follows rather than floating alone above a chasm. */
|
|
223
|
-
.velu-prose > h1 + *,
|
|
224
|
-
.velu-prose > h2 + *,
|
|
225
|
-
.velu-prose > h3 + *,
|
|
226
|
-
.velu-prose > h4 + *,
|
|
227
|
-
.velu-prose > h5 + *,
|
|
228
|
-
.velu-prose > h6 + * {
|
|
229
|
-
margin-block-start: var(--s0);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/* Page hero — the frontmatter (title + description) is wrapped in
|
|
233
|
-
`.velu-hero` so the title and description sit tight as a single
|
|
234
|
-
unit, and a larger break separates the hero from the prose body. */
|
|
235
|
-
.velu-hero > h1 + p {
|
|
236
|
-
margin-block-start: var(--s-2);
|
|
237
|
-
}
|
|
238
|
-
/* hero → body is an h1 → h2 transition (level-down, not peer-to-peer),
|
|
239
|
-
so the break is one modular step LARGER than the regular section
|
|
240
|
-
break above an h2 (--s4). Keeps the scale strictly monotonic:
|
|
241
|
-
level-down break > peer break. */
|
|
242
|
-
.velu-hero + .velu-prose {
|
|
243
|
-
margin-block-start: var(--s5);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/* Discreet thin scrollbar with a tokenised colour in every state — applied
|
|
247
|
-
GLOBALLY (the `*` selector) so every scrollable element inherits it by
|
|
248
|
-
default: the chatbot, dialogs, and any future component, with no
|
|
249
|
-
per-component opt-in. Component-specific scrollbar rules win via
|
|
250
|
-
specificity (e.g. the nav/TOC reveal-on-hover overrides below).
|
|
251
|
-
`.velu-hide-scrollbar` stays as an explicit alias for existing markup.
|
|
252
|
-
|
|
253
|
-
No transitions: Firefox doesn't honour CSS transitions on `scrollbar-color`
|
|
254
|
-
consistently, and the in-between interpolation + its auto-derived
|
|
255
|
-
hover/active colours can flash a yellow/amber accent (an OS / system accent
|
|
256
|
-
when interpolating). Hard switches avoid that. Same reason every WebKit
|
|
257
|
-
thumb pseudo-state is set explicitly — otherwise Chromium can fall back to
|
|
258
|
-
the Windows 11 system accent on hover. */
|
|
259
|
-
*,
|
|
260
|
-
.velu-hide-scrollbar {
|
|
261
|
-
scrollbar-width: thin;
|
|
262
|
-
/* Single colour both at rest and on hover. Firefox auto-darkens on
|
|
263
|
-
interaction, but starting from a defined light grey keeps the
|
|
264
|
-
derived shade in the same family (no yellow flash). */
|
|
265
|
-
scrollbar-color: var(--border-color) transparent;
|
|
266
|
-
}
|
|
267
|
-
*::-webkit-scrollbar,
|
|
268
|
-
.velu-hide-scrollbar::-webkit-scrollbar {
|
|
269
|
-
inline-size: 6px;
|
|
270
|
-
block-size: 6px;
|
|
271
|
-
}
|
|
272
|
-
*::-webkit-scrollbar-track,
|
|
273
|
-
.velu-hide-scrollbar::-webkit-scrollbar-track {
|
|
274
|
-
background: transparent;
|
|
275
|
-
}
|
|
276
|
-
*::-webkit-scrollbar-thumb,
|
|
277
|
-
.velu-hide-scrollbar::-webkit-scrollbar-thumb {
|
|
278
|
-
background: var(--border-color);
|
|
279
|
-
border-radius: 999px;
|
|
280
|
-
}
|
|
281
|
-
*::-webkit-scrollbar-thumb:hover,
|
|
282
|
-
*::-webkit-scrollbar-thumb:active,
|
|
283
|
-
.velu-hide-scrollbar::-webkit-scrollbar-thumb:hover,
|
|
284
|
-
.velu-hide-scrollbar::-webkit-scrollbar-thumb:active {
|
|
285
|
-
background: var(--muted-color);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/* Unitless line-height ratios (height ÷ font-size from Figma) */
|
|
289
|
-
body {
|
|
290
|
-
font-size: var(--f-body);
|
|
291
|
-
line-height: var(--lh-body);
|
|
292
|
-
font-weight: var(--weight-normal);
|
|
293
|
-
background: var(--page-bg);
|
|
294
|
-
color: var(--text-color);
|
|
295
|
-
}
|
|
296
|
-
h1 { font-size: var(--f-h1); line-height: var(--lh-h1); font-weight: var(--weight-semibold); }
|
|
297
|
-
h2 { font-size: var(--f-h2); line-height: var(--lh-h2); font-weight: var(--weight-medium); }
|
|
298
|
-
h3 { font-size: var(--f-h3); line-height: var(--lh-h3); font-weight: var(--weight-medium); }
|
|
299
|
-
h4 { font-size: var(--f-h4); line-height: var(--lh-h4); font-weight: var(--weight-normal); }
|
|
300
|
-
h5 { font-size: var(--f-h5); line-height: var(--lh-h5); font-weight: var(--weight-normal); }
|
|
301
|
-
h6 { font-size: var(--f-h6); line-height: var(--lh-h6); font-weight: var(--weight-normal); }
|
|
302
|
-
|
|
303
|
-
* {
|
|
304
|
-
max-width: var(--measure);
|
|
305
|
-
box-sizing: border-box;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
html,
|
|
309
|
-
body,
|
|
310
|
-
div,
|
|
311
|
-
header,
|
|
312
|
-
nav,
|
|
313
|
-
main,
|
|
314
|
-
footer,
|
|
315
|
-
pre,
|
|
316
|
-
code,
|
|
317
|
-
span,
|
|
318
|
-
button {
|
|
319
|
-
max-width: none;
|
|
320
|
-
}
|
|
1
|
+
/* Fonts are loaded via <link rel="preconnect"/"stylesheet"> in template.html
|
|
2
|
+
(faster than an @import inside critical CSS — non-blocking, parallel). */
|
|
3
|
+
:root {
|
|
4
|
+
--ratio: 1.25;
|
|
5
|
+
--s-6: calc(var(--s-5) / var(--ratio));
|
|
6
|
+
--s-5: calc(var(--s-4) / var(--ratio));
|
|
7
|
+
--s-4: calc(var(--s-3) / var(--ratio));
|
|
8
|
+
--s-3: calc(var(--s-2) / var(--ratio));
|
|
9
|
+
--s-2: calc(var(--s-1) / var(--ratio));
|
|
10
|
+
--s-1: calc(var(--s0) / var(--ratio));
|
|
11
|
+
--s0: 1rem;
|
|
12
|
+
--s1: calc(var(--s0) * var(--ratio));
|
|
13
|
+
--s2: calc(var(--s1) * var(--ratio));
|
|
14
|
+
--s3: calc(var(--s2) * var(--ratio));
|
|
15
|
+
--s4: calc(var(--s3) * var(--ratio));
|
|
16
|
+
--s5: calc(var(--s4) * var(--ratio));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Semantic color tokens — verbatim from Figma (1:1 names, no translation).
|
|
20
|
+
Components reference ONLY these (never raw hex), so theme switching =
|
|
21
|
+
swapping this block (zero component changes).
|
|
22
|
+
--page-bg is PROVISIONAL: Figma has no explicit page-background token yet
|
|
23
|
+
(see note to Aravind) — replace once defined. */
|
|
24
|
+
:root {
|
|
25
|
+
--page-bg: #ffffff;
|
|
26
|
+
|
|
27
|
+
--border-color: #dcdcde;
|
|
28
|
+
--text-color: #000000;
|
|
29
|
+
--accent-color: #dc143c;
|
|
30
|
+
--muted-color: #7a7a7a;
|
|
31
|
+
--surface-color: #f2f3f4;
|
|
32
|
+
|
|
33
|
+
--note-bg-color: #f2f3f4;
|
|
34
|
+
--note-stroke-color: #6b7280;
|
|
35
|
+
--warning-bg-color: #fef3e2;
|
|
36
|
+
--warning-stroke-color: #d97706;
|
|
37
|
+
--info-bg-color: #e8f4fd;
|
|
38
|
+
--info-stroke-color: #3b82f6;
|
|
39
|
+
--tip-bg-color: #e8f5e9;
|
|
40
|
+
--tip-stroke-color: #16a34a;
|
|
41
|
+
--check-bg-color: #e6f9ed;
|
|
42
|
+
--check-stroke-color: #22c55e;
|
|
43
|
+
--danger-bg-color: #fde8e8;
|
|
44
|
+
--danger-stroke-color: #dc2626;
|
|
45
|
+
--callout-bg-color: #f3e8fd;
|
|
46
|
+
--callout-stroke-color: #8b5cf6;
|
|
47
|
+
|
|
48
|
+
--post-pill-color: #e8f4fd;
|
|
49
|
+
--post-pill-stroke-color: #91bbf9;
|
|
50
|
+
--post-cta-color: #3064e3;
|
|
51
|
+
--get-pill-color: #e6f9ed;
|
|
52
|
+
--get-pill-stroke-color: #22c55e;
|
|
53
|
+
--get-cta-color: #22c55e;
|
|
54
|
+
--put-pill-color: #fef3e2;
|
|
55
|
+
--put-pill-stroke-color: #d97706;
|
|
56
|
+
--put-cta-color: #d97706;
|
|
57
|
+
--delete-pill-color: #fde8e8;
|
|
58
|
+
--delete-pill-stroke-color: #dc2626;
|
|
59
|
+
--delete-cta-color: #dc2626;
|
|
60
|
+
--patch-pill-color: #f3e8fd;
|
|
61
|
+
--patch-pill-stroke-color: #8b5cf6;
|
|
62
|
+
--patch-cta-color: #8b5cf6;
|
|
63
|
+
}
|
|
64
|
+
:root[data-theme="dark"] {
|
|
65
|
+
--page-bg: #0D0E10;
|
|
66
|
+
|
|
67
|
+
--border-color: #262827;
|
|
68
|
+
--text-color: #eeeff1;
|
|
69
|
+
--accent-color: #dc143c;
|
|
70
|
+
--muted-color: #7a7a7a;
|
|
71
|
+
--surface-color: #323334;
|
|
72
|
+
|
|
73
|
+
--note-bg-color: #1a1a1c;
|
|
74
|
+
--note-stroke-color: #eeeff1;
|
|
75
|
+
--warning-bg-color: #2a1f0d;
|
|
76
|
+
--warning-stroke-color: #7a5a1f;
|
|
77
|
+
--info-bg-color: #0d1f2a;
|
|
78
|
+
--info-stroke-color: #1f5a7a;
|
|
79
|
+
--tip-bg-color: #0d2a1a;
|
|
80
|
+
--tip-stroke-color: #1f7a4a;
|
|
81
|
+
--check-bg-color: #0d2a1a;
|
|
82
|
+
--check-stroke-color: #1f7a4a;
|
|
83
|
+
--danger-bg-color: #2a0d0d;
|
|
84
|
+
--danger-stroke-color: #7a1f1f;
|
|
85
|
+
--callout-bg-color: #1f0d2a;
|
|
86
|
+
--callout-stroke-color: #5a1f7a;
|
|
87
|
+
|
|
88
|
+
--post-pill-color: #1e3a8a;
|
|
89
|
+
--post-pill-stroke-color: #3b82f6;
|
|
90
|
+
--post-cta-color: #2563eb;
|
|
91
|
+
--get-pill-color: #065f46;
|
|
92
|
+
--get-pill-stroke-color: #10b981;
|
|
93
|
+
--get-cta-color: #059669;
|
|
94
|
+
--put-pill-color: #78350f;
|
|
95
|
+
--put-pill-stroke-color: #f59e0b;
|
|
96
|
+
--put-cta-color: #d97706;
|
|
97
|
+
--delete-pill-color: #7f1d1d;
|
|
98
|
+
--delete-pill-stroke-color: #ef4444;
|
|
99
|
+
--delete-cta-color: #dc2626;
|
|
100
|
+
--patch-pill-color: #4c1d95;
|
|
101
|
+
--patch-pill-stroke-color: #8b5cf6;
|
|
102
|
+
--patch-cta-color: #7c3aed;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
:root {
|
|
106
|
+
--measure: 66ch;
|
|
107
|
+
--font-sans: "Google Sans Flex", sans-serif;
|
|
108
|
+
--font-mono: "Google Sans Code", ui-monospace, SFMono-Regular, monospace;
|
|
109
|
+
--font-brand: "Outfit", var(--font-sans);
|
|
110
|
+
font-family: var(--font-sans);
|
|
111
|
+
|
|
112
|
+
/* Approx height of the docs PageHeader (used as the offset for sticky
|
|
113
|
+
sidebars / TOC so they stick BELOW the header, not behind it). */
|
|
114
|
+
--velu-header-height: 7rem;
|
|
115
|
+
|
|
116
|
+
/* Fluid font sizes — 375px → 1440px viewport */
|
|
117
|
+
--f-body: 1rem; /* 16 → 16 */
|
|
118
|
+
--f-h7: calc(var(--f-h6) / var(--ratio)); /* micro UI text — one modular step below h6 (chips, captions, kbd) */
|
|
119
|
+
--f-h6: clamp(0.75rem, 0.188vw + 0.68rem, 0.875rem); /* 12 → 14 (reversed: mobile 14 → desktop 12, see note) */
|
|
120
|
+
--f-h5: 1rem; /* 16 → 16 */
|
|
121
|
+
--f-h4: clamp(1.125rem, 0.235vw + 1.07rem, 1.375rem); /* 18 → 22 */
|
|
122
|
+
--f-h3: clamp(1.3125rem,0.423vw + 1.214rem, 1.75rem); /* 21 → 28 */
|
|
123
|
+
--f-h2: clamp(1.5rem, 0.704vw + 1.335rem, 2.25rem); /* 24 → 36 */
|
|
124
|
+
--f-h1: clamp(1.6875rem,1.972vw + 1.226rem, 3rem); /* 27 → 48 */
|
|
125
|
+
|
|
126
|
+
/* Line-height tokens — unitless (height ÷ font-size from Figma). The
|
|
127
|
+
single source of truth for leading; components reference these, never
|
|
128
|
+
a hardcoded ratio. */
|
|
129
|
+
--lh-body: 1.75;
|
|
130
|
+
--lh-h1: 1.75;
|
|
131
|
+
--lh-h2: 1.78;
|
|
132
|
+
--lh-h3: 1.71;
|
|
133
|
+
--lh-h4: 1.82;
|
|
134
|
+
--lh-h5: 1.75;
|
|
135
|
+
--lh-h6: 1.71;
|
|
136
|
+
--lh-h7: 1.71;
|
|
137
|
+
|
|
138
|
+
/* Hairline width — single source of truth for every box border, divider
|
|
139
|
+
and rail. (Sub-pixel: crisp on hi-dpi; some 1x displays round it.) */
|
|
140
|
+
--border-width: 0.5px;
|
|
141
|
+
|
|
142
|
+
/* Icon stroke weight — single source of truth for every lucide icon. */
|
|
143
|
+
--icon-stroke: 1.5;
|
|
144
|
+
|
|
145
|
+
/* Icon size scale — em-relative so an icon next to text inherits the
|
|
146
|
+
text size automatically. `--icon-size` matches surrounding text;
|
|
147
|
+
`--icon-size-lg` is one modular step larger (for nav lists / trees
|
|
148
|
+
where the icon should slightly outweigh the label). */
|
|
149
|
+
--icon-size: 1em;
|
|
150
|
+
--icon-size-lg: calc(1em * var(--ratio));
|
|
151
|
+
|
|
152
|
+
/* Corner-radius scale, derived from --s0 (16px) — no raw literals.
|
|
153
|
+
sm 8 / md 16 / lg 32. Components pick the right step. */
|
|
154
|
+
--radius-sm: calc(var(--s0) / 2);
|
|
155
|
+
--radius-md: var(--s0);
|
|
156
|
+
--radius-lg: calc(var(--s0) * 2);
|
|
157
|
+
|
|
158
|
+
/* Font-weight scale — single source of truth so components never
|
|
159
|
+
write raw 300/400/500/600/700. Matches Google Sans Flex's
|
|
160
|
+
variable-font axis stops. */
|
|
161
|
+
--weight-light: 300;
|
|
162
|
+
--weight-normal: 400;
|
|
163
|
+
--weight-medium: 500;
|
|
164
|
+
--weight-semibold: 600;
|
|
165
|
+
--weight-bold: 700;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* lucide-react adds class="lucide …" to every icon svg. This one rule
|
|
169
|
+
tokenizes stroke weight app-wide (CSS overrides the svg's stroke-width
|
|
170
|
+
attribute), so no component sets it per-icon. */
|
|
171
|
+
.lucide {
|
|
172
|
+
stroke-width: var(--icon-stroke);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* Prose rhythm — wraps MDX content. MDX compiles to a flat list of
|
|
176
|
+
sibling block elements (h1, p, the velu-ui components, etc.).
|
|
177
|
+
Spacing is scaled by HEADING LEVEL so the document's structure is
|
|
178
|
+
readable at a glance:
|
|
179
|
+
- default sibling pair (paragraph rhythm): --s1
|
|
180
|
+
- before any heading (section break): scaled by level
|
|
181
|
+
- after a heading (heading → first child): one step under default
|
|
182
|
+
The rules use adjacent-sibling selectors so every same-level heading
|
|
183
|
+
gets the same lead-in regardless of what came before it (sibling
|
|
184
|
+
equality), and the larger before-heading gap reads as the section
|
|
185
|
+
break in every case. The owl rule sets the default; per-heading
|
|
186
|
+
rules below override it via source order (same specificity). */
|
|
187
|
+
|
|
188
|
+
/* Scroll-anchor offset for in-page links: when a TOC click lands on
|
|
189
|
+
a heading, the browser scrolls so the heading sits at the viewport
|
|
190
|
+
top — which would otherwise put it BEHIND the sticky chrome
|
|
191
|
+
(header + TocBar). `scroll-margin-block-start` tells the scroll
|
|
192
|
+
algorithm to leave that much space above the target.
|
|
193
|
+
|
|
194
|
+
--velu-scroll-offset is published by App.jsx as
|
|
195
|
+
`headerHeight + tocbarHeight + 1rem`, measured live via
|
|
196
|
+
ResizeObserver. The scroll-spy reads the SAME variable as its
|
|
197
|
+
trigger line, so scrollIntoView lands the heading exactly where
|
|
198
|
+
the spy promotes it — no magic numbers, no drift. */
|
|
199
|
+
.velu-hero h1,
|
|
200
|
+
.velu-prose :is(h1, h2, h3, h4, h5, h6) {
|
|
201
|
+
scroll-margin-block-start: var(--velu-scroll-offset, 5rem);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* Default prose rhythm. */
|
|
205
|
+
.velu-prose > * + * {
|
|
206
|
+
margin-block-start: var(--s1);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* Before-heading: progressively larger gap above higher-level headings.
|
|
210
|
+
Same level → same gap → siblings read at equal intervals. */
|
|
211
|
+
.velu-prose > * + h2 {
|
|
212
|
+
margin-block-start: var(--s4);
|
|
213
|
+
}
|
|
214
|
+
.velu-prose > * + h3 {
|
|
215
|
+
margin-block-start: var(--s3);
|
|
216
|
+
}
|
|
217
|
+
.velu-prose > * + h4 {
|
|
218
|
+
margin-block-start: var(--s2);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* After-heading: tighter, so the heading reads as "introducing" what
|
|
222
|
+
follows rather than floating alone above a chasm. */
|
|
223
|
+
.velu-prose > h1 + *,
|
|
224
|
+
.velu-prose > h2 + *,
|
|
225
|
+
.velu-prose > h3 + *,
|
|
226
|
+
.velu-prose > h4 + *,
|
|
227
|
+
.velu-prose > h5 + *,
|
|
228
|
+
.velu-prose > h6 + * {
|
|
229
|
+
margin-block-start: var(--s0);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* Page hero — the frontmatter (title + description) is wrapped in
|
|
233
|
+
`.velu-hero` so the title and description sit tight as a single
|
|
234
|
+
unit, and a larger break separates the hero from the prose body. */
|
|
235
|
+
.velu-hero > h1 + p {
|
|
236
|
+
margin-block-start: var(--s-2);
|
|
237
|
+
}
|
|
238
|
+
/* hero → body is an h1 → h2 transition (level-down, not peer-to-peer),
|
|
239
|
+
so the break is one modular step LARGER than the regular section
|
|
240
|
+
break above an h2 (--s4). Keeps the scale strictly monotonic:
|
|
241
|
+
level-down break > peer break. */
|
|
242
|
+
.velu-hero + .velu-prose {
|
|
243
|
+
margin-block-start: var(--s5);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* Discreet thin scrollbar with a tokenised colour in every state — applied
|
|
247
|
+
GLOBALLY (the `*` selector) so every scrollable element inherits it by
|
|
248
|
+
default: the chatbot, dialogs, and any future component, with no
|
|
249
|
+
per-component opt-in. Component-specific scrollbar rules win via
|
|
250
|
+
specificity (e.g. the nav/TOC reveal-on-hover overrides below).
|
|
251
|
+
`.velu-hide-scrollbar` stays as an explicit alias for existing markup.
|
|
252
|
+
|
|
253
|
+
No transitions: Firefox doesn't honour CSS transitions on `scrollbar-color`
|
|
254
|
+
consistently, and the in-between interpolation + its auto-derived
|
|
255
|
+
hover/active colours can flash a yellow/amber accent (an OS / system accent
|
|
256
|
+
when interpolating). Hard switches avoid that. Same reason every WebKit
|
|
257
|
+
thumb pseudo-state is set explicitly — otherwise Chromium can fall back to
|
|
258
|
+
the Windows 11 system accent on hover. */
|
|
259
|
+
*,
|
|
260
|
+
.velu-hide-scrollbar {
|
|
261
|
+
scrollbar-width: thin;
|
|
262
|
+
/* Single colour both at rest and on hover. Firefox auto-darkens on
|
|
263
|
+
interaction, but starting from a defined light grey keeps the
|
|
264
|
+
derived shade in the same family (no yellow flash). */
|
|
265
|
+
scrollbar-color: var(--border-color) transparent;
|
|
266
|
+
}
|
|
267
|
+
*::-webkit-scrollbar,
|
|
268
|
+
.velu-hide-scrollbar::-webkit-scrollbar {
|
|
269
|
+
inline-size: 6px;
|
|
270
|
+
block-size: 6px;
|
|
271
|
+
}
|
|
272
|
+
*::-webkit-scrollbar-track,
|
|
273
|
+
.velu-hide-scrollbar::-webkit-scrollbar-track {
|
|
274
|
+
background: transparent;
|
|
275
|
+
}
|
|
276
|
+
*::-webkit-scrollbar-thumb,
|
|
277
|
+
.velu-hide-scrollbar::-webkit-scrollbar-thumb {
|
|
278
|
+
background: var(--border-color);
|
|
279
|
+
border-radius: 999px;
|
|
280
|
+
}
|
|
281
|
+
*::-webkit-scrollbar-thumb:hover,
|
|
282
|
+
*::-webkit-scrollbar-thumb:active,
|
|
283
|
+
.velu-hide-scrollbar::-webkit-scrollbar-thumb:hover,
|
|
284
|
+
.velu-hide-scrollbar::-webkit-scrollbar-thumb:active {
|
|
285
|
+
background: var(--muted-color);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/* Unitless line-height ratios (height ÷ font-size from Figma) */
|
|
289
|
+
body {
|
|
290
|
+
font-size: var(--f-body);
|
|
291
|
+
line-height: var(--lh-body);
|
|
292
|
+
font-weight: var(--weight-normal);
|
|
293
|
+
background: var(--page-bg);
|
|
294
|
+
color: var(--text-color);
|
|
295
|
+
}
|
|
296
|
+
h1 { font-size: var(--f-h1); line-height: var(--lh-h1); font-weight: var(--weight-semibold); }
|
|
297
|
+
h2 { font-size: var(--f-h2); line-height: var(--lh-h2); font-weight: var(--weight-medium); }
|
|
298
|
+
h3 { font-size: var(--f-h3); line-height: var(--lh-h3); font-weight: var(--weight-medium); }
|
|
299
|
+
h4 { font-size: var(--f-h4); line-height: var(--lh-h4); font-weight: var(--weight-normal); }
|
|
300
|
+
h5 { font-size: var(--f-h5); line-height: var(--lh-h5); font-weight: var(--weight-normal); }
|
|
301
|
+
h6 { font-size: var(--f-h6); line-height: var(--lh-h6); font-weight: var(--weight-normal); }
|
|
302
|
+
|
|
303
|
+
* {
|
|
304
|
+
max-width: var(--measure);
|
|
305
|
+
box-sizing: border-box;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
html,
|
|
309
|
+
body,
|
|
310
|
+
div,
|
|
311
|
+
header,
|
|
312
|
+
nav,
|
|
313
|
+
main,
|
|
314
|
+
footer,
|
|
315
|
+
pre,
|
|
316
|
+
code,
|
|
317
|
+
span,
|
|
318
|
+
button {
|
|
319
|
+
max-width: none;
|
|
320
|
+
}
|