From d1ee19a2940d8950621aa5969e8af44f45c40ce9 Mon Sep 17 00:00:00 2001 From: "xhuang@statsig.com" Date: Mon, 20 Oct 2025 17:55:34 +0000 Subject: [PATCH 1/7] Add Ask AI CTA to Mintlify search results This script augments the Mintlify search bar with an Ask AI call-to-action as the first search result. When users search for content, they'll see an option to 'Ask AI' about their query, which seamlessly transitions them to the Kapa AI widget to get instant AI-powered answers. Features: - Monitors Mintlify search modal for query input - Injects a visually consistent 'Ask AI' CTA as the first search result - Passes the search query to Kapa AI widget when clicked - Auto-submits the query to start the AI conversation - Integrates with Statsig for user tracking when available This provides users with a smooth transition from search to AI assistance while maintaining the native Mintlify search experience. --- scripts/search-ask-ai.js | 259 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 scripts/search-ask-ai.js diff --git a/scripts/search-ask-ai.js b/scripts/search-ask-ai.js new file mode 100644 index 000000000..effcb757e --- /dev/null +++ b/scripts/search-ask-ai.js @@ -0,0 +1,259 @@ +(function() { + 'use strict'; + + const KAPA_CONFIG = { + projectColor: '#202020', + projectName: 'Statsig' + }; + + function waitForElements() { + const checkInterval = setInterval(() => { + const kapaReady = typeof window.Kapa === 'function'; + const searchReady = document.querySelector('[data-search-trigger]') || + document.querySelector('button[aria-label*="Search"]') || + document.querySelector('[cmdk-root]'); + + if (kapaReady && searchReady) { + clearInterval(checkInterval); + setupSearchAugmentation(); + } + }, 100); + + setTimeout(() => clearInterval(checkInterval), 30000); + } + + function setupSearchAugmentation() { + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + mutation.addedNodes.forEach((node) => { + if (node.nodeType === 1) { // Element node + const searchDialog = node.querySelector?.('[cmdk-root]') || + (node.hasAttribute?.('cmdk-root') ? node : null) || + node.querySelector?.('[role="dialog"][aria-label*="Search"]') || + (node.getAttribute?.('role') === 'dialog' && + node.getAttribute?.('aria-label')?.includes('Search') ? node : null); + + if (searchDialog) { + monitorSearchInput(searchDialog); + } + } + }); + }); + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + + const existingDialog = document.querySelector('[cmdk-root]') || + document.querySelector('[role="dialog"][aria-label*="Search"]'); + if (existingDialog) { + monitorSearchInput(existingDialog); + } + } + + function monitorSearchInput(searchDialog) { + let currentQuery = ''; + let askAiElement = null; + + const inputObserver = new MutationObserver(() => { + const searchInput = searchDialog.querySelector('input[type="text"]') || + searchDialog.querySelector('[cmdk-input]'); + + if (searchInput) { + const query = searchInput.value.trim(); + + if (query && query !== currentQuery) { + currentQuery = query; + setTimeout(() => injectAskAiCTA(searchDialog, query), 200); + } else if (!query && currentQuery) { + currentQuery = ''; + if (askAiElement && askAiElement.parentNode) { + askAiElement.remove(); + askAiElement = null; + } + } + } + }); + + inputObserver.observe(searchDialog, { + childList: true, + subtree: true, + characterData: true, + attributes: true + }); + + searchDialog.addEventListener('input', (e) => { + if (e.target.matches('input[type="text"]') || e.target.hasAttribute('cmdk-input')) { + const query = e.target.value.trim(); + + if (query && query !== currentQuery) { + currentQuery = query; + setTimeout(() => injectAskAiCTA(searchDialog, query), 200); + } else if (!query && currentQuery) { + currentQuery = ''; + if (askAiElement && askAiElement.parentNode) { + askAiElement.remove(); + askAiElement = null; + } + } + } + }, true); + } + + function injectAskAiCTA(searchDialog, query) { + const resultsContainer = searchDialog.querySelector('[cmdk-list]') || + searchDialog.querySelector('[role="listbox"]') || + searchDialog.querySelector('[cmdk-group]')?.parentElement; + + if (!resultsContainer) return; + + const existingCTA = resultsContainer.querySelector('.mintlify-ask-ai-cta'); + if (existingCTA) { + existingCTA.remove(); + } + + const askAiItem = document.createElement('div'); + askAiItem.className = 'mintlify-ask-ai-cta'; + askAiItem.setAttribute('role', 'option'); + askAiItem.setAttribute('tabindex', '0'); + askAiItem.style.cssText = ` + display: flex; + align-items: center; + padding: 12px 16px; + cursor: pointer; + background: transparent; + border-radius: 8px; + margin: 4px 8px; + transition: background-color 0.2s; + outline: none; + border: 2px solid transparent; + `; + + const escapeHtml = (text) => { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + }; + + const escapedQuery = escapeHtml(query); + askAiItem.innerHTML = ` + +
+
Ask AI: ${escapedQuery}
+
Get instant answers powered by AI
+
+ `; + + const handleMouseEnter = () => { + askAiItem.style.backgroundColor = 'rgba(0, 0, 0, 0.05)'; + }; + + const handleMouseLeave = () => { + askAiItem.style.backgroundColor = 'transparent'; + }; + + const handleFocus = () => { + askAiItem.style.backgroundColor = 'rgba(0, 0, 0, 0.05)'; + askAiItem.style.border = `2px solid ${KAPA_CONFIG.projectColor}`; + }; + + const handleBlur = () => { + askAiItem.style.backgroundColor = 'transparent'; + askAiItem.style.border = '2px solid transparent'; + }; + + const handleActivation = (e) => { + e.preventDefault(); + e.stopPropagation(); + + const closeButton = searchDialog.querySelector('button[aria-label*="Close"]') || + searchDialog.querySelector('[cmdk-dialog-close]'); + if (closeButton) { + closeButton.click(); + } + + if (window.Kapa && typeof window.Kapa === 'function') { + setTimeout(() => { + try { + const statsigInstance = window.Statsig?.instances?.['client-Wql5Tkj3Wa3sE8VpFjWpCHCPHxYZMbq6RfcRZZVHFdm']; + const stableID = statsigInstance?.getContext?.()?.stableID; + if (stableID) { + window.kapaSettings = { + user: { + stableID: stableID, + }, + }; + } + } catch (e) { + } + + window.Kapa.open({ mode: 'ai', query: query }); + + setTimeout(() => { + const kapaContainer = document.getElementById('kapa-widget-container'); + if (!kapaContainer?.shadowRoot) return; + + const modal = kapaContainer.shadowRoot.querySelector('section[aria-modal="true"]'); + if (!modal) return; + + const textarea = modal.querySelector('textarea'); + if (!textarea) return; + + textarea.focus(); + + const submitButtonSelectors = [ + 'button.mantine-ActionIcon-root[data-variant="filled"]', + 'button[type="submit"]', + 'button[aria-label*="send"]', + 'button[aria-label*="submit"]' + ]; + + let submitButton = null; + for (const selector of submitButtonSelectors) { + submitButton = modal.querySelector(selector); + if (submitButton) break; + } + + if (!submitButton) { + const arrowIcon = modal.querySelector('svg[data-icon="arrow-right"]'); + submitButton = arrowIcon?.closest('button'); + } + + if (submitButton) { + submitButton.click(); + setTimeout(() => textarea.focus(), 100); + } + }, 300); + }, 100); + } + }; + + const handleKeyDown = (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + handleActivation(e); + } + }; + + askAiItem.addEventListener('mouseenter', handleMouseEnter); + askAiItem.addEventListener('mouseleave', handleMouseLeave); + askAiItem.addEventListener('focus', handleFocus); + askAiItem.addEventListener('blur', handleBlur); + askAiItem.addEventListener('click', handleActivation); + askAiItem.addEventListener('keydown', handleKeyDown); + + if (resultsContainer.firstChild) { + resultsContainer.insertBefore(askAiItem, resultsContainer.firstChild); + } else { + resultsContainer.appendChild(askAiItem); + } + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', waitForElements); + } else { + waitForElements(); + } +})(); From 4fca6cef23fe427bd83591efde49827403be9508 Mon Sep 17 00:00:00 2001 From: "xhuang@statsig.com" Date: Tue, 21 Oct 2025 01:51:31 +0000 Subject: [PATCH 2/7] Fix search dialog detection for production Mintlify deployment Updated script to properly detect and inject Ask AI CTA in production: - Remove references to non-existent [cmdk-root] and [cmdk-list] attributes - Use [aria-modal="true"] and [role="listbox"] selectors instead - Simplify search dialog detection logic - Update close button selector to handle case variations The script now correctly finds the Mintlify search modal and listbox container in production deployments. --- scripts/search-ask-ai.js | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/scripts/search-ask-ai.js b/scripts/search-ask-ai.js index effcb757e..861401a4e 100644 --- a/scripts/search-ask-ai.js +++ b/scripts/search-ask-ai.js @@ -10,8 +10,7 @@ const checkInterval = setInterval(() => { const kapaReady = typeof window.Kapa === 'function'; const searchReady = document.querySelector('[data-search-trigger]') || - document.querySelector('button[aria-label*="Search"]') || - document.querySelector('[cmdk-root]'); + document.querySelector('button[aria-label*="Search"]'); if (kapaReady && searchReady) { clearInterval(checkInterval); @@ -27,14 +26,18 @@ mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { // Element node - const searchDialog = node.querySelector?.('[cmdk-root]') || - (node.hasAttribute?.('cmdk-root') ? node : null) || - node.querySelector?.('[role="dialog"][aria-label*="Search"]') || - (node.getAttribute?.('role') === 'dialog' && - node.getAttribute?.('aria-label')?.includes('Search') ? node : null); + const isSearchDialog = (node.getAttribute?.('aria-modal') === 'true' && + node.querySelector?.('input[type="text"]')) || + (node.getAttribute?.('role') === 'dialog' && + node.querySelector?.('input[type="text"]')); - if (searchDialog) { - monitorSearchInput(searchDialog); + if (isSearchDialog) { + monitorSearchInput(node); + } else { + const searchDialog = node.querySelector?.('[aria-modal="true"]'); + if (searchDialog && searchDialog.querySelector('input[type="text"]')) { + monitorSearchInput(searchDialog); + } } } }); @@ -46,9 +49,8 @@ subtree: true }); - const existingDialog = document.querySelector('[cmdk-root]') || - document.querySelector('[role="dialog"][aria-label*="Search"]'); - if (existingDialog) { + const existingDialog = document.querySelector('[aria-modal="true"]'); + if (existingDialog && existingDialog.querySelector('input[type="text"]')) { monitorSearchInput(existingDialog); } } @@ -58,8 +60,7 @@ let askAiElement = null; const inputObserver = new MutationObserver(() => { - const searchInput = searchDialog.querySelector('input[type="text"]') || - searchDialog.querySelector('[cmdk-input]'); + const searchInput = searchDialog.querySelector('input[type="text"]'); if (searchInput) { const query = searchInput.value.trim(); @@ -85,7 +86,7 @@ }); searchDialog.addEventListener('input', (e) => { - if (e.target.matches('input[type="text"]') || e.target.hasAttribute('cmdk-input')) { + if (e.target.matches('input[type="text"]')) { const query = e.target.value.trim(); if (query && query !== currentQuery) { @@ -103,9 +104,7 @@ } function injectAskAiCTA(searchDialog, query) { - const resultsContainer = searchDialog.querySelector('[cmdk-list]') || - searchDialog.querySelector('[role="listbox"]') || - searchDialog.querySelector('[cmdk-group]')?.parentElement; + const resultsContainer = searchDialog.querySelector('[role="listbox"]'); if (!resultsContainer) return; @@ -169,7 +168,7 @@ e.stopPropagation(); const closeButton = searchDialog.querySelector('button[aria-label*="Close"]') || - searchDialog.querySelector('[cmdk-dialog-close]'); + searchDialog.querySelector('button[aria-label*="close"]'); if (closeButton) { closeButton.click(); } From 6acf4e7a9f03aef9560d285161a0e128ef7bf36e Mon Sep 17 00:00:00 2001 From: "xhuang@statsig.com" Date: Tue, 21 Oct 2025 01:57:02 +0000 Subject: [PATCH 3/7] Improve search input monitoring with requestAnimationFrame polling Added continuous polling via requestAnimationFrame to reliably detect search input changes. This ensures the Ask AI CTA is injected even if the input event listener doesn't fire properly. Changes: - Added checkInput() function that polls for input value changes - Keep input event listener as immediate trigger - Use MutationObserver to detect when search dialog is removed - Automatically clean up monitoring when dialog closes This hybrid approach (polling + events) is more reliable than relying solely on mutation observers or event listeners. --- scripts/search-ask-ai.js | 57 ++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/scripts/search-ask-ai.js b/scripts/search-ask-ai.js index 861401a4e..bb2e8504b 100644 --- a/scripts/search-ask-ai.js +++ b/scripts/search-ask-ai.js @@ -57,33 +57,31 @@ function monitorSearchInput(searchDialog) { let currentQuery = ''; - let askAiElement = null; + let monitoringActive = true; - const inputObserver = new MutationObserver(() => { - const searchInput = searchDialog.querySelector('input[type="text"]'); + const checkInput = () => { + if (!monitoringActive) return; + const searchInput = searchDialog.querySelector('input[type="text"]'); if (searchInput) { const query = searchInput.value.trim(); if (query && query !== currentQuery) { currentQuery = query; - setTimeout(() => injectAskAiCTA(searchDialog, query), 200); + injectAskAiCTA(searchDialog, query); } else if (!query && currentQuery) { currentQuery = ''; - if (askAiElement && askAiElement.parentNode) { - askAiElement.remove(); - askAiElement = null; + const existingCTA = searchDialog.querySelector('.mintlify-ask-ai-cta'); + if (existingCTA) { + existingCTA.remove(); } } } - }); - - inputObserver.observe(searchDialog, { - childList: true, - subtree: true, - characterData: true, - attributes: true - }); + + if (monitoringActive) { + requestAnimationFrame(checkInput); + } + }; searchDialog.addEventListener('input', (e) => { if (e.target.matches('input[type="text"]')) { @@ -91,16 +89,37 @@ if (query && query !== currentQuery) { currentQuery = query; - setTimeout(() => injectAskAiCTA(searchDialog, query), 200); + injectAskAiCTA(searchDialog, query); } else if (!query && currentQuery) { currentQuery = ''; - if (askAiElement && askAiElement.parentNode) { - askAiElement.remove(); - askAiElement = null; + const existingCTA = searchDialog.querySelector('.mintlify-ask-ai-cta'); + if (existingCTA) { + existingCTA.remove(); } } } }, true); + + const observer = new MutationObserver((mutations) => { + for (const mutation of mutations) { + if (mutation.removedNodes) { + for (const node of mutation.removedNodes) { + if (node === searchDialog || node.contains?.(searchDialog)) { + monitoringActive = false; + observer.disconnect(); + return; + } + } + } + } + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + + checkInput(); } function injectAskAiCTA(searchDialog, query) { From da23ce445546b19d2e1d91573a2146682decd8b3 Mon Sep 17 00:00:00 2001 From: "xhuang@statsig.com" Date: Tue, 21 Oct 2025 02:00:33 +0000 Subject: [PATCH 4/7] Add snippets/head.html to load custom search-ask-ai script Created head.html snippet file to properly load the search-ask-ai.js script via Mintlify's snippet injection mechanism. This ensures the script is loaded on all pages and can properly augment the search functionality. --- snippets/head.html | 1 + 1 file changed, 1 insertion(+) create mode 100644 snippets/head.html diff --git a/snippets/head.html b/snippets/head.html new file mode 100644 index 000000000..b81361e13 --- /dev/null +++ b/snippets/head.html @@ -0,0 +1 @@ + From d2e1ee3c57be654471bc4bef9a428c72ae78f13f Mon Sep 17 00:00:00 2001 From: "xhuang@statsig.com" Date: Tue, 21 Oct 2025 02:02:32 +0000 Subject: [PATCH 5/7] Add custom script loading via docs.json scripts property Added /scripts/search-ask-ai.js to the scripts array in docs.json to ensure it gets loaded by Mintlify. This is the proper way to load custom scripts in Mintlify deployments. --- docs.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs.json b/docs.json index ed68beca0..9f206a574 100644 --- a/docs.json +++ b/docs.json @@ -36,6 +36,9 @@ "tagId": "GTM-NRDCWNF" } }, + "scripts": [ + "/scripts/search-ask-ai.js" + ], "navigation": { "tabs": [ { @@ -1826,4 +1829,4 @@ "slack": "https://statsig.com/slack" } } -} \ No newline at end of file +} From 718ab40043af2bf55cd9af56a0cc1f10fe69728b Mon Sep 17 00:00:00 2001 From: "xhuang@statsig.com" Date: Tue, 21 Oct 2025 02:05:44 +0000 Subject: [PATCH 6/7] Inline search-ask-ai script directly into snippets/head.html Instead of loading the script from /scripts/, inline the entire JavaScript directly into the snippets/head.html file. This ensures Mintlify properly loads the script since it may not serve files from the /scripts/ directory. Also removed the scripts property from docs.json since it's not needed. --- docs.json | 3 - snippets/head.html | 280 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 279 insertions(+), 4 deletions(-) diff --git a/docs.json b/docs.json index 9f206a574..29e16db7b 100644 --- a/docs.json +++ b/docs.json @@ -36,9 +36,6 @@ "tagId": "GTM-NRDCWNF" } }, - "scripts": [ - "/scripts/search-ask-ai.js" - ], "navigation": { "tabs": [ { diff --git a/snippets/head.html b/snippets/head.html index b81361e13..baeb1ec9f 100644 --- a/snippets/head.html +++ b/snippets/head.html @@ -1 +1,279 @@ - + From e8cd18758aad5d4ac21092ff38224fc803009890 Mon Sep 17 00:00:00 2001 From: "xhuang@statsig.com" Date: Tue, 21 Oct 2025 02:07:54 +0000 Subject: [PATCH 7/7] Move search-ask-ai.js to root directory for Mintlify auto-loading According to Mintlify documentation, any .js file in the content directory (root) will be automatically included in every documentation page. Moved the script from /scripts/ to the root directory to enable this feature. --- search-ask-ai.js | 277 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 search-ask-ai.js diff --git a/search-ask-ai.js b/search-ask-ai.js new file mode 100644 index 000000000..bb2e8504b --- /dev/null +++ b/search-ask-ai.js @@ -0,0 +1,277 @@ +(function() { + 'use strict'; + + const KAPA_CONFIG = { + projectColor: '#202020', + projectName: 'Statsig' + }; + + function waitForElements() { + const checkInterval = setInterval(() => { + const kapaReady = typeof window.Kapa === 'function'; + const searchReady = document.querySelector('[data-search-trigger]') || + document.querySelector('button[aria-label*="Search"]'); + + if (kapaReady && searchReady) { + clearInterval(checkInterval); + setupSearchAugmentation(); + } + }, 100); + + setTimeout(() => clearInterval(checkInterval), 30000); + } + + function setupSearchAugmentation() { + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + mutation.addedNodes.forEach((node) => { + if (node.nodeType === 1) { // Element node + const isSearchDialog = (node.getAttribute?.('aria-modal') === 'true' && + node.querySelector?.('input[type="text"]')) || + (node.getAttribute?.('role') === 'dialog' && + node.querySelector?.('input[type="text"]')); + + if (isSearchDialog) { + monitorSearchInput(node); + } else { + const searchDialog = node.querySelector?.('[aria-modal="true"]'); + if (searchDialog && searchDialog.querySelector('input[type="text"]')) { + monitorSearchInput(searchDialog); + } + } + } + }); + }); + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + + const existingDialog = document.querySelector('[aria-modal="true"]'); + if (existingDialog && existingDialog.querySelector('input[type="text"]')) { + monitorSearchInput(existingDialog); + } + } + + function monitorSearchInput(searchDialog) { + let currentQuery = ''; + let monitoringActive = true; + + const checkInput = () => { + if (!monitoringActive) return; + + const searchInput = searchDialog.querySelector('input[type="text"]'); + if (searchInput) { + const query = searchInput.value.trim(); + + if (query && query !== currentQuery) { + currentQuery = query; + injectAskAiCTA(searchDialog, query); + } else if (!query && currentQuery) { + currentQuery = ''; + const existingCTA = searchDialog.querySelector('.mintlify-ask-ai-cta'); + if (existingCTA) { + existingCTA.remove(); + } + } + } + + if (monitoringActive) { + requestAnimationFrame(checkInput); + } + }; + + searchDialog.addEventListener('input', (e) => { + if (e.target.matches('input[type="text"]')) { + const query = e.target.value.trim(); + + if (query && query !== currentQuery) { + currentQuery = query; + injectAskAiCTA(searchDialog, query); + } else if (!query && currentQuery) { + currentQuery = ''; + const existingCTA = searchDialog.querySelector('.mintlify-ask-ai-cta'); + if (existingCTA) { + existingCTA.remove(); + } + } + } + }, true); + + const observer = new MutationObserver((mutations) => { + for (const mutation of mutations) { + if (mutation.removedNodes) { + for (const node of mutation.removedNodes) { + if (node === searchDialog || node.contains?.(searchDialog)) { + monitoringActive = false; + observer.disconnect(); + return; + } + } + } + } + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + + checkInput(); + } + + function injectAskAiCTA(searchDialog, query) { + const resultsContainer = searchDialog.querySelector('[role="listbox"]'); + + if (!resultsContainer) return; + + const existingCTA = resultsContainer.querySelector('.mintlify-ask-ai-cta'); + if (existingCTA) { + existingCTA.remove(); + } + + const askAiItem = document.createElement('div'); + askAiItem.className = 'mintlify-ask-ai-cta'; + askAiItem.setAttribute('role', 'option'); + askAiItem.setAttribute('tabindex', '0'); + askAiItem.style.cssText = ` + display: flex; + align-items: center; + padding: 12px 16px; + cursor: pointer; + background: transparent; + border-radius: 8px; + margin: 4px 8px; + transition: background-color 0.2s; + outline: none; + border: 2px solid transparent; + `; + + const escapeHtml = (text) => { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + }; + + const escapedQuery = escapeHtml(query); + askAiItem.innerHTML = ` + +
+
Ask AI: ${escapedQuery}
+
Get instant answers powered by AI
+
+ `; + + const handleMouseEnter = () => { + askAiItem.style.backgroundColor = 'rgba(0, 0, 0, 0.05)'; + }; + + const handleMouseLeave = () => { + askAiItem.style.backgroundColor = 'transparent'; + }; + + const handleFocus = () => { + askAiItem.style.backgroundColor = 'rgba(0, 0, 0, 0.05)'; + askAiItem.style.border = `2px solid ${KAPA_CONFIG.projectColor}`; + }; + + const handleBlur = () => { + askAiItem.style.backgroundColor = 'transparent'; + askAiItem.style.border = '2px solid transparent'; + }; + + const handleActivation = (e) => { + e.preventDefault(); + e.stopPropagation(); + + const closeButton = searchDialog.querySelector('button[aria-label*="Close"]') || + searchDialog.querySelector('button[aria-label*="close"]'); + if (closeButton) { + closeButton.click(); + } + + if (window.Kapa && typeof window.Kapa === 'function') { + setTimeout(() => { + try { + const statsigInstance = window.Statsig?.instances?.['client-Wql5Tkj3Wa3sE8VpFjWpCHCPHxYZMbq6RfcRZZVHFdm']; + const stableID = statsigInstance?.getContext?.()?.stableID; + if (stableID) { + window.kapaSettings = { + user: { + stableID: stableID, + }, + }; + } + } catch (e) { + } + + window.Kapa.open({ mode: 'ai', query: query }); + + setTimeout(() => { + const kapaContainer = document.getElementById('kapa-widget-container'); + if (!kapaContainer?.shadowRoot) return; + + const modal = kapaContainer.shadowRoot.querySelector('section[aria-modal="true"]'); + if (!modal) return; + + const textarea = modal.querySelector('textarea'); + if (!textarea) return; + + textarea.focus(); + + const submitButtonSelectors = [ + 'button.mantine-ActionIcon-root[data-variant="filled"]', + 'button[type="submit"]', + 'button[aria-label*="send"]', + 'button[aria-label*="submit"]' + ]; + + let submitButton = null; + for (const selector of submitButtonSelectors) { + submitButton = modal.querySelector(selector); + if (submitButton) break; + } + + if (!submitButton) { + const arrowIcon = modal.querySelector('svg[data-icon="arrow-right"]'); + submitButton = arrowIcon?.closest('button'); + } + + if (submitButton) { + submitButton.click(); + setTimeout(() => textarea.focus(), 100); + } + }, 300); + }, 100); + } + }; + + const handleKeyDown = (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + handleActivation(e); + } + }; + + askAiItem.addEventListener('mouseenter', handleMouseEnter); + askAiItem.addEventListener('mouseleave', handleMouseLeave); + askAiItem.addEventListener('focus', handleFocus); + askAiItem.addEventListener('blur', handleBlur); + askAiItem.addEventListener('click', handleActivation); + askAiItem.addEventListener('keydown', handleKeyDown); + + if (resultsContainer.firstChild) { + resultsContainer.insertBefore(askAiItem, resultsContainer.firstChild); + } else { + resultsContainer.appendChild(askAiItem); + } + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', waitForElements); + } else { + waitForElements(); + } +})();