git0 0.3.17 → 0.3.19
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.
- package/docs/README.md +20 -0
- package/docs/app/(home)/docs-home.css +235 -0
- package/docs/app/(home)/layout.tsx +12 -0
- package/docs/app/(home)/page.tsx +27 -0
- package/docs/app/docs/[[...slug]]/page.tsx +84 -0
- package/docs/app/docs/api/docs-search/route.ts +11 -0
- package/docs/app/docs/layout.tsx +16 -0
- package/docs/app/docs/llms-full.txt/route.ts +15 -0
- package/docs/app/docs/llms.mdx/docs/[[...slug]]/route.ts +24 -0
- package/docs/app/globals.css +814 -0
- package/docs/app/layout.config.tsx +32 -0
- package/docs/app/layout.tsx +22 -0
- package/docs/app/provider.tsx +20 -0
- package/docs/cli.json +11 -0
- package/docs/components/DocsHomepage/code-example.tsx +123 -0
- package/docs/components/DocsHomepage/features-grid.tsx +92 -0
- package/docs/components/DocsHomepage/footer.tsx +58 -0
- package/docs/components/DocsHomepage/hero-section.tsx +114 -0
- package/docs/components/DocsHomepage/project-types.tsx +114 -0
- package/docs/components/fumadocs/ai/ask-ai-dropdown.tsx +299 -0
- package/docs/components/fumadocs/ai/llm-copy-button.tsx +61 -0
- package/docs/components/fumadocs/api/api-page.client.tsx +7 -0
- package/docs/components/fumadocs/api/api-page.tsx +7 -0
- package/docs/components/fumadocs/layout/breadcrumb.tsx +36 -0
- package/docs/components/fumadocs/layout/search.tsx +55 -0
- package/docs/components/fumadocs/layout/theme-dropdown.tsx +3 -0
- package/docs/components/fumadocs/layout/theme-provider.tsx +15 -0
- package/docs/components/fumadocs/layout/theme-toggle.tsx +40 -0
- package/docs/components/ui/badge.tsx +50 -0
- package/docs/components/ui/button.tsx +66 -0
- package/docs/components/ui/collapsible.tsx +44 -0
- package/docs/components/ui/slider.tsx +36 -0
- package/docs/components/ui/tooltip.tsx +63 -0
- package/docs/components/ui/video-modal.tsx +238 -0
- package/docs/content/docs/fm.mdx +11 -0
- package/{docs-config/src/functions/git0.md → docs/content/docs/git0.mdx} +4 -1
- package/{docs-config/src/functions/github-api.md → docs/content/docs/github-api.mdx} +4 -1
- package/{docs-config/src/functions/index.md → docs/content/docs/index.mdx} +9 -14
- package/docs/content/docs/meta.json +15 -0
- package/docs/content/docs/modules.mdx +10 -0
- package/docs/lib/fumadocs/customize-docs.ts +47 -0
- package/docs/lib/fumadocs/generate-api-docs.ts +73 -0
- package/docs/lib/fumadocs/source.tsx +50 -0
- package/docs/lib/utils.ts +10 -0
- package/docs/mdx-components.tsx +21 -0
- package/docs/next-env.d.ts +7 -0
- package/docs/next.config.ts +35 -0
- package/docs/package.json +61 -0
- package/docs/postcss.config.mjs +5 -0
- package/docs/public/apple-touch-icon.png +0 -0
- package/docs/public/favicon-192.png +0 -0
- package/docs/public/favicon-512.png +0 -0
- package/docs/public/favicon.ico +0 -0
- package/docs/public/manifest.webmanifest +14 -0
- package/docs/source.config.ts +29 -0
- package/docs/tsconfig.json +50 -0
- package/docs/vite.config.ts +2 -0
- package/docs/wrangler.jsonc +13 -0
- package/package.json +3 -2
- package/docs/404.html +0 -26
- package/docs/CNAME +0 -1
- package/docs/Footer/index.html +0 -26
- package/docs/assets/css/styles.3dd00f8d.css +0 -1
- package/docs/assets/js/17896441.79ceefeb.js +0 -1
- package/docs/assets/js/1df93b7f.1385eba0.js +0 -2
- package/docs/assets/js/1df93b7f.1385eba0.js.LICENSE.txt +0 -6
- package/docs/assets/js/22dd74f7.e13ac7a4.js +0 -1
- package/docs/assets/js/237.daf7efdf.js +0 -1
- package/docs/assets/js/278.1628756c.js +0 -1
- package/docs/assets/js/28ab763d.192aa3bb.js +0 -1
- package/docs/assets/js/299d276b.c9496717.js +0 -1
- package/docs/assets/js/577.78325c02.js +0 -1
- package/docs/assets/js/591.2156b33d.js +0 -2
- package/docs/assets/js/591.2156b33d.js.LICENSE.txt +0 -61
- package/docs/assets/js/5e95c892.bd6c1093.js +0 -1
- package/docs/assets/js/68cef36b.e5b1975b.js +0 -1
- package/docs/assets/js/a7456010.3054873b.js +0 -1
- package/docs/assets/js/a7bd4aaa.87229397.js +0 -1
- package/docs/assets/js/a94703ab.6d39a596.js +0 -1
- package/docs/assets/js/a9cef9d5.a7253e41.js +0 -1
- package/docs/assets/js/aba21aa0.dfebd789.js +0 -1
- package/docs/assets/js/ac46717f.32345167.js +0 -2
- package/docs/assets/js/ac46717f.32345167.js.LICENSE.txt +0 -6
- package/docs/assets/js/c3a618e1.1c56fb03.js +0 -590
- package/docs/assets/js/main.1f646b09.js +0 -2
- package/docs/assets/js/main.1f646b09.js.LICENSE.txt +0 -68
- package/docs/assets/js/runtime~main.f69f8f44.js +0 -1
- package/docs/functions/fm/index.html +0 -26
- package/docs/functions/git0/index.html +0 -48
- package/docs/functions/github-api/index.html +0 -149
- package/docs/functions/index.html +0 -891
- package/docs/functions/modules/index.html +0 -31
- package/docs/index.html +0 -26
- package/docs/lunr-index-1749760982052.json +0 -1
- package/docs/lunr-index.json +0 -1
- package/docs/search-doc-1749760982052.json +0 -1
- package/docs/search-doc.json +0 -1
- package/docs/sitemap.xml +0 -1
- package/docs-config/.docusaurus/DONT-EDIT-THIS-FOLDER +0 -5
- package/docs-config/.docusaurus/client-manifest.json +0 -271
- package/docs-config/.docusaurus/client-modules.js +0 -8
- package/docs-config/.docusaurus/codeTranslations.json +0 -1
- package/docs-config/.docusaurus/docusaurus-lunr-search/default/__plugin.json +0 -4
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/__mdx-loader-dependency.json +0 -1
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/__plugin.json +0 -4
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/p/docs-175.json +0 -1
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/p/index-466.json +0 -1
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/site-src-functions-fm-md-a9c.json +0 -19
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/site-src-functions-git-0-1-md-d3e.json +0 -19
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/site-src-functions-git-0-md-299.json +0 -23
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/site-src-functions-github-api-md-28a.json +0 -23
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/site-src-functions-globals-md-4a8.json +0 -19
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/site-src-functions-index-md-c3a.json +0 -23
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/site-src-functions-modules-md-68c.json +0 -19
- package/docs-config/.docusaurus/docusaurus-plugin-content-docs/default/site-src-index-md-d14.json +0 -21
- package/docs-config/.docusaurus/docusaurus-plugin-content-pages/default/__plugin.json +0 -4
- package/docs-config/.docusaurus/docusaurus-plugin-google-gtag/default/__plugin.json +0 -4
- package/docs-config/.docusaurus/docusaurus.config.mjs +0 -378
- package/docs-config/.docusaurus/globalData.json +0 -70
- package/docs-config/.docusaurus/i18n.json +0 -17
- package/docs-config/.docusaurus/lunr.client.js +0 -5
- package/docs-config/.docusaurus/registry.js +0 -16
- package/docs-config/.docusaurus/routes.js +0 -67
- package/docs-config/.docusaurus/routesChunkNames.json +0 -49
- package/docs-config/.docusaurus/site-metadata.json +0 -51
- package/docs-config/.docusaurus/site-storage.json +0 -4
- package/docs-config/config/customize-docs.js +0 -31
- package/docs-config/config/docs-theme.css +0 -358
- package/docs-config/config/openapi.mustache +0 -39
- package/docs-config/config/sidebars.ts +0 -21
- package/docs-config/config/typedoc.json +0 -40
- package/docs-config/docusaurus.config.ts +0 -341
- package/docs-config/package.json +0 -40
- package/docs-config/src/functions/fm.md +0 -1
- package/docs-config/src/functions/modules.md +0 -5
- package/docs-config/src/functions/typedoc-sidebar.cjs +0 -22
- package/docs-config/src/pages/Footer.tsx +0 -67
- package/docs-config/src/pages/index.tsx +0 -433
- package/docs-config/static/CNAME +0 -1
- package/docs-config/tsconfig.json +0 -27
|
@@ -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,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,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 }
|