diff --git a/public/assets/prometheus-logo.svg b/public/assets/prometheus-logo.svg new file mode 100644 index 000000000..4e7bb85b9 --- /dev/null +++ b/public/assets/prometheus-logo.svg @@ -0,0 +1 @@ + diff --git a/src/app/ask-ai/page.tsx b/src/app/ask-ai/page.tsx new file mode 100644 index 000000000..dffce159f --- /dev/null +++ b/src/app/ask-ai/page.tsx @@ -0,0 +1,12 @@ +import { getPageMetadata } from "@/page-metadata"; +import KapaPageLauncher from "@/components/KapaPageLauncher"; + +export const metadata = getPageMetadata({ + pageTitle: "Ask AI", + pageDescription: "Chat with the Prometheus documentation using Kapa.ai.", + pagePath: "/ask-ai/", +}); + +export default function AskAiPage() { + return ; +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index d2dbe1d2e..02b9e96b6 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -21,6 +21,7 @@ import "@mantine/code-highlight/styles.layer.css"; import "@mantine/spotlight/styles.layer.css"; import "./globals.css"; import { Header } from "@/components/Header"; +import KapaWidget from "@/components/KapaWidget"; import { ANNOUNCEMENT_HEIGHT_PX, isAnnouncementActive, @@ -74,6 +75,7 @@ export default function RootLayout({ +
diff --git a/src/components/Header.module.css b/src/components/Header.module.css index 2ef18e08a..b12af291f 100644 --- a/src/components/Header.module.css +++ b/src/components/Header.module.css @@ -39,3 +39,7 @@ ); } } + +.askAiButton { + font-weight: 500; +} diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 35efb233e..f1147945f 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -8,11 +8,12 @@ import { Container, TextInput, ActionIcon, + Button, AppShell, Popover, } from "@mantine/core"; import Image from "next/image"; -import { IconSearch } from "@tabler/icons-react"; +import { IconSearch, IconSparkles } from "@tabler/icons-react"; import prometheusLogo from "../assets/prometheus-logo.svg"; import classes from "./Header.module.css"; import githubLogo from "../assets/github-logo.svg"; @@ -61,6 +62,33 @@ export const Header = ({ )); + const renderAskAiButton = ({ + hiddenFrom, + onClick, + }: { + hiddenFrom?: "sm" | "md" | "lg"; + onClick?: () => void; + }) => ( + + ); + const actionIcons = ( <> {items} + {renderAskAiButton({})} @@ -190,6 +219,12 @@ export const Header = ({ {items} + + {renderAskAiButton({ + hiddenFrom: "sm", + onClick: closeBurger, + })} + {actionIcons} diff --git a/src/components/KapaPageLauncher.tsx b/src/components/KapaPageLauncher.tsx new file mode 100644 index 000000000..333152bfe --- /dev/null +++ b/src/components/KapaPageLauncher.tsx @@ -0,0 +1,88 @@ +"use client"; + +import { Button, Stack, Text, Title } from "@mantine/core"; +import { useEffect, useState } from "react"; + +declare global { + interface Window { + Kapa?: { + close?: () => void; + open?: (options?: { + mode?: "search" | "ai"; + query?: string; + submit?: boolean; + }) => void; + render?: (options?: { onRender?: () => void }) => void; + unmount?: () => void; + }; + } +} + +export default function KapaPageLauncher() { + const [hasRendered, setHasRendered] = useState(false); + + const openAssistant = () => { + if (!window.Kapa?.render) { + return; + } + + window.Kapa.render({ + onRender: () => { + setHasRendered(true); + window.Kapa?.open?.({ mode: "ai" }); + }, + }); + }; + + useEffect(() => { + let cancelled = false; + + const openWhenReady = () => { + if (cancelled) { + return; + } + + if (!window.Kapa?.render) { + window.setTimeout(openWhenReady, 100); + return; + } + + window.Kapa.render({ + onRender: () => { + if (cancelled) { + return; + } + + setHasRendered(true); + window.Kapa?.open?.({ mode: "ai" }); + }, + }); + }; + + openWhenReady(); + + return () => { + cancelled = true; + window.Kapa?.close?.(); + window.Kapa?.unmount?.(); + }; + }, []); + + return ( + + Ask AI + + This branch gives Kapa a dedicated route, then opens the assistant in a + full-screen experience so the conversation gets most of the viewport. + + + {hasRendered + ? "If you close the assistant, use the button below to open it again." + : "Loading the assistant..."} + + + + ); +} diff --git a/src/components/KapaWidget.tsx b/src/components/KapaWidget.tsx new file mode 100644 index 000000000..fd7557936 --- /dev/null +++ b/src/components/KapaWidget.tsx @@ -0,0 +1,53 @@ +import Script from "next/script"; +import docsConfig from "../../docs-config"; + +export type KapaWidgetVariant = "drawer" | "modal" | "page"; + +type KapaWidgetProps = { + variant: KapaWidgetVariant; +}; + +const WEBSITE_ID = "80cbacc9-0b84-48aa-bfb8-0002270176bf"; +const PROJECT_NAME = "Prometheus"; +const PROJECT_COLOR = "#D86444"; +const ASK_AI_TRIGGER_SELECTOR = "[data-kapa-trigger='ask-ai']"; +const PROJECT_LOGO_URL = new URL( + "/assets/prometheus-logo.svg", + docsConfig.siteUrl, +).toString(); + +export default function KapaWidget({ variant }: KapaWidgetProps) { + const triggerProps = + variant === "page" + ? {} + : { + "data-modal-override-open-selector-ask-ai": ASK_AI_TRIGGER_SELECTOR, + }; + + const variantProps = + variant === "drawer" + ? { + "data-view-mode": "sidebar", + } + : variant === "page" + ? { + "data-render-on-load": "false", + "data-modal-full-screen": "true", + } + : {}; + + return ( +