git0 0.3.16 → 0.3.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/docs/README.md +20 -0
  2. package/docs/app/(home)/docs-home.css +235 -0
  3. package/docs/app/(home)/layout.tsx +12 -0
  4. package/docs/app/(home)/page.tsx +27 -0
  5. package/docs/app/docs/[[...slug]]/page.tsx +84 -0
  6. package/docs/app/docs/api/docs-search/route.ts +11 -0
  7. package/docs/app/docs/layout.tsx +16 -0
  8. package/docs/app/docs/llms-full.txt/route.ts +15 -0
  9. package/docs/app/docs/llms.mdx/docs/[[...slug]]/route.ts +24 -0
  10. package/docs/app/globals.css +814 -0
  11. package/docs/app/layout.config.tsx +32 -0
  12. package/docs/app/layout.tsx +22 -0
  13. package/docs/app/provider.tsx +20 -0
  14. package/docs/cli.json +11 -0
  15. package/docs/components/DocsHomepage/code-example.tsx +123 -0
  16. package/docs/components/DocsHomepage/features-grid.tsx +92 -0
  17. package/docs/components/DocsHomepage/footer.tsx +58 -0
  18. package/docs/components/DocsHomepage/hero-section.tsx +114 -0
  19. package/docs/components/DocsHomepage/project-types.tsx +114 -0
  20. package/docs/components/fumadocs/ai/ask-ai-dropdown.tsx +299 -0
  21. package/docs/components/fumadocs/ai/llm-copy-button.tsx +61 -0
  22. package/docs/components/fumadocs/api/api-page.client.tsx +7 -0
  23. package/docs/components/fumadocs/api/api-page.tsx +7 -0
  24. package/docs/components/fumadocs/layout/breadcrumb.tsx +36 -0
  25. package/docs/components/fumadocs/layout/search.tsx +55 -0
  26. package/docs/components/fumadocs/layout/theme-dropdown.tsx +3 -0
  27. package/docs/components/fumadocs/layout/theme-provider.tsx +15 -0
  28. package/docs/components/fumadocs/layout/theme-toggle.tsx +40 -0
  29. package/docs/components/ui/badge.tsx +50 -0
  30. package/docs/components/ui/button.tsx +66 -0
  31. package/docs/components/ui/collapsible.tsx +44 -0
  32. package/docs/components/ui/slider.tsx +36 -0
  33. package/docs/components/ui/tooltip.tsx +63 -0
  34. package/docs/components/ui/video-modal.tsx +238 -0
  35. package/docs/content/docs/fm.mdx +11 -0
  36. package/docs/content/docs/git0.mdx +104 -0
  37. package/docs/content/docs/github-api.mdx +764 -0
  38. package/docs/content/docs/index.mdx +98 -0
  39. package/docs/content/docs/meta.json +15 -0
  40. package/docs/content/docs/modules.mdx +10 -0
  41. package/docs/lib/fumadocs/customize-docs.ts +47 -0
  42. package/docs/lib/fumadocs/generate-api-docs.ts +73 -0
  43. package/docs/lib/fumadocs/source.tsx +50 -0
  44. package/docs/lib/utils.ts +10 -0
  45. package/docs/mdx-components.tsx +21 -0
  46. package/docs/next-env.d.ts +7 -0
  47. package/docs/next.config.ts +35 -0
  48. package/docs/package.json +61 -0
  49. package/docs/postcss.config.mjs +5 -0
  50. package/docs/public/apple-touch-icon.png +0 -0
  51. package/docs/public/favicon-192.png +0 -0
  52. package/docs/public/favicon-512.png +0 -0
  53. package/docs/public/favicon.ico +0 -0
  54. package/docs/public/manifest.webmanifest +14 -0
  55. package/docs/source.config.ts +29 -0
  56. package/docs/tsconfig.json +50 -0
  57. package/docs/vite.config.ts +2 -0
  58. package/docs/wrangler.jsonc +13 -0
  59. package/package.json +1 -1
