"use client"; import { useEffect, useState } from "react"; import { createPortal } from "react-dom"; const cards = [ { icon: ( ), title: "Generative UI", description: "AI generates interactive charts, visualizations, and rich components directly in the conversation.", }, { icon: ( ), title: "Interactive Widgets", description: "Complex HTML/JS visualizations run in sandboxed iframes — try asking for an animation or diagram.", }, { icon: ( ), title: "Visualize Anything", description: "Ask for algorithm visualizations, 3D animations, diagrams, or any interactive visual explanation.", }, ]; function ExplainerCards() { return (
{cards.map((card) => (
{card.icon}
{card.title}

{card.description}

))}
); } /** * Portal that injects ExplainerCards into the CopilotKit welcome screen. * Inserts a wrapper div inside the welcome screen's main content area, * positioned before the suggestion pills. Auto-removes when the welcome * screen disappears (user sends a message). */ export function ExplainerCardsPortal() { const [portalTarget, setPortalTarget] = useState(null); useEffect(() => { const WELCOME_SELECTOR = '[data-testid="copilot-welcome-screen"]'; const PORTAL_ID = "explainer-cards-portal"; const tryAttach = () => { const welcomeScreen = document.querySelector(WELCOME_SELECTOR); if (!welcomeScreen) { setPortalTarget(null); return; } // Reuse existing portal container if present let portal = document.getElementById(PORTAL_ID); if (portal) { setPortalTarget(portal); return; } // Insert portal container inside the welcome screen's main content div, // before the suggestions row const mainContent = welcomeScreen.children[0] as HTMLElement | undefined; if (!mainContent) return; portal = document.createElement("div"); portal.id = PORTAL_ID; portal.style.width = "100%"; // Insert before the last child (suggestions row) const suggestionsRow = mainContent.lastElementChild; if (suggestionsRow) { mainContent.insertBefore(portal, suggestionsRow); } else { mainContent.appendChild(portal); } setPortalTarget(portal); }; tryAttach(); const observer = new MutationObserver(() => { const welcomeScreen = document.querySelector(WELCOME_SELECTOR); if (!welcomeScreen) { // Welcome screen removed (chat started) — clean up const stale = document.getElementById(PORTAL_ID); if (stale) stale.remove(); setPortalTarget(null); } else if (!document.getElementById(PORTAL_ID)) { // Welcome screen appeared but no portal yet tryAttach(); } }); observer.observe(document.body, { childList: true, subtree: true }); return () => observer.disconnect(); }, []); if (!portalTarget) return null; return createPortal(, portalTarget); }