Skip to content

Commit 5ca15f0

Browse files
Add kapa.ai (#1107)
* Add kapa.ai * Implement option 2 * Add JS tooltips * Move chat button to bottom-right corner * Move chat below GDPR banner * Fix AI hover * Override button outline from text.scss * Add scaling to Ask AI button wiggle * Update CSP, title, and z-index * More CSP headers * Update CSP headers * Update CSP headers * Update CSP headers * Update code CSS * Update CSS * Update CSS * Update CSS: feedback buttons * Update CSS: source buttons * Update CSS: Source links body * CSS test * Update CSS: tooltip * Update CSS: Popover * Update CSS: Feedback button * Update CSS: Checkboxes * Update CSS: Feedback submit button * Update CSS: Footer * Update CSS: Button border * Update CSS: Stop generation button * Update next.config.js with all connect-src * Trying a tighter CSP --------- Co-authored-by: Thiago Teixeira <[email protected]>
1 parent ecb2cce commit 5ca15f0

13 files changed

+327
-3
lines changed

components/layouts/globalTemplate.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useState, useEffect } from "react";
22
import Header from "../navigation/header";
3+
import ChatSticky from "../navigation/chatSticky";
34

45
import styles from "./globalTemplate.module.css";
56

@@ -25,6 +26,7 @@ const Layout = ({ children }) => {
2526
<div className={isSticky ? styles.stickyPageWrapper : undefined}>
2627
{children}
2728
</div>
29+
<ChatSticky />
2830
</main>
2931
);
3032
};

components/navigation/chatSticky.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import classNames from "classnames";
2+
import Kapa from "../utilities/kapa";
3+
import styles from "./chatSticky.module.css";
4+
5+
const ChatSticky = () => {
6+
return (
7+
<div className={classNames(styles.Container)}>
8+
<nav className={styles.Navigation} id="chat-sticky">
9+
<section className={styles.NavigationContainer}>
10+
<Kapa />
11+
</section>
12+
</nav>
13+
</div>
14+
);
15+
};
16+
17+
export default ChatSticky;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.Container {
2+
@apply fixed bottom-[30px] w-full z-10;
3+
}
4+
5+
.Navigation {
6+
@apply container px-2 xl:px-4 flex items-center justify-between relative transition-all mx-auto h-full left-auto;
7+
}
8+
9+
.NavigationContainer {
10+
@apply flex flex-auto justify-end;
11+
}

components/navigation/header.module.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.Container {
2-
@apply relative w-screen z-30 border-b;
2+
@apply relative w-full z-30 border-b;
33
@apply bg-white !important;
44
}
55

components/utilities/kapa.js

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import styles from "./kapa.module.css";
2+
3+
const Kapa = () => {
4+
const showTooltip = () => {
5+
let tips = document.getElementsByClassName(styles.Tooltip);
6+
if (tips.length > 0) {
7+
tips[0].style.display = "block";
8+
}
9+
};
10+
11+
const hideTooltip = () => {
12+
let tips = document.getElementsByClassName(styles.Tooltip);
13+
if (tips.length > 0) {
14+
tips[0].style.display = "none";
15+
}
16+
};
17+
let kapaWidget = (
18+
<div className={styles.FooterContainer}>
19+
<section className={styles.AskButtonContainer}>
20+
<button
21+
id="kapa-ai"
22+
type="button"
23+
className={styles.AskButton}
24+
onMouseOver={showTooltip}
25+
onMouseOut={hideTooltip}
26+
>
27+
<i className={styles.AskIcon}>forum</i> Ask AI
28+
</button>
29+
{/* <div className={styles.Tooltip}>
30+
<p>Try our new docs assistant!</p>
31+
</div> */}
32+
<script
33+
src="https://widget.kapa.ai/kapa-widget.bundle.js"
34+
data-website-id="e81c2b35-6c03-4576-a56c-3c825f866e06"
35+
data-project-name="Streamlit"
36+
data-project-color="#000000"
37+
data-project-logo="https://docs.streamlit.io/logo.svg"
38+
data-modal-title="Streamlit docs assistant (beta)"
39+
data-modal-disclaimer="
40+
This AI chatbot is powered by kapa.ai and public Streamlit information.
41+
Answers may be inaccurate, inefficient, or biased. Any use or decisions
42+
based on such answers should include reasonable practices including
43+
human oversight to ensure they are safe, accurate, and suitable for
44+
your intended purpose. Streamlit is not liable for any actions, losses,
45+
or damages resulting from the use of the chatbot.
46+
47+
Do not enter any private, sensitive, personal, or regulated data.
48+
By using this chatbot, you acknowledge and agree that input you provide
49+
and answers you receive (collectively, “Content”) may be used by
50+
Streamlit and kapa.ai to provide, maintain, develop, and improve
51+
their respective offerings. For more information on how
52+
kapa.ai may use your Content, see https://www.kapa.ai/content/terms-of-service."
53+
data-button-hide="true"
54+
data-modal-override-open-id="kapa-ai"
55+
data-modal-lock-scroll="false"
56+
data-modal-border-radius="6px"
57+
data-modal-image-height="18px"
58+
data-answer-feedback-button-active-border="1px solid #808495"
59+
></script>
60+
</section>
61+
</div>
62+
);
63+
64+
return kapaWidget;
65+
};
66+
67+
export default Kapa;

