Skip to content

Commit 42fd5b0

Browse files
committed
website: add a modal Kapa Ask AI prototype
Wire the docs header to the Kapa modal flow. Made-with: Cursor Signed-off-by: Arthur Silva Sens <arthursens2005@gmail.com>
1 parent 80809ac commit 42fd5b0

6 files changed

Lines changed: 135 additions & 2 deletions

File tree

public/assets/prometheus-logo.svg

Lines changed: 1 addition & 0 deletions
Loading

src/app/layout.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import "@mantine/code-highlight/styles.layer.css";
2121
import "@mantine/spotlight/styles.layer.css";
2222
import "./globals.css";
2323
import { Header } from "@/components/Header";
24+
import KapaWidget from "@/components/KapaWidget";
25+
import { isKapaConfigured } from "@/components/kapa-config";
2426
import {
2527
ANNOUNCEMENT_HEIGHT_PX,
2628
isAnnouncementActive,
@@ -61,6 +63,7 @@ export default function RootLayout({
6163
const headerHeightPx = activeAnnouncement
6264
? BASE_HEADER_HEIGHT_PX + ANNOUNCEMENT_HEIGHT_PX
6365
: BASE_HEADER_HEIGHT_PX;
66+
const kapaConfigured = isKapaConfigured();
6467

6568
return (
6669
<html
@@ -74,8 +77,12 @@ export default function RootLayout({
7477
</head>
7578
<body>
7679
<MantineProvider theme={theme} defaultColorScheme="auto">
80+
<KapaWidget variant="modal" />
7781
<AppShell header={{ height: "var(--header-height)" }}>
78-
<Header announcement={activeAnnouncement} />
82+
<Header
83+
announcement={activeAnnouncement}
84+
showAskAi={kapaConfigured}
85+
/>
7986

8087
<AppShellMain>
8188
<Container size="xl" mt="xl" px={{ base: "md", xs: "xl" }}>

src/components/Header.module.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,7 @@
3939
);
4040
}
4141
}
42+
43+
.askAiButton {
44+
font-weight: 500;
45+
}

src/components/Header.tsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ import {
88
Container,
99
TextInput,
1010
ActionIcon,
11+
Button,
1112
AppShell,
1213
Popover,
1314
} from "@mantine/core";
1415
import Image from "next/image";
15-
import { IconSearch } from "@tabler/icons-react";
16+
import { IconSearch, IconSparkles } from "@tabler/icons-react";
1617
import prometheusLogo from "../assets/prometheus-logo.svg";
1718
import classes from "./Header.module.css";
1819
import githubLogo from "../assets/github-logo.svg";
@@ -39,8 +40,10 @@ const links = [
3940

4041
export const Header = ({
4142
announcement,
43+
showAskAi = false,
4244
}: {
4345
announcement?: AnnouncementType;
46+
showAskAi?: boolean;
4447
}) => {
4548
const path = usePathname();
4649
const [burgerOpened, { toggle: toggleBurger, close: closeBurger }] =
@@ -61,6 +64,33 @@ export const Header = ({
6164
</Link>
6265
));
6366

67+
const renderAskAiButton = ({
68+
hiddenFrom,
69+
onClick,
70+
}: {
71+
hiddenFrom?: "sm" | "md" | "lg";
72+
onClick?: () => void;
73+
}) => (
74+
<Button
75+
type="button"
76+
variant="subtle"
77+
color="gray"
78+
size="compact-sm"
79+
className={classes.askAiButton}
80+
data-kapa-trigger="ask-ai"
81+
leftSection={
82+
<IconSparkles
83+
style={{ width: rem(16), height: rem(16) }}
84+
stroke={1.8}
85+
/>
86+
}
87+
hiddenFrom={hiddenFrom}
88+
onClick={onClick}
89+
>
90+
Ask AI
91+
</Button>
92+
);
93+
6494
const actionIcons = (
6595
<>
6696
<ActionIcon
@@ -137,6 +167,7 @@ export const Header = ({
137167
<Group align="center">
138168
<Group gap={5} visibleFrom="sm" align="center">
139169
{items}
170+
{showAskAi && renderAskAiButton({})}
140171
</Group>
141172

142173
<Group visibleFrom="md" gap="xs">
@@ -190,6 +221,14 @@ export const Header = ({
190221
</Popover.Target>
191222
<Popover.Dropdown>
192223
{items}
224+
{showAskAi && (
225+
<Group m="xs" gap="xs">
226+
{renderAskAiButton({
227+
hiddenFrom: "sm",
228+
onClick: closeBurger,
229+
})}
230+
</Group>
231+
)}
193232
<Group m="xs" gap="xs">
194233
{actionIcons}
195234
</Group>

src/components/KapaWidget.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import Script from "next/script";
2+
import { getKapaConfig } from "./kapa-config";
3+
4+
export type KapaWidgetVariant = "drawer" | "modal" | "page";
5+
6+
type KapaWidgetProps = {
7+
variant: KapaWidgetVariant;
8+
};
9+
10+
const ASK_AI_TRIGGER_SELECTOR = "[data-kapa-trigger='ask-ai']";
11+
12+
export default function KapaWidget({ variant }: KapaWidgetProps) {
13+
const config = getKapaConfig();
14+
15+
if (!config) {
16+
return null;
17+
}
18+
19+
const triggerProps =
20+
variant === "page"
21+
? {}
22+
: {
23+
"data-modal-override-open-selector-ask-ai": ASK_AI_TRIGGER_SELECTOR,
24+
};
25+
26+
const variantProps =
27+
variant === "drawer"
28+
? {
29+
"data-view-mode": "sidebar",
30+
}
31+
: variant === "page"
32+
? {
33+
"data-render-on-load": "false",
34+
"data-modal-full-screen": "true",
35+
}
36+
: {};
37+
38+
return (
39+
<Script
40+
id="kapa-widget"
41+
strategy="afterInteractive"
42+
src="https://widget.kapa.ai/kapa-widget.bundle.js"
43+
data-website-id={config.websiteId}
44+
data-project-name={config.projectName}
45+
data-project-color={config.projectColor}
46+
data-project-logo={config.projectLogoUrl}
47+
data-button-hide="true"
48+
{...triggerProps}
49+
{...variantProps}
50+
/>
51+
);
52+
}

src/components/kapa-config.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import docsConfig from "../../docs-config";
2+
3+
export type KapaConfig = {
4+
websiteId: string;
5+
projectName: string;
6+
projectColor: string;
7+
projectLogoUrl: string;
8+
};
9+
10+
export const getKapaConfig = (): KapaConfig | null => {
11+
const websiteId = process.env.KAPA_WEBSITE_ID;
12+
const projectName = process.env.KAPA_PROJECT_NAME;
13+
const projectColor = process.env.KAPA_PROJECT_COLOR;
14+
15+
if (!websiteId || !projectName || !projectColor) {
16+
return null;
17+
}
18+
19+
return {
20+
websiteId,
21+
projectName,
22+
projectColor,
23+
projectLogoUrl: new URL(
24+
"/assets/prometheus-logo.svg",
25+
docsConfig.siteUrl,
26+
).toString(),
27+
};
28+
};
29+
30+
export const isKapaConfigured = (): boolean => getKapaConfig() !== null;

0 commit comments

Comments
 (0)