feat(docs): add Kapa.ai sidebar integration#1113
Conversation
Add AI-powered knowledge assistant (Kapa.ai) as a sidebar widget to the SDK documentation site. Includes KapaWidget React component with sidebar state detection, navbar trigger button, and CSS rules for responsive content shifting. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
|
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use Kapa default floating button instead of navbar injection - Set data-launcher-button-image and data-modal-image for proper icons - Rename modal title to "Ask Mysten Labs SDK AI" - Add floating button CSS styles - Revert layout.config.tsx to clean state Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add data-color-scheme-selector for automatic dark mode following - Clean up unused KapaButton component and layout config import Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Kapa widget's built-in launcher button was overlapping with the custom "Ask SDK AI" button since both were fixed to the bottom-right corner. Setting data-button-hide to true hides the native button while keeping the custom one. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@clud-bot review |
| } | ||
|
|
||
| function hookKapa() { | ||
| if (!window.Kapa || !window.Kapa.open || window.Kapa.open === hookedRef) return; |
There was a problem hiding this comment.
is this how they recommend building this out, this feels like a pretty hacky way to manage a sidebar
There was a problem hiding this comment.
Review: COMMENT
Docs-only front-end change (Kapa.ai sidebar). Nothing exploitable or data-losing — the site is fine to run. But the sidebar-detection approach has several concrete UX/robustness defects worth fixing before merge. Left inline comments; summary below.
Major
- The 300ms
elementFromPointpoll overwrites the state set by the hookedopen()/close(), so every open/close flickers as the sidebar animates in. - The whole detection heuristic looks unnecessary and fragile: Kapa already renders in
data-view-mode="sidebar", andgetElementById('nd-docs-layout')resolves to null (that id doesn't exist in the repo), so a fixed/sticky element outside<main>can produce a permanent false positive. Prefer Kapa's official view-mode / state callbacks over DOM probing — this is the "hacky" concern confirmed.
Minor
- Unused
useStateimport (oxlint warning, doesn't fail CI). - Monkeypatch on
window.Kapa.open/closeis never restored; a remount double-wraps. global.csshardcodes a 500px shift not tied to the actual sidebar width.- The global
navselector is over-broad (hits every<nav>). - Launcher button is a silent no-op if clicked before the async Kapa script loads.
Cleared (not issues): hardcoded data-website-id is a public client id (not a secret), missing changeset is allowed for docs-only, and the 'use client'/SSR handling is clean.
| return true; | ||
| } | ||
|
|
||
| const interval = setInterval(() => { |
There was a problem hiding this comment.
Polling overwrites the monkeypatch state, causing flicker. Every 300ms this interval recomputes kapaOpen purely from the elementFromPoint guess, discarding what the hooked open()/close() just set. On click, open() sets kapaOpen=true + adds the class, but Kapa's sidebar animates in over a few hundred ms — the next tick probes the right-middle point before the sidebar occupies it, reads visible=false, flips the class off (body snaps back, floating button reappears), then re-adds it next tick. Result is a flicker on every open/close.
| hookedRef = window.Kapa.open; | ||
| } | ||
|
|
||
| function isSidebarVisible() { |
There was a problem hiding this comment.
This detection heuristic is likely unnecessary and fragile. The <Script> already sets data-view-mode="sidebar" (layout.tsx), so Kapa natively renders a sidebar — this custom elementFromPoint polling reinvents that. Also, getElementById('nd-docs-layout') returns null (that id doesn't exist anywhere in the repo and Fumadocs doesn't emit it), so containment falls back solely to querySelector('main'). Any fixed/sticky element at (innerWidth-50, innerHeight/2) outside <main> (e.g. Fumadocs' right-hand TOC <aside>) yields a permanent false positive, leaving the body shifted 500px with the button hidden. Prefer Kapa's official view-mode / state callbacks over DOM-probing.
|
|
||
| 'use client'; | ||
|
|
||
| import { useEffect, useState } from 'react'; |
There was a problem hiding this comment.
Unused useState import — oxlint's no-unused-vars flags it (warning only, so CI still passes). Remove it.
| document.documentElement.classList.toggle(OPEN_CLASS, kapaOpen); | ||
| } | ||
|
|
||
| function hookKapa() { |
There was a problem hiding this comment.
Monkeypatch is never restored; remount double-wraps. Cleanup only clears the interval — window.Kapa.open/close stay wrapped. React StrictMode (dev) or any remount gets a fresh hookedRef=null and re-wraps the already-wrapped functions. Harmless in today's single-mount layout, latent leak otherwise.
|
|
||
| export function KapaButton() { | ||
| return ( | ||
| <button type="button" onClick={() => window.Kapa?.open()} className="kapa-floating-btn"> |
There was a problem hiding this comment.
Button is a silent no-op before the async script loads: window.Kapa?.open() does nothing if clicked before afterInteractive defines window.Kapa. Consider a disabled/loading state.
| width: calc(100vw - 500px) !important; | ||
| overflow-x: hidden; | ||
| transition: width 0.3s ease; | ||
| } |
There was a problem hiding this comment.
Hardcoded 500px shift isn't tied to Kapa's actual sidebar width. calc(100vw - 500px) (and the nav right: 500px) assume the widget is exactly 500px — if Kapa's sidebar width differs now or later, content overlaps or leaves a gap.
| html.kapa-sidebar-open nav { | ||
| right: 500px !important; | ||
| overflow: hidden; | ||
| transition: right 0.3s ease; |
There was a problem hiding this comment.
The global nav selector is over-broad — these rules target every <nav> (top navbar, left sidebar, TOC), not just the intended one, so any positioned nav shifts 500px when the class is active. Scope this to the specific nav.
|
@clud-bot can you update this to use the proper react bindings rather than trying to hack around their injected script? |
|
Something went wrong:
|
1 similar comment
|
Something went wrong:
|
|
Something went wrong:
|
1 similar comment
|
Something went wrong:
|
Summary
KapaWidget.tsxcomponent withKapaSidebar(state detection) andKapaButton("Ask SDK AI")layout.config.tsxglobal.cssfor 500px content shift, nav adjustment, and mobile responsivenessTest plan
pnpm turbo build --filter=@mysten/docsto verify no build errorsKAPA_API_KEY_SDKsecret)AI Assistance Notice
🤖 Generated with Claude Code