Skip to content

Commit 03cc4fa

Browse files
authored
feat: enable Kapa AI chat widget (#1937)
Adds an `Ask AI` button to the main top bar and an Ask AI tab to the search modal.
1 parent 5295fa9 commit 03cc4fa

File tree

6 files changed

+97
-228
lines changed

6 files changed

+97
-228
lines changed

apify-docs-theme/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
"access": "public"
2020
},
2121
"dependencies": {
22-
"@apify/docs-search-modal": "^1.2.2",
23-
"@apify/ui-library": "^1.97.2",
22+
"@apify/docs-search-modal": "^1.3.3",
2423
"@apify/ui-icons": "^1.19.0",
24+
"@apify/ui-library": "^1.97.2",
2525
"@docusaurus/theme-common": "^3.7.0",
2626
"@stackql/docusaurus-plugin-hubspot": "^1.1.0",
2727
"algoliasearch": "^5.19.0",

apify-docs-theme/src/config.js

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -315,44 +315,27 @@ const plugins = [
315315
];
316316

317317
const scripts = [
318-
// {
319-
// src: 'https://widget.kapa.ai/kapa-widget.bundle.js',
320-
// 'data-website-id': 'a9937f98-9c9d-44d9-a433-fec4cb1c114d',
321-
// 'data-project-name': 'Apify',
322-
// 'data-modal-title': 'Apify AI Assistant',
323-
// 'data-project-color': '#666666',
324-
// 'data-button-hide': 'true',
325-
// 'data-search-mode-enabled': 'true',
326-
// 'data-search-include-source-names': '["Docs"]',
327-
// 'data-project-logo': 'https://apify.com/img/apify-logo/logomark-32x32.svg',
328-
// 'data-modal-example-questions': 'How to run an Actor?,Create a version of an Actor?',
329-
// 'data-modal-override-open-id': 'ask-ai-input',
330-
// 'data-modal-override-open-class': 'search-input',
331-
// 'data-font-size-xs': '1.2rem',
332-
// 'data-font-size-sm': '1.4rem',
333-
// 'data-font-size-md': '1.6rem',
334-
// 'data-font-size-lg': '1.8rem',
335-
// 'data-font-size-xl': '2.0rem',
336-
// async: true,
337-
// },
338-
// {
339-
// src: 'https://cdn.jsdelivr.net/npm/@inkeep/[email protected]/dist/embed.js',
340-
// type: 'module',
341-
// async: true,
342-
// },
318+
{
319+
src: 'https://widget.kapa.ai/kapa-widget.bundle.js',
320+
'data-website-id': 'a9937f98-9c9d-44d9-a433-fec4cb1c114d',
321+
'data-project-name': 'Apify',
322+
'data-modal-title': 'Apify AI Assistant',
323+
'data-project-color': '#666666',
324+
'data-button-hide': 'true',
325+
'data-project-logo': 'https://apify.com/img/apify-logo/logomark-32x32.svg',
326+
'data-modal-example-questions': 'How to run an Actor?,Create a version of an Actor?',
327+
'data-modal-override-open-id': 'ask-ai-input',
328+
'data-modal-override-open-class': 'search-input',
329+
'data-scale-factor': '1.6',
330+
'data-modal-size': '800px',
331+
async: true,
332+
},
343333
];
344334

345-
const customFields = {
346-
// inkeepApiKey: process.env.LOCALHOST || process.env.DEV
347-
// ? 'bbbb9f1001a9b66f282431a80bb743a24e2bdefb85d4f1e4' // development, works with localhost
348-
// : '8af30e40009f26622237f75aab8256064c26a3063717c48a', // production, only works on apify.com (any subdomain)
349-
};
350-
351335
module.exports = {
352336
themeConfig,
353337
plugins,
354338
absoluteUrl,
355339
noIndex,
356340
scripts,
357-
customFields,
358341
};

apify-docs-theme/src/theme/SearchBar/index.js

Lines changed: 38 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,9 @@ import BrowserOnly from '@docusaurus/BrowserOnly';
33
import RouterLink from '@docusaurus/Link';
44
import { useHistory, useLocation } from '@docusaurus/router';
55
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
6-
// import clsx from 'clsx';
7-
// import React, { useEffect, useState } from 'react';
8-
import React, { useCallback } from 'react';
9-
// import { useHotkeys } from 'react-hotkeys-hook';
6+
import { useState, useCallback } from 'react';
107

118
import { ApifySearch } from '@apify/docs-search-modal';
12-
// import { ControlKeyIcon, SearchIcon } from '@apify/docs-search-modal/dist/utils/icons';
139

1410
// needs to be imported as the last thing, so that it can override the default styles
1511
// TODO: update simple-import-sort to allow importing css as last.
@@ -67,7 +63,9 @@ export default function SearchBar({ onClick }) {
6763
return (
6864
<BrowserOnly>
6965
{() => (
70-
<div onClick={onClick}>
66+
<div className="SearchButton-Container">
67+
68+
<div onClick={onClick} className="AlgoliaContainer" style={{ marginRight: '12px' }}>
7169
<ApifySearch
7270
algoliaAppId={siteConfig.themeConfig.algolia.appId}
7371
algoliaIndexName='apify_sdk_v2'
@@ -76,169 +74,42 @@ export default function SearchBar({ onClick }) {
7674
navigate={navigate}
7775
/>
7876
</div>
77+
<KapaAIButton />
78+
</div>
7979
)}
8080
</BrowserOnly>
8181
);
8282
}
8383

84-
// export default function SearchBar({ onClick }) {
85-
// const [variant, setVariant] = useState(null);
86-
// const [opened, setOpened] = useState(false);
87-
// const { siteConfig } = useDocusaurusContext();
88-
// const { inkeepApiKey } = siteConfig.customFields;
89-
//
90-
// useEffect(() => {
91-
// const storedVariant = localStorage.getItem('search-provider');
92-
//
93-
// if (storedVariant) {
94-
// setVariant(storedVariant);
95-
// } else {
96-
// const assignedVariant = Math.random() < 0.5 ? 'inkeep' : 'kapa';
97-
// localStorage.setItem('search-provider', assignedVariant);
98-
// setVariant(assignedVariant);
99-
// }
100-
// }, []);
101-
//
102-
// onClick = () => {
103-
// if (opened) {
104-
// return;
105-
// }
106-
//
107-
// setOpened(true);
108-
//
109-
// if (variant === 'kapa') {
110-
// if (window.Kapa && typeof window.Kapa.open === 'function') {
111-
// window.Kapa.open();
112-
// window.Kapa('onModalClose', () => {
113-
// setOpened(false);
114-
// });
115-
// } else {
116-
// console.error('Kapa.ai widget is not available.');
117-
// }
118-
// return;
119-
// }
120-
//
121-
// if (variant !== 'inkeep') {
122-
// console.warn('Unknown search variant:', variant);
123-
// return;
124-
// }
125-
//
126-
// if (window.Inkeep) {
127-
// const config = {
128-
// baseSettings: {
129-
// apiKey: inkeepApiKey,
130-
// organizationDisplayName: 'Apify',
131-
// primaryBrandColor: '#FF9013',
132-
// transformSource: (source) => {
133-
// function getTabForSource(src) {
134-
// if (src.url.includes('help.apify.com')) {
135-
// return 'Help';
136-
// }
137-
// return 'Docs';
138-
// }
139-
//
140-
// if (source.contentType === 'documentation') {
141-
// return {
142-
// ...source,
143-
// tabs: [...(source.tabs || []), getTabForSource(source)],
144-
// };
145-
// }
146-
// return source;
147-
// },
148-
// trigger: {
149-
// disableDefaultTrigger: true,
150-
// },
151-
// theme: {
152-
// styles: [
153-
// {
154-
// key: 'main',
155-
// type: 'link',
156-
// value: '/inkeep-overrides.css',
157-
// },
158-
// ],
159-
// },
160-
// },
161-
// modalSettings: {
162-
// onOpenChange: handleOpenChange,
163-
// },
164-
// searchSettings: {
165-
// tabs: [
166-
// ['Docs', { isAlwaysVisible: true }],
167-
// 'GitHub',
168-
// 'All',
169-
// ],
170-
// },
171-
// aiChatSettings: {
172-
// aiAssistantAvatar: 'https://intercom.help/apify/assets/favicon',
173-
// chatSubjectName: 'Apify',
174-
// exampleQuestions: [
175-
// 'What is an Actor?',
176-
// 'How to use my own proxies?',
177-
// 'How to integrate Apify Actors with GitHub?',
178-
// 'How to share key-value stores between runs?',
179-
// ],
180-
// getHelpOptions: [
181-
// {
182-
// action: {
183-
// type: 'open_link',
184-
// url: 'https://apify.com/contact',
185-
// },
186-
// icon: {
187-
// builtIn: 'IoChatbubblesOutline',
188-
// },
189-
// name: 'Contact Us',
190-
// },
191-
// ],
192-
// },
193-
// defaultView: 'chat',
194-
// };
195-
// const modal = window.Inkeep.ModalSearchAndChat(config);
196-
//
197-
// function handleOpenChange(newOpen) {
198-
// modal.update({ modalSettings: { isOpen: newOpen } });
199-
// setOpened(newOpen);
200-
// }
201-
//
202-
// modal.update({ modalSettings: { isOpen: true } });
203-
// } else {
204-
// console.error('Inkeep widget is not available.');
205-
// }
206-
// };
207-
//
208-
// const [key, setKey] = useState(null);
209-
//
210-
// useEffect(() => {
211-
// if (typeof navigator !== 'undefined') {
212-
// const isMac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
213-
// setKey(isMac ? '⌘' : 'ctrl');
214-
// }
215-
// }, []);
216-
//
217-
// useHotkeys('mod+k, /', () => {
218-
// onClick();
219-
// }, { preventDefault: true });
220-
//
221-
// return (
222-
// <BrowserOnly>
223-
// {() => (
224-
// <div onClick={onClick}>
225-
// <button type="button" className="DocSearch DocSearch-Button" aria-label="Search">
226-
// <span className="DocSearch-Button-Container">
227-
// <SearchIcon/>
228-
// <span className="DocSearch-Button-Placeholder">Search</span>
229-
// </span>
230-
// <span className="DocSearch-Button-Keys">
231-
// {key !== null && (<>
232-
// <kbd className={clsx(key === 'ctrl' ? 'ctrl' : 'cmd', 'DocSearch-Button-Key')}>
233-
// {key === 'ctrl' ? <ControlKeyIcon/> : key}
234-
// </kbd>
235-
// <kbd className="DocSearch-Button-Key">K</kbd>
236-
// </>)}
237-
// </span>
238-
//
239-
// </button>
240-
// </div>
241-
// )}
242-
// </BrowserOnly>
243-
// );
244-
// }
84+
function KapaAIButton({ onClick }) {
85+
const [opened, setOpened] = useState(false);
86+
87+
onClick = () => {
88+
if (opened) {
89+
return;
90+
}
91+
92+
setOpened(true);
93+
94+
if (window.Kapa && typeof window.Kapa.open === 'function') {
95+
window.Kapa.open();
96+
window.Kapa('onModalClose', () => {
97+
setOpened(false);
98+
});
99+
} else {
100+
console.error('Kapa.ai widget is not available.');
101+
}
102+
};
103+
104+
return (
105+
<BrowserOnly>
106+
{() => (
107+
<div onClick={onClick}>
108+
<button type="button" className="AskAI-Button" aria-label="Ask AI">
109+
Ask AI
110+
</button>
111+
</div>
112+
)}
113+
</BrowserOnly>
114+
);
115+
}

apify-docs-theme/src/theme/SearchBar/styles.css

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,54 @@
2222
color var(--ifm-transition-fast) var(--ifm-transition-timing-default);
2323
}
2424

25-
.navbar-sidebar .DocSearch-Button {
25+
.AskAI-Button {
26+
height: 4rem;
27+
padding: 0.8rem 1.6rem !important;
28+
background-color: var(--ifm-color-primary);
29+
border-radius: 8px;
30+
color: var(--color-neutral-text-on-primary);
31+
font-size: 1.6rem;
32+
font-weight: 500;
33+
line-height: 2.4rem;
34+
border: none;
35+
box-shadow: none;
36+
outline: none;
37+
box-sizing: border-box;
38+
cursor: pointer;
39+
display: block;
40+
position: relative;
41+
text-align: center;
42+
transition: all var(--ifm-transition-fast) var(--ifm-transition-timing-default);
43+
}
44+
45+
.SearchButton-Container {
46+
display: flex;
47+
align-items: center;
48+
}
49+
50+
.navbar-sidebar .SearchButton-Container {
2651
display: none;
2752
}
2853

2954
@media (max-width: 768px) {
55+
.SearchButton-Container {
56+
width: 100%;
57+
}
58+
59+
.AlgoliaContainer {
60+
flex: 1;
61+
}
62+
3063
.DocSearch-Button {
3164
width: 100%;
65+
justify-content: space-between;
3266
}
3367

34-
.navbar__inner .DocSearch-Button {
68+
.navbar__inner .SearchButton-Container {
3569
display: none;
3670
}
3771

38-
.navbar-sidebar .DocSearch-Button {
72+
.navbar-sidebar .SearchButton-Container {
3973
display: flex;
4074
}
4175

package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)