components/utilities/kapa.module.css

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
@keyframes wiggle {
2+
0% {
3+
transform: rotate(0deg);
4+
}
5+
50% {
6+
transform: rotate(0deg);
7+
}
8+
60% {
9+
transform: rotate(5deg) scale(1.25);
10+
}
11+
70% {
12+
transform: rotate(-5deg) scale(1.25);
13+
}
14+
80% {
15+
transform: rotate(5deg) scale(1.25);
16+
}
17+
90% {
18+
transform: rotate(-5deg) scale(1.25);
19+
}
20+
100% {
21+
transform: rotate(0deg);
22+
}
23+
}
24+
25+
.AskButtonContainer {
26+
@apply flex justify-end;
27+
}
28+
29+
.AskButton {
30+
@apply flex items-center justify-center p-0 rounded-md h-8 px-4 cursor-pointer bg-gray-100 text-white hover:opacity-90 hover:shadow-sm;
31+
animation: wiggle 2s 1;
32+
}
33+
34+
.AskButton:hover {
35+
transform: scale(1.025);
36+
}
37+
38+
.AskButton:focus,
39+
.AskButton:focus-visible {
40+
@apply outline-0;
41+
}
42+
43+
:global(.dark) .AskButton {
44+
@apply text-gray-100 bg-gray-40 !important;
45+
}
46+
47+
.AskIcon {
48+
@apply text-lg m-0 pr-2 group-hover:opacity-70;
49+
@apply text-white !important;
50+
}
51+
52+
:global(.dark) .AskIcon {
53+
@apply text-gray-100 !important;
54+
}
55+
56+
.Tooltip {
57+
@apply hidden absolute top-20 right-[4.5rem] h-8 px-2 pt-0.5 rounded-md bg-gray-20;
58+
}
59+
60+
.Tooltip p {
61+
@apply text-gray-70;
62+
}
63+
64+
:global(.dark) .Tooltip {
65+
@apply bg-gray-90;
66+
}

components/utilities/kapaModal.css

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
.mantine-Modal-overlay {
2+
background-color: rgba(166, 168, 184, 0.6) !important;
3+
}
4+
5+
.mantine-Modal-header,
6+
.mantine-Modal-header h3 {
7+
@apply bg-white dark:bg-gray-90 text-gray-90 dark:text-gray-40 border-b-0 font-normal tracking-wide;
8+
}
9+
10+
.mantine-Modal-header > .mantine-Group-root:first-child .mantine-Image-root {
11+
@apply hidden;
12+
}
13+
14+
.mantine-Modal-body,
15+
.mantine-Modal-body a,
16+
.mantine-Modal-body .mantine-List-root,
17+
.mantine-Modal-body .mantine-List-item {
18+
@apply bg-white dark:bg-gray-90;
19+
@apply text-gray-90 dark:text-gray-40;
20+
}
21+
22+
.mantine-Paper-root
23+
> .mantine-Modal-body
24+
> .mantine-Modal-body
25+
> div:first-child
26+
> div:first-child:has(.mantine-Text-root) {
27+
@apply bg-gray-20 dark:bg-gray-80;
28+
}
29+
30+
.mantine-Paper-root
31+
> .mantine-Modal-body
32+
> .mantine-Modal-body
33+
> div:first-child
34+
> div:first-child
35+
.mantine-Text-root {
36+
@apply text-gray-70 dark:text-gray-50;
37+
}
38+
39+
.mantine-Group-root button {
40+
@apply text-gray-70;
41+
}
42+
43+
.mantine-Group-root button:hover {
44+
@apply bg-gray-20 dark:bg-gray-80;
45+
}
46+
47+
.mantine-Input-input {
48+
@apply bg-white dark:bg-gray-90 border-gray-70 focus:border-orange-70 text-gray-90 dark:text-gray-40;
49+
}
50+
51+
.mantine-Input-rightSection > .mantine-Group-root > .mantine-ActionIcon-root {
52+
@apply bg-white dark:bg-gray-90 border-none text-orange-70 !important;
53+
}
54+
55+
.mantine-Input-rightSection
56+
> .mantine-Group-root
57+
> .mantine-ActionIcon-root
58+
svg {
59+
@apply scale-150 hover:scale-[1.6];
60+
}
61+
62+
.mantine-Code-root {
63+
@apply bg-transparent border border-gray-40 dark:border-gray-80 rounded-md text-red-70 px-1 mx-1;
64+
}
65+
66+
.mantine-Grid-root .mantine-Grid-col a {
67+
@apply border-gray-20 dark:border-gray-80 bg-transparent;
68+
}
69+
70+
.mantine-Grid-root .mantine-Grid-col a:hover {
71+
@apply bg-gray-20 dark:bg-gray-80;
72+
}
73+
74+
.mantine-Grid-root .mantine-Grid-col div {
75+
@apply text-gray-90 dark:text-gray-40;
76+
}
77+
78+
.mantine-Grid-root .mantine-Grid-col div.mantine-Tooltip-tooltip {
79+
@apply bg-gray-80 dark:bg-gray-20 text-gray-50 dark:text-gray-70;
80+
}
81+
82+
.mantine-Popover-dropdown,
83+
.mantine-Popover-arrow {
84+
@apply bg-white dark:bg-gray-90 text-gray-90 dark:text-gray-40;
85+
}
86+
87+
.mantine-Popover-dropdown .mantine-Button-root {
88+
@apply text-white;
89+
}
90+
91+
.mantine-Popover-dropdown h5 {
92+
@apply text-gray-90 dark:text-gray-40;
93+
}
94+
95+
.mantine-Checkbox-input {
96+
@apply bg-gray-20 dark:bg-gray-80 border-gray-70;
97+
}
98+
99+
.mantine-Checkbox-label {
100+
@apply text-gray-90 dark:text-gray-40;
101+
}
102+
103+
.mantine-Paper-root
104+
> .mantine-Modal-body
105+
> .mantine-Modal-body
106+
> div:last-child {
107+
@apply text-gray-70;
108+
}
109+
110+
.mantine-Paper-root
111+
> .mantine-Modal-body
112+
> .mantine-Modal-body
113+
> div:last-child
114+
a {
115+
@apply text-gray-70;
116+
}
117+
118+
.mantine-Button-icon:has(.tabler-icon-player-stop) {
119+
@apply hidden;
120+
}
121+
122+
.mantine-Button-root:has(.tabler-icon-player-stop) {
123+
@apply py-0 px-4;
124+
}

