@veluai/velu 0.2.38 → 0.2.39
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/dist/cli.js +38 -38
- package/docs/aalam.md +44 -0
- package/docs/mintlify-migration.md +8 -3
- package/docs/thulir.md +23 -0
- package/package.json +4 -2
- package/runtime/velu-ui/base.css +9 -0
- package/runtime/velu-ui/components/ApiReferencePage.jsx +4 -3
- package/runtime/velu-ui/components/ApiSamples.jsx +9 -2
- package/runtime/velu-ui/components/Callout.jsx +4 -1
- package/runtime/velu-ui/components/PageFooter.jsx +3 -1
- package/runtime/velu-ui/components/PageHeader.jsx +7 -1
- package/runtime/velu-ui/components/PageNav.jsx +98 -22
- package/runtime/velu-ui/components/Sidebar.jsx +21 -9
- package/runtime/velu-ui/components/ThemeToggle.jsx +1 -0
- package/runtime/velu-ui/components/TocBar.jsx +21 -2
- package/runtime/velu-ui/components/VepaFooter.jsx +19 -17
- package/runtime/velu-ui/components/api-page.css +6 -3
- package/runtime/velu-ui/components/chatbot.css +5 -4
- package/runtime/velu-ui/components/docs-layout.css +99 -114
- package/runtime/velu-ui/components/page-footer.css +2 -3
- package/runtime/velu-ui/components/page-header.css +6 -0
- package/runtime/velu-ui/components/page-nav.css +192 -0
- package/runtime/velu-ui/components/sidebar.css +5 -13
- package/runtime/velu-ui/primitives/switcher.css +4 -0
- package/runtime/velu-ui/styles.css +2 -0
- package/runtime/velu-ui/themes/aalam.css +266 -0
- package/runtime/velu-ui/themes/thulir.css +428 -0
- package/schema/velu.schema.json +23 -3
- package/src/navigation.js +22 -3
- package/src/runtime/App.jsx +171 -106
- package/templates/starter/ai-tools/claude-code.mdx +1 -0
- package/templates/starter/ai-tools/cursor.mdx +1 -0
- package/templates/starter/api-reference/introduction.mdx +1 -0
- package/templates/starter/development.mdx +1 -0
- package/templates/starter/essentials/code.mdx +1 -0
- package/templates/starter/essentials/images.mdx +1 -0
- package/templates/starter/essentials/markdown.mdx +1 -0
- package/templates/starter/essentials/navigation.mdx +1 -0
- package/templates/starter/essentials/settings.mdx +1 -0
- package/templates/starter/index.mdx +1 -0
- package/templates/starter/quickstart.mdx +1 -0
package/src/runtime/App.jsx
CHANGED
|
@@ -59,7 +59,7 @@ import {
|
|
|
59
59
|
NotFound,
|
|
60
60
|
VeluMark,
|
|
61
61
|
} from 'velu-ui';
|
|
62
|
-
import { X, ChevronDown
|
|
62
|
+
import { X, ChevronDown } from 'lucide-react';
|
|
63
63
|
import ErrorBoundary from './ErrorBoundary.jsx';
|
|
64
64
|
|
|
65
65
|
// True under `velu dev`, false in the deployed production build (Vite injects
|
|
@@ -894,6 +894,7 @@ function DocsPage() {
|
|
|
894
894
|
<NavSelect
|
|
895
895
|
value={nav.activeProduct}
|
|
896
896
|
options={productOptions}
|
|
897
|
+
icon={productOptions.find((p) => p.active)?.icon}
|
|
897
898
|
linkComponent={RouterLink}
|
|
898
899
|
ariaLabel="Product"
|
|
899
900
|
component="nav-dropdown-products-selector"
|
|
@@ -928,7 +929,7 @@ function DocsPage() {
|
|
|
928
929
|
// against it like any other heading.
|
|
929
930
|
const pageId = React.useMemo(() => {
|
|
930
931
|
if (!frontmatter.title) return null;
|
|
931
|
-
if (site.theme === 'vepa') return 'page-title';
|
|
932
|
+
if (site.theme === 'vepa' || ['thulir', 'aalam'].includes(site.theme)) return 'page-title';
|
|
932
933
|
return new GithubSlugger().slug(frontmatter.title);
|
|
933
934
|
}, [frontmatter.title, site.theme]);
|
|
934
935
|
|
|
@@ -962,6 +963,49 @@ function DocsPage() {
|
|
|
962
963
|
// of sidebarOpen so neither breakpoint's default leaks into the
|
|
963
964
|
// other.
|
|
964
965
|
const [drawerOpen, setDrawerOpen] = React.useState(false);
|
|
966
|
+
const drawerRef = React.useRef(null);
|
|
967
|
+
const [drawerViewport, setDrawerViewport] = React.useState(false);
|
|
968
|
+
React.useEffect(() => {
|
|
969
|
+
const root = drawerRef.current?.parentElement;
|
|
970
|
+
if (!root) return;
|
|
971
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
972
|
+
const narrow = entry.contentRect.width <= (['thulir', 'aalam'].includes(site.theme) ? 1023 : 640);
|
|
973
|
+
setDrawerViewport(narrow);
|
|
974
|
+
if (!narrow) setDrawerOpen(false);
|
|
975
|
+
});
|
|
976
|
+
observer.observe(root);
|
|
977
|
+
return () => observer.disconnect();
|
|
978
|
+
}, [site.theme]);
|
|
979
|
+
React.useEffect(() => {
|
|
980
|
+
if (!drawerOpen || !drawerViewport) return;
|
|
981
|
+
const drawer = drawerRef.current;
|
|
982
|
+
const previousFocus = document.activeElement;
|
|
983
|
+
const previousOverflow = document.body.style.overflow;
|
|
984
|
+
document.body.style.overflow = 'hidden';
|
|
985
|
+
const siblings = [...drawer.parentElement.children].filter(e => e !== drawer && !e.classList.contains('velu-docs-layout__scrim'));
|
|
986
|
+
const inertStates = siblings.map(e => e.inert);
|
|
987
|
+
siblings.forEach(e => { e.inert = true; });
|
|
988
|
+
drawer.querySelector('.velu-docs-layout__drawer-close')?.focus();
|
|
989
|
+
const onKey = e => {
|
|
990
|
+
if (e.key === 'Escape') {
|
|
991
|
+
if (drawer.querySelector('.velu-docs-layout__drawer-docselect[data-open="true"]')) return;
|
|
992
|
+
setDrawerOpen(false); return;
|
|
993
|
+
}
|
|
994
|
+
if (e.key !== 'Tab') return;
|
|
995
|
+
const items = [...drawer.querySelectorAll('a[href],button,input,select,textarea,[tabindex]')].filter(el => !el.disabled && el.tabIndex >= 0 && el.getClientRects().length && getComputedStyle(el).visibility !== 'hidden');
|
|
996
|
+
const first = items[0], last = items.at(-1);
|
|
997
|
+
if (!first) { e.preventDefault(); return; }
|
|
998
|
+
if (e.shiftKey && (document.activeElement === first || !drawer.contains(document.activeElement))) { e.preventDefault(); last.focus(); }
|
|
999
|
+
else if (!e.shiftKey && (document.activeElement === last || !drawer.contains(document.activeElement))) { e.preventDefault(); first.focus(); }
|
|
1000
|
+
};
|
|
1001
|
+
document.addEventListener('keydown', onKey);
|
|
1002
|
+
return () => {
|
|
1003
|
+
document.removeEventListener('keydown', onKey);
|
|
1004
|
+
document.body.style.overflow = previousOverflow;
|
|
1005
|
+
siblings.forEach((e,i) => { e.inert = inertStates[i]; });
|
|
1006
|
+
if (previousFocus?.isConnected) previousFocus.focus({preventScroll:true});
|
|
1007
|
+
};
|
|
1008
|
+
}, [drawerOpen, drawerViewport]);
|
|
965
1009
|
|
|
966
1010
|
// Drawer's nav dropdown — list of section links (Home/Docs/Blog),
|
|
967
1011
|
// mirrors the desktop tabs. Click-outside + Escape close.
|
|
@@ -973,7 +1017,7 @@ function DocsPage() {
|
|
|
973
1017
|
if (!navRef.current?.contains(e.target)) setNavOpen(false);
|
|
974
1018
|
};
|
|
975
1019
|
const onKey = (e) => {
|
|
976
|
-
if (e.key === 'Escape') setNavOpen(false);
|
|
1020
|
+
if (e.key === 'Escape') { setNavOpen(false); navRef.current?.querySelector('button')?.focus(); }
|
|
977
1021
|
};
|
|
978
1022
|
document.addEventListener('mousedown', onDocClick);
|
|
979
1023
|
document.addEventListener('keydown', onKey);
|
|
@@ -1072,40 +1116,30 @@ function DocsPage() {
|
|
|
1072
1116
|
// a gap above the full-page Ask AI canvas.
|
|
1073
1117
|
}, [chrome.mode]);
|
|
1074
1118
|
|
|
1075
|
-
// The
|
|
1076
|
-
//
|
|
1077
|
-
//
|
|
1078
|
-
//
|
|
1079
|
-
// re-render). Re-binds on chatOpen toggle (the right TOC
|
|
1080
|
-
// mounts/unmounts with it).
|
|
1119
|
+
// The right TOC scrolls independently of the page. On scroll/resize
|
|
1120
|
+
// we set data-fade-top/-bottom so CSS can fade its edges only when
|
|
1121
|
+
// there's content beyond them. Written imperatively (no re-render).
|
|
1122
|
+
// Re-binds on chatOpen toggle (the right TOC mounts/unmounts with it).
|
|
1081
1123
|
const leftAsideRef = React.useRef(null);
|
|
1082
1124
|
const rightAsideRef = React.useRef(null);
|
|
1083
1125
|
React.useEffect(() => {
|
|
1084
|
-
const
|
|
1085
|
-
if (!
|
|
1126
|
+
const el = rightAsideRef.current;
|
|
1127
|
+
if (!el) return undefined;
|
|
1086
1128
|
const update = () => {
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
el.
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
: 'false';
|
|
1093
|
-
}
|
|
1129
|
+
el.dataset.fadeTop = el.scrollTop > 0 ? 'true' : 'false';
|
|
1130
|
+
el.dataset.fadeBottom =
|
|
1131
|
+
el.scrollTop + el.clientHeight < el.scrollHeight - 1
|
|
1132
|
+
? 'true'
|
|
1133
|
+
: 'false';
|
|
1094
1134
|
};
|
|
1095
1135
|
update();
|
|
1096
|
-
// Recompute on scroll AND on any size change of the scroll region
|
|
1097
|
-
// or its content (ResizeObserver) + window resize — so the fade
|
|
1098
|
-
// reflects hidden content persistently, not just during a scroll
|
|
1099
|
-
// gesture (e.g. after a route change shifts the nav's height).
|
|
1100
1136
|
const ro = new ResizeObserver(update);
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
if (el.firstElementChild) ro.observe(el.firstElementChild);
|
|
1105
|
-
});
|
|
1137
|
+
el.addEventListener('scroll', update, { passive: true });
|
|
1138
|
+
ro.observe(el);
|
|
1139
|
+
if (el.firstElementChild) ro.observe(el.firstElementChild);
|
|
1106
1140
|
window.addEventListener('resize', update);
|
|
1107
1141
|
return () => {
|
|
1108
|
-
|
|
1142
|
+
el.removeEventListener('scroll', update);
|
|
1109
1143
|
ro.disconnect();
|
|
1110
1144
|
window.removeEventListener('resize', update);
|
|
1111
1145
|
};
|
|
@@ -1113,9 +1147,8 @@ function DocsPage() {
|
|
|
1113
1147
|
|
|
1114
1148
|
// Flag the sidebar section heading currently pinned at the top of the
|
|
1115
1149
|
// scroll region (CSS sticky gives no "is-stuck" hook). When the pinned
|
|
1116
|
-
// heading changes as you scroll, the new one gets data-stuck
|
|
1117
|
-
//
|
|
1118
|
-
// section set changes with it.
|
|
1150
|
+
// heading changes as you scroll, the new one gets data-stuck.
|
|
1151
|
+
// Re-binds on page/tab change since the section set changes with it.
|
|
1119
1152
|
React.useEffect(() => {
|
|
1120
1153
|
const scroller = leftAsideRef.current;
|
|
1121
1154
|
if (!scroller) return;
|
|
@@ -1198,8 +1231,8 @@ function DocsPage() {
|
|
|
1198
1231
|
// Callback ref so this rebinds when the footer mounts/unmounts.
|
|
1199
1232
|
// Custom and assistant unmount the footer; a mount-once listener
|
|
1200
1233
|
// would keep reading the detached node (getBoundingClientRect top
|
|
1201
|
-
// is 0)
|
|
1202
|
-
//
|
|
1234
|
+
// is 0). footerOverlap still pads the right TOC so the last items
|
|
1235
|
+
// can scroll clear of the footer as it rises under content + TOC.
|
|
1203
1236
|
const [footerEl, setFooterEl] = React.useState(null);
|
|
1204
1237
|
const [footerOverlap, setFooterOverlap] = React.useState(0);
|
|
1205
1238
|
React.useEffect(() => {
|
|
@@ -1349,17 +1382,19 @@ function DocsPage() {
|
|
|
1349
1382
|
</Cluster>
|
|
1350
1383
|
}
|
|
1351
1384
|
actions={navActions}
|
|
1352
|
-
trailing={<ThemeToggle variant={site.theme === 'vepa' ? 'menu' : undefined} />}
|
|
1385
|
+
trailing={<ThemeToggle variant={site.theme === 'aalam' ? 'inline' : site.theme === 'vepa' || site.theme === 'thulir' ? 'menu' : undefined} />}
|
|
1353
1386
|
tabsTrailing={
|
|
1354
1387
|
chrome.mode === 'custom' || chrome.mode === 'assistant'
|
|
1355
1388
|
? undefined
|
|
1356
1389
|
: languageSwitcher || undefined
|
|
1357
1390
|
}
|
|
1358
1391
|
onMenuClick={chrome.sidebar ? () => setDrawerOpen((v) => !v) : undefined}
|
|
1392
|
+
menuOpen={drawerOpen}
|
|
1393
|
+
menuId={site.theme === 'vepa' ? 'sidebar-content' : 'sidebar'}
|
|
1359
1394
|
breadcrumb={
|
|
1360
1395
|
chrome.mode === 'custom' || chrome.mode === 'assistant'
|
|
1361
1396
|
? []
|
|
1362
|
-
: (nav?.breadcrumb ?? [])
|
|
1397
|
+
: ['thulir', 'aalam'].includes(site.theme) ? (nav?.breadcrumb ?? []).slice(-2) : (nav?.breadcrumb ?? [])
|
|
1363
1398
|
}
|
|
1364
1399
|
activeTab={nav?.activeTab}
|
|
1365
1400
|
tabs={
|
|
@@ -1369,23 +1404,19 @@ function DocsPage() {
|
|
|
1369
1404
|
}
|
|
1370
1405
|
/>
|
|
1371
1406
|
|
|
1372
|
-
{/* Fixed left sidebar — pinned to viewport-left
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
as plain `top`). */}
|
|
1407
|
+
{/* Fixed left sidebar — pinned to viewport-left, full height.
|
|
1408
|
+
The site footer is indented under content + TOC only, so the
|
|
1409
|
+
rail never lifts for the footer. `top` + `bottom` give a
|
|
1410
|
+
robust height (some browsers don't honour `inset-block-start`
|
|
1411
|
+
for fixed positioning the same way as plain `top`). */}
|
|
1378
1412
|
<aside
|
|
1413
|
+
ref={drawerRef}
|
|
1414
|
+
role={drawerViewport ? 'dialog' : undefined}
|
|
1415
|
+
aria-modal={drawerViewport && drawerOpen ? true : undefined}
|
|
1416
|
+
aria-label={drawerViewport ? 'Navigation' : undefined}
|
|
1417
|
+
inert={drawerViewport && !drawerOpen ? '' : undefined}
|
|
1379
1418
|
id={site.theme === 'vepa' ? 'sidebar-content' : 'sidebar'}
|
|
1380
1419
|
className="velu-docs-layout__aside velu-docs-layout__aside--left"
|
|
1381
|
-
style={{
|
|
1382
|
-
/* Bottom edge stays a fixed gap above the viewport bottom,
|
|
1383
|
-
AND lifts to keep that gap above the footer as it scrolls
|
|
1384
|
-
into view (footerOverlap = how far the footer intrudes).
|
|
1385
|
-
Set as a custom prop so the mobile drawer's
|
|
1386
|
-
`inset-block-end: 0` override still wins. */
|
|
1387
|
-
'--velu-aside-bottom': `calc(${footerOverlap}px + var(--s4))`,
|
|
1388
|
-
}}
|
|
1389
1420
|
// Close the mobile drawer as soon as a nav link is activated.
|
|
1390
1421
|
// The pathname effect below also closes it on route change; this
|
|
1391
1422
|
// covers same-route hash jumps and feels snappier on touch devices.
|
|
@@ -1413,11 +1444,11 @@ function DocsPage() {
|
|
|
1413
1444
|
) : (
|
|
1414
1445
|
<>
|
|
1415
1446
|
<VeluMark />
|
|
1416
|
-
<span className="velu-header__wordmark">{site.name}</span>
|
|
1447
|
+
<span className="velu-header__wordmark" title={site.name}>{site.name}</span>
|
|
1417
1448
|
</>
|
|
1418
1449
|
)}
|
|
1419
1450
|
</RouterLink>
|
|
1420
|
-
<ThemeToggle variant={site.theme === 'vepa' ? 'menu' : undefined} />
|
|
1451
|
+
<ThemeToggle variant={site.theme === 'vepa' || site.theme === 'thulir' ? 'menu' : undefined} />
|
|
1421
1452
|
<button
|
|
1422
1453
|
type="button"
|
|
1423
1454
|
className="velu-docs-layout__drawer-close"
|
|
@@ -1427,6 +1458,19 @@ function DocsPage() {
|
|
|
1427
1458
|
<X aria-hidden="true" focusable="false" />
|
|
1428
1459
|
</button>
|
|
1429
1460
|
</div>
|
|
1461
|
+
{site.theme === 'aalam' && productSwitcher && (
|
|
1462
|
+
<div className="velu-docs-aside-product">{productSwitcher}</div>
|
|
1463
|
+
)}
|
|
1464
|
+
{site.theme === 'aalam' && (
|
|
1465
|
+
<div className="velu-docs-aside-search">
|
|
1466
|
+
<Search
|
|
1467
|
+
id="search-bar-entry-sidebar"
|
|
1468
|
+
unavailable={IS_DEV_PREVIEW}
|
|
1469
|
+
search={IS_DEV_PREVIEW ? undefined : searchDocs}
|
|
1470
|
+
onSelect={(item) => item.href && navigate(item.href)}
|
|
1471
|
+
/>
|
|
1472
|
+
</div>
|
|
1473
|
+
)}
|
|
1430
1474
|
{/* Nav dropdown — custom button + menu, fills drawer width.
|
|
1431
1475
|
Items mirror the desktop tabs (Home / Docs / Blog).
|
|
1432
1476
|
Click-outside + Escape close (see navOpen useEffect
|
|
@@ -1438,12 +1482,21 @@ function DocsPage() {
|
|
|
1438
1482
|
className="velu-docs-layout__drawer-docselect"
|
|
1439
1483
|
data-open={navOpen ? 'true' : 'false'}
|
|
1440
1484
|
>
|
|
1485
|
+
<label htmlFor="drawer-section-picker">Documentation section</label>
|
|
1441
1486
|
<button
|
|
1487
|
+
id="drawer-section-picker"
|
|
1442
1488
|
type="button"
|
|
1443
1489
|
className="velu-docs-layout__drawer-docselect-btn"
|
|
1444
1490
|
onClick={() => setNavOpen((o) => !o)}
|
|
1445
1491
|
aria-haspopup="menu"
|
|
1446
1492
|
aria-expanded={navOpen}
|
|
1493
|
+
aria-controls="drawer-section-options"
|
|
1494
|
+
onKeyDown={(e) => {
|
|
1495
|
+
if (e.key === 'ArrowDown') {
|
|
1496
|
+
e.preventDefault(); setNavOpen(true);
|
|
1497
|
+
requestAnimationFrame(() => navRef.current?.querySelector('[role="menuitem"]')?.focus());
|
|
1498
|
+
}
|
|
1499
|
+
}}
|
|
1447
1500
|
>
|
|
1448
1501
|
<span className="velu-docs-layout__drawer-docselect-label">
|
|
1449
1502
|
{activeNavLabel}
|
|
@@ -1455,9 +1508,16 @@ function DocsPage() {
|
|
|
1455
1508
|
/>
|
|
1456
1509
|
</button>
|
|
1457
1510
|
<ul
|
|
1511
|
+
id="drawer-section-options"
|
|
1458
1512
|
className="velu-docs-layout__drawer-docselect-menu"
|
|
1459
1513
|
role="menu"
|
|
1460
1514
|
aria-hidden={!navOpen}
|
|
1515
|
+
onKeyDown={(e) => {
|
|
1516
|
+
const items = [...e.currentTarget.querySelectorAll('[role="menuitem"]')];
|
|
1517
|
+
const index = items.indexOf(document.activeElement);
|
|
1518
|
+
const next = e.key === 'ArrowDown' ? (index + 1) % items.length : e.key === 'ArrowUp' ? (index + items.length - 1) % items.length : e.key === 'Home' ? 0 : e.key === 'End' ? items.length - 1 : null;
|
|
1519
|
+
if (next !== null) { e.preventDefault(); items[next]?.focus(); }
|
|
1520
|
+
}}
|
|
1461
1521
|
>
|
|
1462
1522
|
{navItems.map((it) => (
|
|
1463
1523
|
<li key={it.href} role="none">
|
|
@@ -1480,21 +1540,21 @@ function DocsPage() {
|
|
|
1480
1540
|
{/* Context zone — product switcher + anchors at the top of
|
|
1481
1541
|
the sidebar (all breakpoints), plus version/language
|
|
1482
1542
|
switchers that only show on mobile (desktop has them in
|
|
1483
|
-
the header).
|
|
1484
|
-
|
|
1485
|
-
{(productSwitcher ||
|
|
1486
|
-
versionSwitcher ||
|
|
1543
|
+
the header). Aalam (Maple) puts product above search and
|
|
1544
|
+
pins version to the sidebar footer instead. */}
|
|
1545
|
+
{((productSwitcher && site.theme !== 'aalam') ||
|
|
1546
|
+
(versionSwitcher && site.theme !== 'aalam') ||
|
|
1487
1547
|
languageSwitcher ||
|
|
1488
|
-
anchors.length > 0) && (
|
|
1548
|
+
(anchors.length > 0 && site.theme !== 'aalam')) && (
|
|
1489
1549
|
<Stack space="var(--s-1)" className="velu-docs-context">
|
|
1490
|
-
{productSwitcher}
|
|
1491
|
-
{versionSwitcher && (
|
|
1550
|
+
{site.theme !== 'aalam' && productSwitcher}
|
|
1551
|
+
{versionSwitcher && site.theme !== 'aalam' && (
|
|
1492
1552
|
<span className="velu-show-on-mobile">{versionSwitcher}</span>
|
|
1493
1553
|
)}
|
|
1494
1554
|
{languageSwitcher && (
|
|
1495
1555
|
<span className="velu-show-on-mobile">{languageSwitcher}</span>
|
|
1496
1556
|
)}
|
|
1497
|
-
{anchors.length > 0 && (
|
|
1557
|
+
{anchors.length > 0 && site.theme !== 'aalam' && (
|
|
1498
1558
|
<ul className="velu-docs-anchors" data-component="nav-anchors">
|
|
1499
1559
|
{anchors.map((a, i) => (
|
|
1500
1560
|
<li key={i}>
|
|
@@ -1523,26 +1583,50 @@ function DocsPage() {
|
|
|
1523
1583
|
)}
|
|
1524
1584
|
{/* Hairline separating the top anchor links from the nav sections
|
|
1525
1585
|
(faithful to the sidebar design's anchor↔sidebar divider). */}
|
|
1526
|
-
{anchors.length > 0 && (
|
|
1586
|
+
{anchors.length > 0 && site.theme !== 'aalam' && (
|
|
1527
1587
|
<sidebar-nav-group-divider class="velu-docs-context-divider" aria-hidden="true" />
|
|
1528
1588
|
)}
|
|
1529
1589
|
{/* Only this region scrolls — the context zone above stays
|
|
1530
|
-
pinned.
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
nav fully to that end. */}
|
|
1590
|
+
pinned. Active page links scroll into view on navigation
|
|
1591
|
+
(Sidebar / ApiSidebar). Aalam (Maple) scrolls the whole
|
|
1592
|
+
left column, including anchors, in one overflow. */}
|
|
1534
1593
|
<div className="velu-docs-nav-region">
|
|
1535
1594
|
<div
|
|
1536
|
-
id={site.theme === 'vepa' ? 'navigation-items' : 'sidebar-content'}
|
|
1595
|
+
id={site.theme === 'vepa' || ['thulir', 'aalam'].includes(site.theme) ? 'navigation-items' : 'sidebar-content'}
|
|
1537
1596
|
ref={leftAsideRef}
|
|
1538
|
-
className=
|
|
1597
|
+
className={`velu-docs-nav-scroll${site.theme === 'aalam' ? '' : ' velu-hide-scrollbar'}`}
|
|
1539
1598
|
style={{
|
|
1540
|
-
/*
|
|
1541
|
-
|
|
1542
|
-
|
|
1599
|
+
/* scroll-padding only — keep content clear of sticky
|
|
1600
|
+
headings / footer without shortening the scrollbar. */
|
|
1601
|
+
scrollPaddingBlockStart: '2.75rem',
|
|
1543
1602
|
scrollPaddingBlockEnd: 'var(--s1)',
|
|
1544
1603
|
}}
|
|
1545
1604
|
>
|
|
1605
|
+
{site.theme === 'aalam' && anchors.length > 0 && (
|
|
1606
|
+
<ul className="velu-docs-anchors" data-component="nav-anchors">
|
|
1607
|
+
{anchors.map((a, i) => (
|
|
1608
|
+
<li key={i}>
|
|
1609
|
+
<a
|
|
1610
|
+
data-component="nav-anchor"
|
|
1611
|
+
className="velu-docs-anchors__link"
|
|
1612
|
+
href={a.href}
|
|
1613
|
+
target="_blank"
|
|
1614
|
+
rel="noreferrer"
|
|
1615
|
+
>
|
|
1616
|
+
{a.icon && (
|
|
1617
|
+
<span
|
|
1618
|
+
className="velu-docs-anchors__icon"
|
|
1619
|
+
aria-hidden="true"
|
|
1620
|
+
>
|
|
1621
|
+
{resolveIcon(a.icon, { size: 16 })}
|
|
1622
|
+
</span>
|
|
1623
|
+
)}
|
|
1624
|
+
<span>{a.label}</span>
|
|
1625
|
+
</a>
|
|
1626
|
+
</li>
|
|
1627
|
+
))}
|
|
1628
|
+
</ul>
|
|
1629
|
+
)}
|
|
1546
1630
|
{/* Sidebar STYLE is chosen per-tab, not per-page: if this tab
|
|
1547
1631
|
holds any API page, the whole tab uses the flat API sidebar
|
|
1548
1632
|
(so opening an intro page next to API operations doesn't flip
|
|
@@ -1565,31 +1649,11 @@ function DocsPage() {
|
|
|
1565
1649
|
/>
|
|
1566
1650
|
)}
|
|
1567
1651
|
</div>
|
|
1568
|
-
<button
|
|
1569
|
-
type="button"
|
|
1570
|
-
className="velu-docs-nav-arrow velu-docs-nav-arrow--up"
|
|
1571
|
-
aria-label="Scroll navigation to top"
|
|
1572
|
-
onClick={() =>
|
|
1573
|
-
leftAsideRef.current?.scrollTo({ top: 0, behavior: 'smooth' })
|
|
1574
|
-
}
|
|
1575
|
-
>
|
|
1576
|
-
<ChevronUp aria-hidden="true" focusable="false" />
|
|
1577
|
-
</button>
|
|
1578
|
-
<button
|
|
1579
|
-
type="button"
|
|
1580
|
-
className="velu-docs-nav-arrow velu-docs-nav-arrow--down"
|
|
1581
|
-
aria-label="Scroll navigation to bottom"
|
|
1582
|
-
onClick={() =>
|
|
1583
|
-
leftAsideRef.current?.scrollTo({
|
|
1584
|
-
top: leftAsideRef.current.scrollHeight,
|
|
1585
|
-
behavior: 'smooth',
|
|
1586
|
-
})
|
|
1587
|
-
}
|
|
1588
|
-
>
|
|
1589
|
-
<ChevronDown aria-hidden="true" focusable="false" />
|
|
1590
|
-
</button>
|
|
1591
1652
|
</div>
|
|
1592
1653
|
</Stack>
|
|
1654
|
+
{site.theme === 'aalam' && versionSwitcher && (
|
|
1655
|
+
<div className="velu-docs-aside-footer">{versionSwitcher}</div>
|
|
1656
|
+
)}
|
|
1593
1657
|
</aside>
|
|
1594
1658
|
|
|
1595
1659
|
{/* No separate rail element — at narrow widths the sidebar's
|
|
@@ -1626,12 +1690,12 @@ function DocsPage() {
|
|
|
1626
1690
|
/>
|
|
1627
1691
|
) : isChangelog && changelogTags.length && site.theme !== 'vepa' ? (
|
|
1628
1692
|
<ChangelogFilters tags={changelogTags} />
|
|
1629
|
-
) : site.theme === 'vepa' ? (
|
|
1693
|
+
) : site.theme === 'vepa' || ['thulir', 'aalam'].includes(site.theme) ? (
|
|
1630
1694
|
<>
|
|
1631
1695
|
{isChangelog && changelogTags.length > 0 ? (
|
|
1632
1696
|
<ChangelogFilters tags={changelogTags} />
|
|
1633
1697
|
) : null}
|
|
1634
|
-
<VepaToc items={pageToc} activeId={activeId} onSelect={scrollTo} />
|
|
1698
|
+
<VepaToc items={pageToc} activeId={['thulir', 'aalam'].includes(site.theme) && activeId === pageId ? pageToc[0]?.id : activeId} onSelect={scrollTo} />
|
|
1635
1699
|
</>
|
|
1636
1700
|
) : (
|
|
1637
1701
|
<Toc id="table-of-contents-content" items={toc} activeId={activeId} onSelect={scrollTo} />
|
|
@@ -1676,7 +1740,7 @@ function DocsPage() {
|
|
|
1676
1740
|
on tab/mobile we keep the normal TOC bar (no filters). Hidden
|
|
1677
1741
|
entirely when the page mode has no table of contents. */}
|
|
1678
1742
|
{chrome.toc && (
|
|
1679
|
-
<TocBar items={toc} activeId={activeId} onSelect={scrollTo} />
|
|
1743
|
+
<TocBar items={toc} activeId={activeId} onSelect={scrollTo} label={['thulir', 'aalam'].includes(site.theme) ? 'On this page' : undefined} />
|
|
1680
1744
|
)}
|
|
1681
1745
|
<main
|
|
1682
1746
|
id="content-area"
|
|
@@ -1716,7 +1780,7 @@ function DocsPage() {
|
|
|
1716
1780
|
</span>
|
|
1717
1781
|
</button>
|
|
1718
1782
|
)}
|
|
1719
|
-
<div id={site.theme === 'vepa' ? undefined : 'content'} data-contextual-actions={site.contextual?.options?.length ? 'true' : 'false'} className="velu-docs-layout__article" data-pagefind-body={chrome.assistant ? undefined : ""}>
|
|
1783
|
+
<div id={site.theme === 'vepa' || ['thulir', 'aalam'].includes(site.theme) ? undefined : 'content'} data-contextual-actions={site.contextual?.options?.length ? 'true' : 'false'} className="velu-docs-layout__article" data-pagefind-body={chrome.assistant ? undefined : ""}>
|
|
1720
1784
|
{/* Per-page agent/IDE action bar: the section eyebrow + a
|
|
1721
1785
|
"Copy Page" split-button whose dropdown is driven by the
|
|
1722
1786
|
Mintlify-compatible `contextual` config. Renders nothing
|
|
@@ -1746,7 +1810,7 @@ function DocsPage() {
|
|
|
1746
1810
|
Custom / frame / assistant are a blank canvas — no auto hero. */}
|
|
1747
1811
|
{chrome.hero && (frontmatter.title || frontmatter.description) && (
|
|
1748
1812
|
<div className="velu-hero">
|
|
1749
|
-
{frontmatter.title && <h1 id={site.theme === 'vepa' ? 'page-title' : pageId}>{frontmatter.title}</h1>}
|
|
1813
|
+
{frontmatter.title && <h1 id={site.theme === 'vepa' || ['thulir', 'aalam'].includes(site.theme) ? 'page-title' : pageId}>{frontmatter.title}</h1>}
|
|
1750
1814
|
{frontmatter.description && (
|
|
1751
1815
|
<p
|
|
1752
1816
|
style={{
|
|
@@ -1767,7 +1831,7 @@ function DocsPage() {
|
|
|
1767
1831
|
level. Falls back to a not-found / missing-file notice
|
|
1768
1832
|
when the route has no page (or its file is absent). */}
|
|
1769
1833
|
<MDXProvider components={defaultMdxComponents}>
|
|
1770
|
-
<mdx-content key={site.theme === 'vepa' ? pathname : undefined} id={site.theme === 'vepa' && !entry?.api ? 'content' : undefined} class="velu-prose">
|
|
1834
|
+
<mdx-content key={site.theme === 'vepa' ? pathname : undefined} id={(site.theme === 'vepa' || ['thulir', 'aalam'].includes(site.theme)) && !entry?.api ? 'content' : undefined} class="velu-prose">
|
|
1771
1835
|
{PageComponent ? (
|
|
1772
1836
|
<ErrorBoundary key={pathname} file={entry?.relPath}>
|
|
1773
1837
|
{entry?.mdxApi ? <ApiReferencePage {...entry.mdxApi} preset={site.theme}><PageComponent /></ApiReferencePage> : <PageComponent />}
|
|
@@ -1783,7 +1847,7 @@ function DocsPage() {
|
|
|
1783
1847
|
</MDXProvider>
|
|
1784
1848
|
{/* Page-foot feedback widget — ref'd so the sticky AskBar
|
|
1785
1849
|
above can hide as the user scrolls near it. */}
|
|
1786
|
-
{chrome.articleChrome && (
|
|
1850
|
+
{chrome.articleChrome && !['thulir', 'aalam'].includes(site.theme) && (
|
|
1787
1851
|
<div ref={setFeedbackEl} style={{ marginTop: 'var(--s3)' }}>
|
|
1788
1852
|
{/* key resets the widget's vote state on page change. "Yes"
|
|
1789
1853
|
submits immediately; "No" submits once its form is sent.
|
|
@@ -1804,7 +1868,8 @@ function DocsPage() {
|
|
|
1804
1868
|
{chrome.articleChrome && !frontmatter.hidePagination && (nav?.prev || nav?.next) && (
|
|
1805
1869
|
<PageNav
|
|
1806
1870
|
id="pagination"
|
|
1807
|
-
style={{ marginTop: 'var(--s2)' }}
|
|
1871
|
+
style={['thulir', 'aalam'].includes(site.theme) ? undefined : { marginTop: 'var(--s2)' }}
|
|
1872
|
+
variant={site.theme === 'aalam' ? 'aalam' : 'default'}
|
|
1808
1873
|
prev={nav?.prev}
|
|
1809
1874
|
next={nav?.next}
|
|
1810
1875
|
linkComponent={RouterLink}
|
|
@@ -1844,7 +1909,7 @@ function DocsPage() {
|
|
|
1844
1909
|
full footer section); with link columns they live in the full
|
|
1845
1910
|
footer below instead. */}
|
|
1846
1911
|
{chrome.articleChrome && (footerHasLinks ? (
|
|
1847
|
-
site.theme === 'vepa' ? null : <PoweredBy />
|
|
1912
|
+
site.theme === 'vepa' || ['thulir', 'aalam'].includes(site.theme) ? null : <PoweredBy />
|
|
1848
1913
|
) : (
|
|
1849
1914
|
<div className="velu-content-foot">
|
|
1850
1915
|
<SocialLinks socials={footerSocials} />
|
|
@@ -1857,13 +1922,13 @@ function DocsPage() {
|
|
|
1857
1922
|
)}
|
|
1858
1923
|
</div>
|
|
1859
1924
|
|
|
1860
|
-
{/* Full site footer — only when the config provides link columns.
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1925
|
+
{/* Full site footer — only when the config provides link columns.
|
|
1926
|
+
Indented under content + TOC (see docs-layout.css); the left
|
|
1927
|
+
rail stays full-height beside it. Right TOC pads for the
|
|
1928
|
+
overlap via footerOverlap below. */}
|
|
1864
1929
|
{footerHasLinks && chrome.footer && (
|
|
1865
1930
|
<advanced-footer
|
|
1866
|
-
id={site.theme === 'vepa' ? undefined : 'footer'}
|
|
1931
|
+
id={site.theme === 'vepa' || ['thulir', 'aalam'].includes(site.theme) ? undefined : 'footer'}
|
|
1867
1932
|
ref={setFooterEl}
|
|
1868
1933
|
data-velu-footer
|
|
1869
1934
|
style={{ position: 'relative', zIndex: 20 }}
|