docstra 0.1.0 → 1.0.0
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/dist/{index.d.mts → client/index.d.mts} +26 -8
- package/dist/{index.d.ts → client/index.d.ts} +26 -8
- package/dist/client/index.js +824 -0
- package/dist/client/index.mjs +781 -0
- package/dist/server/index.d.mts +51 -0
- package/dist/server/index.d.ts +51 -0
- package/dist/server/index.js +176 -0
- package/dist/server/index.mjs +136 -0
- package/dist/styles.css +548 -2
- package/package.json +32 -8
- package/dist/index.js +0 -2
- package/dist/index.mjs +0 -2
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/context/docstra-context.tsx
|
|
4
|
+
import { createContext, useContext, useState as useState2 } from "react";
|
|
5
|
+
import { ToastContainer } from "react-toast-msg";
|
|
6
|
+
|
|
7
|
+
// src/client/search-box.tsx
|
|
8
|
+
import { SearchIcon } from "lucide-react";
|
|
9
|
+
|
|
10
|
+
// src/utils/cn.ts
|
|
11
|
+
import { twMerge } from "tailwind-merge";
|
|
12
|
+
import clsx from "clsx";
|
|
13
|
+
function cn(...inputs) {
|
|
14
|
+
return twMerge(clsx(inputs));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/client/search-box.tsx
|
|
18
|
+
import { useEffect, useState } from "react";
|
|
19
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
function DocstraSearchBox() {
|
|
21
|
+
const { openSearchBox, setOpenSearchBox } = useDocstra();
|
|
22
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
console.log(`Search query: ${searchQuery}`);
|
|
25
|
+
}, [searchQuery]);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const handleKeyDown = (event) => {
|
|
28
|
+
if (event.ctrlKey && event.key === "k") {
|
|
29
|
+
event.preventDefault();
|
|
30
|
+
setOpenSearchBox(true);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
34
|
+
return () => {
|
|
35
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
36
|
+
};
|
|
37
|
+
}, []);
|
|
38
|
+
return /* @__PURE__ */ jsx(
|
|
39
|
+
"div",
|
|
40
|
+
{
|
|
41
|
+
onClick: () => {
|
|
42
|
+
setOpenSearchBox(false);
|
|
43
|
+
setSearchQuery("");
|
|
44
|
+
},
|
|
45
|
+
className: cn(
|
|
46
|
+
"fixed inset-0 z-25 flex items-start justify-center bg-white/40 backdrop-blur-md opacity-0 pointer-events-none transition-all duration-300",
|
|
47
|
+
openSearchBox && "opacity-100 pointer-events-auto"
|
|
48
|
+
),
|
|
49
|
+
children: /* @__PURE__ */ jsx(
|
|
50
|
+
"div",
|
|
51
|
+
{
|
|
52
|
+
onClick: (e) => e.stopPropagation(),
|
|
53
|
+
className: "flex flex-col items-center mt-30 max-w-lg w-full max-md:px-4",
|
|
54
|
+
children: /* @__PURE__ */ jsx(
|
|
55
|
+
"form",
|
|
56
|
+
{
|
|
57
|
+
className: cn(
|
|
58
|
+
"relative flex items-center justify-between w-full bg-white border border-slate-200 text-gray-400 h-15 p-0.5 rounded-md"
|
|
59
|
+
// searchQuery && "rounded-b-none border-b-0"
|
|
60
|
+
),
|
|
61
|
+
children: openSearchBox && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
62
|
+
/* @__PURE__ */ jsx(SearchIcon, { className: "size-5.5 mx-3 shrink-0" }),
|
|
63
|
+
/* @__PURE__ */ jsx(
|
|
64
|
+
"input",
|
|
65
|
+
{
|
|
66
|
+
className: "w-full bg-transparent h-full outline-none text-gray-400 placeholder:text-gray-400",
|
|
67
|
+
type: "text",
|
|
68
|
+
placeholder: "Search components",
|
|
69
|
+
spellCheck: "false",
|
|
70
|
+
autoFocus: true,
|
|
71
|
+
value: searchQuery,
|
|
72
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
73
|
+
name: "searchQuery",
|
|
74
|
+
required: true
|
|
75
|
+
}
|
|
76
|
+
),
|
|
77
|
+
/* @__PURE__ */ jsxs(
|
|
78
|
+
"svg",
|
|
79
|
+
{
|
|
80
|
+
className: "h-4.5 shrink-0 w-auto mr-3",
|
|
81
|
+
width: "29",
|
|
82
|
+
height: "18",
|
|
83
|
+
viewBox: "0 0 29 18",
|
|
84
|
+
fill: "none",
|
|
85
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ jsx(
|
|
88
|
+
"path",
|
|
89
|
+
{
|
|
90
|
+
d: "M13.5 2.25a2.25 2.25 0 0 0-2.25 2.25v9a2.25 2.25 0 1 0 2.25-2.25h-9a2.25 2.25 0 1 0 2.25 2.25v-9A2.25 2.25 0 1 0 4.5 6.75h9a2.25 2.25 0 0 0 0-4.5",
|
|
91
|
+
stroke: "#99A1AF",
|
|
92
|
+
strokeWidth: "1.5",
|
|
93
|
+
strokeLinecap: "round",
|
|
94
|
+
strokeLinejoin: "round"
|
|
95
|
+
}
|
|
96
|
+
),
|
|
97
|
+
/* @__PURE__ */ jsx(
|
|
98
|
+
"path",
|
|
99
|
+
{
|
|
100
|
+
d: "M25.986 14 21.45 8.89l4.438-4.69h2.058l-4.9 5.096v-.882L28.086 14zm-5.922 0V4.2h1.61V14z",
|
|
101
|
+
fill: "#99A1AF"
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
] })
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/context/docstra-context.tsx
|
|
117
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
118
|
+
var DocstraContext = createContext(null);
|
|
119
|
+
function DocstraProvider({
|
|
120
|
+
children,
|
|
121
|
+
docstraConfig
|
|
122
|
+
}) {
|
|
123
|
+
const [openSidebar, setOpenSidebar] = useState2(false);
|
|
124
|
+
const [openSearchBox, setOpenSearchBox] = useState2(false);
|
|
125
|
+
return /* @__PURE__ */ jsxs2(
|
|
126
|
+
DocstraContext.Provider,
|
|
127
|
+
{
|
|
128
|
+
value: {
|
|
129
|
+
openSidebar,
|
|
130
|
+
setOpenSidebar,
|
|
131
|
+
docstraConfig,
|
|
132
|
+
openSearchBox,
|
|
133
|
+
setOpenSearchBox
|
|
134
|
+
},
|
|
135
|
+
children: [
|
|
136
|
+
/* @__PURE__ */ jsx2(ToastContainer, {}),
|
|
137
|
+
/* @__PURE__ */ jsx2(DocstraSearchBox, {}),
|
|
138
|
+
children
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
function useDocstra() {
|
|
144
|
+
const ctx = useContext(DocstraContext);
|
|
145
|
+
if (!ctx) throw new Error("Please wrap your app with DocstraProvider");
|
|
146
|
+
return ctx;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/client/header.tsx
|
|
150
|
+
import { TextAlignEnd, XIcon } from "lucide-react";
|
|
151
|
+
import { useEffect as useEffect2 } from "react";
|
|
152
|
+
|
|
153
|
+
// src/client/link.tsx
|
|
154
|
+
import LinkComponent from "next/link";
|
|
155
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
156
|
+
function Link({ href, children, className, onNavigate, ...props }) {
|
|
157
|
+
if (href.startsWith("http")) {
|
|
158
|
+
return /* @__PURE__ */ jsx3("a", { href, className, ...props, target: "_blank", rel: "noopener noreferrer", children });
|
|
159
|
+
}
|
|
160
|
+
return /* @__PURE__ */ jsx3(LinkComponent, { href, className, onNavigate, ...props, "aria-label": "Ns", children });
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/client/header.tsx
|
|
164
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
165
|
+
function DocstraHeader() {
|
|
166
|
+
const { openSidebar, setOpenSidebar, docstraConfig } = useDocstra();
|
|
167
|
+
useEffect2(() => {
|
|
168
|
+
if (openSidebar) {
|
|
169
|
+
document.body.classList.add("max-md:overflow-hidden");
|
|
170
|
+
} else {
|
|
171
|
+
document.body.classList.remove("max-md:overflow-hidden");
|
|
172
|
+
}
|
|
173
|
+
}, [openSidebar]);
|
|
174
|
+
return /* @__PURE__ */ jsxs3("header", { className: "sticky top-0 z-10 text-sm flex items-center justify-between border-b border-gray-100 h-18 px-4 md:px-6 bg-white", children: [
|
|
175
|
+
/* @__PURE__ */ jsx4(Link, { href: docstraConfig.navbar?.logo?.link || "/", children: /* @__PURE__ */ jsx4(
|
|
176
|
+
"img",
|
|
177
|
+
{
|
|
178
|
+
src: docstraConfig.navbar?.logo?.src || "/logo.png",
|
|
179
|
+
alt: docstraConfig.navbar?.logo?.alt || "Logo",
|
|
180
|
+
className: cn("h-9.5 w-auto", docstraConfig.navbar?.logo?.className)
|
|
181
|
+
}
|
|
182
|
+
) }),
|
|
183
|
+
/* @__PURE__ */ jsxs3("div", { className: "hidden divide-x divide-gray-200 md:flex items-center", children: [
|
|
184
|
+
docstraConfig.navbar?.links?.map((link) => /* @__PURE__ */ jsx4(Link, { href: link.href, className: "px-6 hover:text-gray-500", children: link.name }, link.name)),
|
|
185
|
+
/* @__PURE__ */ jsx4(Link, { href: docstraConfig?.githubRepo || "https://github.com/sudhucodes/docstra", children: /* @__PURE__ */ jsx4("svg", { className: "size-6 mx-6", width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx4("path", { d: "M12 .3a12 12 0 0 0-3.8 23.38c.6.12.83-.26.83-.57L9 21.07c-3.34.72-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.08-.74.09-.73.09-.73 1.2.09 1.83 1.24 1.83 1.24 1.08 1.83 2.81 1.3 3.5 1 .1-.78.42-1.31.76-1.61-2.67-.3-5.47-1.33-5.47-5.93 0-1.31.47-2.38 1.24-3.22-.14-.3-.54-1.52.1-3.18 0 0 1-.32 3.3 1.23a11.5 11.5 0 0 1 6 0c2.28-1.55 3.29-1.23 3.29-1.23.64 1.66.24 2.88.12 3.18a4.65 4.65 0 0 1 1.23 3.22c0 4.61-2.8 5.63-5.48 5.92.42.36.81 1.1.81 2.22l-.01 3.29c0 .31.2.69.82.57A12 12 0 0 0 12 .3" }) }) })
|
|
186
|
+
] }),
|
|
187
|
+
/* @__PURE__ */ jsx4(
|
|
188
|
+
"button",
|
|
189
|
+
{
|
|
190
|
+
onClick: () => setOpenSidebar(!openSidebar),
|
|
191
|
+
className: "md:hidden transition text-gray-600 active:ring-2 ring-gray-200 p-1.5 rounded-md",
|
|
192
|
+
children: openSidebar ? /* @__PURE__ */ jsx4(XIcon, { className: "size-6.5" }) : /* @__PURE__ */ jsx4(TextAlignEnd, { className: "size-6.5" })
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
] });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/client/sidebar.tsx
|
|
199
|
+
import { SearchIcon as SearchIcon2 } from "lucide-react";
|
|
200
|
+
import { usePathname } from "next/navigation";
|
|
201
|
+
|
|
202
|
+
// src/utils/get-icon.ts
|
|
203
|
+
import * as Icons from "lucide-react";
|
|
204
|
+
function getIcon(name) {
|
|
205
|
+
if (!name) return void 0;
|
|
206
|
+
return Icons[name];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/client/sidebar.tsx
|
|
210
|
+
import { toast } from "react-toast-msg";
|
|
211
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
212
|
+
function DocstraSidebar() {
|
|
213
|
+
const { openSidebar, setOpenSidebar, docstraConfig } = useDocstra();
|
|
214
|
+
const pathname = usePathname();
|
|
215
|
+
return /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
216
|
+
/* @__PURE__ */ jsx5(
|
|
217
|
+
"div",
|
|
218
|
+
{
|
|
219
|
+
className: cn(
|
|
220
|
+
"fixed inset-0 z-20 bg-black/50 opacity-0 pointer-events-none transition-all duration-300",
|
|
221
|
+
openSidebar && "opacity-100 pointer-events-auto"
|
|
222
|
+
),
|
|
223
|
+
onClick: () => setOpenSidebar(false)
|
|
224
|
+
}
|
|
225
|
+
),
|
|
226
|
+
/* @__PURE__ */ jsxs4(
|
|
227
|
+
"aside",
|
|
228
|
+
{
|
|
229
|
+
className: cn(
|
|
230
|
+
"sticky md:top-18 h-[calc(100svh-72px)] scrollbar-y w-screen z-21 md:w-72 pb-10 text-base md:text-sm shrink-0 border-r border-gray-200 p-4 max-md:fixed bg-white overflow-y-auto transition-all duration-300",
|
|
231
|
+
openSidebar ? "top-32" : "top-full"
|
|
232
|
+
),
|
|
233
|
+
children: [
|
|
234
|
+
/* @__PURE__ */ jsxs4(
|
|
235
|
+
"div",
|
|
236
|
+
{
|
|
237
|
+
className: "flex items-center gap-2 cursor-pointer mt-6 mb-4 p-2.5 text-gray-500 border border-gray-200 rounded-lg hover:bg-gray-50",
|
|
238
|
+
onClick: () => toast.success("Docstra: Search is coming soon!"),
|
|
239
|
+
children: [
|
|
240
|
+
/* @__PURE__ */ jsx5(SearchIcon2, { className: "size-4.5" }),
|
|
241
|
+
/* @__PURE__ */ jsx5("p", { children: "Search" }),
|
|
242
|
+
/* @__PURE__ */ jsxs4("div", { className: "ms-auto font-mono inline-flex gap-0.5", children: [
|
|
243
|
+
/* @__PURE__ */ jsx5("span", { className: "rounded-md border border-gray-200 px-1.5", children: "Ctrl" }),
|
|
244
|
+
/* @__PURE__ */ jsx5("span", { className: "rounded-md border border-gray-200 px-1.5", children: "K" })
|
|
245
|
+
] })
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
),
|
|
249
|
+
docstraConfig.sidebar?.links?.map((group) => /* @__PURE__ */ jsxs4("div", { children: [
|
|
250
|
+
/* @__PURE__ */ jsx5("p", { className: "inline-flex items-center gap-2 mb-2 mt-2 px-2", children: group.section }),
|
|
251
|
+
/* @__PURE__ */ jsx5("ul", { className: "mb-4", children: group.items.map((link) => {
|
|
252
|
+
const Icon = getIcon(link.icon);
|
|
253
|
+
return /* @__PURE__ */ jsx5("li", { children: /* @__PURE__ */ jsxs4(
|
|
254
|
+
Link,
|
|
255
|
+
{
|
|
256
|
+
href: link.href,
|
|
257
|
+
onNavigate: () => openSidebar && setOpenSidebar(false),
|
|
258
|
+
className: cn(
|
|
259
|
+
"flex items-center gap-2 text-gray-500 hover:bg-gray-100 py-2 px-2.5 rounded-lg text-sm",
|
|
260
|
+
pathname === link.href && "bg-gray-100 text-gray-800"
|
|
261
|
+
),
|
|
262
|
+
children: [
|
|
263
|
+
Icon && /* @__PURE__ */ jsx5(Icon, { className: "size-4" }),
|
|
264
|
+
/* @__PURE__ */ jsx5("span", { children: link.name })
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
) }, link.href);
|
|
268
|
+
}) })
|
|
269
|
+
] }, group.section))
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
)
|
|
273
|
+
] });
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// src/client/docs-page.tsx
|
|
277
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
278
|
+
function DocstraPage({ children }) {
|
|
279
|
+
return /* @__PURE__ */ jsx6("div", { className: "min-h-screen flex bg-white w-full", children });
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/client/breadcrumbs.tsx
|
|
283
|
+
import { usePathname as usePathname2 } from "next/navigation";
|
|
284
|
+
import { ChevronRight } from "lucide-react";
|
|
285
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
286
|
+
function DocstraBreadcrumbs() {
|
|
287
|
+
const pathname = usePathname2();
|
|
288
|
+
const paths = pathname.split("/").filter(Boolean);
|
|
289
|
+
const breadcrumbs = paths.map((segment, index) => {
|
|
290
|
+
const href = "/" + paths.slice(0, index + 1).join("/");
|
|
291
|
+
const title = segment.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
292
|
+
return { href, title };
|
|
293
|
+
});
|
|
294
|
+
return /* @__PURE__ */ jsx7("nav", { "aria-label": "Breadcrumb", className: "flex text-sm items-center pb-4 text-gray-500", children: /* @__PURE__ */ jsxs5("ol", { className: "flex items-center space-x-2", children: [
|
|
295
|
+
/* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsx7(Link, { href: "/", className: "hover:text-gray-700 transition-colors font-medium", children: "Home" }) }),
|
|
296
|
+
breadcrumbs.map((crumb, index) => {
|
|
297
|
+
const isLast = index === breadcrumbs.length - 1;
|
|
298
|
+
return /* @__PURE__ */ jsxs5("li", { className: "flex items-center space-x-2", children: [
|
|
299
|
+
/* @__PURE__ */ jsx7(ChevronRight, { className: "w-4 h-4 text-gray-400" }),
|
|
300
|
+
isLast ? /* @__PURE__ */ jsx7("span", { className: "text-gray-600 font-medium", children: crumb.title }) : /* @__PURE__ */ jsx7(Link, { href: crumb.href, className: "hover:text-gray-700 font-medium transition-colors", children: crumb.title })
|
|
301
|
+
] }, crumb.href);
|
|
302
|
+
})
|
|
303
|
+
] }) });
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// src/client/page-buttons.tsx
|
|
307
|
+
import { CheckIcon, CopyIcon } from "lucide-react";
|
|
308
|
+
import { usePathname as usePathname3 } from "next/navigation";
|
|
309
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
310
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
311
|
+
function DocstraPageButtons({ rawMdxContent }) {
|
|
312
|
+
const [isCopied, setIsCopied] = useState3(false);
|
|
313
|
+
const [href, setHref] = useState3(null);
|
|
314
|
+
const pathname = usePathname3();
|
|
315
|
+
useEffect3(() => {
|
|
316
|
+
setHref(window.location.href);
|
|
317
|
+
}, []);
|
|
318
|
+
const prompt = `Read from this URL: ${href + pathname} and explain it to me.`;
|
|
319
|
+
const handleCopy = () => {
|
|
320
|
+
navigator.clipboard.writeText(rawMdxContent);
|
|
321
|
+
setIsCopied(true);
|
|
322
|
+
setTimeout(() => setIsCopied(false), 3e3);
|
|
323
|
+
};
|
|
324
|
+
return /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3 mt-6", children: [
|
|
325
|
+
/* @__PURE__ */ jsxs6(
|
|
326
|
+
"button",
|
|
327
|
+
{
|
|
328
|
+
title: "Copy Markdown",
|
|
329
|
+
onClick: handleCopy,
|
|
330
|
+
className: "flex items-center gap-2 bg-gray-50 hover:bg-gray-100 border border-gray-200 px-3 py-2 rounded-md text-xs",
|
|
331
|
+
children: [
|
|
332
|
+
isCopied ? /* @__PURE__ */ jsx8(CheckIcon, { className: "size-3.5" }) : /* @__PURE__ */ jsx8(CopyIcon, { className: "size-3.5" }),
|
|
333
|
+
"Copy Markdown"
|
|
334
|
+
]
|
|
335
|
+
}
|
|
336
|
+
),
|
|
337
|
+
/* @__PURE__ */ jsx8(
|
|
338
|
+
"a",
|
|
339
|
+
{
|
|
340
|
+
title: "Ask ChatGPT",
|
|
341
|
+
href: `https://chatgpt.com/?hints=search&q=${encodeURIComponent(prompt)}`,
|
|
342
|
+
className: "flex items-center gap-2 bg-gray-50 hover:bg-gray-100 border border-gray-200 px-3 py-2 rounded-md text-xs",
|
|
343
|
+
rel: "noreferrer noopener",
|
|
344
|
+
children: "Ask ChatGPT"
|
|
345
|
+
}
|
|
346
|
+
)
|
|
347
|
+
] });
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// src/client/docstra-page-head.tsx
|
|
351
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
352
|
+
function DocstraPageHead({ metadata, mdxContent }) {
|
|
353
|
+
return /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
354
|
+
/* @__PURE__ */ jsx9("h1", { className: "text-3xl font-bold", children: metadata.title }),
|
|
355
|
+
/* @__PURE__ */ jsx9("p", { className: "my-4 text-gray-500", children: metadata.description }),
|
|
356
|
+
/* @__PURE__ */ jsx9(DocstraPageButtons, { rawMdxContent: mdxContent }),
|
|
357
|
+
/* @__PURE__ */ jsx9("hr", { className: "my-10 border-gray-200" })
|
|
358
|
+
] });
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/client/feedback.tsx
|
|
362
|
+
import { useState as useState4 } from "react";
|
|
363
|
+
import { ThumbsUp, ThumbsDown } from "lucide-react";
|
|
364
|
+
|
|
365
|
+
// src/client/input.tsx
|
|
366
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
367
|
+
function Input({
|
|
368
|
+
label,
|
|
369
|
+
type,
|
|
370
|
+
placeholder = "",
|
|
371
|
+
id,
|
|
372
|
+
required = false,
|
|
373
|
+
onChange,
|
|
374
|
+
value,
|
|
375
|
+
readOnly = false,
|
|
376
|
+
className = "",
|
|
377
|
+
optional = false
|
|
378
|
+
}) {
|
|
379
|
+
return /* @__PURE__ */ jsxs8("div", { className: cn("flex flex-col mt-4 w-full", className), children: [
|
|
380
|
+
label && /* @__PURE__ */ jsxs8("label", { htmlFor: id, className: "font-medium w-max cursor-pointer", children: [
|
|
381
|
+
label,
|
|
382
|
+
optional && /* @__PURE__ */ jsx10("span", { className: "text-xs font-normal text-gray-400 ml-1 mt-1", children: "(Optional)" })
|
|
383
|
+
] }),
|
|
384
|
+
type === "textarea" ? /* @__PURE__ */ jsx10(
|
|
385
|
+
"textarea",
|
|
386
|
+
{
|
|
387
|
+
id,
|
|
388
|
+
name: id,
|
|
389
|
+
className: cn(
|
|
390
|
+
"mt-2 w-full p-3 border border-gray-300 resize-none not-focus:hover:border-gray-500 read-only:text-gray-400/80 outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-all duration-200 rounded-lg",
|
|
391
|
+
className
|
|
392
|
+
),
|
|
393
|
+
placeholder,
|
|
394
|
+
required,
|
|
395
|
+
onChange,
|
|
396
|
+
rows: 4,
|
|
397
|
+
value,
|
|
398
|
+
readOnly
|
|
399
|
+
}
|
|
400
|
+
) : /* @__PURE__ */ jsx10(
|
|
401
|
+
"input",
|
|
402
|
+
{
|
|
403
|
+
type,
|
|
404
|
+
id,
|
|
405
|
+
name: id,
|
|
406
|
+
className: "mt-2 w-full h-12 px-3 border border-gray-300 not-focus:hover:border-gray-500 read-only:text-gray-400/80 outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-all duration-200 rounded-lg",
|
|
407
|
+
placeholder,
|
|
408
|
+
required,
|
|
409
|
+
onChange,
|
|
410
|
+
value,
|
|
411
|
+
readOnly
|
|
412
|
+
}
|
|
413
|
+
)
|
|
414
|
+
] });
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// src/client/button.tsx
|
|
418
|
+
import { Loader2Icon } from "lucide-react";
|
|
419
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
420
|
+
function Button({ label, loading, type = "submit", className = "", disabled = false, onClick }) {
|
|
421
|
+
return /* @__PURE__ */ jsx11(
|
|
422
|
+
"button",
|
|
423
|
+
{
|
|
424
|
+
type,
|
|
425
|
+
disabled,
|
|
426
|
+
className: cn(
|
|
427
|
+
"relative w-full mt-4 h-12 px-6 py-3 font-medium bg-gray-900 hover:opacity-85 text-white rounded-lg",
|
|
428
|
+
className
|
|
429
|
+
),
|
|
430
|
+
"aria-label": label,
|
|
431
|
+
onClick,
|
|
432
|
+
children: loading ? /* @__PURE__ */ jsx11(Loader2Icon, { className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 animate-spin mx-auto" }) : label
|
|
433
|
+
}
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// src/client/feedback.tsx
|
|
438
|
+
import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
439
|
+
function DocstraFeedback() {
|
|
440
|
+
const [opinion, setOpinion] = useState4(null);
|
|
441
|
+
const { docstraConfig } = useDocstra();
|
|
442
|
+
const [message, setMessage] = useState4("");
|
|
443
|
+
const [submitted, setSubmitted] = useState4(false);
|
|
444
|
+
return /* @__PURE__ */ jsx12("div", { className: "border-y border-gray-200 mt-20 py-10 space-y-4", children: submitted ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
445
|
+
/* @__PURE__ */ jsx12("p", { className: "font-medium text-gray-900", children: "Thank you for your feedback!" }),
|
|
446
|
+
/* @__PURE__ */ jsx12(
|
|
447
|
+
Button,
|
|
448
|
+
{
|
|
449
|
+
onClick: () => {
|
|
450
|
+
setSubmitted(false);
|
|
451
|
+
setOpinion(null);
|
|
452
|
+
setMessage("");
|
|
453
|
+
},
|
|
454
|
+
label: "Submit Again",
|
|
455
|
+
className: "w-max text-sm"
|
|
456
|
+
}
|
|
457
|
+
)
|
|
458
|
+
] }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
459
|
+
/* @__PURE__ */ jsx12("p", { className: "font-medium", children: "How is this guide?" }),
|
|
460
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex gap-2", children: [
|
|
461
|
+
/* @__PURE__ */ jsxs9(
|
|
462
|
+
"button",
|
|
463
|
+
{
|
|
464
|
+
onClick: () => setOpinion("good"),
|
|
465
|
+
className: `flex items-center gap-1 px-3 py-2 rounded-full border text-sm ${opinion === "good" ? "bg-green-100 text-green-600 border-green-300" : "border-gray-200 text-gray-600 hover:bg-gray-100"}`,
|
|
466
|
+
children: [
|
|
467
|
+
/* @__PURE__ */ jsx12(ThumbsUp, { className: `size-4 ${opinion === "good" ? "fill-green-600" : "text-gray-500"}` }),
|
|
468
|
+
"Good"
|
|
469
|
+
]
|
|
470
|
+
}
|
|
471
|
+
),
|
|
472
|
+
/* @__PURE__ */ jsxs9(
|
|
473
|
+
"button",
|
|
474
|
+
{
|
|
475
|
+
onClick: () => setOpinion("bad"),
|
|
476
|
+
className: `flex items-center gap-1 px-3 py-2 rounded-full border text-sm ${opinion === "bad" ? "bg-red-100 text-red-600 border-red-300" : "border-gray-200 text-gray-600 hover:bg-gray-100"}`,
|
|
477
|
+
children: [
|
|
478
|
+
/* @__PURE__ */ jsx12(
|
|
479
|
+
ThumbsDown,
|
|
480
|
+
{
|
|
481
|
+
className: `size-4 pt-0.5 ${opinion === "bad" ? "fill-red-600" : "text-gray-500"}`
|
|
482
|
+
}
|
|
483
|
+
),
|
|
484
|
+
"Bad"
|
|
485
|
+
]
|
|
486
|
+
}
|
|
487
|
+
)
|
|
488
|
+
] }),
|
|
489
|
+
opinion && /* @__PURE__ */ jsxs9(
|
|
490
|
+
"form",
|
|
491
|
+
{
|
|
492
|
+
className: "flex flex-col gap-2",
|
|
493
|
+
action: `https://formsync.app/v1/s/${docstraConfig?.formSyncFormID || "your-form-id"}`,
|
|
494
|
+
method: "POST",
|
|
495
|
+
children: [
|
|
496
|
+
/* @__PURE__ */ jsx12(
|
|
497
|
+
Input,
|
|
498
|
+
{
|
|
499
|
+
value: message,
|
|
500
|
+
id: "message",
|
|
501
|
+
onChange: (e) => setMessage(e.target.value),
|
|
502
|
+
placeholder: "Leave your feedback...",
|
|
503
|
+
required: true,
|
|
504
|
+
type: "textarea"
|
|
505
|
+
}
|
|
506
|
+
),
|
|
507
|
+
/* @__PURE__ */ jsx12("input", { type: "hidden", name: "opinion", value: opinion }),
|
|
508
|
+
/* @__PURE__ */ jsx12("input", { type: "hidden", name: "page", value: window.location.href }),
|
|
509
|
+
/* @__PURE__ */ jsx12("input", { type: "hidden", name: "_redirect", value: window.location.href }),
|
|
510
|
+
/* @__PURE__ */ jsx12(Button, { label: "Submit", className: "w-max text-sm" }),
|
|
511
|
+
/* @__PURE__ */ jsxs9("p", { className: "text-left text-sm text-gray-500 mt-6", children: [
|
|
512
|
+
"Powered by",
|
|
513
|
+
" ",
|
|
514
|
+
/* @__PURE__ */ jsx12("a", { href: "https://www.formsync.app?utm_source=formsync-docs", className: "text-gray-800", children: "FormSync" })
|
|
515
|
+
] })
|
|
516
|
+
]
|
|
517
|
+
}
|
|
518
|
+
)
|
|
519
|
+
] }) });
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// src/client/pagination.tsx
|
|
523
|
+
import { usePathname as usePathname4 } from "next/navigation";
|
|
524
|
+
import Link2 from "next/link";
|
|
525
|
+
import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react";
|
|
526
|
+
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
527
|
+
function DocstraPagination() {
|
|
528
|
+
const pathname = usePathname4();
|
|
529
|
+
const { docstraConfig } = useDocstra();
|
|
530
|
+
const flatLinks = docstraConfig?.sidebar?.links?.flatMap((section) => section.items);
|
|
531
|
+
const currentIndex = flatLinks.findIndex((item) => item.href === pathname);
|
|
532
|
+
const prev = currentIndex > 0 ? flatLinks[currentIndex - 1] : null;
|
|
533
|
+
const next = currentIndex < flatLinks.length - 1 ? flatLinks[currentIndex + 1] : null;
|
|
534
|
+
return /* @__PURE__ */ jsxs10("div", { className: "flex flex-col md:flex-row gap-2 justify-between py-10 mt-10", children: [
|
|
535
|
+
prev ? /* @__PURE__ */ jsxs10(
|
|
536
|
+
Link2,
|
|
537
|
+
{
|
|
538
|
+
href: prev.href,
|
|
539
|
+
className: "flex flex-col items-start gap-2 hover:bg-gray-100 py-3 md:min-w-52 pl-4 pr-10 rounded-lg text-sm",
|
|
540
|
+
children: [
|
|
541
|
+
/* @__PURE__ */ jsx13("span", { className: "text-gray-500", children: "Previous" }),
|
|
542
|
+
/* @__PURE__ */ jsxs10("p", { className: "flex items-center font-medium", children: [
|
|
543
|
+
/* @__PURE__ */ jsx13(ArrowLeftIcon, { className: "size-5 mr-2" }),
|
|
544
|
+
prev.name
|
|
545
|
+
] })
|
|
546
|
+
]
|
|
547
|
+
}
|
|
548
|
+
) : /* @__PURE__ */ jsx13("div", {}),
|
|
549
|
+
next ? /* @__PURE__ */ jsxs10(
|
|
550
|
+
Link2,
|
|
551
|
+
{
|
|
552
|
+
href: next.href,
|
|
553
|
+
className: "flex flex-col items-end gap-2 hover:bg-gray-100 py-3 pr-4 md:min-w-52 pl-10 rounded-lg text-sm",
|
|
554
|
+
children: [
|
|
555
|
+
/* @__PURE__ */ jsx13("span", { className: "text-gray-500", children: "Next" }),
|
|
556
|
+
/* @__PURE__ */ jsxs10("p", { className: "flex items-center font-medium", children: [
|
|
557
|
+
next.name,
|
|
558
|
+
/* @__PURE__ */ jsx13(ArrowRightIcon, { className: "size-5 ml-2" })
|
|
559
|
+
] })
|
|
560
|
+
]
|
|
561
|
+
}
|
|
562
|
+
) : /* @__PURE__ */ jsx13("div", {})
|
|
563
|
+
] });
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// src/client/docs-body.tsx
|
|
567
|
+
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
568
|
+
function DocstraBody({ children, metadata, mdxContent }) {
|
|
569
|
+
return /* @__PURE__ */ jsxs11("main", { className: "flex-1 px-4 md:px-8 py-10 max-w-full text-base/7", children: [
|
|
570
|
+
/* @__PURE__ */ jsx14(DocstraBreadcrumbs, {}),
|
|
571
|
+
/* @__PURE__ */ jsx14(DocstraPageHead, { metadata, mdxContent }),
|
|
572
|
+
children,
|
|
573
|
+
/* @__PURE__ */ jsx14(DocstraFeedback, {}),
|
|
574
|
+
/* @__PURE__ */ jsx14(DocstraPagination, {})
|
|
575
|
+
] });
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// src/client/docstra-toc.tsx
|
|
579
|
+
import { ArrowUpCircleIcon, SquareArrowOutUpRightIcon, TextAlignStartIcon } from "lucide-react";
|
|
580
|
+
import { usePathname as usePathname5 } from "next/navigation";
|
|
581
|
+
import { useEffect as useEffect4, useRef, useState as useState5 } from "react";
|
|
582
|
+
|
|
583
|
+
// src/utils/generate-id-from-text.ts
|
|
584
|
+
function generateIdFromText(text) {
|
|
585
|
+
return text.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// src/utils/extract-headings-from-mdx.ts
|
|
589
|
+
function extractHeadingsFromMdx(raw) {
|
|
590
|
+
const lines = raw.split("\n");
|
|
591
|
+
const results = [];
|
|
592
|
+
let currentH2 = null;
|
|
593
|
+
for (let line of lines) {
|
|
594
|
+
line = line.trim();
|
|
595
|
+
const h2Match = line.match(/^##\s+(.*)/);
|
|
596
|
+
const h3Match = line.match(/^###\s+(.*)/);
|
|
597
|
+
if (h2Match) {
|
|
598
|
+
const text = h2Match[1].trim();
|
|
599
|
+
const id = generateIdFromText(text);
|
|
600
|
+
currentH2 = { id, text, children: [] };
|
|
601
|
+
results.push(currentH2);
|
|
602
|
+
}
|
|
603
|
+
if (h3Match && currentH2) {
|
|
604
|
+
const text = h3Match[1].trim();
|
|
605
|
+
const id = generateIdFromText(text);
|
|
606
|
+
currentH2.children.push({ id, text });
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return results;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// src/client/docstra-toc.tsx
|
|
613
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
614
|
+
function DocstraTOC({ mdxFilePath, rawMdxContent }) {
|
|
615
|
+
const [headings, setHeadings] = useState5([]);
|
|
616
|
+
const [activeId, setActiveId] = useState5(null);
|
|
617
|
+
const [scrollDir, setScrollDir] = useState5("down");
|
|
618
|
+
const [isScrolled, setIsScrolled] = useState5(false);
|
|
619
|
+
const [isManualClick, setIsManualClick] = useState5(false);
|
|
620
|
+
const { docstraConfig } = useDocstra();
|
|
621
|
+
const lastScrollY = useRef(0);
|
|
622
|
+
const observerRef = useRef(null);
|
|
623
|
+
const pathname = usePathname5();
|
|
624
|
+
const baseUrlOfGithub = docstraConfig?.githubRepo || "https://github.com/sudhucodes/docstra/edit/main";
|
|
625
|
+
const githubLink = baseUrlOfGithub + mdxFilePath.split("app")[1];
|
|
626
|
+
useEffect4(() => {
|
|
627
|
+
const onScroll = () => {
|
|
628
|
+
const currentY = window.scrollY;
|
|
629
|
+
setScrollDir(currentY > lastScrollY.current ? "down" : "up");
|
|
630
|
+
setIsScrolled(currentY > 100);
|
|
631
|
+
lastScrollY.current = currentY;
|
|
632
|
+
};
|
|
633
|
+
window.addEventListener("scroll", onScroll);
|
|
634
|
+
return () => window.removeEventListener("scroll", onScroll);
|
|
635
|
+
}, []);
|
|
636
|
+
useEffect4(() => {
|
|
637
|
+
const structured = extractHeadingsFromMdx(rawMdxContent);
|
|
638
|
+
setHeadings(structured);
|
|
639
|
+
}, [rawMdxContent]);
|
|
640
|
+
useEffect4(() => {
|
|
641
|
+
const allHeadings = document.querySelectorAll(`h2[id], h3[id]`);
|
|
642
|
+
const observer = new IntersectionObserver(
|
|
643
|
+
(entries) => {
|
|
644
|
+
if (isManualClick) return;
|
|
645
|
+
const visible = entries.filter((e) => e.isIntersecting).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);
|
|
646
|
+
if (visible.length > 0) {
|
|
647
|
+
const nextActive = scrollDir === "down" ? visible[0].target.id : visible[visible.length - 1].target.id;
|
|
648
|
+
setActiveId(nextActive);
|
|
649
|
+
}
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
rootMargin: "-40% 0px -50% 0px",
|
|
653
|
+
threshold: [0, 0.2, 0.6, 1]
|
|
654
|
+
}
|
|
655
|
+
);
|
|
656
|
+
allHeadings.forEach((heading) => observer.observe(heading));
|
|
657
|
+
observerRef.current = observer;
|
|
658
|
+
return () => observer.disconnect();
|
|
659
|
+
}, [pathname, scrollDir, isManualClick]);
|
|
660
|
+
useEffect4(() => {
|
|
661
|
+
const scrolled = window.scrollY > 100;
|
|
662
|
+
!scrolled && setActiveId(headings[0]?.id);
|
|
663
|
+
}, [headings]);
|
|
664
|
+
useEffect4(() => {
|
|
665
|
+
if (!isManualClick) return;
|
|
666
|
+
const timer = setTimeout(() => setIsManualClick(false), 800);
|
|
667
|
+
return () => clearTimeout(timer);
|
|
668
|
+
}, [isManualClick]);
|
|
669
|
+
const handleClick = (id) => {
|
|
670
|
+
setActiveId(id);
|
|
671
|
+
setIsManualClick(true);
|
|
672
|
+
};
|
|
673
|
+
return /* @__PURE__ */ jsxs12("aside", { className: "sticky top-18 text-sm hidden xl:block text-gray-500 shrink-0 h-[calc(100svh-72px)] w-64 border-l border-gray-200 p-6 overflow-y-auto", children: [
|
|
674
|
+
/* @__PURE__ */ jsxs12("p", { className: "flex items-center gap-2 mb-5", children: [
|
|
675
|
+
/* @__PURE__ */ jsx15(TextAlignStartIcon, { className: "size-4" }),
|
|
676
|
+
"On this page"
|
|
677
|
+
] }),
|
|
678
|
+
/* @__PURE__ */ jsx15("ul", { children: headings.map((h2) => /* @__PURE__ */ jsxs12("li", { children: [
|
|
679
|
+
/* @__PURE__ */ jsx15(TableOfContentsLink, { heading: h2, activeId, handleClick }),
|
|
680
|
+
h2.children.map((h3) => /* @__PURE__ */ jsx15(
|
|
681
|
+
TableOfContentsLink,
|
|
682
|
+
{
|
|
683
|
+
heading: h3,
|
|
684
|
+
activeId,
|
|
685
|
+
handleClick,
|
|
686
|
+
className: "pl-8"
|
|
687
|
+
},
|
|
688
|
+
h3.id
|
|
689
|
+
))
|
|
690
|
+
] }, h2.id)) }),
|
|
691
|
+
/* @__PURE__ */ jsx15("hr", { className: "my-6 border-gray-200" }),
|
|
692
|
+
docstraConfig.editOnGithub && /* @__PURE__ */ jsxs12(
|
|
693
|
+
"a",
|
|
694
|
+
{
|
|
695
|
+
href: githubLink,
|
|
696
|
+
rel: "noopener noreferrer",
|
|
697
|
+
className: "flex items-center gap-2 text-gray-400 hover:text-gray-700 transition",
|
|
698
|
+
children: [
|
|
699
|
+
"Edit this page on GitHub",
|
|
700
|
+
/* @__PURE__ */ jsx15(SquareArrowOutUpRightIcon, { className: "size-4" })
|
|
701
|
+
]
|
|
702
|
+
}
|
|
703
|
+
),
|
|
704
|
+
isScrolled && /* @__PURE__ */ jsxs12(
|
|
705
|
+
"button",
|
|
706
|
+
{
|
|
707
|
+
onClick: () => scrollTo({ top: 0, behavior: "smooth" }),
|
|
708
|
+
className: "flex items-center gap-2 mt-3 text-gray-400 hover:text-gray-700 transition",
|
|
709
|
+
children: [
|
|
710
|
+
"Scroll to top",
|
|
711
|
+
/* @__PURE__ */ jsx15(ArrowUpCircleIcon, { className: "size-4" })
|
|
712
|
+
]
|
|
713
|
+
}
|
|
714
|
+
)
|
|
715
|
+
] });
|
|
716
|
+
}
|
|
717
|
+
function TableOfContentsLink({ heading, activeId, handleClick, className }) {
|
|
718
|
+
return /* @__PURE__ */ jsx15(
|
|
719
|
+
"a",
|
|
720
|
+
{
|
|
721
|
+
href: `#${heading.id}`,
|
|
722
|
+
className: cn("border-l border-gray-200 block py-1.5 pl-4 transition-colors", className, {
|
|
723
|
+
"border-gray-800 text-gray-900 font-medium": activeId === heading.id,
|
|
724
|
+
"hover:text-gray-800 hover:border-gray-400": activeId !== heading.id
|
|
725
|
+
}),
|
|
726
|
+
onClick: () => handleClick(heading.id),
|
|
727
|
+
children: heading.text
|
|
728
|
+
}
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// src/client/code-block.tsx
|
|
733
|
+
import { useEffect as useEffect5, useState as useState6 } from "react";
|
|
734
|
+
import { Highlight, themes } from "prism-react-renderer";
|
|
735
|
+
import { CheckIcon as CheckIcon2, CopyIcon as CopyIcon2 } from "lucide-react";
|
|
736
|
+
import { toast as toast2 } from "react-toast-msg";
|
|
737
|
+
import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
738
|
+
function DocstraCodeBlock(props) {
|
|
739
|
+
const { className, children } = props.children?.props || props;
|
|
740
|
+
if (!className || !className.startsWith("language-")) {
|
|
741
|
+
return /* @__PURE__ */ jsx16("code", { className: "px-1 py-0.5 rounded border border-gray-200 text-gray-800 text-sm", children });
|
|
742
|
+
}
|
|
743
|
+
const language = className.replace("language-", "") || "text";
|
|
744
|
+
const code = typeof children === "string" ? children.trim() : Array.isArray(children) ? children.join("").trim() : "";
|
|
745
|
+
const [copied, setCopied] = useState6(false);
|
|
746
|
+
const handleCopy = () => {
|
|
747
|
+
navigator.clipboard.writeText(code);
|
|
748
|
+
toast2.success("Copied to clipboard!");
|
|
749
|
+
setCopied(true);
|
|
750
|
+
};
|
|
751
|
+
useEffect5(() => {
|
|
752
|
+
if (copied) {
|
|
753
|
+
const timeout = setTimeout(() => setCopied(false), 2e3);
|
|
754
|
+
return () => clearTimeout(timeout);
|
|
755
|
+
}
|
|
756
|
+
}, [copied]);
|
|
757
|
+
return /* @__PURE__ */ jsxs13("div", { className: "max-w-2xl overflow-hidden rounded-lg text-sm text-gray-800 border border-gray-200/80 mt-4", children: [
|
|
758
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center bg-gray-50 justify-between border-b border-gray-200/80", children: [
|
|
759
|
+
/* @__PURE__ */ jsx16("div", { className: "text-xs text-gray-400 p-4", children: language }),
|
|
760
|
+
/* @__PURE__ */ jsx16(
|
|
761
|
+
"button",
|
|
762
|
+
{
|
|
763
|
+
onClick: handleCopy,
|
|
764
|
+
className: "rounded aspect-square p-2 m-2 text-xs hover:bg-gray-200 transition",
|
|
765
|
+
children: copied ? /* @__PURE__ */ jsx16(CheckIcon2, { className: "size-4" }) : /* @__PURE__ */ jsx16(CopyIcon2, { className: "size-4" })
|
|
766
|
+
}
|
|
767
|
+
)
|
|
768
|
+
] }),
|
|
769
|
+
/* @__PURE__ */ jsx16(Highlight, { code, language, theme: themes.nightOwlLight, children: ({ style, tokens, getLineProps, getTokenProps }) => /* @__PURE__ */ jsx16("pre", { className: "p-4 font-mono whitespace-pre scrollbar-x overflow-x-auto", style, children: tokens.map((line, i) => /* @__PURE__ */ jsx16("div", { ...getLineProps({ line }), children: line.map((token, key) => /* @__PURE__ */ jsx16("span", { ...getTokenProps({ token }) }, key)) }, i)) }) })
|
|
770
|
+
] });
|
|
771
|
+
}
|
|
772
|
+
export {
|
|
773
|
+
DocstraBody,
|
|
774
|
+
DocstraCodeBlock,
|
|
775
|
+
DocstraHeader,
|
|
776
|
+
DocstraPage,
|
|
777
|
+
DocstraProvider,
|
|
778
|
+
DocstraSidebar,
|
|
779
|
+
DocstraTOC,
|
|
780
|
+
useDocstra
|
|
781
|
+
};
|