From 6291ecbcb49be998b31e49f20826eef253280efb Mon Sep 17 00:00:00 2001 From: Parteek Singh Date: Tue, 13 Jan 2026 15:46:25 -0800 Subject: [PATCH 1/8] Embed SDK Explorer in docs - Add SDKExplorerIframe component with theme sync via postMessage - Add SDK-Explorer.mdx page with full-width iframe layout - Update redirect and nav URL to /SDK-Explorer - Fade-in iframe on load, prevent reload on theme change --- app/(docs)/[[...slug]]/page.tsx | 17 ++++- app/global.css | 24 +++++++ app/layout.config.tsx | 2 +- components/SDKExplorerIframe.tsx | 63 +++++++++++++++++++ .../what-is-agentuity.mdx} | 26 ++++---- content/SDK-Explorer.mdx | 7 +++ content/meta.json | 2 +- next.config.mjs | 6 +- package-lock.json | 20 +++++- 9 files changed, 148 insertions(+), 19 deletions(-) create mode 100644 components/SDKExplorerIframe.tsx rename content/{index.mdx => Get-Started/what-is-agentuity.mdx} (75%) create mode 100644 content/SDK-Explorer.mdx diff --git a/app/(docs)/[[...slug]]/page.tsx b/app/(docs)/[[...slug]]/page.tsx index a936a02a..cf5a8b29 100644 --- a/app/(docs)/[[...slug]]/page.tsx +++ b/app/(docs)/[[...slug]]/page.tsx @@ -17,13 +17,12 @@ import { ThemeImage } from '@/components/ThemeImage'; import { TypingAnimation } from '@/components/TypingAnimation'; import { XButton } from '@/components/XButton'; import { source } from '@/lib/source'; +import CodeFromFiles from '../../../components/CodeFromFiles'; import { CommunityButton } from '../../../components/Community'; import CopyPageDropdown from '../../../components/CopyPageDropdown'; import { NavButton } from '../../../components/NavButton'; -import CodeFromFiles from '../../../components/CodeFromFiles'; import TutorialStep from '../../../components/TutorialStep'; - export default async function Page(props: { params: Promise<{ slug?: string[] }>; }) { @@ -32,6 +31,20 @@ export default async function Page(props: { if (!page) notFound(); + // Handle SDK Explorer page specially - render directly without DocsPage wrapper + const isSDKExplorer = params.slug?.[0] === 'SDK-Explorer'; + + if (isSDKExplorer) { + const { SDKExplorerIframe } = await import( + '@/components/SDKExplorerIframe' + ); + return ( +
+ +
+ ); + } + const MDX = page.data.body; return ( diff --git a/app/global.css b/app/global.css index d18e9357..1d22c4df 100644 --- a/app/global.css +++ b/app/global.css @@ -140,3 +140,27 @@ article > p { .dark .prose a:not([data-card]) { text-decoration-color: var(--color-cyan-500); } + +/* SDK Explorer - iframe rendered directly inside DocsLayout */ +.sdk-explorer-wrapper { + position: fixed; + inset: 0; + top: var(--fd-nav-height, 0px); + left: var(--fd-sidebar-width, 0px); + z-index: 10; + background: var(--color-fd-background); +} + +.sdk-explorer-wrapper iframe { + width: 100%; + height: 100%; + border: 0; +} + +/* Mobile: full width, account for nav */ +@media (max-width: 767px) { + .sdk-explorer-wrapper { + left: 0; + top: 56px; + } +} diff --git a/app/layout.config.tsx b/app/layout.config.tsx index 732988aa..48e5e032 100644 --- a/app/layout.config.tsx +++ b/app/layout.config.tsx @@ -8,7 +8,7 @@ import { XButton } from '../components/XButton'; */ export const baseOptions: BaseLayoutProps = { nav: { - url: '/Get-Started/what-is-agentuity', + url: '/SDK-Explorer', title: (
(null); + const [mounted, setMounted] = useState(false); + const [iframeLoaded, setIframeLoaded] = useState(false); + // Capture initial theme for iframe src (don't change src on theme updates) + const [initialTheme] = useState(() => + typeof window !== 'undefined' + ? document.documentElement.classList.contains('dark') + ? 'dark' + : 'light' + : 'dark' + ); + + // Only render iframe after mount to avoid hydration mismatch + useEffect(() => { + setMounted(true); + }, []); + + // Send theme changes to iframe via postMessage + useEffect(() => { + if (mounted && iframeRef.current?.contentWindow) { + iframeRef.current.contentWindow.postMessage( + { type: 'SET_THEME', theme: resolvedTheme }, + '*' + ); + } + }, [resolvedTheme, mounted]); + + // Listen for navigation requests from iframe + useEffect(() => { + const handleMessage = (event: MessageEvent) => { + if (event.data?.type === 'NAVIGATE' && event.data.path) { + window.location.href = event.data.path; + } + }; + window.addEventListener('message', handleMessage); + return () => window.removeEventListener('message', handleMessage); + }, []); + + // Show placeholder until mounted to avoid hydration mismatch + if (!mounted) { + return
; + } + + return ( +