@@ -0,0 +1,299 @@
1
+ /**
2
+ * @file ask-ai-dropdown.tsx
3
+ * @description Dropdown component providing links to various AI providers for page interaction.
4
+ */
5
+ "use client";
6
+
7
+ import React, { useMemo } from "react";
8
+ import { ChevronDown, ExternalLinkIcon } from "lucide-react";
9
+ import { cn } from "@/lib/utils";
10
+ import {
11
+ Popover,
12
+ PopoverContent,
13
+ PopoverTrigger as PopoverTriggerBase,
14
+ } from "fumadocs-ui/components/ui/popover";
15
+ import { cva } from "class-variance-authority";
16
+ import { buttonVariants } from "../../ui/button";
17
+
18
+ const PopoverTrigger = PopoverTriggerBase as any;
19
+
20
+ const optionVariants = cva(
21
+ "text-sm p-2 rounded-lg inline-flex items-center gap-2 hover:text-fd-accent-foreground hover:bg-fd-accent [&_svg]:size-4",
22
+ );
23
+
24
+ interface AIProvider {
25
+ id: string;
26
+ title: string;
27
+ getHref: (params: { q: string; githubUrl?: string }) => string;
28
+ icon?: React.ReactNode;
29
+ }
30
+
31
+ const AI_PROVIDERS: AIProvider[] = [
32
+ {
33
+ id: "github",
34
+ title: "Open in GitHub",
35
+ getHref: ({ githubUrl }) => githubUrl || "",
36
+ icon: (
37
+ <svg fill="currentColor" role="img" viewBox="0 0 24 24">
38
+ <path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
39
+ </svg>
40
+ ),
41
+ },
42
+ {
43
+ id: "qwksearch",
44
+ title: "QwkSearch",
45
+ getHref: ({ q }) => `https://qwksearch.com/?q=${new URLSearchParams({ q })}`,
46
+ icon: (
47
+ <svg
48
+ role="img"
49
+ viewBox="0 0 24 24"
50
+ fill="currentColor"
51
+ xmlns="http://www.w3.org/2000/svg"
52
+ >
53
+ <path
54
+ fillRule="evenodd"
55
+ clipRule="evenodd"
56
+ d="
57
+ M10 1
58
+ a9 9 0 1 0 0 18
59
+ a9 9 0 0 0 0 -18
60
+ z
61
+ M10 3.7
62
+ a6.3 6.3 0 1 1 0 12.6
63
+ a6.3 6.3 0 0 1 0 -12.6
64
+ z
65
+ "
66
+ />
67
+ <path
68
+ d="M15.5 15.5 L20.8 20.8"
69
+ stroke="currentColor"
70
+ strokeWidth="2.9"
71
+ strokeLinecap="round"
72
+ fill="none"
73
+ />
74
+ <path
75
+ d="M4.3 4.3 L1.5 1.5"
76
+ stroke="currentColor"
77
+ strokeWidth="2.1"
78
+ strokeLinecap="round"
79
+ fill="none"
80
+ />
81
+ <circle cx="1.1" cy="1.1" r="1.4" />
82
+ <path
83
+ d="M15.7 4.3 L18.5 1.5"
84
+ stroke="currentColor"
85
+ strokeWidth="2.1"
86
+ strokeLinecap="round"
87
+ fill="none"
88
+ />
89
+ <circle cx="18.9" cy="1.1" r="1.4" />
90
+ <path
91
+ d="M4.3 15.7 L1.5 18.5"
92
+ stroke="currentColor"
93
+ strokeWidth="2.1"
94
+ strokeLinecap="round"
95
+ fill="none"
96
+ />
97
+ <circle cx="1.1" cy="18.9" r="1.4" />
98
+ </svg>
99
+ ),
100
+ },
101
+ {
102
+ id: "claude",
103
+ title: "Claude",
104
+ getHref: ({ q }) => `https://claude.ai/new?${new URLSearchParams({ q })}`,
105
+ icon: (
106
+ <svg
107
+ fill="currentColor"
108
+ role="img"
109
+ viewBox="0 0 24 24"
110
+ xmlns="http://www.w3.org/2000/svg"
111
+ >
112
+ <path d="M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z" />
113
+ </svg>
114
+ ),
115
+ },
116
+ {
117
+ id: "perplexity",
118
+ title: "Perplexity",
119
+ getHref: ({ q }) =>
120
+ `https://www.perplexity.ai/search?${new URLSearchParams({ q })}`,
121
+ icon: (
122
+ <svg
123
+ role="img"
124
+ viewBox="0 0 24 24"
125
+ fill="currentColor"
126
+ xmlns="http://www.w3.org/2000/svg"
127
+ >
128
+ <path d="M22.3977 7.0896h-2.3106V.0676l-7.5094 6.3542V.1577h-1.1554v6.1966L4.4904 0v7.0896H1.6023v10.3976h2.8882V24l6.932-6.3591v6.2005h1.1554v-6.0469l6.9318 6.1807v-6.4879h2.8882V7.0896zm-3.4657-4.531v4.531h-5.355l5.355-4.531zm-13.2862.0676 4.8691 4.4634H5.6458V2.6262zM2.7576 16.332V8.245h7.8476l-6.1149 6.1147v1.9723H2.7576zm2.8882 5.0404v-3.8852h.0001v-2.6488l5.7763-5.7764v7.0111l-5.7764 5.2993zm12.7086.0248-5.7766-5.1509V9.0618l5.7766 5.7766v6.5588zm2.8882-5.0652h-1.733v-1.9723L13.3948 8.245h7.8478v8.087z" />
129
+ </svg>
130
+ ),
131
+ },
132
+ {
133
+ id: "chatgpt",
134
+ title: "ChatGPT",
135
+ getHref: ({ q }) =>
136
+ `https://chatgpt.com/?${new URLSearchParams({ hints: "search", q })}`,
137
+ icon: (
138
+ <svg
139
+ role="img"
140
+ viewBox="0 0 24 24"
141
+ fill="currentColor"
142
+ xmlns="http://www.w3.org/2000/svg"
143
+ >
144
+ <path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" />
145
+ </svg>
146
+ ),
147
+ },
148
+ {
149
+ id: "gemini",
150
+ title: "Gemini",
151
+ getHref: ({ q }) =>
152
+ `https://aistudio.google.com/prompts/new_chat?prompt=${encodeURIComponent(q)}`,
153
+ icon: (
154
+ <svg
155
+ role="img"
156
+ viewBox="0 0 24 24"
157
+ fill="currentColor"
158
+ xmlns="http://www.w3.org/2000/svg"
159
+ >
160
+ <path d="M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81" />
161
+ </svg>
162
+ ),
163
+ },
164
+ {
165
+ id: "brave",
166
+ title: "Brave",
167
+ getHref: ({ q }) =>
168
+ `https://search.brave.com/ask?q=${encodeURIComponent(q)}`,
169
+ icon: (<svg fill="currentColor" viewBox="0 0 14 14" role="img">
170
+ <g strokeWidth="0"/>
171
+ <g strokeLinecap="round" strokeLinejoin="round"/>
172
+ <g >
173
+ <path d="m 6.5,12.77 c -.21,-.13 -.87,-.57 -1.48,-.98 -1.06,-.71 -1.5,-1.05 -1.45,-1.13 .01,-.02 -.01,-.05 -.05,-.06 -.04,-.01 -.06,-.04 -.04,-.07 .01,-.02 0,-.04 -.02,-.04 -.05,0 -.21,-.34 -.23,-.5 -.01,-.05 -.03,-.12 -.05,-.15 -.02,-.03 -.02,-.08 -0,-.1 .02,-.03 .01,-.06 -.01,-.08 -.02,-.01 -.06,-.12 -.09,-.23 -.03,-.11 -.09,-.35 -.14,-.53 -.05,-.18 -.1,-.37 -.11,-.43 -.01,-.05 -.12,-.48 -.24,-.95 -.12,-.47 -.3,-1.12 -.38,-1.45 -.09,-.33 -.19,-.73 -.24,-.9 l -.08,-.3 .19,-.46 c .21,-.51 .21,-.42 -.02,-1.01 l -.1,-.26 .44,-.44 c .45,-.46 .6,-.56 .95,-.65 .17,-.05 .24,-.04 .48,.02 l .28,.08 .25,-.26 c .14,-.14 .38,-.41 .55,-.58 l .3,-.32 1.82,0 1.82,0 .35,.36 c .19,.2 .44,.46 .55,.58 l .2,.22 .28,-.1 c .3,-.11 .34,-.11 .78,.09 .17,.07 1.02,.89 1.07,1.01 .01,.02 -.02,.13 -.07,.23 -.22,.47 -.22,.46 -.02,1 l .18,.49 -.3,1.16 c -.17,.64 -.4,1.53 -.52,2 -.48,1.88 -.54,2.08 -.65,2.29 -.25,.51 -.39,.62 -2.22,1.85 -1.42,.96 -1.38,.95 -1.95,.58 z m 1.07,-2.62 C 7.82,9.93 8.17,9.65 8.36,9.52 c .33,-.23 .4,-.34 .29,-.43 -.1,-.08 -.67,-.37 -1.07,-.54 -.39,-.16 -.73,-.25 -.73,-.19 0,.02 -.04,.04 -.1,.04 -.05,0 -.11,.03 -.11,.05 -.01,.03 -.03,.04 -.06,.02 -.02,-.01 -.04,0 -.04,.02 0,.03 -.03,.04 -.06,.02 -.03,-.01 -.09,.01 -.13,.04 -.04,.04 -.08,.05 -.09,.04 -.01,-.01 -.03,0 -.03,.03 0,.03 -.02,.04 -.04,.03 -.02,-.01 -.04,-.01 -.04,.02 0,.03 -.02,.04 -.04,.02 -.02,-.01 -.04,0 -.04,.02 0,.03 -.02,.04 -.04,.02 -.02,-.01 -.04,-.01 -.04,.02 0,.03 -.02,.04 -.04,.02 -.02,-.01 -.04,-.01 -.04,.02 0,.03 -.02,.04 -.04,.02 -.02,-.01 -.04,-.01 -.04,.02 0,.03 -.02,.04 -.04,.02 -.02,-.01 -.04,-.01 -.04,.02 0,.03 -.01,.04 -.03,.04 -.09,-.01 -.15,.01 -.26,.12 -.11,.1 -.11,.12 -.07,.22 .03,.06 .07,.1 .09,.09 .02,-.01 .05,.01 .07,.05 .01,.04 .04,.06 .06,.04 .01,-.01 .06,.01 .09,.06 .03,.05 .08,.08 .1,.07 .02,-.01 .05,.01 .06,.05 .01,.04 .04,.06 .05,.05 .01,-.01 .06,.02 .11,.07 .04,.05 .08,.08 .08,.06 0,-.02 .05,.03 .12,.1 .06,.08 .13,.13 .14,.12 .01,-.01 .09,.06 .18,.15 .09,.1 .17,.16 .18,.15 .01,-.01 .06,.02 .1,.08 .05,.06 .14,.1 .22,.11 .12,.01 .21,-.05 .59,-.38 z M 5.21,8.77 c 0,-.03 .02,-.04 .04,-.02 .05,.03 .36,-.11 .36,-.16 0,-.02 .02,-.03 .04,-.01 .02,.01 .04,.01 .04,-.02 0,-.03 .02,-.04 .04,-.02 .02,.01 .04,.01 .04,-.02 0,-.03 .02,-.04 .04,-.02 .02,.01 .04,0 .04,-.02 0,-.03 .02,-.04 .04,-.02 .02,.01 .04,.01 .04,-.02 0,-.03 .02,-.04 .04,-.02 .02,.01 .09,-.02 .15,-.08 .06,-.06 .12,-.1 .13,-.09 .01,.01 .1,-.07 .2,-.18 .1,-.11 .18,-.18 .18,-.17 0,.02 .05,-.02 .11,-.07 .06,-.06 .1,-.12 .09,-.14 -.01,-.02 -.01,-.04 .01,-.04 .05,0 .04,-.18 -0,-.26 -.04,-.07 -1.09,-.77 -1.09,-.73 0,.02 -.04,-.02 -.09,-.08 -.11,-.14 -.11,-.21 -0,-.43 .05,-.09 .07,-.18 .06,-.2 -.01,-.01 -0,-.03 .03,-.03 .03,0 .04,-.02 .03,-.04 -.01,-.02 -.01,-.04 .02,-.04 .03,0 .04,-.02 .02,-.04 -.01,-.02 -.01,-.04 .02,-.04 .08,0 .2,-.28 .2,-.5 0,-.12 -.01,-.21 -.03,-.21 -.02,0 -.03,-.02 -.01,-.04 .01,-.02 -.02,-.07 -.06,-.12 -.05,-.04 -.09,-.07 -.09,-.05 0,.02 -.03,0 -.07,-.04 -.04,-.04 -.09,-.06 -.11,-.04 -.02,.01 -.04,0 -.04,-.03 0,-.03 -.03,-.04 -.06,-.03 -.04,.01 -.07,0 -.08,-.02 -.01,-.02 -.06,-.05 -.11,-.05 -.05,0 -.1,-.03 -.1,-.05 0,-.02 -.03,-.03 -.06,-.02 -.03,.01 -.08,-.01 -.12,-.04 -.03,-.03 -.09,-.05 -.12,-.04 -.03,.01 -.06,0 -.06,-.02 0,-.03 -.03,-.04 -.07,-.02 -.04,.01 -.07,0 -.07,-.02 0,-.03 -.02,-.03 -.04,-.02 -.02,.01 -.05,0 -.07,-.02 -.01,-.03 -.05,-.03 -.07,-.02 -.02,.01 -.04,0 -.04,-.03 0,-.03 -.03,-.04 -.07,-.03 -.04,.01 -.07,.01 -.07,-.02 0,-.02 .08,-.04 .17,-.04 .09,0 .18,-.01 .2,-.03 .04,-.04 .73,-.04 .75,0 .01,.02 .07,.04 .14,.05 .07,.01 .17,.04 .22,.06 .05,.03 .18,.07 .29,.1 .18,.05 .2,.07 .2,.18 -0,.07 -.02,.14 -.04,.17 -.02,.03 -.02,.09 -0,.14 .02,.05 .01,.09 -.02,.09 -.03,0 -.04,.04 -.03,.11 .01,.06 0,.11 -.02,.11 -.02,0 -.03,.05 -.02,.11 .01,.06 0,.11 -.02,.11 -.02,0 -.03,.06 -.02,.13 .01,.07 0,.13 -.02,.13 -.02,0 -.03,.06 -.01,.13 .02,.08 .01,.13 -.02,.13 -.03,0 -.04,.04 -.02,.11 .01,.06 .01,.12 -.02,.14 -.07,.04 -.05,.24 .04,.34 .05,.05 .11,.08 .13,.06 .03,-.02 .05,-.01 .05,.02 0,.03 .04,.04 .09,.03 .05,-.01 .09,0 .09,.02 0,.03 .05,.03 .11,.02 .06,-.01 .12,-.01 .14,.02 .02,.03 .1,.04 .19,.02 .82,-.13 .93,-.17 .94,-.34 0,-.05 -.07,-.5 -.16,-.99 -.14,-.77 -.15,-.9 -.1,-.96 .04,-.03 .27,-.12 .53,-.18 .44,-.11 .5,-.12 1.03,-.09 .31,.02 .56,.04 .55,.05 -.01,.01 -.35,.14 -.76,.3 -1.16,.44 -1.18,.48 -.75,1.31 .16,.31 .28,.59 .27,.63 -.01,.04 -.31,.26 -.67,.49 -.35,.24 -.65,.46 -.67,.5 -.05,.12 .05,.26 .39,.56 .23,.21 .48,.37 .81,.54 .26,.13 .51,.24 .55,.24 .19,-0 .59,-.36 .72,-.64 .11,-.24 .1,-.45 -.03,-.75 -.06,-.14 -.11,-.31 -.11,-.39 0,-.15 .02,-.18 .96,-1.19 .57,-.61 .58,-.63 .58,-.82 0,-.11 -.03,-.26 -.07,-.34 -.13,-.26 -.51,-.8 -.91,-1.3 -.38,-.48 -.4,-.49 -.53,-.47 -.08,.01 -.33,.06 -.55,.11 -.56,.11 -.67,.11 -1.24,-.07 -.62,-.2 -.8,-.2 -1.42,0 -.27,.09 -.56,.16 -.65,.16 -.09,0 -.41,-.05 -.71,-.11 l -.55,-.11 -.18,.18 c -.1,.1 -.18,.19 -.17,.2 .01,.01 -.02,.05 -.07,.08 -.05,.03 -.08,.08 -.07,.1 .01,.02 -.03,.07 -.09,.11 -.06,.04 -.1,.09 -.09,.1 .01,.01 -.01,.05 -.06,.09 -.05,.03 -.08,.08 -.07,.1 .01,.02 -.01,.05 -.05,.06 -.04,.01 -.06,.04 -.04,.07 .01,.02 -.01,.05 -.04,.07 -.04,.01 -.06,.04 -.04,.07 .01,.02 -.01,.05 -.05,.07 -.04,.01 -.06,.04 -.05,.05 .01,.01 -.02,.07 -.08,.14 -.06,.06 -.1,.13 -.08,.15 .01,.02 -.01,.05 -.05,.06 -.04,.01 -.06,.05 -.04,.07 .01,.02 .01,.04 -.02,.04 -.03,0 -.04,.02 -.02,.04 .01,.02 .01,.05 -.02,.07 -.06,.04 -.06,.38 0,.38 .03,0 .04,.02 .02,.04 -.01,.02 -.01,.04 .02,.04 .03,0 .05,.03 .05,.06 0,.03 .08,.14 .19,.23 .1,.09 .18,.18 .18,.2 -.01,.02 .15,.18 .34,.36 .19,.18 .34,.34 .33,.35 -.01,.01 .07,.1 .18,.21 .11,.11 .2,.22 .2,.25 0,.03 .03,.06 .06,.08 .04,.02 .04,.03 -0,.06 -.03,.02 -.06,.09 -.07,.16 -0,.06 -.03,.12 -.05,.12 -.02,0 -.03,.01 -.01,.03 .01,.01 -0,.06 -.04,.09 -.04,.04 -.06,.09 -.04,.13 .01,.03 0,.06 -.02,.06 -.02,0 -.04,.07 -.04,.15 0,.09 .02,.15 .04,.15 .02,0 .03,.03 .02,.07 -.01,.04 -0,.07 .03,.07 .03,0 .04,.02 .02,.04 -.01,.02 -.01,.04 .02,.04 .03,0 .04,.02 .02,.04 -.01,.02 -.01,.04 .02,.04 .03,0 .04,.01 .04,.03 -.01,.05 .37,.43 .41,.42 .02,-.01 .04,.01 .04,.04 0,.03 .02,.04 .04,.02 .02,-.01 .05,-.01 .07,.02 .04,.06 .15,.06 .15,0 z"/>
174
+ </g>
175
+ </svg>
176
+ ),
177
+ },
178
+ {
179
+ id: "cursor",
180
+ title: "Cursor",
181
+ getHref: ({ q }) =>
182
+ `https://cursor.com/link/prompt?text=${encodeURIComponent(q)}`,
183
+ icon: (
184
+ <svg
185
+ role="img"
186
+ viewBox="0 0 24 24"
187
+ fill="currentColor"
188
+ xmlns="http://www.w3.org/2000/svg"
189
+ >
190
+ <path d="M11.503.131 1.891 5.678a.84.84 0 0 0-.42.726v11.188c0 .3.162.575.42.724l9.609 5.55a1 1 0 0 0 .998 0l9.61-5.55a.84.84 0 0 0 .42-.724V6.404a.84.84 0 0 0-.42-.726L12.497.131a1.01 1.01 0 0 0-.996 0M2.657 6.338h18.55c.263 0 .43.287.297.515L12.23 22.918c-.062.107-.229.064-.229-.06V12.335a.59.59 0 0 0-.295-.51l-9.11-5.257c-.109-.063-.064-.23.061-.23" />
191
+ </svg>
192
+ ),
193
+ },
194
+ ];
195
+
196
+ export type AIProviderID = (typeof AI_PROVIDERS)[number]["id"];
197
+
198
+ export function AskAIDropdown({
199
+ markdownUrl,
200
+ githubUrl,
201
+ providers,
202
+ }: {
203
+ /**
204
+ * A URL to the raw Markdown/MDX content of page
205
+ */
206
+ markdownUrl: string;
207
+
208
+ /**
209
+ * Source file URL on GitHub
210
+ */
211
+ githubUrl?: string;
212
+
213
+ /**
214
+ * List of provider IDs to show (e.g. ['claude', 'chatgpt']),
215
+ * or custom AIProvider objects, or a mix of both.
216
+ * Defaults to all providers.
217
+ */
218
+ providers?: (AIProviderID | AIProvider)[];
219
+ }) {
220
+ const items = useMemo(() => {
221
+ const fullMarkdownUrl =
222
+ typeof window !== "undefined"
223
+ ? new URL(markdownUrl, window.location.origin)
224
+ : "loading";
225
+ const q = `Read ${fullMarkdownUrl}, I want to ask questions about it.`;
226
+
227
+ const resolvedProviders: AIProvider[] = providers
228
+ ? providers
229
+ .map((p) =>
230
+ typeof p === "string" ? AI_PROVIDERS.find((ap) => ap.id === p)! : p,
231
+ )
232
+ .filter(Boolean)
233
+ : AI_PROVIDERS;
234
+
235
+ return resolvedProviders
236
+ .map((provider) => {
237
+ if (provider.id === "github" && !githubUrl) return null;
238
+
239
+ const href = provider.getHref({ q, githubUrl });
240
+ const icon =
241
+ provider.icon ??
242
+ (href ? (
243
+ <img
244
+ src={`https://s2.googleusercontent.com/s2/favicons?domain_url=${encodeURIComponent(new URL(href).origin)}`}
245
+ alt=""
246
+ className="size-4"
247
+ />
248
+ ) : null);
249
+
250
+ return {
251
+ id: provider.id,
252
+ title: provider.title,
253
+ href,
254
+ icon,
255
+ };
256
+ })
257
+ .filter((item): item is NonNullable<typeof item> => item !== null);
258
+ }, [githubUrl, markdownUrl, providers]);
259
+
260
+ return (
261
+ <Popover>
262
+ <PopoverTrigger
263
+ className={cn(
264
+ buttonVariants({
265
+ size: "sm",
266
+ className: "gap-2",
267
+ }),
268
+ )}
269
+ >
270
+ {items.find((p) => p.id !== "github")?.icon}
271
+ Ask AI
272
+ <ChevronDown className="size-3.5 text-fd-muted-foreground" />
273
+ </PopoverTrigger>
274
+ <PopoverContent className="flex flex-col overflow-auto !w-48 !min-w-0 !p-1">
275
+ {items.map((item, index) => (
276
+ <React.Fragment key={item.href}>
277
+ <a
278
+ href={item.href}
279
+ rel="noreferrer noopener"
280
+ target="_blank"
281
+ className={cn(optionVariants())}
282
+ >
283
+ {item.icon}
284
+ {item.title}
285
+ <ExternalLinkIcon className="text-fd-muted-foreground size-3.5 ms-auto" />
286
+ </a>
287
+ {index === 0 && (
288
+ <div className="flex items-center gap-2 px-2 py-2 text-xs font-medium text-fd-muted-foreground">
289
+ <span className="h-px flex-1 bg-fd-border" />
290
+ Ask AI Model
291
+ <span className="h-px flex-1 bg-fd-border" />
292
+ </div>
293
+ )}
294
+ </React.Fragment>
295
+ ))}
296
+ </PopoverContent>
297
+ </Popover>
298
+ );
299
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @file llm-copy-button.tsx
3
+ * @description Button component that fetches and copies raw MDX content for LLMs.
4
+ */
5
+ 'use client';
6
+
7
+ import { useState } from 'react';
8
+ import { Check, Copy } from 'lucide-react';
9
+ import { cn } from '@/lib/utils';
10
+ import { useCopyButton } from 'fumadocs-ui/utils/use-copy-button';
11
+ import { buttonVariants } from '../../ui/button';
12
+
13
+ const cache = new Map<string, string>();
14
+
15
+ export function LLMCopyButton({
16
+ /**
17
+ * A URL to fetch the raw Markdown/MDX content of page
18
+ */
19
+ markdownUrl,
20
+ }: {
21
+ markdownUrl: string;
22
+ }) {
23
+ const [isLoading, setLoading] = useState(false);
24
+ const [checked, onClick] = useCopyButton(async () => {
25
+ const cached = cache.get(markdownUrl);
26
+ if (cached) return navigator.clipboard.writeText(cached);
27
+
28
+ setLoading(true);
29
+
30
+ try {
31
+ await navigator.clipboard.write([
32
+ new ClipboardItem({
33
+ 'text/plain': fetch(markdownUrl).then(async (res) => {
34
+ const content = await res.text();
35
+ cache.set(markdownUrl, content);
36
+
37
+ return content;
38
+ }),
39
+ }),
40
+ ]);
41
+ } finally {
42
+ setLoading(false);
43
+ }
44
+ });
45
+
46
+ return (
47
+ <button
48
+ disabled={isLoading}
49
+ className={cn(
50
+ buttonVariants({
51
+ size: 'sm',
52
+ className: 'gap-2 [&_svg]:size-3.5 [&_svg]:text-fd-muted-foreground',
53
+ }),
54
+ )}
55
+ onClick={onClick}
56
+ >
57
+ {checked ? <Check /> : <Copy />}
58
+ Copy
59
+ </button>
60
+ );
61
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @file api-page.client.tsx
3
+ * @description Client-side configuration and setup for the Fumadocs API page.
4
+ */
5
+ 'use client';
6
+
7
+ export default {};
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @file api-page.tsx
3
+ * @description API page component placeholder
4
+ */
5
+ export const APIPage = {
6
+ generateMetadata: () => ({ title: 'API' }),
7
+ };
@@ -0,0 +1,36 @@
1
+ 'use client';
2
+ import { usePathname } from 'next/navigation';
3
+ import { useBreadcrumb } from 'fumadocs-core/breadcrumb';
4
+ import type { Root } from 'fumadocs-core/page-tree';
5
+ import { Fragment } from 'react';
6
+ import { ChevronRight } from 'lucide-react';
7
+ import Link from 'next/link';
8
+
9
+ export function Breadcrumb({ tree }: { tree: Root }) {
10
+ const pathname = usePathname();
11
+ const items = useBreadcrumb(pathname, tree);
12
+
13
+ if (items.length === 0) return null;
14
+
15
+ return (
16
+ <div className="-mb-3 flex flex-row items-center gap-1 text-sm font-medium text-fd-muted-foreground">
17
+ {items.map((item, i) => (
18
+ <Fragment key={i}>
19
+ {i !== 0 && (
20
+ <ChevronRight className="size-4 shrink-0 rtl:rotate-180" />
21
+ )}
22
+ {item.url ? (
23
+ <Link
24
+ href={item.url}
25
+ className="truncate hover:text-fd-accent-foreground"
26
+ >
27
+ {item.name}
28
+ </Link>
29
+ ) : (
30
+ <span className="truncate">{item.name}</span>
31
+ )}
32
+ </Fragment>
33
+ ))}
34
+ </div>
35
+ );
36
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @file search.tsx
3
+ * @description Custom search dialog component using Orama for documentation search.
4
+ */
5
+ 'use client';
6
+ import {
7
+ SearchDialog,
8
+ SearchDialogClose,
9
+ SearchDialogContent,
10
+ SearchDialogHeader,
11
+ SearchDialogIcon,
12
+ SearchDialogInput,
13
+ SearchDialogList,
14
+ SearchDialogOverlay,
15
+ type SharedProps,
16
+ } from 'fumadocs-ui/components/dialog/search';
17
+ import { useDocsSearch } from 'fumadocs-core/search/client';
18
+ import { create } from 'zbsearch';
19
+ import { useI18n } from 'fumadocs-ui/contexts/i18n';
20
+
21
+ function initOrama() {
22
+ return create({
23
+ schema: { _: 'string' },
24
+ language: 'english',
25
+ });
26
+ }
27
+
28
+ export default function DefaultSearchDialog(props: SharedProps) {
29
+ const { locale } = useI18n(); // (optional) for i18n
30
+ const { search, setSearch, query } = useDocsSearch({
31
+ type: 'static',
32
+ from: '/docs/api/docs-search',
33
+ initOrama,
34
+ locale,
35
+ });
36
+
37
+ return (
38
+ <SearchDialog
39
+ search={search}
40
+ onSearchChange={setSearch}
41
+ isLoading={query.isLoading}
42
+ {...props}
43
+ >
44
+ <SearchDialogOverlay />
45
+ <SearchDialogContent>
46
+ <SearchDialogHeader>
47
+ <SearchDialogIcon />
48
+ <SearchDialogInput />
49
+ <SearchDialogClose />
50
+ </SearchDialogHeader>
51
+ <SearchDialogList items={query.data !== 'empty' ? query.data : null} />
52
+ </SearchDialogContent>
53
+ </SearchDialog>
54
+ );
55
+ }
@@ -0,0 +1,3 @@
1
+ 'use client';
2
+
3
+ export { ThemeDropdown } from 'shadcn-theme-menu';
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @file theme-provider.tsx
3
+ * @description Theme provider component for managing light and dark mode.
4
+ */
5
+ 'use client'
6
+
7
+ import * as React from 'react'
8
+ import {
9
+ ThemeProvider as NextThemesProvider,
10
+ type ThemeProviderProps,
11
+ } from 'next-themes'
12
+
13
+ export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
14
+ return <NextThemesProvider {...props}>{children}</NextThemesProvider>
15
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @file theme-toggle.tsx
3
+ * @description Component for toggling between light and dark themes.
4
+ */
5
+ "use client"
6
+
7
+ import { useState, useEffect } from "react"
8
+ import { Moon, Sun } from "lucide-react"
9
+ import { Button } from "@/components/ui/button"
10
+
11
+ export function ThemeToggle() {
12
+ const [theme, setTheme] = useState<"light" | "dark">("light")
13
+
14
+ useEffect(() => {
15
+ const savedTheme = localStorage.getItem("theme") as "light" | "dark" | null
16
+ const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches
17
+ const initialTheme = savedTheme || (prefersDark ? "dark" : "light")
18
+ setTheme(initialTheme)
19
+ document.documentElement.classList.toggle("dark", initialTheme === "dark")
20
+ }, [])
21
+
22
+ const toggleTheme = () => {
23
+ const newTheme = theme === "light" ? "dark" : "light"
24
+ setTheme(newTheme)
25
+ localStorage.setItem("theme", newTheme)
26
+ document.documentElement.classList.toggle("dark", newTheme === "dark")
27
+ }
28
+
29
+ return (
30
+ <Button
31
+ variant="outline"
32
+ size="icon"
33
+ onClick={toggleTheme}
34
+ className="fixed top-4 right-4 z-50 bg-card/80 backdrop-blur-sm border-border hover:bg-secondary"
35
+ >
36
+ {theme === "light" ? <Moon className="h-5 w-5 text-foreground" /> : <Sun className="h-5 w-5 text-foreground" />}
37
+ <span className="sr-only">Toggle theme</span>
38
+ </Button>
39
+ )
40
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @file badge.tsx
3
+ * @description Badge component for displaying small amounts of information or status.
4
+ */
5
+ import * as React from 'react'
6
+ import { Slot } from '@radix-ui/react-slot'
7
+ import { cva, type VariantProps } from 'class-variance-authority'
8
+
9
+ import { cn } from '@/lib/utils'
10
+
11
+ const badgeVariants = cva(
12
+ 'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
13
+ {
14
+ variants: {
15
+ variant: {
16
+ default:
17
+ 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
18
+ secondary:
19
+ 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
20
+ destructive:
21
+ 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
22
+ outline:
23
+ 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
24
+ },
25
+ },
26
+ defaultVariants: {
27
+ variant: 'default',
28
+ },
29
+ },
30
+ )
31
+
32
+ function Badge({
33
+ className,
34
+ variant,
35
+ asChild = false,
36
+ ...props
37
+ }: React.ComponentProps<'span'> &
38
+ VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
39
+ const Comp = asChild ? Slot : 'span'
40
+
41
+ return (
42
+ <Comp
43
+ data-slot="badge"
44
+ className={cn(badgeVariants({ variant }), className)}
45
+ {...props}
46
+ />
47
+ )
48
+ }
49
+
50
+ export { Badge, badgeVariants }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @file button.tsx
3
+ * @description Versatile button component with multiple variants and sizes.
4
+ */
5
+
6
+ import * as React from 'react'
7
+
8
+ import { Slot } from '@radix-ui/react-slot'
9
+ import { cva, type VariantProps } from 'class-variance-authority'
10
+
11
+ import { cn } from '@/lib/utils'
12
+
13
+ const buttonVariants = cva(
14
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
15
+ {
16
+ variants: {
17
+ variant: {
18
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90',
19
+ destructive:
20
+ 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
21
+ outline:
22
+ 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
23
+ secondary:
24
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
25
+ ghost:
26
+ 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
27
+ link: 'text-primary underline-offset-4 hover:underline',
28
+ },
29
+ size: {
30
+ default: 'h-9 px-4 py-2 has-[>svg]:px-3',
31
+ sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
32
+ lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
33
+ icon: 'size-9',
34
+ 'icon-sm': 'size-8',
35
+ 'icon-lg': 'size-10',
36
+ },
37
+ },
38
+ defaultVariants: {
39
+ variant: 'default',
40
+ size: 'default',
41
+ },
42
+ },
43
+ )
44
+
45
+ function Button({
46
+ className,
47
+ variant,
48
+ size,
49
+ asChild = false,
50
+ ...props
51
+ }: React.ComponentProps<'button'> &
52
+ VariantProps<typeof buttonVariants> & {
53
+ asChild?: boolean
54
+ }) {
55
+ const Comp = asChild ? Slot : 'button'
56
+
57
+ return (
58
+ <Comp
59
+ data-slot="button"
60
+ className={cn(buttonVariants({ variant, size, className }))}
61
+ {...props as any}
62
+ />
63
+ )
64
+ }
65
+
66
+ export { Button, buttonVariants }