Skip to content

Commit 0cebd5f

Browse files
docs: add Ask AI button and related functionality with cookie consent handling
risk: low
1 parent 5a675f7 commit 0cebd5f

File tree

10 files changed

+230
-17
lines changed

10 files changed

+230
-17
lines changed

docs/assets/icons/ai.svg

Lines changed: 12 additions & 0 deletions
Loading

docs/assets/scss/_styles_project.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
@import "parameter";
3131
@import "skip-links";
3232
@import "heading-anchor";
33+
@import "ask-ai-button";
3334

3435
#print {
3536
display: none; // Hide print functionality for now
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// (C) 2025 GoodData Corporation
2+
@import "variables/variables";
3+
4+
.ask-ai-button-container {
5+
display: flex;
6+
margin-left: 20px;
7+
justify-content: flex-start;
8+
button {
9+
display: flex;
10+
align-items: center;
11+
gap: 5px;
12+
&:disabled {
13+
cursor: not-allowed;
14+
opacity: 0.2;
15+
&:hover,
16+
&:focus,
17+
&:active {
18+
color: inherit;
19+
border-color: inherit;
20+
}
21+
22+
&:focus {
23+
box-shadow: inherit;
24+
}
25+
}
26+
}
27+
.ask-ai-icon {
28+
display: flex;
29+
width: fit-content;
30+
svg {
31+
width: 15px;
32+
height: 15px;
33+
margin: 0;
34+
}
35+
}
36+
}

docs/assets/scss/tooltip.scss

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,59 @@
1-
@import "variables/variables";
1+
// (C) 2023 GoodData Corporation
2+
// Custom tooltip styles
23

