diff --git a/src/components/Context7Widget.js b/src/components/Context7Widget.js index d9a56cf..033b44e 100644 --- a/src/components/Context7Widget.js +++ b/src/components/Context7Widget.js @@ -94,43 +94,257 @@ function injectWidget(widget) { document.body.appendChild(script); } +// --------------------------------------------------------------------------- +// Chat state detection helpers +// --------------------------------------------------------------------------- + +/** Returns true when the chat panel is open AND the user has sent at least one message. */ +function isChatEngaged() { + const container = document.getElementById('context7-widget'); + const sr = container?.shadowRoot; + if (!sr) return false; + + const panelOpen = sr.querySelector('.c7-panel')?.classList.contains('open'); + const hasUserMessages = sr.querySelectorAll('.c7-msg.user').length > 0; + return panelOpen && hasUserMessages; +} + +/** Returns true when the chat panel is currently open. */ +function isPanelOpen() { + const container = document.getElementById('context7-widget'); + const sr = container?.shadowRoot; + if (!sr) return false; + return sr.querySelector('.c7-panel')?.classList.contains('open') ?? false; +} + +/** + * Watch for the chat panel to open for the first time. + * Calls `callback` once when that happens, then auto-disconnects. + * Returns a cleanup function to cancel the observer early. + */ +function observePanelOpen(callback) { + const container = document.getElementById('context7-widget'); + const sr = container?.shadowRoot; + if (!sr) return () => {}; + + const panel = sr.querySelector('.c7-panel'); + if (!panel) return () => {}; + + // Already open. + if (panel.classList.contains('open')) { + callback(); + return () => {}; + } + + const observer = new MutationObserver(() => { + if (panel.classList.contains('open')) { + observer.disconnect(); + callback(); + } + }); + + observer.observe(panel, {attributes: true, attributeFilter: ['class']}); + return () => observer.disconnect(); +} + +/** + * Watch for the chat panel to close (`.c7-panel` loses the `open` class). + * Calls `callback` once when that happens, then auto-disconnects. + * Returns a cleanup function to cancel the observer early. + */ +function observePanelClose(callback) { + const container = document.getElementById('context7-widget'); + const sr = container?.shadowRoot; + if (!sr) return () => {}; + + const panel = sr.querySelector('.c7-panel'); + if (!panel) return () => {}; + + const observer = new MutationObserver(() => { + if (!panel.classList.contains('open')) { + observer.disconnect(); + callback(); + } + }); + + observer.observe(panel, {attributes: true, attributeFilter: ['class']}); + return () => observer.disconnect(); +} + +/** + * Update the widget's brand color in-place by rewriting the shadow DOM + *