@btst/stack 1.7.0 → 1.9.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.
Files changed (110) hide show
  1. package/dist/api/index.d.cts +2 -2
  2. package/dist/api/index.d.mts +2 -2
  3. package/dist/api/index.d.ts +2 -2
  4. package/dist/client/index.cjs +6 -2
  5. package/dist/client/index.d.cts +2 -1
  6. package/dist/client/index.d.mts +2 -1
  7. package/dist/client/index.d.ts +2 -1
  8. package/dist/client/index.mjs +6 -2
  9. package/dist/index.d.cts +1 -1
  10. package/dist/index.d.mts +1 -1
  11. package/dist/index.d.ts +1 -1
  12. package/dist/packages/better-stack/src/plugins/cms/api/plugin.cjs +445 -16
  13. package/dist/packages/better-stack/src/plugins/cms/api/plugin.mjs +445 -16
  14. package/dist/packages/better-stack/src/plugins/cms/client/components/forms/content-form.cjs +24 -7
  15. package/dist/packages/better-stack/src/plugins/cms/client/components/forms/content-form.mjs +25 -8
  16. package/dist/packages/better-stack/src/plugins/cms/client/components/forms/relation-field.cjs +224 -0
  17. package/dist/packages/better-stack/src/plugins/cms/client/components/forms/relation-field.mjs +222 -0
  18. package/dist/packages/better-stack/src/plugins/cms/client/components/inverse-relations-panel.cjs +243 -0
  19. package/dist/packages/better-stack/src/plugins/cms/client/components/inverse-relations-panel.mjs +241 -0
  20. package/dist/packages/better-stack/src/plugins/cms/client/components/pages/content-editor-page.internal.cjs +56 -2
  21. package/dist/packages/better-stack/src/plugins/cms/client/components/pages/content-editor-page.internal.mjs +56 -2
  22. package/dist/packages/better-stack/src/plugins/cms/client/hooks/cms-hooks.cjs +190 -0
  23. package/dist/packages/better-stack/src/plugins/cms/client/hooks/cms-hooks.mjs +187 -1
  24. package/dist/packages/better-stack/src/plugins/cms/db.cjs +38 -0
  25. package/dist/packages/better-stack/src/plugins/cms/db.mjs +38 -0
  26. package/dist/packages/better-stack/src/plugins/route-docs/client/components/loading/docs-skeleton.cjs +43 -0
  27. package/dist/packages/better-stack/src/plugins/route-docs/client/components/loading/docs-skeleton.mjs +41 -0
  28. package/dist/packages/better-stack/src/plugins/route-docs/client/components/pages/docs-page.cjs +794 -0
  29. package/dist/packages/better-stack/src/plugins/route-docs/client/components/pages/docs-page.mjs +788 -0
  30. package/dist/packages/better-stack/src/plugins/route-docs/client/plugin.cjs +111 -0
  31. package/dist/packages/better-stack/src/plugins/route-docs/client/plugin.mjs +106 -0
  32. package/dist/packages/better-stack/src/plugins/route-docs/generator.cjs +244 -0
  33. package/dist/packages/better-stack/src/plugins/route-docs/generator.mjs +227 -0
  34. package/dist/packages/ui/src/components/auto-form/fields/object.cjs +81 -1
  35. package/dist/packages/ui/src/components/auto-form/fields/object.mjs +81 -1
  36. package/dist/packages/ui/src/components/dialog.cjs +6 -0
  37. package/dist/packages/ui/src/components/dialog.mjs +6 -1
  38. package/dist/packages/ui/src/components/sheet.cjs +25 -0
  39. package/dist/packages/ui/src/components/sheet.mjs +24 -1
  40. package/dist/plugins/api/index.d.cts +2 -2
  41. package/dist/plugins/api/index.d.mts +2 -2
  42. package/dist/plugins/api/index.d.ts +2 -2
  43. package/dist/plugins/blog/api/index.d.cts +1 -1
  44. package/dist/plugins/blog/api/index.d.mts +1 -1
  45. package/dist/plugins/blog/api/index.d.ts +1 -1
  46. package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
  47. package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
  48. package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
  49. package/dist/plugins/blog/client/index.d.cts +1 -1
  50. package/dist/plugins/blog/client/index.d.mts +1 -1
  51. package/dist/plugins/blog/client/index.d.ts +1 -1
  52. package/dist/plugins/blog/query-keys.d.cts +2 -2
  53. package/dist/plugins/blog/query-keys.d.mts +2 -2
  54. package/dist/plugins/blog/query-keys.d.ts +2 -2
  55. package/dist/plugins/client/index.d.cts +2 -2
  56. package/dist/plugins/client/index.d.mts +2 -2
  57. package/dist/plugins/client/index.d.ts +2 -2
  58. package/dist/plugins/cms/api/index.d.cts +67 -3
  59. package/dist/plugins/cms/api/index.d.mts +67 -3
  60. package/dist/plugins/cms/api/index.d.ts +67 -3
  61. package/dist/plugins/cms/client/hooks/index.cjs +4 -0
  62. package/dist/plugins/cms/client/hooks/index.d.cts +82 -3
  63. package/dist/plugins/cms/client/hooks/index.d.mts +82 -3
  64. package/dist/plugins/cms/client/hooks/index.d.ts +82 -3
  65. package/dist/plugins/cms/client/hooks/index.mjs +1 -1
  66. package/dist/plugins/cms/query-keys.d.cts +1 -1
  67. package/dist/plugins/cms/query-keys.d.mts +1 -1
  68. package/dist/plugins/cms/query-keys.d.ts +1 -1
  69. package/dist/plugins/form-builder/api/index.d.cts +1 -1
  70. package/dist/plugins/form-builder/api/index.d.mts +1 -1
  71. package/dist/plugins/form-builder/api/index.d.ts +1 -1
  72. package/dist/plugins/open-api/api/index.d.cts +1 -1
  73. package/dist/plugins/open-api/api/index.d.mts +1 -1
  74. package/dist/plugins/open-api/api/index.d.ts +1 -1
  75. package/dist/plugins/route-docs/client/index.cjs +10 -0
  76. package/dist/plugins/route-docs/client/index.d.cts +126 -0
  77. package/dist/plugins/route-docs/client/index.d.mts +126 -0
  78. package/dist/plugins/route-docs/client/index.d.ts +126 -0
  79. package/dist/plugins/route-docs/client/index.mjs +1 -0
  80. package/dist/plugins/route-docs/client.css +3 -0
  81. package/dist/plugins/route-docs/style.css +19 -0
  82. package/dist/shared/{stack.L-UFwz2G.d.mts → stack.oGOteE6g.d.cts} +27 -5
  83. package/dist/shared/{stack.L-UFwz2G.d.ts → stack.oGOteE6g.d.mts} +27 -5
  84. package/dist/shared/{stack.L-UFwz2G.d.cts → stack.oGOteE6g.d.ts} +27 -5
  85. package/dist/shared/{stack.CSce37mX.d.cts → stack.u9iYV6vt.d.cts} +14 -2
  86. package/dist/shared/{stack.CSce37mX.d.mts → stack.u9iYV6vt.d.mts} +14 -2
  87. package/dist/shared/{stack.CSce37mX.d.ts → stack.u9iYV6vt.d.ts} +14 -2
  88. package/package.json +15 -1
  89. package/src/client/index.ts +11 -4
  90. package/src/plugins/cms/api/plugin.ts +667 -21
  91. package/src/plugins/cms/client/components/forms/content-form.tsx +60 -18
  92. package/src/plugins/cms/client/components/forms/relation-field.tsx +299 -0
  93. package/src/plugins/cms/client/components/inverse-relations-panel.tsx +329 -0
  94. package/src/plugins/cms/client/components/pages/content-editor-page.internal.tsx +127 -1
  95. package/src/plugins/cms/client/hooks/cms-hooks.tsx +344 -0
  96. package/src/plugins/cms/db.ts +38 -0
  97. package/src/plugins/cms/types.ts +99 -10
  98. package/src/plugins/route-docs/client/components/loading/docs-skeleton.tsx +82 -0
  99. package/src/plugins/route-docs/client/components/loading/index.tsx +1 -0
  100. package/src/plugins/route-docs/client/components/pages/docs-page.tsx +1240 -0
  101. package/src/plugins/route-docs/client/index.ts +7 -0
  102. package/src/plugins/route-docs/client/plugin.tsx +187 -0
  103. package/src/plugins/route-docs/client.css +3 -0
  104. package/src/plugins/route-docs/generator.ts +385 -0
  105. package/src/plugins/route-docs/index.ts +12 -0
  106. package/src/plugins/route-docs/style.css +19 -0
  107. package/src/types.ts +19 -1
  108. package/dist/shared/{stack.CcI4sYJP.d.mts → stack.DLhzx1-D.d.cts} +1 -1
  109. package/dist/shared/{stack.CcI4sYJP.d.ts → stack.DLhzx1-D.d.mts} +1 -1
  110. package/dist/shared/{stack.CcI4sYJP.d.cts → stack.DLhzx1-D.d.ts} +1 -1