4+
// Override Bootstrap tooltip background color
35
.tooltip {
46
font-family: inherit;
57

68
.tooltip-inner {
7-
padding: 12px 15px;
8-
text-align: left;
9-
max-width: 300px;
10-
font-family: inherit;
11-
color: $color-white;
12-
background-color: $color-tooltip;
9+
padding: 12px 15px;
10+
text-align: left;
11+
max-width: 300px;
12+
font-family: inherit;
13+
color: $color-white;
14+
text-align: center;
15+
background-color: $color-deep-purple;
1316
}
1417

15-
&.bs-tooltip-right .arrow:before {
16-
border-right-color: $color-tooltip;
18+
// Override tooltip arrow colors for all directions
19+
&.bs-tooltip-top .tooltip-arrow::before,
20+
&.bs-tooltip-auto[data-popper-placement^="top"] .tooltip-arrow::before {
21+
border-top-color: $color-deep-purple;
1722
}
1823

19-
&.bs-tooltip-top .arrow:before {
20-
border-top-color: $color-tooltip;
24+
&.bs-tooltip-right .tooltip-arrow::before,
25+
&.bs-tooltip-auto[data-popper-placement^="right"] .tooltip-arrow::before {
26+
border-right-color: $color-deep-purple;
2127
}
2228

23-
&.bs-tooltip-left .arrow:before {
24-
border-left-color: $color-tooltip;
29+
&.bs-tooltip-bottom .tooltip-arrow::before,
30+
&.bs-tooltip-auto[data-popper-placement^="bottom"] .tooltip-arrow::before {
31+
border-bottom-color: $color-deep-purple;
2532
}
2633

27-
&.bs-tooltip-bottom .arrow:before {
28-
border-bottom-color: $color-tooltip;
34+
&.bs-tooltip-left .tooltip-arrow::before,
35+
&.bs-tooltip-auto[data-popper-placement^="left"] .tooltip-arrow::before {
36+
border-left-color: $color-deep-purple;
2937
}
30-
}
38+
}
39+
40+
// Additional fallback for older Bootstrap versions
41+
.bs-tooltip-top .tooltip-arrow::before,
42+
.bs-tooltip-auto[data-popper-placement^="top"] .tooltip-arrow::before {
43+
border-top-color: $color-deep-purple;
44+
}
45+
46+
.bs-tooltip-right .tooltip-arrow::before,
47+
.bs-tooltip-auto[data-popper-placement^="right"] .tooltip-arrow::before {
48+
border-right-color: $color-deep-purple;
49+
}
50+
51+
.bs-tooltip-bottom .tooltip-arrow::before,
52+
.bs-tooltip-auto[data-popper-placement^="bottom"] .tooltip-arrow::before {
53+
border-bottom-color: $color-deep-purple;
54+
}
55+
56+
.bs-tooltip-left .tooltip-arrow::before,
57+
.bs-tooltip-auto[data-popper-placement^="left"] .tooltip-arrow::before {
58+
border-left-color: $color-deep-purple;
59+
}

docs/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.20
44

55
require (
66
github.com/FortAwesome/Font-Awesome v0.0.0-20230327165841-0698449d50f2 // indirect
7-
github.com/gooddata/gooddata-docs-theme v0.0.0-20250821103203-74c7725a1374 // indirect
7+
github.com/gooddata/gooddata-docs-theme v0.0.0-20250923082246-5b1d8dd060b7 // indirect
88
github.com/google/docsy v0.7.1 // indirect
99
github.com/google/docsy/dependencies v0.7.1 // indirect
1010
github.com/twbs/bootstrap v5.3.1+incompatible // indirect

docs/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ github.com/gooddata/gooddata-docs-theme v0.0.0-20250814105944-65486e0f9cfb h1:ac
3636
github.com/gooddata/gooddata-docs-theme v0.0.0-20250814105944-65486e0f9cfb/go.mod h1:VVNP6Cmo+vC37RD3T/YHjyU/QdqftGY5z4G513LYyrA=
3737
github.com/gooddata/gooddata-docs-theme v0.0.0-20250821103203-74c7725a1374 h1:pdQfwqjy/PW2CBh0HlMtgnsSuNHNLP+SyWlACDhSBnU=
3838
github.com/gooddata/gooddata-docs-theme v0.0.0-20250821103203-74c7725a1374/go.mod h1:VVNP6Cmo+vC37RD3T/YHjyU/QdqftGY5z4G513LYyrA=
39+
github.com/gooddata/gooddata-docs-theme v0.0.0-20250923082246-5b1d8dd060b7 h1:Nngc10J9JAV904CUGjOyua3im6fB4biWZ34weMfSzd0=
40+
github.com/gooddata/gooddata-docs-theme v0.0.0-20250923082246-5b1d8dd060b7/go.mod h1:VVNP6Cmo+vC37RD3T/YHjyU/QdqftGY5z4G513LYyrA=
3941
github.com/google/docsy v0.7.1 h1:DUriA7Nr3lJjNi9Ulev1SfiG1sUYmvyDeU4nTp7uDxY=
4042
github.com/google/docsy v0.7.1/go.mod h1:JCmE+c+izhE0Rvzv3y+AzHhz1KdwlA9Oj5YBMklJcfc=
4143
github.com/google/docsy/dependencies v0.7.1 h1:NbzYKJYMin2q50xdWSUzR2c9gCp7zR/XHDBcxklEcTQ=
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<div class="ask-ai-button-container">
2+
<button
3+
disabled
4+
data-html="true"
5+
data-toggle="tooltip"
6+
data-placement="top"
7+
title="You need to accept cookies <br/> to use this feature"
8+
class="gd-docs-header-nav__cta gd-docs-header-nav__github open-kapa-widget ask-ai-button"
9+
id="ask-ai-button"
10+
>
11+
Ask AI
12+
<div class="ask-ai-icon">
13+
{{ with resources.Get "icons/ai.svg" }}{{ ( . | minify).Content | safeHTML }}{{ end }}
14+
</div>
15+
</button>
16+
</div>

docs/layouts/partials/hooks/body-end.html

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,21 @@
77
<script src="/js/404-old-version.js"></script>
88
<script src="/js/prism-accessibility.js"></script>
99

10+
{{/* additional scripts */}}
11+
<script src="/js/archive-link.js"></script>
12+
<script src="/js/ask-ai-button.js"></script>
13+
<script
14+
async
15+
src="https://widget.kapa.ai/kapa-widget.bundle.js"
16+
data-website-id="321ae018-8175-44b4-b907-18d793521ab4"
17+
data-project-name="GoodData"
18+
data-project-color="#ED26B7"
19+
data-project-logo="https://www.gooddata.com/img/generic/logo-g.svg"
20+
data-button-hide="true"
21+
data-modal-disclaimer-text-color="#ED26B7"
22+
data-modal-override-open-class="open-kapa-widget"
23+
data-modal-open-on-command-k="true"
24+
data-modal-y-offset="20vh"
25+
data-modal-title-color="#1c0d3f"
26+
data-modal-title-font-family="bca6d3310b5c9dae1dae416e8abc8405,helvetica,arial,sans-serif"
27+
></script>

docs/layouts/partials/navbar.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<div class="gd-docs-header-nav__center">
1919
<div id="adds-container" class="gd-docs-header-nav__search"></div>
2020
</div>
21+
{{ partial "ask-ai-button.html" . }}
2122
{{ if .Site.Params.versions }}
2223
<div class="gd-docs-header-nav__right">
2324
{{ partial "navbar-version-selector.html" . }}

docs/static/js/ask-ai-button.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
$(document).ready(function () {
2+
const $askAiButton = $("#ask-ai-button");
3+
const currentUrl = window.location.href;
4+
let lastCookieValue = null;
5+
6+
const getCookie = (name) => {
7+
const value = `; ${document.cookie}`;
8+
const parts = value.split(`; ${name}=`);
9+
if (parts.length === 2) return parts.pop().split(";").shift();
10+
return null;
11+
};
12+
13+
// Initialize tooltips with HTML support
14+
$('[data-toggle="tooltip"]').tooltip({
15+
html: true,
16+
});
17+
18+
// Check if user has accepted cookie policy
19+
const hasCookieConsent = () => {
20+
const cookieValue = getCookie("cookiePolicy");
21+
if (cookieValue && cookieValue.split(",").includes("2")) {
22+
return true;
23+
}
24+
return false;
25+
};
26+
27+
// Update button state based on cookie consent
28+
const updateButtonState = () => {
29+
if (hasCookieConsent()) {
30+
$askAiButton.prop("disabled", false);
31+
$askAiButton.removeAttr("title");
32+
$askAiButton.tooltip("dispose");
33+
} else {
34+
$askAiButton.prop("disabled", true);
35+
$askAiButton.tooltip("dispose").tooltip({
36+
html: true,
37+
});
38+
}
39+
};
40+
41+
// Watch for cookie changes using MutationObserver
42+
const createCookieObserver = () => {
43+
// Store original document.cookie descriptor
44+
const originalCookieDescriptor =
45+
Object.getOwnPropertyDescriptor(Document.prototype, "cookie") ||
46+
Object.getOwnPropertyDescriptor(HTMLDocument.prototype, "cookie");
47+
48+
if (originalCookieDescriptor && originalCookieDescriptor.configurable) {
49+
Object.defineProperty(document, "cookie", {
50+
get() {
51+
return originalCookieDescriptor.get.call(this);
52+
},
53+
set(value) {
54+
const result = originalCookieDescriptor.set.call(this, value);
55+
56+
// Check if cookiePolicy was changed
57+
if (value.includes("cookiePolicy")) {
58+
setTimeout(updateButtonState, 100); // Small delay to ensure cookie is set
59+
}
60+
61+
return result;
62+
},
63+
configurable: true,
64+
});
65+
}
66+
67+
// Also observe DOM changes for cookie banners
68+
const observer = new MutationObserver(() => {
69+
const currentCookieValue = getCookie("cookiePolicy");
70+
if (currentCookieValue !== lastCookieValue) {
71+
lastCookieValue = currentCookieValue;
72+
updateButtonState();
73+
}
74+
});
75+
76+
// Observe cookie banner or body changes
77+
observer.observe(document.body, {
78+
childList: true,
79+
subtree: true,
80+
attributes: true,
81+
attributeFilter: ["class", "style"],
82+
});
83+
84+
return observer;
85+
};
86+
87+
lastCookieValue = getCookie("cookiePolicy");
88+
updateButtonState();
89+
90+
// Create cookie observer instead of interval
91+
const observer = createCookieObserver();
92+
93+
window.askAiButtonCleanup = function () {
94+
if (observer) {
95+
observer.disconnect();
96+
}
97+
};
98+
});

0 commit comments

Comments
 (0)