Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion docs-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@ export default {

announcement: {
text: "Take the [Prometheus User Survey (Edition 03.2026)](https://forms.gle/uuEsawKm7u9wCT4T8) and help the community prioritize future development!",
mobileText: "[Prometheus User Survey (Edition 03.2026)](https://forms.gle/uuEsawKm7u9wCT4T8)",
mobileText:
"[Prometheus User Survey (Edition 03.2026)](https://forms.gle/uuEsawKm7u9wCT4T8)",
startDate: "2026-03-24",
endDate: "2026-04-07",
},

kapa: {
websiteId: "80cbacc9-0b84-48aa-bfb8-0002270176bf",
projectName: "Prometheus",
projectColor: "#D86444",
projectLogoPath: "/assets/prometheus-logo.svg",
},

// Docs to load from repo-local files.
localMarkdownSources: [
{
Expand Down
1 change: 1 addition & 0 deletions public/assets/prometheus-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 6 additions & 3 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -53,8 +54,7 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
const activeAnnouncement =
docsConfig.announcement &&
isAnnouncementActive(docsConfig.announcement)
docsConfig.announcement && isAnnouncementActive(docsConfig.announcement)
? docsConfig.announcement
: undefined;

Expand All @@ -67,13 +67,16 @@ export default function RootLayout({
lang="en"
{...mantineHtmlProps}
className={`${interFont.variable} ${latoFont.variable}`}
style={{ "--header-height": `${headerHeightPx}px` } as React.CSSProperties}
style={
{ "--header-height": `${headerHeightPx}px` } as React.CSSProperties
}
>
<head>
<ColorSchemeScript defaultColorScheme="auto" />
</head>
<body>
<MantineProvider theme={theme} defaultColorScheme="auto">
<KapaWidget />
<AppShell header={{ height: "var(--header-height)" }}>
<Header announcement={activeAnnouncement} />

Expand Down
2 changes: 1 addition & 1 deletion src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export const Header = ({

<Group visibleFrom="md" gap="xs">
<TextInput
placeholder="Search"
placeholder="Search / Ask AI"
w={220}
mx="lg"
leftSection={
Expand Down
42 changes: 42 additions & 0 deletions src/components/KapaWidget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"use client";

import { useComputedColorScheme } from "@mantine/core";
import Script from "next/script";
import { useEffect } from "react";
import docsConfig from "../../docs-config";

export default function KapaWidget() {
const colorScheme = useComputedColorScheme("light");

// Sync the resolved Mantine color scheme to a data-theme attribute on <html>
// so that the Kapa widget can detect theme changes. Kapa only watches
// class, data-theme, data-color-mode, and data-bs-theme.
useEffect(() => {
document.documentElement.setAttribute("data-theme", colorScheme);
}, [colorScheme]);

if (!docsConfig.kapa) {
return null;
}

const { websiteId, projectName, projectColor, projectLogoPath } =
docsConfig.kapa;
const projectLogoUrl = new URL(
projectLogoPath,
docsConfig.siteUrl,
).toString();

return (
<Script
id="kapa-widget"
strategy="afterInteractive"
src="https://widget.kapa.ai/kapa-widget.bundle.js"
data-website-id={websiteId}
data-project-name={projectName}
data-project-color={projectColor}
data-project-logo={projectLogoUrl}
data-button-hide="true"
data-color-scheme-selector="[data-theme='dark']"
/>
);
}
53 changes: 44 additions & 9 deletions src/components/SpotlightSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
"use client";

import { Spotlight } from "@mantine/spotlight";
import { IconSearch } from "@tabler/icons-react";
import { Spotlight, spotlight } from "@mantine/spotlight";
import { IconSearch, IconSparkles } from "@tabler/icons-react";
import { useRouter } from "next/navigation";
import { Divider, Group, Highlight, Loader, Space } from "@mantine/core";
import React, { useState, useEffect } from "react";
import {
Button,
Divider,
Group,
Highlight,
Loader,
Space,
} from "@mantine/core";
import React, { useState, useEffect, useRef } from "react";
import { decode } from "html-entities";

// Extend Window interface to include pagefind
// Extend Window interface to include pagefind and Kapa
declare global {
interface Window {
/* eslint-disable @typescript-eslint/no-explicit-any */
pagefind: any;
Kapa: any;
}
}

Expand Down Expand Up @@ -127,6 +135,7 @@ type PagefindResult = {
export default function SpotlightSearch() {
const [activeQuery, setActiveQuery] = useState("");
const [results, setResults] = useState<PagefindResult[]>([]);
const queryRef = useRef("");

useEffect(() => {
async function loadPagefind() {
Expand Down Expand Up @@ -175,12 +184,24 @@ export default function SpotlightSearch() {
loadPagefind();
}, []);

const handleAskAI = () => {
const query = queryRef.current.trim();
spotlight.close();
// Small delay to let the Spotlight close animation finish before opening Kapa.
setTimeout(() => {
if (window.Kapa) {
window.Kapa.open({ mode: "ai", query, submit: query.length > 0 });
}
}, 100);
};

return (
<Spotlight.Root
size="xl"
maxHeight="90vh"
scrollable
onQueryChange={async (query) => {
queryRef.current = query;
const search = await window.pagefind.debouncedSearch(query);
if (search === null) {
// A more recent search call has been made, nothing to do.
Expand All @@ -190,10 +211,24 @@ export default function SpotlightSearch() {
setActiveQuery(query);
}}
>
<Spotlight.Search
placeholder="Search..."
leftSection={<IconSearch stroke={1.5} />}
/>
<Group gap={0} align="center" wrap="nowrap">
<Spotlight.Search
placeholder="Search..."
leftSection={<IconSearch stroke={1.5} />}
style={{ flex: 1 }}
/>
<Button
variant="light"
size="compact-md"
onClick={handleAskAI}
leftSection={<IconSparkles size={16} stroke={1.8} />}
mr="xs"
fw={500}
style={{ flexShrink: 0 }}
>
Ask AI
</Button>
</Group>
<Spotlight.ActionsList>
{results.length > 0 ? (
results.map((result, idx) => (
Expand Down
8 changes: 8 additions & 0 deletions src/docs-config-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,17 @@ export type Announcement = {
endDate?: string;
};

export type KapaConfig = {
websiteId: string;
projectName: string;
projectColor: string;
projectLogoPath: string;
};

export type DocsConfig = {
siteUrl: string;
announcement?: Announcement;
kapa?: KapaConfig;
localMarkdownSources: LocalMarkdownSource[];
githubMarkdownSources: GithubMarkdownSource[];
ltsVersions: LTSConfig;
Expand Down
Loading