Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
7 changes: 5 additions & 2 deletions apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
"@fumadocs/cli": "catalog:",
"@kapaai/react-sdk": "catalog:",
"@mixedbread/sdk": "catalog:",
"@prisma/eclipse": "workspace:^",
"@prisma-docs/ui": "workspace:*",
"@prisma/eclipse": "workspace:^",
"@radix-ui/react-tooltip": "catalog:",
"@sentry/nextjs": "catalog:",
"@streamdown/code": "catalog:",
Expand All @@ -49,13 +49,15 @@
"scroll-into-view-if-needed": "catalog:",
"streamdown": "catalog:",
"tailwind-merge": "catalog:",
"unist-util-visit": "^5.1.0",
"use-stick-to-bottom": "catalog:",
"zod": "catalog:"
},
"devDependencies": {
"@argos-ci/playwright": "catalog:",
"@playwright/test": "catalog:",
"@tailwindcss/postcss": "catalog:",
"@types/mdast": "^4.0.4",
"@types/mdx": "catalog:",
"@types/node": "catalog:",
"@types/react": "catalog:",
Expand All @@ -69,6 +71,7 @@
"tailwindcss": "catalog:",
"tsx": "catalog:",
"tw-animate-css": "catalog:",
"typescript": "catalog:"
"typescript": "catalog:",
"unified": "^11.0.5"
}
}
14 changes: 4 additions & 10 deletions apps/docs/source.config.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import remarkDirective from "remark-directive";
import {
remarkDirectiveAdmonition,
remarkMdxFiles,
} from "fumadocs-core/mdx-plugins";
import { remarkDirectiveAdmonition, remarkMdxFiles } from "fumadocs-core/mdx-plugins";
import { remarkImage } from "fumadocs-core/mdx-plugins";
import {
defineConfig,
defineDocs,
frontmatterSchema,
metaSchema,
} from "fumadocs-mdx/config";
import { defineConfig, defineDocs, frontmatterSchema, metaSchema } from "fumadocs-mdx/config";
import lastModified from "fumadocs-mdx/plugins/last-modified";
import { z } from "zod";
import convert from "npm-to-yarn";
import remarkConsoleUtm from "@/lib/remark-console-utm";

