@veluai/velu 0.2.31 → 0.2.32

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veluai/velu",
3
- "version": "0.2.31",
3
+ "version": "0.2.32",
4
4
  "type": "module",
5
5
  "bin": "./dist/cli.js",
6
6
  "publishConfig": {
@@ -179,8 +179,9 @@ function citeTitle(s) {
179
179
  return seg.replace(/[-_]/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
180
180
  }
181
181
 
182
- /* Source click: SPA-navigate same-origin targets via onNavigate (keeps the chat
183
- panel open + scrolls to the heading); otherwise let the <a href> navigate. */
182
+ /* Source click: SPA-navigate same-origin targets via onNavigate (host decides
183
+ whether to keep the panel open desktop multi-cite hops vs mobile sheet
184
+ close); otherwise let the <a href> navigate. */
184
185
  function onSourceClick(e, s, onNavigate) {
185
186
  const href = sourceHref(s);
186
187
  if (!href) { e.preventDefault(); return; }
@@ -189,7 +190,15 @@ function onSourceClick(e, s, onNavigate) {
189
190
  const u = new URL(href, window.location.origin);
190
191
  if (u.origin === window.location.origin) {
191
192
  e.preventDefault();
192
- onNavigate(u.pathname + u.search + u.hash);
193
+ // Prefer the docs route path (e.g. "/installation") over the absolute
194
+ // URL pathname ("/docs/installation"). React Router's basename is
195
+ // already "/docs" on subpath hosts — passing the full pathname makes
196
+ // navigate() produce /docs/docs/... and 404.
197
+ const route =
198
+ s?.path && s.path.startsWith('/')
199
+ ? `${s.path}${u.search || ''}${u.hash || ''}`
200
+ : `${u.pathname}${u.search}${u.hash}`;
201
+ onNavigate(route);
193
202
  }
194
203
  } catch { /* malformed — fall back to href */ }
195
204
  }
@@ -1277,6 +1277,16 @@ function DocsPage() {
1277
1277
  `inset-block-end: 0` override still wins. */
1278
1278
  '--velu-aside-bottom': `calc(${footerOverlap}px + var(--s4))`,
1279
1279
  }}
1280
+ // Close the mobile drawer as soon as a nav link is activated.
1281
+ // The pathname effect below also closes it on route change; this
1282
+ // covers same-route hash jumps and feels snappier on touch devices.
1283
+ onClick={(e) => {
1284
+ if (!drawerOpen) return;
1285
+ const a = e.target.closest?.('a[href]');
1286
+ if (!a) return;
1287
+ setDrawerOpen(false);
1288
+ setNavOpen(false);
1289
+ }}
1280
1290
  >
1281
1291
  {/* Drawer body — Stack with 32px gap composes the slots
1282
1292
  (topbar / tab-dropdown / context / nav). The aside is a flex
@@ -1732,7 +1742,27 @@ function DocsPage() {
1732
1742
  loadConversation={assistant?.loadConversation}
1733
1743
  suggestions={site.assistant?.suggestions}
1734
1744
  onNavigate={(to) => {
1735
- navigate(to);
1745
+ // Strip the Vite base path so react-router basename is not applied
1746
+ // twice (e.g. "/docs/installation" → "/installation" when
1747
+ // BASE_PATH="/docs"). Absolute Ask-AI citation URLs include /docs.
1748
+ let dest = to || '/';
1749
+ if (BASE_PATH) {
1750
+ if (dest === BASE_PATH || dest === `${BASE_PATH}/`) dest = '/';
1751
+ else if (dest.startsWith(`${BASE_PATH}/`)) {
1752
+ dest = dest.slice(BASE_PATH.length) || '/';
1753
+ }
1754
+ }
1755
+ navigate(dest);
1756
+ // Ask AI becomes a bottom sheet below 1024px (chatbot.css) and covers
1757
+ // the article — close it so the user lands on the linked page, not
1758
+ // behind the sheet. Desktop keeps the panel open so multi-cite hops
1759
+ // stay convenient.
1760
+ if (
1761
+ typeof window !== 'undefined' &&
1762
+ window.matchMedia('(max-width: 1024px)').matches
1763
+ ) {
1764
+ setChatOpen(false);
1765
+ }
1736
1766
  // After the destination page mounts, scroll to the cited section
1737
1767
  // (its heading id) — or the top of the page when there's no anchor.
1738
1768
  const hash = to.includes('#') ? to.slice(to.indexOf('#') + 1) : '';