diff --git a/apps/docs/src/app/(docs)/(default)/[[...slug]]/page.tsx b/apps/docs/src/app/(docs)/(default)/[[...slug]]/page.tsx index 4bdfa59fb7..8c92935617 100644 --- a/apps/docs/src/app/(docs)/(default)/[[...slug]]/page.tsx +++ b/apps/docs/src/app/(docs)/(default)/[[...slug]]/page.tsx @@ -15,10 +15,8 @@ import { EditOnGitHub, PageLastUpdate, } from "@/components/layout/notebook/page"; -import { - TechArticleSchema, - BreadcrumbSchema, -} from "@/components/structured-data"; +import { TechArticleSchema, BreadcrumbSchema } from "@/components/structured-data"; +import { PageFeedback } from "@/components/page-feedback"; interface PageParams { slug?: string[]; @@ -79,6 +77,7 @@ export default async function Page({ params }: { params: Promise }) /> )} + ); diff --git a/apps/docs/src/components/page-feedback.tsx b/apps/docs/src/components/page-feedback.tsx new file mode 100644 index 0000000000..31b1bb75a5 --- /dev/null +++ b/apps/docs/src/components/page-feedback.tsx @@ -0,0 +1,133 @@ +"use client"; + +import { useState, useEffect, useCallback } from "react"; +import { ThumbsUp, ThumbsDown, Send } from "lucide-react"; +import { cn } from "@prisma-docs/ui/lib/cn"; +import { usePathname } from "fumadocs-core/framework"; +import posthog from "posthog-js"; + +type FeedbackState = "idle" | "upvoted" | "downvoted" | "submitted"; + +function getStorageKey(path: string) { + return `prisma-docs:page-feedback:${path}`; +} + +export function PageFeedback() { + const pathname = usePathname(); + const [state, setState] = useState(null); + const [comment, setComment] = useState(""); + const [showTextarea, setShowTextarea] = useState(false); + + useEffect(() => { + try { + const stored = localStorage.getItem(getStorageKey(pathname)); + setState(stored ? "submitted" : "idle"); + } catch { + setState("idle"); + } + }, [pathname]); + + const persist = useCallback( + (vote: "up" | "down", text?: string) => { + try { + localStorage.setItem(getStorageKey(pathname), JSON.stringify({ vote, text })); + } catch {} + posthog.capture("docs:page_feedback", { + path: pathname, + vote, + comment: text ?? null, + }); + }, + [pathname], + ); + + const handleUp = () => { + setState("submitted"); + persist("up"); + }; + + const handleDown = () => { + setState("downvoted"); + setShowTextarea(true); + }; + + const handleSubmitComment = () => { + setState("submitted"); + persist("down", comment || undefined); + }; + + if (state === null) return null; + + if (state === "submitted") { + return ( +
+ Thanks for your feedback! +
+ ); + } + + return ( +
+
+ Was this page helpful? +
+ + +
+
+ + {showTextarea && ( +
+