// npm-to-yarn only converts the last line of multi-line strings,
// so we split, convert each line, and rejoin.
Expand Down Expand Up @@ -89,6 +82,7 @@ export default defineConfig({
],
[remarkImage, { useImport: false }],
remarkMdxFiles,
remarkConsoleUtm,
],
remarkCodeTabOptions: {
parseMdx: true,
Expand Down
20 changes: 18 additions & 2 deletions apps/docs/src/components/page-actions.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";
import { useMemo, useState } from "react";

import posthog from "posthog-js";
import { useCopyButton } from "fumadocs-ui/utils/use-copy-button";
import { buttonVariants } from "@prisma-docs/ui/components/button";
import { cn } from "@prisma-docs/ui/lib/cn";
Expand Down Expand Up @@ -46,6 +46,7 @@ async function fetchMarkdownWithFallback(
export function CopyPromptButton({ fullPrompt }: { fullPrompt: string }) {
const [checked, onClick] = useCopyButton(async () => {
await navigator.clipboard.writeText(fullPrompt);
posthog.capture("docs:copy_prompt", { page_path: window.location.pathname });
});

return (
Expand Down Expand Up @@ -77,7 +78,11 @@ export function LLMCopyButton({
const [checked, onClick] = useCopyButton(async () => {
const fallbackUrl = toIndexMarkdownUrl(markdownUrl);
const cached = cache.get(markdownUrl) ?? (fallbackUrl ? cache.get(fallbackUrl) : undefined);
if (cached) return navigator.clipboard.writeText(cached);
if (cached) {
await navigator.clipboard.writeText(cached);
posthog.capture("docs:copy_markdown", { page_path: window.location.pathname });
return;
}

setLoading(true);

Expand All @@ -91,6 +96,7 @@ export function LLMCopyButton({
}),
}),
]);
posthog.capture("docs:copy_markdown", { page_path: window.location.pathname });
} finally {
setLoading(false);
}
Expand Down Expand Up @@ -140,6 +146,7 @@ export function ViewOptions({
return [
{
title: "Open in GitHub",
tool: "github",
href: githubUrl,
icon: (
<svg fill="currentColor" role="img" viewBox="0 0 24 24">
Expand All @@ -150,6 +157,7 @@ export function ViewOptions({
},
{
title: "Open in ChatGPT",
tool: "chatgpt",
href: `https://chatgpt.com/?${new URLSearchParams({
hints: "search",
q,
Expand All @@ -168,6 +176,7 @@ export function ViewOptions({
},
{
title: "Open in Claude",
tool: "claude",
href: `https://claude.ai/new?${new URLSearchParams({
q,
})}`,
Expand All @@ -185,6 +194,7 @@ export function ViewOptions({
},
{
title: "Open in T3 Chat",
tool: "t3_chat",
href: `https://t3.chat/new?${new URLSearchParams({
q,
})}`,
Expand Down Expand Up @@ -215,6 +225,12 @@ export function ViewOptions({
rel="noreferrer noopener"
target="_blank"
className={cn(optionVariants())}
onClick={() =>
posthog.capture("docs:open_external_tool", {
page_path: window.location.pathname,
tool: item.tool,
})
}
>
{item.icon}
{item.title}
Expand Down
50 changes: 26 additions & 24 deletions apps/docs/src/components/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
'use client';
import { RootProvider } from 'fumadocs-ui/provider/next';
import { NextProvider } from 'fumadocs-core/framework/next';
import { KapaProvider } from '@kapaai/react-sdk';
import CustomSearchDialog from '@/components/search';
import type { ReactNode } from 'react';
import { source } from '@/lib/source';
import { TreeContextProvider } from 'fumadocs-ui/contexts/tree';
"use client";
import { RootProvider } from "fumadocs-ui/provider/next";
import { NextProvider } from "fumadocs-core/framework/next";
import { KapaProvider } from "@kapaai/react-sdk";
import CustomSearchDialog from "@/components/search";
import type { ReactNode } from "react";
import { source } from "@/lib/source";
import { TreeContextProvider } from "fumadocs-ui/contexts/tree";
import { TrackingProvider } from "@/components/tracking-provider";

const KAPA_INTEGRATION_ID = '1b51bb03-43cc-4ef4-95f1-93288a91b560';
const KAPA_INTEGRATION_ID = "1b51bb03-43cc-4ef4-95f1-93288a91b560";

export function Provider({ children }: { children: ReactNode }) {
return (
<NextProvider>
<KapaProvider
integrationId={KAPA_INTEGRATION_ID}
callbacks={{
askAI: {
onQuerySubmit: (data: { question: string }) => {
console.log('Question asked:', data.question);
},
<KapaProvider
integrationId={KAPA_INTEGRATION_ID}
callbacks={{
askAI: {
onQuerySubmit: (data: { question: string }) => {
console.log("Question asked:", data.question);
},
},
}}
>
<RootProvider
search={{
SearchDialog: CustomSearchDialog,
}}
>
<RootProvider
search={{
SearchDialog: CustomSearchDialog,
}}
>
{children}
</RootProvider>
</KapaProvider>
<TrackingProvider />
{children}
</RootProvider>
</KapaProvider>
</NextProvider>
);
}
39 changes: 39 additions & 0 deletions apps/docs/src/components/tracking-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use client";
import { useEffect } from "react";
import { usePathname } from "next/navigation";
import posthog from "posthog-js";
import { getContentArea, getContentSubtype, isPpgOrCompute } from "@/lib/tracking";

export function TrackingProvider() {
const pathname = usePathname();

useEffect(() => {
const area = getContentArea(pathname);
posthog.register({
content_area: area,
is_ppg_or_compute: isPpgOrCompute(area),
content_subtype: getContentSubtype(pathname),
});
}, [pathname]);

useEffect(() => {
function handleClick(e: MouseEvent) {
const anchor = (e.target as HTMLElement).closest<HTMLAnchorElement>(
'a[href*="console.prisma.io"]',
);
if (!anchor) return;

const url = anchor.href;
posthog.capture("docs:console_link_click", {
page_path: pathname,
destination_url: url,
has_utm: url.includes("utm_source"),
});
}

document.addEventListener("click", handleClick);
return () => document.removeEventListener("click", handleClick);
}, [pathname]);

return null;
}
33 changes: 33 additions & 0 deletions apps/docs/src/lib/remark-console-utm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { Root } from "mdast";
import type { Plugin } from "unified";
import { visit } from "unist-util-visit";

const CONSOLE_HOST = "console.prisma.io";

const remarkConsoleUtm: Plugin<[], Root> = () => (tree, vfile) => {
const filePath = vfile.path ?? "";
const isV6 = filePath.includes("content/docs.v6/");
const utmSource = isV6 ? "docs-v6" : "docs";

const sectionMatch = filePath.match(/content\/docs(?:\.v6)?\/([^/]+)/);
const section = sectionMatch?.[1] ?? "unknown";

visit(tree, "link", (node) => {
let url: URL;
try {
url = new URL(node.url);
} catch {
return;
}

if (url.hostname !== CONSOLE_HOST) return;
if (url.searchParams.has("utm_source")) return;

url.searchParams.set("utm_source", utmSource);
url.searchParams.set("utm_medium", "content");
url.searchParams.set("utm_content", section);
node.url = url.toString();
});
};

export default remarkConsoleUtm;
32 changes: 32 additions & 0 deletions apps/docs/src/lib/tracking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
type ContentArea = "ppg" | "orm" | "accelerate" | "console" | "guides" | "ai" | "other";

const PREFIX_MAP: [string, ContentArea][] = [
["/postgres", "ppg"],
["/prisma-postgres", "ppg"],
["/orm", "orm"],
["/prisma-orm", "orm"],
["/accelerate", "accelerate"],
["/console", "console"],
["/guides", "guides"],
["/ai", "ai"],
];

const PPG_AREAS: Set<ContentArea> = new Set(["ppg"]);

export function getContentArea(pathname: string): ContentArea {
const stripped = pathname.replace(/^\/docs\/v\d+/, "");
for (const [prefix, area] of PREFIX_MAP) {
if (stripped.startsWith(prefix)) return area;
}
return "other";
}

export function isPpgOrCompute(area: ContentArea): boolean {
return PPG_AREAS.has(area);
}

export function getContentSubtype(pathname: string): string | null {
if (pathname.includes("/quickstart")) return "quickstart";
if (pathname.includes("/getting-started")) return "getting-started";
return null;
}
Loading
Loading