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