diff --git a/src/lib/algolia-ask-ai.ts b/src/lib/algolia-ask-ai.ts index 31f81ed9b8b..4f8092d71dd 100644 --- a/src/lib/algolia-ask-ai.ts +++ b/src/lib/algolia-ask-ai.ts @@ -75,10 +75,21 @@ function highlightedAskAiQuery(): string | null { * message DocSearch renders is the one it sends. * * Replaying is abandoned if the user keeps typing or leaves, and falls through to the original - * behaviour on timeout so Enter can never be swallowed outright. + * behaviour on timeout so Enter can never be swallowed outright. At most one wait is ever pending: + * a later Enter supersedes it and uninstall clears it, so a replay can never land after the + * question it was holding back has already been asked. */ function installStaleQuestionGuard(): () => void { let replaying = false + let poll: number | undefined + + const stopPoll = () => { + if (poll === undefined) { + return + } + window.clearInterval(poll) + poll = undefined + } const submit = (input: HTMLInputElement) => { replaying = true @@ -101,6 +112,10 @@ function installStaleQuestionGuard(): () => void { return } + // Every Enter the user presses supersedes a wait already in flight, including one this guard + // lets through: DocSearch acts on it there and then, so replaying afterwards would ask twice. + stopPoll() + const optionQuery = highlightedAskAiQuery() const intendedQuery = input.value if (optionQuery === null || normalizeQuery(optionQuery) === normalizeQuery(intendedQuery)) { @@ -111,18 +126,18 @@ function installStaleQuestionGuard(): () => void { event.stopImmediatePropagation() const deadline = Date.now() + OPTION_CATCH_UP_TIMEOUT_MS - const poll = window.setInterval(() => { + poll = window.setInterval(() => { const caughtUp = normalizeQuery(highlightedAskAiQuery() ?? '') === normalizeQuery(intendedQuery) const abandoned = !input.isConnected || input.value !== intendedQuery if (abandoned) { - window.clearInterval(poll) + stopPoll() return } if (caughtUp || Date.now() > deadline) { - window.clearInterval(poll) + stopPoll() submit(input) } }, OPTION_CATCH_UP_POLL_MS) @@ -131,6 +146,7 @@ function installStaleQuestionGuard(): () => void { document.addEventListener('keydown', onKeyDown, true) return () => { + stopPoll() document.removeEventListener('keydown', onKeyDown, true) } } diff --git a/src/scss/theme/_doc-search.scss b/src/scss/theme/_doc-search.scss index 93ab42ffbf5..96d021c67dd 100644 --- a/src/scss/theme/_doc-search.scss +++ b/src/scss/theme/_doc-search.scss @@ -236,6 +236,15 @@ } } +// Ask AI renders a fenced code block as `
`, which the site's Prism
+// theme claims with `!important` and paints in the light gray it uses on the dark code blocks of
+// doc pages. DocSearch backs its code blocks with the modal surface instead, so in light mode that
+// gray lands on near-white. Matched from the document because this markup is shared by the search
+// modal and the sidepanel.
+.DocSearch-Markdown-Content [class*='language-'] {
+ color: var(--docsearch-text-color) !important;
+}
+
.main-wrapper {
.search-page-wrapper & {
margin: auto;