@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
|
@@ -1,234 +1,234 @@
|
|
|
1
|
-
/* TocBar — narrow-layout counterpart to <Toc>.
|
|
2
|
-
|
|
3
|
-
Rendered always (so SSR / hydration markup matches at every size)
|
|
4
|
-
but VISIBLE only at narrow widths via a container query against the
|
|
5
|
-
docs layout. At wide widths the right-rail <Toc> takes over and
|
|
6
|
-
this bar is `display: none` — no media queries.
|
|
7
|
-
|
|
8
|
-
All values are tokens; light/dark via [data-theme]. */
|
|
9
|
-
|
|
10
|
-
.velu-toc-bar {
|
|
11
|
-
/* Hidden by default — the wide layout uses the right-rail <Toc>.
|
|
12
|
-
Container query below flips it on at narrow widths. */
|
|
13
|
-
display: none;
|
|
14
|
-
/* Sticky to the top of the article so it stays in view as the
|
|
15
|
-
user scrolls through the page. Sits below the page header. */
|
|
16
|
-
position: sticky;
|
|
17
|
-
inset-block-start: var(--velu-header-height);
|
|
18
|
-
z-index: 5;
|
|
19
|
-
/* Frosted-glass background — same recipe as the scrolled header
|
|
20
|
-
(.velu-header--scrolled in page-header.css). 75% --page-bg + a
|
|
21
|
-
saturate/blur backdrop lets article content show through faintly
|
|
22
|
-
so the bar reads as a layer over the page rather than a solid
|
|
23
|
-
band. The dropdown below uses the same recipe so the bar +
|
|
24
|
-
expanded list look like one continuous translucent fabric. */
|
|
25
|
-
background: color-mix(in srgb, var(--page-bg) 75%, transparent);
|
|
26
|
-
backdrop-filter: saturate(140%) blur(12px);
|
|
27
|
-
-webkit-backdrop-filter: saturate(140%) blur(12px);
|
|
28
|
-
border-block-end: var(--border-width) solid var(--surface-color);
|
|
29
|
-
/* base.css's global `* { max-width: 66ch }` (the prose measure)
|
|
30
|
-
would otherwise cap the bar AND its dropdown well short of the
|
|
31
|
-
viewport edge — explicitly override it for the bar's subtree. */
|
|
32
|
-
max-inline-size: none;
|
|
33
|
-
}
|
|
34
|
-
.velu-toc-bar *,
|
|
35
|
-
.velu-toc-bar {
|
|
36
|
-
max-inline-size: none;
|
|
37
|
-
}
|
|
38
|
-
/* When expanded, the dropdown's own border-block-end terminates
|
|
39
|
-
the combined bar+dropdown — suppress the bar's bottom border so
|
|
40
|
-
there isn't a double-printed line between bar and dropdown. The
|
|
41
|
-
toggle's `border-block-end` still draws the divider between the
|
|
42
|
-
toggle row and the list. Also drop the frosted recipe — the
|
|
43
|
-
dropdown reveals article content underneath, and a translucent
|
|
44
|
-
bar+dropdown would let the article text bleed through the menu.
|
|
45
|
-
Solid --page-bg keeps the list readable in either theme. */
|
|
46
|
-
.velu-toc-bar[data-expanded='true'] {
|
|
47
|
-
border-block-end-color: transparent;
|
|
48
|
-
background: var(--page-bg);
|
|
49
|
-
backdrop-filter: none;
|
|
50
|
-
-webkit-backdrop-filter: none;
|
|
51
|
-
}
|
|
52
|
-
.velu-toc-bar[data-expanded='true'] .velu-toc-bar__list {
|
|
53
|
-
background: var(--page-bg);
|
|
54
|
-
backdrop-filter: none;
|
|
55
|
-
-webkit-backdrop-filter: none;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
@container docs (max-width: 1024px) {
|
|
59
|
-
.velu-toc-bar {
|
|
60
|
-
display: block;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/* ── Toggle (collapsed header) ─────────────────────────────────────── */
|
|
65
|
-
.velu-toc-bar__toggle {
|
|
66
|
-
display: flex;
|
|
67
|
-
align-items: center;
|
|
68
|
-
gap: var(--s-2);
|
|
69
|
-
inline-size: 100%;
|
|
70
|
-
/* Block padding fixed at 8px so the bar hugs its single-row
|
|
71
|
-
content tightly; inline padding stays on the spacing scale. */
|
|
72
|
-
padding-block: 0.5rem;
|
|
73
|
-
padding-inline: var(--s3);
|
|
74
|
-
/* Divider between the toggle row and the expanded list lives
|
|
75
|
-
here (not on the list) so it spans the toggle's full inline
|
|
76
|
-
size — touching the sidebar's vertical border on the left
|
|
77
|
-
instead of being inset by the list's leading margin. Hidden
|
|
78
|
-
when collapsed (TocBar's own bottom border terminates the
|
|
79
|
-
row). */
|
|
80
|
-
border-width: 0 0 var(--border-width) 0;
|
|
81
|
-
border-style: solid;
|
|
82
|
-
border-color: var(--surface-color);
|
|
83
|
-
background: transparent;
|
|
84
|
-
color: var(--text-color);
|
|
85
|
-
font: inherit;
|
|
86
|
-
font-size: var(--f-h5);
|
|
87
|
-
text-align: start;
|
|
88
|
-
cursor: pointer;
|
|
89
|
-
}
|
|
90
|
-
/* No interior divider between the toggle row and the dropdown —
|
|
91
|
-
they're one continuous fabric. The only horizontal line in the
|
|
92
|
-
expanded state is the dropdown's own border-block-end, at the
|
|
93
|
-
very bottom of the combined element. */
|
|
94
|
-
.velu-toc-bar__toggle {
|
|
95
|
-
border-block-end-color: transparent;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/* Reading-progress ring — SVG circle whose stroke fills as the
|
|
99
|
-
reader scrolls. Sized like a chip so it reads as a peer of the
|
|
100
|
-
chevron at the other edge of the toggle row. */
|
|
101
|
-
.velu-toc-bar__progress {
|
|
102
|
-
flex: none;
|
|
103
|
-
inline-size: 1.25em;
|
|
104
|
-
block-size: 1.25em;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.velu-toc-bar__title {
|
|
108
|
-
flex: 1;
|
|
109
|
-
min-inline-size: 0;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.velu-toc-bar__chevron {
|
|
113
|
-
flex: none;
|
|
114
|
-
inline-size: var(--f-body);
|
|
115
|
-
block-size: var(--f-body);
|
|
116
|
-
color: var(--muted-color);
|
|
117
|
-
transition: transform 0.2s ease;
|
|
118
|
-
}
|
|
119
|
-
.velu-toc-bar[data-expanded='true'] .velu-toc-bar__chevron {
|
|
120
|
-
transform: rotate(180deg);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/* ── Expanded list (overlay) ───────────────────────────────────────── */
|
|
124
|
-
/* `position: absolute` overlay anchored to the bottom of the sticky
|
|
125
|
-
TocBar — the list does NOT participate in the article's normal
|
|
126
|
-
flow. That's the critical bit: when the user expands/collapses
|
|
127
|
-
the dropdown, the article does not reflow. Scroll targets
|
|
128
|
-
computed against the article (e.g. for a "scroll to this heading"
|
|
129
|
-
click) therefore remain valid regardless of dropdown state. */
|
|
130
|
-
.velu-toc-bar__list {
|
|
131
|
-
/* `absolute` (relative to the sticky TocBar root) so the dropdown
|
|
132
|
-
stays glued to the bar — no measurement gap between bar's bottom
|
|
133
|
-
and dropdown's top. The bar itself is full-width of the centre
|
|
134
|
-
column, which at narrow widths reaches the viewport's right edge
|
|
135
|
-
(centre's `margin-inline-end: 0` via @container), so the dropdown
|
|
136
|
-
also reaches the viewport right edge via `inset-inline-end: 0`. */
|
|
137
|
-
position: absolute;
|
|
138
|
-
inset-block-start: 100%;
|
|
139
|
-
inset-inline-start: 0;
|
|
140
|
-
inset-inline-end: 0;
|
|
141
|
-
margin: 0;
|
|
142
|
-
list-style: none;
|
|
143
|
-
/* Vertical breathing room around items. */
|
|
144
|
-
padding-block: var(--s-1);
|
|
145
|
-
/* Items are pushed --s3 off the bar's left edge so they sit at
|
|
146
|
-
the rail's x position (drawn by ::before below). */
|
|
147
|
-
padding-inline-start: var(--s3);
|
|
148
|
-
padding-inline-end: 0;
|
|
149
|
-
/* Collapsed state — invisible, lifted slightly upward and out
|
|
150
|
-
of pointer events. The `[data-expanded='true']` rule below
|
|
151
|
-
animates these back on open. The list is ALWAYS in the DOM
|
|
152
|
-
(not conditionally rendered) so the transition can run both
|
|
153
|
-
directions. `visibility` is delayed via the transition's
|
|
154
|
-
0.18s tail so it switches AFTER the opacity fade completes
|
|
155
|
-
when closing. */
|
|
156
|
-
opacity: 0;
|
|
157
|
-
visibility: hidden;
|
|
158
|
-
transform: translateY(-0.25rem);
|
|
159
|
-
transform-origin: 0 0;
|
|
160
|
-
pointer-events: none;
|
|
161
|
-
transition:
|
|
162
|
-
opacity 0.18s ease,
|
|
163
|
-
transform 0.18s ease,
|
|
164
|
-
visibility 0s linear 0.18s;
|
|
165
|
-
/* Same frosted recipe as the bar above (no shadow, no top
|
|
166
|
-
border) so the open dropdown reads as the bar EXTENDED DOWN,
|
|
167
|
-
not a separate floating panel. */
|
|
168
|
-
background: color-mix(in srgb, var(--page-bg) 75%, transparent);
|
|
169
|
-
backdrop-filter: saturate(140%) blur(12px);
|
|
170
|
-
-webkit-backdrop-filter: saturate(140%) blur(12px);
|
|
171
|
-
/* Bottom border terminates the combined bar+dropdown against
|
|
172
|
-
the article below. Spans the FULL list width so it touches
|
|
173
|
-
the sidebar's vertical border on the left. */
|
|
174
|
-
border-block-end: var(--border-width) solid var(--surface-color);
|
|
175
|
-
/* Cap height so a long TOC scrolls INSIDE the dropdown rather
|
|
176
|
-
than overflowing the viewport. The active row is auto-scrolled
|
|
177
|
-
into view by `scrollIntoNearestView` in TocBar.jsx. */
|
|
178
|
-
max-block-size: min(
|
|
179
|
-
75vh,
|
|
180
|
-
calc(100vh - var(--velu-scroll-offset, 5rem) - 2rem)
|
|
181
|
-
);
|
|
182
|
-
overflow-y: auto;
|
|
183
|
-
overscroll-behavior: contain;
|
|
184
|
-
/* Above the article but below sticky chrome above it. */
|
|
185
|
-
z-index: 4;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/* Expanded state — fade + slide into view. The opacity / transform
|
|
189
|
-
transitions run forward; visibility flips to `visible` instantly
|
|
190
|
-
so the dropdown is interactive immediately when opening. */
|
|
191
|
-
.velu-toc-bar[data-expanded='true'] .velu-toc-bar__list {
|
|
192
|
-
opacity: 1;
|
|
193
|
-
visibility: visible;
|
|
194
|
-
transform: translateY(0);
|
|
195
|
-
pointer-events: auto;
|
|
196
|
-
transition:
|
|
197
|
-
opacity 0.18s ease,
|
|
198
|
-
transform 0.18s ease,
|
|
199
|
-
visibility 0s;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/* Vertical guide rail — inset by --s3 from the list's leading edge,
|
|
203
|
-
tall enough to span the items (between the padding-block bands).
|
|
204
|
-
Active item's 2px accent border (below) overlays it at its row. */
|
|
205
|
-
.velu-toc-bar__list::before {
|
|
206
|
-
content: '';
|
|
207
|
-
position: absolute;
|
|
208
|
-
inset-block-start: var(--s-1);
|
|
209
|
-
inset-block-end: var(--s-1);
|
|
210
|
-
inset-inline-start: var(--s3);
|
|
211
|
-
inline-size: 1px;
|
|
212
|
-
background: var(--border-color);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
.velu-toc-bar__item {
|
|
216
|
-
/* The list's own `padding-inline-start: var(--s3)` already places
|
|
217
|
-
each item's leading edge AT the rail's x position, so the
|
|
218
|
-
active item's 2px accent border overlays the rail at its row
|
|
219
|
-
with no negative-margin tricks. */
|
|
220
|
-
padding-block: var(--s-2);
|
|
221
|
-
padding-inline-end: var(--s3);
|
|
222
|
-
border-inline-start: 2px solid transparent;
|
|
223
|
-
color: var(--text-color);
|
|
224
|
-
font-size: var(--f-h6);
|
|
225
|
-
cursor: pointer;
|
|
226
|
-
transition: color 0.12s ease, border-color 0.12s ease;
|
|
227
|
-
}
|
|
228
|
-
.velu-toc-bar__item:hover {
|
|
229
|
-
color: var(--accent-color);
|
|
230
|
-
}
|
|
231
|
-
.velu-toc-bar__item--active {
|
|
232
|
-
color: var(--accent-color);
|
|
233
|
-
border-inline-start-color: var(--accent-color);
|
|
234
|
-
}
|
|
1
|
+
/* TocBar — narrow-layout counterpart to <Toc>.
|
|
2
|
+
|
|
3
|
+
Rendered always (so SSR / hydration markup matches at every size)
|
|
4
|
+
but VISIBLE only at narrow widths via a container query against the
|
|
5
|
+
docs layout. At wide widths the right-rail <Toc> takes over and
|
|
6
|
+
this bar is `display: none` — no media queries.
|
|
7
|
+
|
|
8
|
+
All values are tokens; light/dark via [data-theme]. */
|
|
9
|
+
|
|
10
|
+
.velu-toc-bar {
|
|
11
|
+
/* Hidden by default — the wide layout uses the right-rail <Toc>.
|
|
12
|
+
Container query below flips it on at narrow widths. */
|
|
13
|
+
display: none;
|
|
14
|
+
/* Sticky to the top of the article so it stays in view as the
|
|
15
|
+
user scrolls through the page. Sits below the page header. */
|
|
16
|
+
position: sticky;
|
|
17
|
+
inset-block-start: var(--velu-header-height);
|
|
18
|
+
z-index: 5;
|
|
19
|
+
/* Frosted-glass background — same recipe as the scrolled header
|
|
20
|
+
(.velu-header--scrolled in page-header.css). 75% --page-bg + a
|
|
21
|
+
saturate/blur backdrop lets article content show through faintly
|
|
22
|
+
so the bar reads as a layer over the page rather than a solid
|
|
23
|
+
band. The dropdown below uses the same recipe so the bar +
|
|
24
|
+
expanded list look like one continuous translucent fabric. */
|
|
25
|
+
background: color-mix(in srgb, var(--page-bg) 75%, transparent);
|
|
26
|
+
backdrop-filter: saturate(140%) blur(12px);
|
|
27
|
+
-webkit-backdrop-filter: saturate(140%) blur(12px);
|
|
28
|
+
border-block-end: var(--border-width) solid var(--surface-color);
|
|
29
|
+
/* base.css's global `* { max-width: 66ch }` (the prose measure)
|
|
30
|
+
would otherwise cap the bar AND its dropdown well short of the
|
|
31
|
+
viewport edge — explicitly override it for the bar's subtree. */
|
|
32
|
+
max-inline-size: none;
|
|
33
|
+
}
|
|
34
|
+
.velu-toc-bar *,
|
|
35
|
+
.velu-toc-bar {
|
|
36
|
+
max-inline-size: none;
|
|
37
|
+
}
|
|
38
|
+
/* When expanded, the dropdown's own border-block-end terminates
|
|
39
|
+
the combined bar+dropdown — suppress the bar's bottom border so
|
|
40
|
+
there isn't a double-printed line between bar and dropdown. The
|
|
41
|
+
toggle's `border-block-end` still draws the divider between the
|
|
42
|
+
toggle row and the list. Also drop the frosted recipe — the
|
|
43
|
+
dropdown reveals article content underneath, and a translucent
|
|
44
|
+
bar+dropdown would let the article text bleed through the menu.
|
|
45
|
+
Solid --page-bg keeps the list readable in either theme. */
|
|
46
|
+
.velu-toc-bar[data-expanded='true'] {
|
|
47
|
+
border-block-end-color: transparent;
|
|
48
|
+
background: var(--page-bg);
|
|
49
|
+
backdrop-filter: none;
|
|
50
|
+
-webkit-backdrop-filter: none;
|
|
51
|
+
}
|
|
52
|
+
.velu-toc-bar[data-expanded='true'] .velu-toc-bar__list {
|
|
53
|
+
background: var(--page-bg);
|
|
54
|
+
backdrop-filter: none;
|
|
55
|
+
-webkit-backdrop-filter: none;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@container docs (max-width: 1024px) {
|
|
59
|
+
.velu-toc-bar {
|
|
60
|
+
display: block;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* ── Toggle (collapsed header) ─────────────────────────────────────── */
|
|
65
|
+
.velu-toc-bar__toggle {
|
|
66
|
+
display: flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
gap: var(--s-2);
|
|
69
|
+
inline-size: 100%;
|
|
70
|
+
/* Block padding fixed at 8px so the bar hugs its single-row
|
|
71
|
+
content tightly; inline padding stays on the spacing scale. */
|
|
72
|
+
padding-block: 0.5rem;
|
|
73
|
+
padding-inline: var(--s3);
|
|
74
|
+
/* Divider between the toggle row and the expanded list lives
|
|
75
|
+
here (not on the list) so it spans the toggle's full inline
|
|
76
|
+
size — touching the sidebar's vertical border on the left
|
|
77
|
+
instead of being inset by the list's leading margin. Hidden
|
|
78
|
+
when collapsed (TocBar's own bottom border terminates the
|
|
79
|
+
row). */
|
|
80
|
+
border-width: 0 0 var(--border-width) 0;
|
|
81
|
+
border-style: solid;
|
|
82
|
+
border-color: var(--surface-color);
|
|
83
|
+
background: transparent;
|
|
84
|
+
color: var(--text-color);
|
|
85
|
+
font: inherit;
|
|
86
|
+
font-size: var(--f-h5);
|
|
87
|
+
text-align: start;
|
|
88
|
+
cursor: pointer;
|
|
89
|
+
}
|
|
90
|
+
/* No interior divider between the toggle row and the dropdown —
|
|
91
|
+
they're one continuous fabric. The only horizontal line in the
|
|
92
|
+
expanded state is the dropdown's own border-block-end, at the
|
|
93
|
+
very bottom of the combined element. */
|
|
94
|
+
.velu-toc-bar__toggle {
|
|
95
|
+
border-block-end-color: transparent;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Reading-progress ring — SVG circle whose stroke fills as the
|
|
99
|
+
reader scrolls. Sized like a chip so it reads as a peer of the
|
|
100
|
+
chevron at the other edge of the toggle row. */
|
|
101
|
+
.velu-toc-bar__progress {
|
|
102
|
+
flex: none;
|
|
103
|
+
inline-size: 1.25em;
|
|
104
|
+
block-size: 1.25em;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.velu-toc-bar__title {
|
|
108
|
+
flex: 1;
|
|
109
|
+
min-inline-size: 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.velu-toc-bar__chevron {
|
|
113
|
+
flex: none;
|
|
114
|
+
inline-size: var(--f-body);
|
|
115
|
+
block-size: var(--f-body);
|
|
116
|
+
color: var(--muted-color);
|
|
117
|
+
transition: transform 0.2s ease;
|
|
118
|
+
}
|
|
119
|
+
.velu-toc-bar[data-expanded='true'] .velu-toc-bar__chevron {
|
|
120
|
+
transform: rotate(180deg);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* ── Expanded list (overlay) ───────────────────────────────────────── */
|
|
124
|
+
/* `position: absolute` overlay anchored to the bottom of the sticky
|
|
125
|
+
TocBar — the list does NOT participate in the article's normal
|
|
126
|
+
flow. That's the critical bit: when the user expands/collapses
|
|
127
|
+
the dropdown, the article does not reflow. Scroll targets
|
|
128
|
+
computed against the article (e.g. for a "scroll to this heading"
|
|
129
|
+
click) therefore remain valid regardless of dropdown state. */
|
|
130
|
+
.velu-toc-bar__list {
|
|
131
|
+
/* `absolute` (relative to the sticky TocBar root) so the dropdown
|
|
132
|
+
stays glued to the bar — no measurement gap between bar's bottom
|
|
133
|
+
and dropdown's top. The bar itself is full-width of the centre
|
|
134
|
+
column, which at narrow widths reaches the viewport's right edge
|
|
135
|
+
(centre's `margin-inline-end: 0` via @container), so the dropdown
|
|
136
|
+
also reaches the viewport right edge via `inset-inline-end: 0`. */
|
|
137
|
+
position: absolute;
|
|
138
|
+
inset-block-start: 100%;
|
|
139
|
+
inset-inline-start: 0;
|
|
140
|
+
inset-inline-end: 0;
|
|
141
|
+
margin: 0;
|
|
142
|
+
list-style: none;
|
|
143
|
+
/* Vertical breathing room around items. */
|
|
144
|
+
padding-block: var(--s-1);
|
|
145
|
+
/* Items are pushed --s3 off the bar's left edge so they sit at
|
|
146
|
+
the rail's x position (drawn by ::before below). */
|
|
147
|
+
padding-inline-start: var(--s3);
|
|
148
|
+
padding-inline-end: 0;
|
|
149
|
+
/* Collapsed state — invisible, lifted slightly upward and out
|
|
150
|
+
of pointer events. The `[data-expanded='true']` rule below
|
|
151
|
+
animates these back on open. The list is ALWAYS in the DOM
|
|
152
|
+
(not conditionally rendered) so the transition can run both
|
|
153
|
+
directions. `visibility` is delayed via the transition's
|
|
154
|
+
0.18s tail so it switches AFTER the opacity fade completes
|
|
155
|
+
when closing. */
|
|
156
|
+
opacity: 0;
|
|
157
|
+
visibility: hidden;
|
|
158
|
+
transform: translateY(-0.25rem);
|
|
159
|
+
transform-origin: 0 0;
|
|
160
|
+
pointer-events: none;
|
|
161
|
+
transition:
|
|
162
|
+
opacity 0.18s ease,
|
|
163
|
+
transform 0.18s ease,
|
|
164
|
+
visibility 0s linear 0.18s;
|
|
165
|
+
/* Same frosted recipe as the bar above (no shadow, no top
|
|
166
|
+
border) so the open dropdown reads as the bar EXTENDED DOWN,
|
|
167
|
+
not a separate floating panel. */
|
|
168
|
+
background: color-mix(in srgb, var(--page-bg) 75%, transparent);
|
|
169
|
+
backdrop-filter: saturate(140%) blur(12px);
|
|
170
|
+
-webkit-backdrop-filter: saturate(140%) blur(12px);
|
|
171
|
+
/* Bottom border terminates the combined bar+dropdown against
|
|
172
|
+
the article below. Spans the FULL list width so it touches
|
|
173
|
+
the sidebar's vertical border on the left. */
|
|
174
|
+
border-block-end: var(--border-width) solid var(--surface-color);
|
|
175
|
+
/* Cap height so a long TOC scrolls INSIDE the dropdown rather
|
|
176
|
+
than overflowing the viewport. The active row is auto-scrolled
|
|
177
|
+
into view by `scrollIntoNearestView` in TocBar.jsx. */
|
|
178
|
+
max-block-size: min(
|
|
179
|
+
75vh,
|
|
180
|
+
calc(100vh - var(--velu-scroll-offset, 5rem) - 2rem)
|
|
181
|
+
);
|
|
182
|
+
overflow-y: auto;
|
|
183
|
+
overscroll-behavior: contain;
|
|
184
|
+
/* Above the article but below sticky chrome above it. */
|
|
185
|
+
z-index: 4;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Expanded state — fade + slide into view. The opacity / transform
|
|
189
|
+
transitions run forward; visibility flips to `visible` instantly
|
|
190
|
+
so the dropdown is interactive immediately when opening. */
|
|
191
|
+
.velu-toc-bar[data-expanded='true'] .velu-toc-bar__list {
|
|
192
|
+
opacity: 1;
|
|
193
|
+
visibility: visible;
|
|
194
|
+
transform: translateY(0);
|
|
195
|
+
pointer-events: auto;
|
|
196
|
+
transition:
|
|
197
|
+
opacity 0.18s ease,
|
|
198
|
+
transform 0.18s ease,
|
|
199
|
+
visibility 0s;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* Vertical guide rail — inset by --s3 from the list's leading edge,
|
|
203
|
+
tall enough to span the items (between the padding-block bands).
|
|
204
|
+
Active item's 2px accent border (below) overlays it at its row. */
|
|
205
|
+
.velu-toc-bar__list::before {
|
|
206
|
+
content: '';
|
|
207
|
+
position: absolute;
|
|
208
|
+
inset-block-start: var(--s-1);
|
|
209
|
+
inset-block-end: var(--s-1);
|
|
210
|
+
inset-inline-start: var(--s3);
|
|
211
|
+
inline-size: 1px;
|
|
212
|
+
background: var(--border-color);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.velu-toc-bar__item {
|
|
216
|
+
/* The list's own `padding-inline-start: var(--s3)` already places
|
|
217
|
+
each item's leading edge AT the rail's x position, so the
|
|
218
|
+
active item's 2px accent border overlays the rail at its row
|
|
219
|
+
with no negative-margin tricks. */
|
|
220
|
+
padding-block: var(--s-2);
|
|
221
|
+
padding-inline-end: var(--s3);
|
|
222
|
+
border-inline-start: 2px solid transparent;
|
|
223
|
+
color: var(--text-color);
|
|
224
|
+
font-size: var(--f-h6);
|
|
225
|
+
cursor: pointer;
|
|
226
|
+
transition: color 0.12s ease, border-color 0.12s ease;
|
|
227
|
+
}
|
|
228
|
+
.velu-toc-bar__item:hover {
|
|
229
|
+
color: var(--accent-color);
|
|
230
|
+
}
|
|
231
|
+
.velu-toc-bar__item--active {
|
|
232
|
+
color: var(--accent-color);
|
|
233
|
+
border-inline-start-color: var(--accent-color);
|
|
234
|
+
}
|
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
/* Tree — file-tree display. Monospace + small line-height for the
|
|
2
|
-
"code editor sidebar" look. All values are tokens; light/dark via
|
|
3
|
-
[data-theme]. */
|
|
4
|
-
|
|
5
|
-
.velu-tree {
|
|
6
|
-
font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
|
|
7
|
-
font-size: var(--f-body);
|
|
8
|
-
line-height: 1.6;
|
|
9
|
-
color: var(--text-color);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.velu-tree__item {
|
|
13
|
-
display: flex;
|
|
14
|
-
align-items: center;
|
|
15
|
-
gap: var(--s-1);
|
|
16
|
-
padding-block: var(--s-4);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/* Folder summary acts as the click target — strip the native
|
|
20
|
-
disclosure triangle and make the whole row look like a button. */
|
|
21
|
-
.velu-tree__item--folder {
|
|
22
|
-
cursor: pointer;
|
|
23
|
-
list-style: none;
|
|
24
|
-
}
|
|
25
|
-
.velu-tree__item--folder::-webkit-details-marker {
|
|
26
|
-
display: none;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.velu-tree__icon {
|
|
30
|
-
display: inline-flex;
|
|
31
|
-
align-items: center;
|
|
32
|
-
flex: none;
|
|
33
|
-
inline-size: var(--icon-size-lg);
|
|
34
|
-
block-size: var(--icon-size-lg);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.velu-tree__label {
|
|
38
|
-
font-family: inherit;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/* Nested children sit inside a div with a vertical rail (border-inline-
|
|
42
|
-
start) — that's the line connecting a folder's siblings. The
|
|
43
|
-
margin/padding offset places the rail roughly under the parent
|
|
44
|
-
folder icon's horizontal center. */
|
|
45
|
-
.velu-tree__nest {
|
|
46
|
-
margin-inline-start: 0.625em;
|
|
47
|
-
padding-inline-start: 1em;
|
|
48
|
-
border-inline-start: var(--border-width) solid var(--border-color);
|
|
49
|
-
}
|
|
1
|
+
/* Tree — file-tree display. Monospace + small line-height for the
|
|
2
|
+
"code editor sidebar" look. All values are tokens; light/dark via
|
|
3
|
+
[data-theme]. */
|
|
4
|
+
|
|
5
|
+
.velu-tree {
|
|
6
|
+
font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
|
|
7
|
+
font-size: var(--f-body);
|
|
8
|
+
line-height: 1.6;
|
|
9
|
+
color: var(--text-color);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.velu-tree__item {
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
gap: var(--s-1);
|
|
16
|
+
padding-block: var(--s-4);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Folder summary acts as the click target — strip the native
|
|
20
|
+
disclosure triangle and make the whole row look like a button. */
|
|
21
|
+
.velu-tree__item--folder {
|
|
22
|
+
cursor: pointer;
|
|
23
|
+
list-style: none;
|
|
24
|
+
}
|
|
25
|
+
.velu-tree__item--folder::-webkit-details-marker {
|
|
26
|
+
display: none;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.velu-tree__icon {
|
|
30
|
+
display: inline-flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
flex: none;
|
|
33
|
+
inline-size: var(--icon-size-lg);
|
|
34
|
+
block-size: var(--icon-size-lg);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.velu-tree__label {
|
|
38
|
+
font-family: inherit;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Nested children sit inside a div with a vertical rail (border-inline-
|
|
42
|
+
start) — that's the line connecting a folder's siblings. The
|
|
43
|
+
margin/padding offset places the rail roughly under the parent
|
|
44
|
+
folder icon's horizontal center. */
|
|
45
|
+
.velu-tree__nest {
|
|
46
|
+
margin-inline-start: 0.625em;
|
|
47
|
+
padding-inline-start: 1em;
|
|
48
|
+
border-inline-start: var(--border-width) solid var(--border-color);
|
|
49
|
+
}
|