components/utilities/themeToggle.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ const ThemeToggle = () => {
2424
localStorage.setItem("theme", theme);
2525
};
2626

27+
const showTooltip = () => {
28+
document.getElementsByClassName(styles.Tooltip)[0].style.display = "block";
29+
};
30+
31+
const hideTooltip = () => {
32+
document.getElementsByClassName(styles.Tooltip)[0].style.display = "none";
33+
};
34+
2735
useEffect(() => {
2836
if (getUserPreference() === "dark") {
2937
changeTailwindTheme("dark");
@@ -35,19 +43,22 @@ const ThemeToggle = () => {
3543
return (
3644
<React.Fragment>
3745
<button
38-
aria-label={`Change to ${inactiveTheme} mode`}
39-
title={`Change to ${inactiveTheme} mode`}
4046
type="button"
4147
onClick={
4248
activeTheme === "light"
4349
? () => changeTailwindTheme("dark")
4450
: () => changeTailwindTheme("light")
4551
}
52+
onMouseOver={showTooltip}
53+
onMouseOut={hideTooltip}
4654
className={styles.Container}
4755
>
4856
<i className={classNames(styles.DarkIcon, styles.Icon)}>dark_mode</i>
4957
<i className={classNames(styles.LightIcon, styles.Icon)}>light_mode</i>
5058
</button>
59+
<div className={styles.Tooltip}>
60+
<p>Change to {inactiveTheme} mode</p>
61+
</div>
5162
</React.Fragment>
5263
);
5364
};

components/utilities/themeToggle.module.css

+12
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,15 @@
3131
:global(.dark) .LightIcon {
3232
@apply opacity-0;
3333
}
34+
35+
.Tooltip {
36+
@apply hidden absolute top-20 right-4 h-8 px-2 pt-0.5 rounded-md bg-gray-20;
37+
}
38+
39+
.Tooltip p {
40+
@apply text-gray-70;
41+
}
42+
43+
:global(.dark) .Tooltip {
44+
@apply bg-gray-90;
45+
}

netlify.toml

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ connect-src \
2525
https://px.ads.linkedin.com/ \
2626
https://*.algolia.net/ \
2727
https://*.algolianet.com/ \
28+
https://kapa-widget-proxy-la7dkmplpq-uc.a.run.app/ \
2829
; \
2930
default-src 'none' ; \
3031
font-src 'self' ; \
@@ -53,6 +54,9 @@ script-src \
5354
https://connect.facebook.net/ \
5455
https://*.algolia.net/ \
5556
https://*.algolianet.com/ \
57+
https://widget.kapa.ai/kapa-widget.bundle.js \
58+
https://www.google.com/recaptcha/api.js \
59+
https://www.gstatic.com/recaptcha/releases/ \
5660
; \
5761
style-src \
5862
'self' \

0 commit comments

Comments
 (0)