@@ -0,0 +1,794 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const React = require('react');
6
+ const card = require('../../../../../../../ui/src/components/card.cjs');
7
+ const badge = require('../../../../../../../ui/src/components/badge.cjs');
8
+ const scrollArea = require('../../../../../../../ui/src/components/scroll-area.cjs');
9
+ const separator = require('../../../../../../../ui/src/components/separator.cjs');
10
+ const table = require('../../../../../../../ui/src/components/table.cjs');
11
+ const button = require('../../../../../../../ui/src/components/button.cjs');
12
+ const input = require('../../../../../../../ui/src/components/input.cjs');
13
+ const label = require('../../../../../../../ui/src/components/label.cjs');
14
+ const sheet = require('../../../../../../../ui/src/components/sheet.cjs');
15
+ const lucideReact = require('lucide-react');
16
+ const reactQuery = require('@tanstack/react-query');
17
+ const plugin = require('../../plugin.cjs');
18
+
19
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
20
+
21
+ const React__default = /*#__PURE__*/_interopDefaultCompat(React);
22
+
23
+ function escapeRegexForRoutePath(path) {
24
+ const PARAM_PLACEHOLDER = "\0PARAM\0";
25
+ const WILDCARD_PLACEHOLDER = "\0WILDCARD\0";
26
+ let result = path.replace(/:[^/]+/g, PARAM_PLACEHOLDER).replace(/\*/g, WILDCARD_PLACEHOLDER);
27
+ result = result.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
28
+ result = result.replace(new RegExp(PARAM_PLACEHOLDER, "g"), "[^/]+").replace(new RegExp(WILDCARD_PLACEHOLDER, "g"), ".*");
29
+ return result;
30
+ }
31
+ function HighlightedPath({ path }) {
32
+ const parts = path.split("/");
33
+ return /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-xl break-all", children: parts.map((part, i) => {
34
+ const isParam = part.startsWith(":") || part.startsWith("*");
35
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__default.Fragment, { children: [
36
+ i > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "/" }),
37
+ isParam ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary font-semibold", children: part }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: part })
38
+ ] }, i);
39
+ }) });
40
+ }
41
+ function ParameterCard({ param }) {
42
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border p-4 space-y-2", children: [
43
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
44
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-sm text-primary font-semibold", children: param.name }),
45
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
46
+ /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "secondary", className: "font-mono text-xs", children: param.type }),
47
+ /* @__PURE__ */ jsxRuntime.jsx(
48
+ badge.Badge,
49
+ {
50
+ variant: param.required ? "destructive" : "outline",
51
+ className: "text-xs",
52
+ children: param.required ? "required" : "optional"
53
+ }
54
+ )
55
+ ] })
56
+ ] }),
57
+ param.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: param.description }),
58
+ param.schema?.enum && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground", children: [
59
+ "Values: ",
60
+ param.schema.enum.join(" | ")
61
+ ] })
62
+ ] });
63
+ }
64
+ function ParametersSection({
65
+ params,
66
+ title
67
+ }) {
68
+ if (params.length === 0) return null;
69
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
70
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-muted-foreground uppercase tracking-wide", children: title }),
71
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:block rounded-lg border overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(table.Table, { children: [
72
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(table.TableRow, { children: [
73
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[150px]", children: "Name" }),
74
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[120px]", children: "Type" }),
75
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[100px]", children: "Required" }),
76
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { children: "Description" })
77
+ ] }) }),
78
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableBody, { children: params.map((param) => /* @__PURE__ */ jsxRuntime.jsxs(table.TableRow, { children: [
79
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-sm text-primary", children: param.name }) }),
80
+ /* @__PURE__ */ jsxRuntime.jsxs(table.TableCell, { children: [
81
+ /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "secondary", className: "font-mono text-xs", children: param.type }),
82
+ param.schema?.enum && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-2 text-xs text-muted-foreground", children: [
83
+ "(",
84
+ param.schema.enum.join(" | "),
85
+ ")"
86
+ ] })
87
+ ] }),
88
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsx(
89
+ badge.Badge,
90
+ {
91
+ variant: param.required ? "destructive" : "outline",
92
+ className: "text-xs",
93
+ children: param.required ? "required" : "optional"
94
+ }
95
+ ) }),
96
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { className: "text-muted-foreground", children: param.description || "\u2014" })
97
+ ] }, param.name)) })
98
+ ] }) }),
99
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:hidden space-y-3", children: params.map((param) => /* @__PURE__ */ jsxRuntime.jsx(ParameterCard, { param }, param.name)) })
100
+ ] });
101
+ }
102
+ function NavigationForm({
103
+ route,
104
+ siteBasePath
105
+ }) {
106
+ const [paramValues, setParamValues] = React.useState({});
107
+ const handleParamChange = (name, value) => {
108
+ setParamValues((prev) => ({ ...prev, [name]: value }));
109
+ };
110
+ const buildUrl = () => {
111
+ let url = route.path;
112
+ for (const param of route.pathParams) {
113
+ const value = paramValues[param.name] || `{${param.name}}`;
114
+ if (param.name === "_") {
115
+ url = url.replace("*", value);
116
+ } else if (url.includes(`*:${param.name}`)) {
117
+ url = url.replace(`*:${param.name}`, value);
118
+ } else {
119
+ url = url.replace(`:${param.name}`, value);
120
+ }
121
+ }
122
+ return `${siteBasePath}${url}`;
123
+ };
124
+ const handleVisit = () => {
125
+ const url = buildUrl();
126
+ const hasUnfilledParams = route.pathParams.some(
127
+ (p) => !paramValues[p.name]
128
+ );
129
+ if (hasUnfilledParams) {
130
+ return;
131
+ }
132
+ window.open(url, "_blank");
133
+ };
134
+ const allParamsFilled = route.pathParams.every((p) => paramValues[p.name]);
135
+ const previewUrl = buildUrl();
136
+ return /* @__PURE__ */ jsxRuntime.jsxs(card.Card, { children: [
137
+ /* @__PURE__ */ jsxRuntime.jsx(card.CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsxs(card.CardTitle, { className: "text-base flex items-center gap-2", children: [
138
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Navigation, { className: "h-4 w-4" }),
139
+ "Navigate to Route"
140
+ ] }) }),
141
+ /* @__PURE__ */ jsxRuntime.jsx(card.CardContent, { className: "space-y-4", children: route.pathParams.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
142
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-4 grid-cols-1 sm:grid-cols-2", children: route.pathParams.map((param) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
143
+ /* @__PURE__ */ jsxRuntime.jsxs(label.Label, { htmlFor: `param-${param.name}`, className: "font-mono", children: [
144
+ ":",
145
+ param.name
146
+ ] }),
147
+ /* @__PURE__ */ jsxRuntime.jsx(
148
+ input.Input,
149
+ {
150
+ id: `param-${param.name}`,
151
+ placeholder: `Enter ${param.name}...`,
152
+ value: paramValues[param.name] || "",
153
+ onChange: (e) => handleParamChange(param.name, e.target.value)
154
+ }
155
+ )
156
+ ] }, param.name)) }),
157
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row items-stretch sm:items-center gap-3 pt-2", children: [
158
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "flex-1 text-xs bg-muted px-3 py-2 rounded-md font-mono text-muted-foreground break-all", children: previewUrl }),
159
+ /* @__PURE__ */ jsxRuntime.jsxs(
160
+ button.Button,
161
+ {
162
+ onClick: handleVisit,
163
+ disabled: !allParamsFilled,
164
+ className: "shrink-0",
165
+ children: [
166
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-4 w-4 mr-2" }),
167
+ "Visit"
168
+ ]
169
+ }
170
+ )
171
+ ] })
172
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row items-stretch sm:items-center gap-3", children: [
173
+ /* @__PURE__ */ jsxRuntime.jsxs("code", { className: "flex-1 text-sm bg-muted px-3 py-2 rounded-md font-mono break-all", children: [
174
+ siteBasePath,
175
+ route.path
176
+ ] }),
177
+ /* @__PURE__ */ jsxRuntime.jsxs(
178
+ button.Button,
179
+ {
180
+ onClick: () => window.open(`${siteBasePath}${route.path}`, "_blank"),
181
+ className: "shrink-0",
182
+ children: [
183
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-4 w-4 mr-2" }),
184
+ "Visit"
185
+ ]
186
+ }
187
+ )
188
+ ] }) })
189
+ ] });
190
+ }
191
+ function getMatchingSitemapEntries(route, sitemapEntries) {
192
+ const hasParams = route.pathParams.length > 0;
193
+ if (!hasParams) {
194
+ return sitemapEntries.filter((e) => {
195
+ try {
196
+ const url = new URL(e.url);
197
+ return url.pathname.endsWith(route.path);
198
+ } catch {
199
+ return false;
200
+ }
201
+ });
202
+ } else {
203
+ const routePattern = escapeRegexForRoutePath(route.path);
204
+ const regex = new RegExp(`${routePattern}$`);
205
+ return sitemapEntries.filter((e) => {
206
+ try {
207
+ const url = new URL(e.url);
208
+ return regex.test(url.pathname);
209
+ } catch {
210
+ return false;
211
+ }
212
+ });
213
+ }
214
+ }
215
+ function RouteSitemapSection({
216
+ route,
217
+ sitemapEntries
218
+ }) {
219
+ const matchingEntries = React.useMemo(
220
+ () => getMatchingSitemapEntries(route, sitemapEntries),
221
+ [route, sitemapEntries]
222
+ );
223
+ if (matchingEntries.length === 0) return null;
224
+ return /* @__PURE__ */ jsxRuntime.jsxs(card.Card, { children: [
225
+ /* @__PURE__ */ jsxRuntime.jsx(card.CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsxs(card.CardTitle, { className: "text-base flex items-center gap-2", children: [
226
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { className: "h-4 w-4" }),
227
+ "Sitemap Entries",
228
+ /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "secondary", className: "ml-1", children: matchingEntries.length })
229
+ ] }) }),
230
+ /* @__PURE__ */ jsxRuntime.jsxs(card.CardContent, { children: [
231
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:block rounded-lg border overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(table.Table, { children: [
232
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(table.TableRow, { children: [
233
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { children: "URL" }),
234
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[120px]", children: "Last Modified" }),
235
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[80px]", children: "Priority" }),
236
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[80px]", children: "Actions" })
237
+ ] }) }),
238
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableBody, { children: matchingEntries.map((entry, idx) => /* @__PURE__ */ jsxRuntime.jsxs(table.TableRow, { children: [
239
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsx(
240
+ "a",
241
+ {
242
+ href: entry.url,
243
+ target: "_blank",
244
+ rel: "noopener noreferrer",
245
+ className: "hover:underline",
246
+ children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-xs text-primary truncate block max-w-[400px]", children: entry.url })
247
+ }
248
+ ) }),
249
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { className: "text-xs text-muted-foreground", children: formatDate(entry.lastModified) }),
250
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { className: "text-xs text-muted-foreground", children: entry.priority !== void 0 ? entry.priority : "\u2014" }),
251
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsx(
252
+ button.Button,
253
+ {
254
+ variant: "ghost",
255
+ size: "sm",
256
+ className: "h-7 px-2",
257
+ onClick: () => window.open(entry.url, "_blank"),
258
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3" })
259
+ }
260
+ ) })
261
+ ] }, idx)) })
262
+ ] }) }),
263
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:hidden space-y-3", children: matchingEntries.map((entry, idx) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border p-3 space-y-2", children: [
264
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
265
+ /* @__PURE__ */ jsxRuntime.jsx(
266
+ "a",
267
+ {
268
+ href: entry.url,
269
+ target: "_blank",
270
+ rel: "noopener noreferrer",
271
+ className: "font-mono text-xs text-primary break-all hover:underline",
272
+ children: entry.url
273
+ }
274
+ ),
275
+ /* @__PURE__ */ jsxRuntime.jsx(
276
+ button.Button,
277
+ {
278
+ variant: "ghost",
279
+ size: "sm",
280
+ className: "h-7 w-7 p-0 shrink-0",
281
+ onClick: () => window.open(entry.url, "_blank"),
282
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3" })
283
+ }
284
+ )
285
+ ] }),
286
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2 text-xs text-muted-foreground", children: [
287
+ entry.lastModified && /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatDate(entry.lastModified) }),
288
+ entry.priority !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
289
+ "Priority: ",
290
+ entry.priority
291
+ ] })
292
+ ] })
293
+ ] }, idx)) })
294
+ ] })
295
+ ] });
296
+ }
297
+ function RouteDetail({
298
+ route,
299
+ pluginName,
300
+ sitemapEntries,
301
+ siteBasePath
302
+ }) {
303
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
304
+ route.meta && (route.meta.title || route.meta.description) && /* @__PURE__ */ jsxRuntime.jsxs(card.Card, { children: [
305
+ /* @__PURE__ */ jsxRuntime.jsx(card.CardHeader, { className: "pb-3", children: route.meta.title && /* @__PURE__ */ jsxRuntime.jsx(card.CardTitle, { className: "text-lg sm:text-xl", children: route.meta.title }) }),
306
+ (route.meta.description || route.meta.tags && route.meta.tags.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs(card.CardContent, { className: "space-y-3", children: [
307
+ route.meta.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-sm sm:text-base", children: route.meta.description }),
308
+ route.meta.tags && route.meta.tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: route.meta.tags.map((tag) => /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "secondary", children: tag }, tag)) })
309
+ ] })
310
+ ] }),
311
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center gap-3 flex-wrap", children: [
312
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-mono overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx(HighlightedPath, { path: route.path }) }),
313
+ /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "outline", children: pluginName })
314
+ ] }),
315
+ /* @__PURE__ */ jsxRuntime.jsx(NavigationForm, { route, siteBasePath }),
316
+ /* @__PURE__ */ jsxRuntime.jsx(ParametersSection, { params: route.pathParams, title: "Path Parameters" }),
317
+ /* @__PURE__ */ jsxRuntime.jsx(ParametersSection, { params: route.queryParams, title: "Query Parameters" }),
318
+ /* @__PURE__ */ jsxRuntime.jsx(RouteSitemapSection, { route, sitemapEntries })
319
+ ] });
320
+ }
321
+ function getRouteAnchorId(pluginKey, routeKey) {
322
+ return `route-${pluginKey}-${routeKey}`;
323
+ }
324
+ function SidebarRouteItem({
325
+ route,
326
+ pluginKey,
327
+ onNavigate
328
+ }) {
329
+ const anchorId = getRouteAnchorId(pluginKey, route.key);
330
+ const handleClick = (e) => {
331
+ e.preventDefault();
332
+ const element = document.getElementById(anchorId);
333
+ if (element) {
334
+ element.scrollIntoView({ behavior: "smooth", block: "start" });
335
+ window.history.pushState(null, "", `#${anchorId}`);
336
+ }
337
+ onNavigate?.();
338
+ };
339
+ return /* @__PURE__ */ jsxRuntime.jsxs(
340
+ "a",
341
+ {
342
+ href: `#${anchorId}`,
343
+ onClick: handleClick,
344
+ className: "flex items-center w-full justify-start font-mono text-xs h-auto py-2 px-3 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors",
345
+ children: [
346
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "mr-2 h-3 w-3 shrink-0" }),
347
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: route.path })
348
+ ]
349
+ }
350
+ );
351
+ }
352
+ function SidebarPluginGroup({
353
+ plugin,
354
+ onNavigate
355
+ }) {
356
+ const [isExpanded, setIsExpanded] = React.useState(true);
357
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
358
+ /* @__PURE__ */ jsxRuntime.jsxs(
359
+ button.Button,
360
+ {
361
+ variant: "ghost",
362
+ size: "sm",
363
+ className: "w-full justify-between font-medium h-auto py-2",
364
+ onClick: () => setIsExpanded(!isExpanded),
365
+ children: [
366
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center", children: [
367
+ isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpen, { className: "mr-2 h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Folder, { className: "mr-2 h-4 w-4" }),
368
+ plugin.name
369
+ ] }),
370
+ /* @__PURE__ */ jsxRuntime.jsx(
371
+ lucideReact.ChevronRight,
372
+ {
373
+ className: `h-4 w-4 transition-transform ${isExpanded ? "rotate-90" : ""}`
374
+ }
375
+ )
376
+ ]
377
+ }
378
+ ),
379
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-2 space-y-0.5", children: plugin.routes.map((route) => /* @__PURE__ */ jsxRuntime.jsx(
380
+ SidebarRouteItem,
381
+ {
382
+ route,
383
+ pluginKey: plugin.key,
384
+ onNavigate
385
+ },
386
+ route.key
387
+ )) })
388
+ ] });
389
+ }
390
+ function SidebarContent({
391
+ schema,
392
+ onNavigate
393
+ }) {
394
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 space-y-4", children: schema.plugins.map((plugin) => /* @__PURE__ */ jsxRuntime.jsx(
395
+ SidebarPluginGroup,
396
+ {
397
+ plugin,
398
+ onNavigate
399
+ },
400
+ plugin.key
401
+ )) });
402
+ }
403
+ function RouteCard({
404
+ pluginName,
405
+ route,
406
+ hasParams,
407
+ staticUrl,
408
+ sitemapCount = 0,
409
+ onSelect
410
+ }) {
411
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border p-4 space-y-3", children: [
412
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
413
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onSelect, className: "text-left hover:underline", children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-sm text-primary break-all", children: route.path }) }),
414
+ staticUrl ? /* @__PURE__ */ jsxRuntime.jsx(
415
+ button.Button,
416
+ {
417
+ variant: "ghost",
418
+ size: "sm",
419
+ className: "h-8 w-8 p-0 shrink-0",
420
+ onClick: () => window.open(staticUrl, "_blank"),
421
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-4 w-4" })
422
+ }
423
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
424
+ button.Button,
425
+ {
426
+ variant: "ghost",
427
+ size: "sm",
428
+ className: "h-8 w-8 p-0 shrink-0",
429
+ onClick: onSelect,
430
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Navigation, { className: "h-4 w-4" })
431
+ }
432
+ )
433
+ ] }),
434
+ route.meta?.title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: route.meta.title }),
435
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
436
+ /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "outline", className: "text-xs", children: pluginName }),
437
+ hasParams && /* @__PURE__ */ jsxRuntime.jsxs(badge.Badge, { variant: "secondary", className: "text-xs", children: [
438
+ route.pathParams.length,
439
+ " param",
440
+ route.pathParams.length > 1 ? "s" : ""
441
+ ] }),
442
+ sitemapCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(badge.Badge, { variant: "secondary", className: "text-xs", children: [
443
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2, { className: "h-3 w-3 mr-1" }),
444
+ sitemapCount,
445
+ " in sitemap"
446
+ ] })
447
+ ] })
448
+ ] });
449
+ }
450
+ function formatDate(date) {
451
+ if (!date) return "\u2014";
452
+ const d = typeof date === "string" ? new Date(date) : date;
453
+ return d.toLocaleDateString(void 0, {
454
+ year: "numeric",
455
+ month: "short",
456
+ day: "numeric"
457
+ });
458
+ }
459
+ function SitemapSection({
460
+ entries,
461
+ schema
462
+ }) {
463
+ const [isExpanded, setIsExpanded] = React.useState(false);
464
+ const getPluginName = (pluginKey) => {
465
+ const plugin = schema.plugins.find((p) => p.key === pluginKey);
466
+ return plugin?.name || pluginKey;
467
+ };
468
+ if (entries.length === 0) return null;
469
+ const displayedEntries = isExpanded ? entries : entries.slice(0, 10);
470
+ const hasMore = entries.length > 10;
471
+ return /* @__PURE__ */ jsxRuntime.jsxs(card.Card, { children: [
472
+ /* @__PURE__ */ jsxRuntime.jsx(card.CardHeader, { className: "pb-3 sm:pb-6", children: /* @__PURE__ */ jsxRuntime.jsxs(card.CardTitle, { className: "text-lg flex items-center gap-2", children: [
473
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { className: "h-5 w-5" }),
474
+ "Sitemap Entries",
475
+ /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "secondary", className: "ml-2", children: entries.length })
476
+ ] }) }),
477
+ /* @__PURE__ */ jsxRuntime.jsxs(card.CardContent, { children: [
478
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:block rounded-lg border overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(table.Table, { children: [
479
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(table.TableRow, { children: [
480
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { children: "URL" }),
481
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[100px]", children: "Plugin" }),
482
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[120px]", children: "Last Modified" }),
483
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[80px]", children: "Actions" })
484
+ ] }) }),
485
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableBody, { children: displayedEntries.map((entry, idx) => /* @__PURE__ */ jsxRuntime.jsxs(table.TableRow, { children: [
486
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsx(
487
+ "a",
488
+ {
489
+ href: entry.url,
490
+ target: "_blank",
491
+ rel: "noopener noreferrer",
492
+ className: "hover:underline",
493
+ children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-xs text-primary truncate block max-w-[400px]", children: entry.url })
494
+ }
495
+ ) }),
496
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "outline", className: "text-xs", children: getPluginName(entry.pluginKey) }) }),
497
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { className: "text-xs text-muted-foreground", children: formatDate(entry.lastModified) }),
498
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsx(
499
+ button.Button,
500
+ {
501
+ variant: "ghost",
502
+ size: "sm",
503
+ className: "h-7 px-2",
504
+ onClick: () => window.open(entry.url, "_blank"),
505
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3" })
506
+ }
507
+ ) })
508
+ ] }, `${entry.pluginKey}-${idx}`)) })
509
+ ] }) }),
510
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:hidden space-y-3", children: displayedEntries.map((entry, idx) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border p-3 space-y-2", children: [
511
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
512
+ /* @__PURE__ */ jsxRuntime.jsx(
513
+ "a",
514
+ {
515
+ href: entry.url,
516
+ target: "_blank",
517
+ rel: "noopener noreferrer",
518
+ className: "font-mono text-xs text-primary break-all hover:underline",
519
+ children: entry.url
520
+ }
521
+ ),
522
+ /* @__PURE__ */ jsxRuntime.jsx(
523
+ button.Button,
524
+ {
525
+ variant: "ghost",
526
+ size: "sm",
527
+ className: "h-7 w-7 p-0 shrink-0",
528
+ onClick: () => window.open(entry.url, "_blank"),
529
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3" })
530
+ }
531
+ )
532
+ ] }),
533
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2 text-xs text-muted-foreground", children: [
534
+ /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "outline", className: "text-xs", children: getPluginName(entry.pluginKey) }),
535
+ entry.lastModified && /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatDate(entry.lastModified) })
536
+ ] })
537
+ ] }, idx)) }),
538
+ hasMore && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(
539
+ button.Button,
540
+ {
541
+ variant: "outline",
542
+ size: "sm",
543
+ onClick: () => setIsExpanded(!isExpanded),
544
+ children: isExpanded ? "Show less" : `Show all ${entries.length} entries`
545
+ }
546
+ ) })
547
+ ] })
548
+ ] });
549
+ }
550
+ function AllRoutesSection({
551
+ schema,
552
+ siteBasePath
553
+ }) {
554
+ const scrollToRoute = (pluginKey, routeKey) => {
555
+ const anchorId = getRouteAnchorId(pluginKey, routeKey);
556
+ const element = document.getElementById(anchorId);
557
+ if (element) {
558
+ element.scrollIntoView({ behavior: "smooth", block: "start" });
559
+ window.history.pushState(null, "", `#${anchorId}`);
560
+ }
561
+ };
562
+ const allRoutes = React.useMemo(() => {
563
+ const routes = [];
564
+ for (const plugin of schema.plugins) {
565
+ for (const route of plugin.routes) {
566
+ const hasParams = route.pathParams.length > 0;
567
+ let sitemapCount = 0;
568
+ if (!hasParams) {
569
+ sitemapCount = plugin.sitemapEntries.filter((e) => {
570
+ try {
571
+ const url = new URL(e.url);
572
+ return url.pathname.endsWith(route.path);
573
+ } catch {
574
+ return false;
575
+ }
576
+ }).length;
577
+ } else {
578
+ const routePattern = escapeRegexForRoutePath(route.path);
579
+ const regex = new RegExp(`${routePattern}$`);
580
+ sitemapCount = plugin.sitemapEntries.filter((e) => {
581
+ try {
582
+ const url = new URL(e.url);
583
+ return regex.test(url.pathname);
584
+ } catch {
585
+ return false;
586
+ }
587
+ }).length;
588
+ }
589
+ routes.push({
590
+ pluginKey: plugin.key,
591
+ pluginName: plugin.name,
592
+ route,
593
+ hasParams,
594
+ staticUrl: hasParams ? null : `${siteBasePath}${route.path}`,
595
+ sitemapCount
596
+ });
597
+ }
598
+ }
599
+ return routes;
600
+ }, [schema, siteBasePath]);
601
+ if (allRoutes.length === 0) return null;
602
+ return /* @__PURE__ */ jsxRuntime.jsxs(card.Card, { children: [
603
+ /* @__PURE__ */ jsxRuntime.jsx(card.CardHeader, { className: "pb-3 sm:pb-6", children: /* @__PURE__ */ jsxRuntime.jsx(card.CardTitle, { className: "text-lg", children: "All Routes" }) }),
604
+ /* @__PURE__ */ jsxRuntime.jsxs(card.CardContent, { children: [
605
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:block rounded-lg border overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(table.Table, { children: [
606
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(table.TableRow, { children: [
607
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { children: "Route" }),
608
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[100px]", children: "Plugin" }),
609
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[80px]", children: "Params" }),
610
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[80px]", children: "Sitemap" }),
611
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableHead, { className: "w-[80px]", children: "Actions" })
612
+ ] }) }),
613
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableBody, { children: allRoutes.map(
614
+ ({
615
+ pluginKey,
616
+ pluginName,
617
+ route,
618
+ hasParams,
619
+ staticUrl,
620
+ sitemapCount
621
+ }) => /* @__PURE__ */ jsxRuntime.jsxs(table.TableRow, { children: [
622
+ /* @__PURE__ */ jsxRuntime.jsxs(table.TableCell, { children: [
623
+ /* @__PURE__ */ jsxRuntime.jsx(
624
+ "button",
625
+ {
626
+ onClick: () => scrollToRoute(pluginKey, route.key),
627
+ className: "text-left hover:underline",
628
+ children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-sm text-primary", children: route.path })
629
+ }
630
+ ),
631
+ route.meta?.title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-1", children: route.meta.title })
632
+ ] }),
633
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "outline", className: "text-xs", children: pluginName }) }),
634
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { children: hasParams ? /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { variant: "secondary", className: "text-xs", children: route.pathParams.length }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "\u2014" }) }),
635
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { children: sitemapCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(badge.Badge, { variant: "secondary", className: "text-xs", children: [
636
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2, { className: "h-3 w-3 mr-1" }),
637
+ sitemapCount
638
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "\u2014" }) }),
639
+ /* @__PURE__ */ jsxRuntime.jsx(table.TableCell, { children: staticUrl ? /* @__PURE__ */ jsxRuntime.jsx(
640
+ button.Button,
641
+ {
642
+ variant: "ghost",
643
+ size: "sm",
644
+ className: "h-7 px-2",
645
+ onClick: () => window.open(staticUrl, "_blank"),
646
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3" })
647
+ }
648
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
649
+ button.Button,
650
+ {
651
+ variant: "ghost",
652
+ size: "sm",
653
+ className: "h-7 px-2",
654
+ onClick: () => scrollToRoute(pluginKey, route.key),
655
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Navigation, { className: "h-3 w-3" })
656
+ }
657
+ ) })
658
+ ] }, `${pluginKey}-${route.key}`)
659
+ ) })
660
+ ] }) }),
661
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:hidden space-y-3", children: allRoutes.map(
662
+ ({
663
+ pluginKey,
664
+ pluginName,
665
+ route,
666
+ hasParams,
667
+ staticUrl,
668
+ sitemapCount
669
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
670
+ RouteCard,
671
+ {
672
+ pluginName,
673
+ route,
674
+ hasParams,
675
+ staticUrl,
676
+ sitemapCount,
677
+ onSelect: () => scrollToRoute(pluginKey, route.key)
678
+ },
679
+ `${pluginKey}-${route.key}`
680
+ )
681
+ ) })
682
+ ] })
683
+ ] });
684
+ }
685
+ function DocsPageComponent({
686
+ title = "Route Documentation",
687
+ description = "Documentation for all client routes in your application",
688
+ siteBasePath = "/pages"
689
+ }) {
690
+ const { data: schema } = reactQuery.useSuspenseQuery({
691
+ queryKey: plugin.ROUTE_DOCS_QUERY_KEY,
692
+ queryFn: plugin.generateSchema,
693
+ staleTime: Infinity
694
+ // Don't refetch - schema is static for this session
695
+ });
696
+ const [mobileMenuOpen, setMobileMenuOpen] = React.useState(false);
697
+ const totalRoutes = schema.plugins.reduce(
698
+ (sum, p) => sum + p.routes.length,
699
+ 0
700
+ );
701
+ const handleMobileNavigate = () => {
702
+ setMobileMenuOpen(false);
703
+ };
704
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-screen bg-background", children: [
705
+ /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "hidden md:block w-72 border-r bg-card shrink-0 sticky top-0 h-screen", children: [
706
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 border-b", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "font-semibold text-sm text-muted-foreground uppercase tracking-wide", children: "Routes" }) }),
707
+ /* @__PURE__ */ jsxRuntime.jsx(scrollArea.ScrollArea, { className: "h-[calc(100vh-57px)]", children: /* @__PURE__ */ jsxRuntime.jsx(SidebarContent, { schema }) })
708
+ ] }),
709
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:hidden fixed top-0 left-0 right-0 z-40 bg-card border-b", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-4", children: [
710
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "font-semibold text-sm text-muted-foreground uppercase tracking-wide", children: "Route Docs" }),
711
+ /* @__PURE__ */ jsxRuntime.jsxs(sheet.Sheet, { open: mobileMenuOpen, onOpenChange: setMobileMenuOpen, children: [
712
+ /* @__PURE__ */ jsxRuntime.jsx(sheet.SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(button.Button, { variant: "outline", size: "sm", children: [
713
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "h-4 w-4 mr-2" }),
714
+ "Routes"
715
+ ] }) }),
716
+ /* @__PURE__ */ jsxRuntime.jsxs(sheet.SheetContent, { side: "left", className: "w-80 p-0", children: [
717
+ /* @__PURE__ */ jsxRuntime.jsx(sheet.SheetHeader, { className: "p-4 border-b", children: /* @__PURE__ */ jsxRuntime.jsx(sheet.SheetTitle, { className: "text-left text-sm text-muted-foreground uppercase tracking-wide", children: "Routes" }) }),
718
+ /* @__PURE__ */ jsxRuntime.jsx(scrollArea.ScrollArea, { className: "h-[calc(100vh-57px)]", children: /* @__PURE__ */ jsxRuntime.jsx(
719
+ SidebarContent,
720
+ {
721
+ schema,
722
+ onNavigate: handleMobileNavigate
723
+ }
724
+ ) })
725
+ ] })
726
+ ] })
727
+ ] }) }),
728
+ /* @__PURE__ */ jsxRuntime.jsx("main", { className: "flex-1 overflow-auto pt-16 md:pt-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-4xl mx-auto p-4 sm:p-6 lg:p-8", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6 sm:space-y-8", children: [
729
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
730
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl sm:text-3xl font-bold tracking-tight", children: title }),
731
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mt-2 text-sm sm:text-base", children: description })
732
+ ] }),
733
+ /* @__PURE__ */ jsxRuntime.jsx(separator.Separator, {}),
734
+ totalRoutes > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
735
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
736
+ /* @__PURE__ */ jsxRuntime.jsxs(badge.Badge, { variant: "secondary", children: [
737
+ schema.plugins.length,
738
+ " plugins"
739
+ ] }),
740
+ /* @__PURE__ */ jsxRuntime.jsxs(badge.Badge, { variant: "secondary", children: [
741
+ totalRoutes,
742
+ " routes"
743
+ ] }),
744
+ schema.allSitemapEntries.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(badge.Badge, { variant: "secondary", children: [
745
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { className: "h-3 w-3 mr-1" }),
746
+ schema.allSitemapEntries.length,
747
+ " sitemap entries"
748
+ ] })
749
+ ] }),
750
+ /* @__PURE__ */ jsxRuntime.jsx(AllRoutesSection, { schema, siteBasePath }),
751
+ schema.plugins.map((plugin) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
752
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 pt-4", children: [
753
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Folder, { className: "h-6 w-6 text-muted-foreground" }),
754
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold", children: plugin.name }),
755
+ /* @__PURE__ */ jsxRuntime.jsxs(badge.Badge, { variant: "outline", children: [
756
+ plugin.routes.length,
757
+ " routes"
758
+ ] })
759
+ ] }),
760
+ plugin.routes.map((route) => /* @__PURE__ */ jsxRuntime.jsx(
761
+ "div",
762
+ {
763
+ id: getRouteAnchorId(plugin.key, route.key),
764
+ className: "scroll-mt-20 md:scroll-mt-4",
765
+ children: /* @__PURE__ */ jsxRuntime.jsx(
766
+ RouteDetail,
767
+ {
768
+ route,
769
+ pluginName: plugin.name,
770
+ sitemapEntries: plugin.sitemapEntries,
771
+ siteBasePath
772
+ }
773
+ )
774
+ },
775
+ route.key
776
+ )),
777
+ /* @__PURE__ */ jsxRuntime.jsx(separator.Separator, {})
778
+ ] }, plugin.key)),
779
+ /* @__PURE__ */ jsxRuntime.jsx(
780
+ SitemapSection,
781
+ {
782
+ entries: schema.allSitemapEntries,
783
+ schema
784
+ }
785
+ )
786
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(card.Card, { children: /* @__PURE__ */ jsxRuntime.jsxs(card.CardContent, { className: "py-8 sm:py-12 text-center", children: [
787
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "No documented routes found." }),
788
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-2", children: "Add client plugins with routes to see documentation here." })
789
+ ] }) })
790
+ ] }) }) })
791
+ ] });
792
+ }
793
+
794
+ exports.DocsPageComponent = DocsPageComponent;