@veluai/velu 0.2.35 → 0.2.36
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 +39 -0
- package/dist/cli.js +57 -49
- package/package.json +1 -1
- package/runtime/velu-ui/components/Accordion.jsx +3 -3
- package/runtime/velu-ui/components/ApiClient.jsx +4 -2
- package/runtime/velu-ui/components/ApiReferencePage.jsx +12 -12
- package/runtime/velu-ui/components/ApiSamples.jsx +2 -2
- package/runtime/velu-ui/components/AskBar.jsx +3 -2
- package/runtime/velu-ui/components/Callout.jsx +11 -26
- package/runtime/velu-ui/components/Card.jsx +9 -8
- package/runtime/velu-ui/components/ChangelogFilters.jsx +2 -1
- package/runtime/velu-ui/components/Chatbot.jsx +11 -5
- package/runtime/velu-ui/components/CodeBlock.jsx +7 -6
- package/runtime/velu-ui/components/Columns.jsx +1 -0
- package/runtime/velu-ui/components/ContextMenu.jsx +3 -2
- package/runtime/velu-ui/components/Field.jsx +2 -2
- package/runtime/velu-ui/components/Icon.jsx +1 -0
- package/runtime/velu-ui/components/Image.jsx +2 -2
- package/runtime/velu-ui/components/MethodBadge.jsx +2 -2
- package/runtime/velu-ui/components/NavSelect.jsx +22 -4
- package/runtime/velu-ui/components/NotFound.jsx +7 -7
- package/runtime/velu-ui/components/PageFeedback.jsx +13 -3
- package/runtime/velu-ui/components/PageHeader.jsx +24 -9
- package/runtime/velu-ui/components/PageNav.jsx +2 -1
- package/runtime/velu-ui/components/Prompt.jsx +2 -2
- package/runtime/velu-ui/components/Search.jsx +1 -0
- package/runtime/velu-ui/components/Sidebar.jsx +18 -6
- package/runtime/velu-ui/components/Steps.jsx +4 -4
- package/runtime/velu-ui/components/ThemeToggle.jsx +1 -0
- package/runtime/velu-ui/components/Toc.jsx +6 -4
- package/runtime/velu-ui/components/Tree.jsx +6 -5
- package/runtime/velu-ui/components/TryItBar.jsx +1 -0
- package/runtime/velu-ui/components/Update.jsx +2 -2
- package/runtime/velu-ui/components/callout.css +28 -0
- package/runtime/velu-ui/components/docs-layout.css +5 -0
- package/runtime/velu-ui/components/sidebar.css +5 -5
- package/runtime/velu-ui/element-selectors.css +66 -0
- package/runtime/velu-ui/primitives/Cluster.jsx +12 -0
- package/runtime/velu-ui/primitives/Stack.jsx +12 -0
- package/runtime/velu-ui/primitives/Switcher.jsx +11 -1
- package/runtime/velu-ui/styles.css +51 -35
- package/src/runtime/App.jsx +43 -11
- package/src/runtime/client-entry.jsx +23 -0
- package/src/runtime/dev-warnings.js +16 -0
- package/src/runtime/server-entry.jsx +1 -0
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
/* Aggregate stylesheet for velu-ui. Consumers import this once.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Cascade layers, lowest to highest precedence:
|
|
4
|
+
Tailwind's theme / base (preflight) / components / utilities
|
|
5
|
+
velu - everything in this package (base.css + every component sheet)
|
|
6
|
+
(unlayered) - the PROJECT's own custom CSS (any .css file in a docs
|
|
7
|
+
project is linked after this sheet, unlayered)
|
|
8
|
+
Unlayered styles beat every layer regardless of specificity, so a project
|
|
9
|
+
can restyle components with Mintlify-style element selectors - a plain
|
|
10
|
+
`card { border-radius: 0 }` (specificity 0,0,1) overrides `.velu-card`
|
|
11
|
+
(0,1,0) because velu-ui lives in a layer and the project sheet does not.
|
|
12
|
+
The `velu` layer is declared after Tailwind's, so our fluid type/measure
|
|
13
|
+
still beat Tailwind's preflight, as before. */
|
|
14
|
+
@layer theme, base, components, utilities, velu;
|
|
15
|
+
|
|
7
16
|
@import 'tailwindcss';
|
|
8
17
|
|
|
9
18
|
/* Map Tailwind's `dark:` variant onto our [data-theme="dark"] attribute
|
|
@@ -14,36 +23,43 @@
|
|
|
14
23
|
and ignores node_modules — velu-ui is reached via a workspace symlink
|
|
15
24
|
there, so its component classes would NOT be scanned. This @source is
|
|
16
25
|
relative to THIS file (packages/velu-ui/src/styles.css); "." == the
|
|
17
|
-
velu-ui src tree, so Tailwind also scans velu-ui components.
|
|
26
|
+
velu-ui src tree, so Tailwind also scans velu-ui components.
|
|
27
|
+
|
|
28
|
+
Project MDX/JSX (the docs author's content) is registered as an extra
|
|
29
|
+
`@source` at `velu dev` / `velu build` time by
|
|
30
|
+
`veluTailwindProjectSource` in velu-cli — so utilities used in content
|
|
31
|
+
(`w-full`, `rounded-xl`, `dark:…`, …) are generated too. */
|
|
18
32
|
@source ".";
|
|
19
33
|
|
|
20
|
-
@import './base.css';
|
|
21
|
-
@import './
|
|
22
|
-
@import './
|
|
23
|
-
@import './components/
|
|
24
|
-
@import './components/
|
|
25
|
-
@import './components/
|
|
26
|
-
@import './components/
|
|
27
|
-
@import './components/
|
|
28
|
-
@import './components/
|
|
29
|
-
@import './components/
|
|
30
|
-
@import './components/
|
|
31
|
-
@import './components/
|
|
32
|
-
@import './components/
|
|
33
|
-
@import './components/
|
|
34
|
-
@import './components/
|
|
35
|
-
@import './components/
|
|
36
|
-
@import './components/
|
|
37
|
-
@import './components/
|
|
38
|
-
@import './components/
|
|
39
|
-
@import './components/
|
|
40
|
-
@import './components/
|
|
41
|
-
@import './components/
|
|
42
|
-
@import './components/
|
|
43
|
-
@import './components/page-
|
|
44
|
-
@import './components/
|
|
45
|
-
@import './components/page-
|
|
46
|
-
@import './components/
|
|
47
|
-
@import './components/
|
|
48
|
-
@import './components/
|
|
49
|
-
@import './components/
|
|
34
|
+
@import './base.css' layer(velu);
|
|
35
|
+
@import './element-selectors.css' layer(velu);
|
|
36
|
+
@import './primitives/switcher.css' layer(velu);
|
|
37
|
+
@import './components/sidebar.css' layer(velu);
|
|
38
|
+
@import './components/nav-select.css' layer(velu);
|
|
39
|
+
@import './components/context-menu.css' layer(velu);
|
|
40
|
+
@import './components/accordion.css' layer(velu);
|
|
41
|
+
@import './components/callout.css' layer(velu);
|
|
42
|
+
@import './components/card.css' layer(velu);
|
|
43
|
+
@import './components/icon.css' layer(velu);
|
|
44
|
+
@import './components/image.css' layer(velu);
|
|
45
|
+
@import './components/code-block.css' layer(velu);
|
|
46
|
+
@import './components/field.css' layer(velu);
|
|
47
|
+
@import './components/prompt.css' layer(velu);
|
|
48
|
+
@import './components/steps.css' layer(velu);
|
|
49
|
+
@import './components/tree.css' layer(velu);
|
|
50
|
+
@import './components/update.css' layer(velu);
|
|
51
|
+
@import './components/changelog-filters.css' layer(velu);
|
|
52
|
+
@import './components/api.css' layer(velu);
|
|
53
|
+
@import './components/api-page.css' layer(velu);
|
|
54
|
+
@import './components/not-found.css' layer(velu);
|
|
55
|
+
@import './components/ask-bar.css' layer(velu);
|
|
56
|
+
@import './components/chatbot.css' layer(velu);
|
|
57
|
+
@import './components/page-feedback.css' layer(velu);
|
|
58
|
+
@import './components/page-nav.css' layer(velu);
|
|
59
|
+
@import './components/page-footer.css' layer(velu);
|
|
60
|
+
@import './components/powered-by.css' layer(velu);
|
|
61
|
+
@import './components/page-header.css' layer(velu);
|
|
62
|
+
@import './components/theme-toggle.css' layer(velu);
|
|
63
|
+
@import './components/docs-layout.css' layer(velu);
|
|
64
|
+
@import './components/toc-bar.css' layer(velu);
|
|
65
|
+
@import './components/search.css' layer(velu);
|
package/src/runtime/App.jsx
CHANGED
|
@@ -683,6 +683,19 @@ function ImageDemo() {
|
|
|
683
683
|
|
|
684
684
|
const RouterLink = ({ href, ...rest }) => <Link to={href} {...rest} />;
|
|
685
685
|
|
|
686
|
+
// Look up a heading by its slug id. Prefers a match INSIDE the article: the
|
|
687
|
+
// layout chrome carries stable, Mintlify-compatible ids for custom CSS
|
|
688
|
+
// (#sidebar, #content, #footer, …), and a heading titled "Sidebar" or "Footer"
|
|
689
|
+
// would slug to the same id — document.getElementById would then return the
|
|
690
|
+
// chrome element (earlier in DOM order) and the TOC would scroll to the wrong
|
|
691
|
+
// place.
|
|
692
|
+
function sectionById(id) {
|
|
693
|
+
if (typeof document === 'undefined' || !id) return null;
|
|
694
|
+
const article = document.getElementById('content');
|
|
695
|
+
const esc = id.replace(/["\\]/g, '\\$&');
|
|
696
|
+
return article?.querySelector(`[id="${esc}"]`) ?? document.getElementById(id);
|
|
697
|
+
}
|
|
698
|
+
|
|
686
699
|
// Flatten a nested TOC tree to {id, label, depth} for scroll-spy.
|
|
687
700
|
function flat(nodes, depth = 0, out = []) {
|
|
688
701
|
for (const n of nodes) {
|
|
@@ -730,7 +743,7 @@ function useScrollSpy(ids) {
|
|
|
730
743
|
let best = ids[0];
|
|
731
744
|
let bestDist = Infinity;
|
|
732
745
|
for (const id of ids) {
|
|
733
|
-
const node =
|
|
746
|
+
const node = sectionById(id);
|
|
734
747
|
if (!node) continue;
|
|
735
748
|
const top = node.getBoundingClientRect().top;
|
|
736
749
|
if (top >= vh) continue;
|
|
@@ -867,6 +880,7 @@ function DocsPage() {
|
|
|
867
880
|
options={languageOptions}
|
|
868
881
|
linkComponent={RouterLink}
|
|
869
882
|
ariaLabel="Language"
|
|
883
|
+
idPrefix="localization-select"
|
|
870
884
|
/>
|
|
871
885
|
);
|
|
872
886
|
const productSwitcher = productOptions.length > 1 && (
|
|
@@ -875,6 +889,7 @@ function DocsPage() {
|
|
|
875
889
|
options={productOptions}
|
|
876
890
|
linkComponent={RouterLink}
|
|
877
891
|
ariaLabel="Product"
|
|
892
|
+
component="nav-dropdown-products-selector"
|
|
878
893
|
/>
|
|
879
894
|
);
|
|
880
895
|
|
|
@@ -897,6 +912,9 @@ function DocsPage() {
|
|
|
897
912
|
}
|
|
898
913
|
descTag.setAttribute('content', frontmatter.description || '');
|
|
899
914
|
document.documentElement.lang = nav?.activeLanguageCode || 'en';
|
|
915
|
+
// Mirrors the SSR'd attribute so custom CSS scoped with
|
|
916
|
+
// html[data-current-path="/x"] follows client-side navigation too.
|
|
917
|
+
document.documentElement.dataset.currentPath = pathname;
|
|
900
918
|
}, [pathname, isNotFound, frontmatter.title, frontmatter.description, nav?.activeLanguageCode]);
|
|
901
919
|
|
|
902
920
|
// Frontmatter title needs an id so scroll-spy + click-to-scroll work
|
|
@@ -1161,6 +1179,7 @@ function DocsPage() {
|
|
|
1161
1179
|
label: 'Log out',
|
|
1162
1180
|
onClick: logoutPrivateAccess,
|
|
1163
1181
|
kind: 'outlined',
|
|
1182
|
+
component: 'logout-link',
|
|
1164
1183
|
});
|
|
1165
1184
|
}
|
|
1166
1185
|
|
|
@@ -1211,7 +1230,7 @@ function DocsPage() {
|
|
|
1211
1230
|
|
|
1212
1231
|
const scrollTo = React.useCallback(
|
|
1213
1232
|
(id) => {
|
|
1214
|
-
const node =
|
|
1233
|
+
const node = sectionById(id);
|
|
1215
1234
|
if (!node) return;
|
|
1216
1235
|
// 1) Set + lock the active id IMMEDIATELY so the spy doesn't
|
|
1217
1236
|
// overwrite it during the smooth-scroll animation.
|
|
@@ -1242,6 +1261,7 @@ function DocsPage() {
|
|
|
1242
1261
|
|
|
1243
1262
|
return (
|
|
1244
1263
|
<div
|
|
1264
|
+
id="body-content"
|
|
1245
1265
|
className="velu-docs-layout"
|
|
1246
1266
|
data-chat-open={chatOpen ? 'true' : 'false'}
|
|
1247
1267
|
data-sidebar-open={sidebarOpen ? 'true' : 'false'}
|
|
@@ -1264,6 +1284,7 @@ function DocsPage() {
|
|
|
1264
1284
|
{/* Site header — brand, centered search, right-side actions,
|
|
1265
1285
|
tabs row. Configurable: pass any number of actions / tabs. */}
|
|
1266
1286
|
<PageHeader
|
|
1287
|
+
id="navbar"
|
|
1267
1288
|
linkComponent={RouterLink}
|
|
1268
1289
|
brand={{
|
|
1269
1290
|
label: site.name,
|
|
@@ -1279,6 +1300,7 @@ function DocsPage() {
|
|
|
1279
1300
|
center={
|
|
1280
1301
|
<Cluster space="var(--s-6)" align="center">
|
|
1281
1302
|
<Search
|
|
1303
|
+
id="search-bar-entry"
|
|
1282
1304
|
style={{ inlineSize: '30ch' }}
|
|
1283
1305
|
unavailable={IS_DEV_PREVIEW}
|
|
1284
1306
|
search={IS_DEV_PREVIEW ? undefined : searchDocs}
|
|
@@ -1290,6 +1312,7 @@ function DocsPage() {
|
|
|
1290
1312
|
{!IS_DEV_PREVIEW && !askAiHidden && (
|
|
1291
1313
|
<button
|
|
1292
1314
|
type="button"
|
|
1315
|
+
id="assistant-entry"
|
|
1293
1316
|
className="velu-header__action velu-header__action--outlined"
|
|
1294
1317
|
onClick={() => askAI('')}
|
|
1295
1318
|
>
|
|
@@ -1316,6 +1339,7 @@ function DocsPage() {
|
|
|
1316
1339
|
honour `inset-block-start` for fixed positioning the same way
|
|
1317
1340
|
as plain `top`). */}
|
|
1318
1341
|
<aside
|
|
1342
|
+
id="sidebar"
|
|
1319
1343
|
className="velu-docs-layout__aside velu-docs-layout__aside--left"
|
|
1320
1344
|
style={{
|
|
1321
1345
|
/* Bottom edge stays a fixed gap above the viewport bottom,
|
|
@@ -1400,6 +1424,8 @@ function DocsPage() {
|
|
|
1400
1424
|
<li key={it.href} role="none">
|
|
1401
1425
|
<a
|
|
1402
1426
|
role="menuitem"
|
|
1427
|
+
data-component="mobile-nav-tabs-item"
|
|
1428
|
+
data-active={it.href === nav?.activeTab ? 'true' : undefined}
|
|
1403
1429
|
className="velu-docs-layout__drawer-docselect-item"
|
|
1404
1430
|
href={it.href}
|
|
1405
1431
|
tabIndex={navOpen ? 0 : -1}
|
|
@@ -1429,10 +1455,11 @@ function DocsPage() {
|
|
|
1429
1455
|
<span className="velu-show-on-mobile">{languageSwitcher}</span>
|
|
1430
1456
|
)}
|
|
1431
1457
|
{anchors.length > 0 && (
|
|
1432
|
-
<ul className="velu-docs-anchors">
|
|
1458
|
+
<ul className="velu-docs-anchors" data-component="nav-anchors">
|
|
1433
1459
|
{anchors.map((a, i) => (
|
|
1434
1460
|
<li key={i}>
|
|
1435
1461
|
<a
|
|
1462
|
+
data-component="nav-anchor"
|
|
1436
1463
|
className="velu-docs-anchors__link"
|
|
1437
1464
|
href={a.href}
|
|
1438
1465
|
target="_blank"
|
|
@@ -1457,7 +1484,7 @@ function DocsPage() {
|
|
|
1457
1484
|
{/* Hairline separating the top anchor links from the nav sections
|
|
1458
1485
|
(faithful to the sidebar design's anchor↔sidebar divider). */}
|
|
1459
1486
|
{anchors.length > 0 && (
|
|
1460
|
-
<
|
|
1487
|
+
<sidebar-nav-group-divider class="velu-docs-context-divider" aria-hidden="true" />
|
|
1461
1488
|
)}
|
|
1462
1489
|
{/* Only this region scrolls — the context zone above stays
|
|
1463
1490
|
pinned. The up/down arrows overlay its top/bottom edges and
|
|
@@ -1466,6 +1493,7 @@ function DocsPage() {
|
|
|
1466
1493
|
nav fully to that end. */}
|
|
1467
1494
|
<div className="velu-docs-nav-region">
|
|
1468
1495
|
<div
|
|
1496
|
+
id="sidebar-content"
|
|
1469
1497
|
ref={leftAsideRef}
|
|
1470
1498
|
className="velu-docs-nav-scroll velu-hide-scrollbar"
|
|
1471
1499
|
style={{
|
|
@@ -1536,6 +1564,7 @@ function DocsPage() {
|
|
|
1536
1564
|
Ask-AI chatbot is open (the panel takes that edge). */}
|
|
1537
1565
|
{!chatOpen && (
|
|
1538
1566
|
<aside
|
|
1567
|
+
id="table-of-contents"
|
|
1539
1568
|
ref={rightAsideRef}
|
|
1540
1569
|
className="velu-docs-layout__aside velu-docs-layout__aside--right velu-hide-scrollbar"
|
|
1541
1570
|
style={{
|
|
@@ -1555,7 +1584,7 @@ function DocsPage() {
|
|
|
1555
1584
|
) : isChangelog && changelogTags.length ? (
|
|
1556
1585
|
<ChangelogFilters tags={changelogTags} />
|
|
1557
1586
|
) : (
|
|
1558
|
-
<Toc items={toc} activeId={activeId} onSelect={scrollTo} />
|
|
1587
|
+
<Toc id="table-of-contents-content" items={toc} activeId={activeId} onSelect={scrollTo} />
|
|
1559
1588
|
)}
|
|
1560
1589
|
</aside>
|
|
1561
1590
|
)}
|
|
@@ -1590,6 +1619,7 @@ function DocsPage() {
|
|
|
1590
1619
|
on tab/mobile we keep the normal TOC bar (no filters). */}
|
|
1591
1620
|
<TocBar items={toc} activeId={activeId} onSelect={scrollTo} />
|
|
1592
1621
|
<main
|
|
1622
|
+
id="content-area"
|
|
1593
1623
|
className="velu-docs-layout__main"
|
|
1594
1624
|
style={{
|
|
1595
1625
|
/* No padding-block-end — the article's last child (PoweredBy)
|
|
@@ -1624,7 +1654,7 @@ function DocsPage() {
|
|
|
1624
1654
|
})}
|
|
1625
1655
|
</span>
|
|
1626
1656
|
</button>
|
|
1627
|
-
<div className="velu-docs-layout__article" data-pagefind-body="">
|
|
1657
|
+
<div id="content" className="velu-docs-layout__article" data-pagefind-body="">
|
|
1628
1658
|
{/* Per-page agent/IDE action bar: the section eyebrow + a
|
|
1629
1659
|
"Copy Page" split-button whose dropdown is driven by the
|
|
1630
1660
|
Mintlify-compatible `contextual` config. Renders nothing
|
|
@@ -1672,7 +1702,7 @@ function DocsPage() {
|
|
|
1672
1702
|
level. Falls back to a not-found / missing-file notice
|
|
1673
1703
|
when the route has no page (or its file is absent). */}
|
|
1674
1704
|
<MDXProvider components={defaultMdxComponents}>
|
|
1675
|
-
<
|
|
1705
|
+
<mdx-content class="velu-prose">
|
|
1676
1706
|
{PageComponent ? (
|
|
1677
1707
|
<ErrorBoundary key={pathname} file={entry?.relPath}>
|
|
1678
1708
|
<PageComponent />
|
|
@@ -1684,7 +1714,7 @@ function DocsPage() {
|
|
|
1684
1714
|
: 'Page not found.'}
|
|
1685
1715
|
</p>
|
|
1686
1716
|
)}
|
|
1687
|
-
</
|
|
1717
|
+
</mdx-content>
|
|
1688
1718
|
</MDXProvider>
|
|
1689
1719
|
{/* Page-foot feedback widget — ref'd so the sticky AskBar
|
|
1690
1720
|
above can hide as the user scrolls near it. */}
|
|
@@ -1706,6 +1736,7 @@ function DocsPage() {
|
|
|
1706
1736
|
sidebar reading order of the active section. */}
|
|
1707
1737
|
{(nav?.prev || nav?.next) && (
|
|
1708
1738
|
<PageNav
|
|
1739
|
+
id="pagination"
|
|
1709
1740
|
style={{ marginTop: 'var(--s2)' }}
|
|
1710
1741
|
prev={nav?.prev}
|
|
1711
1742
|
next={nav?.next}
|
|
@@ -1764,7 +1795,8 @@ function DocsPage() {
|
|
|
1764
1795
|
of the fixed sidebar and TOC as the page scrolls into it, and the ref
|
|
1765
1796
|
is watched so the asides can pad their bottom by the overlap. */}
|
|
1766
1797
|
{footerHasLinks && (
|
|
1767
|
-
<
|
|
1798
|
+
<advanced-footer
|
|
1799
|
+
id="footer"
|
|
1768
1800
|
ref={footerRef}
|
|
1769
1801
|
data-velu-footer
|
|
1770
1802
|
style={{ position: 'relative', zIndex: 20 }}
|
|
@@ -1774,7 +1806,7 @@ function DocsPage() {
|
|
|
1774
1806
|
columns={site.footer.links}
|
|
1775
1807
|
socials={footerSocials}
|
|
1776
1808
|
/>
|
|
1777
|
-
</
|
|
1809
|
+
</advanced-footer>
|
|
1778
1810
|
)}
|
|
1779
1811
|
|
|
1780
1812
|
{/* Ask-AI chatbot — slides in from the inline-end edge. Hidden when the
|
|
@@ -1817,7 +1849,7 @@ function DocsPage() {
|
|
|
1817
1849
|
let tries = 0;
|
|
1818
1850
|
const go = () => {
|
|
1819
1851
|
if (hash) {
|
|
1820
|
-
if (
|
|
1852
|
+
if (sectionById(hash)) { scrollTo(hash); return; }
|
|
1821
1853
|
if (tries++ < 10) { setTimeout(go, 60); return; }
|
|
1822
1854
|
}
|
|
1823
1855
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import './dev-warnings.js';
|
|
1
2
|
import React from 'react';
|
|
2
3
|
import { hydrateRoot } from 'react-dom/client';
|
|
3
4
|
import { BrowserRouter } from 'react-router-dom';
|
|
4
5
|
import 'velu-ui/styles.css';
|
|
6
|
+
import { site } from 'virtual:velu-site';
|
|
5
7
|
import App from './App.jsx';
|
|
6
8
|
|
|
7
9
|
// Subpath hosting: Vite sets BASE_URL from the build's `base` (e.g. "/docs/").
|
|
@@ -9,10 +11,31 @@ import App from './App.jsx';
|
|
|
9
11
|
// case ("/") becomes undefined so the router behaves as if mounted at origin.
|
|
10
12
|
const basename = (import.meta.env.BASE_URL || '/').replace(/\/$/, '') || undefined;
|
|
11
13
|
|
|
14
|
+
// Custom JavaScript (Mintlify-compatible): every `.js` file in the project is
|
|
15
|
+
// run on every page. Loaded from an effect so it runs AFTER hydration commits —
|
|
16
|
+
// the page is interactive and a script that mutates the DOM can't cause a
|
|
17
|
+
// hydration mismatch. Classic (non-module) scripts, appended in the discovered
|
|
18
|
+
// order; `async = false` keeps that order for dynamically inserted scripts.
|
|
19
|
+
// Runs once per full page load, not per client-side navigation — same as a
|
|
20
|
+
// <script> tag in the HTML would.
|
|
21
|
+
function CustomScripts() {
|
|
22
|
+
React.useEffect(() => {
|
|
23
|
+
for (const url of site.customScripts ?? []) {
|
|
24
|
+
const el = document.createElement('script');
|
|
25
|
+
el.src = (basename || '') + url;
|
|
26
|
+
el.async = false;
|
|
27
|
+
el.dataset.veluCustom = '';
|
|
28
|
+
document.body.appendChild(el);
|
|
29
|
+
}
|
|
30
|
+
}, []);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
12
34
|
hydrateRoot(
|
|
13
35
|
document.getElementById('root'),
|
|
14
36
|
<BrowserRouter basename={basename}>
|
|
15
37
|
<App />
|
|
38
|
+
<CustomScripts />
|
|
16
39
|
</BrowserRouter>
|
|
17
40
|
);
|
|
18
41
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// velu-ui renders component roots as Mintlify-compatible custom tags
|
|
2
|
+
// (`<card>`, `<callout>`, `<code-block>`, …) so project CSS can use element
|
|
3
|
+
// selectors. Browsers handle unknown elements fine (HTMLUnknownElement), and
|
|
4
|
+
// React renders them fine too, but React's DEVELOPMENT build logs
|
|
5
|
+
// "Warning: The tag <card> is unrecognized in this browser. …"
|
|
6
|
+
// once per tag name for the ones without a hyphen. Production builds never
|
|
7
|
+
// emit it. This drops exactly that message in dev (server + browser) so
|
|
8
|
+
// `velu dev` output stays readable; every other console.error passes through.
|
|
9
|
+
if (import.meta.env.DEV && typeof console !== 'undefined') {
|
|
10
|
+
const original = console.error;
|
|
11
|
+
console.error = function veluFilteredError(...args) {
|
|
12
|
+
const first = args[0];
|
|
13
|
+
if (typeof first === 'string' && first.includes('is unrecognized in this browser')) return;
|
|
14
|
+
original.apply(this, args);
|
|
15
|
+
};
|
|
16
|
+
}
|