blodemd 0.0.15 → 0.2.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 (286) hide show
  1. package/README.md +26 -1
  2. package/dist/cli.mjs +217 -217
  3. package/dist/cli.mjs.map +1 -1
  4. package/package.json +3 -36
  5. package/dev-server/app/[[...slug]]/page.tsx +0 -140
  6. package/dev-server/app/blodemd-dev/invalidate/route.ts +0 -12
  7. package/dev-server/app/blodemd-dev/static/[...path]/route.ts +0 -32
  8. package/dev-server/app/blodemd-dev/version/route.ts +0 -14
  9. package/dev-server/app/blodemd-internal/proxy/route.ts +0 -86
  10. package/dev-server/app/error.tsx +0 -24
  11. package/dev-server/app/favicon.ico +0 -0
  12. package/dev-server/app/globals.css +0 -4
  13. package/dev-server/app/layout.tsx +0 -38
  14. package/dev-server/app/not-found.tsx +0 -18
  15. package/dev-server/app/search/route.ts +0 -17
  16. package/dev-server/components/dev-reload-script.tsx +0 -86
  17. package/dev-server/components/providers.tsx +0 -15
  18. package/dev-server/lib/dev-state.ts +0 -8
  19. package/dev-server/lib/local-content-source.ts +0 -103
  20. package/dev-server/lib/local-runtime.tsx +0 -555
  21. package/dev-server/next-env.d.ts +0 -5
  22. package/dev-server/next.config.js +0 -54
  23. package/dev-server/package.json +0 -61
  24. package/dev-server/postcss.config.mjs +0 -7
  25. package/dev-server/public/glide-variable.woff2 +0 -0
  26. package/dev-server/tsconfig.json +0 -50
  27. package/docs/app/globals.css +0 -471
  28. package/docs/components/animate-ui/primitives/buttons/button.tsx +0 -14
  29. package/docs/components/api/api-playground.tsx +0 -467
  30. package/docs/components/api/api-reference.tsx +0 -157
  31. package/docs/components/content/collection-index.tsx +0 -114
  32. package/docs/components/docs/contextual-menu.tsx +0 -495
  33. package/docs/components/docs/copy-page-menu.tsx +0 -364
  34. package/docs/components/docs/doc-header.tsx +0 -223
  35. package/docs/components/docs/doc-shell.tsx +0 -355
  36. package/docs/components/docs/doc-sidebar.tsx +0 -256
  37. package/docs/components/docs/doc-toc.tsx +0 -46
  38. package/docs/components/docs/mobile-nav.tsx +0 -195
  39. package/docs/components/docs/sidebar-active-highlight.tsx +0 -34
  40. package/docs/components/docs/sidebar-scroll-area.tsx +0 -63
  41. package/docs/components/git/repo-picker.tsx +0 -529
  42. package/docs/components/icons/doc-icon.tsx +0 -96
  43. package/docs/components/mdx/accordion.tsx +0 -83
  44. package/docs/components/mdx/agent-instructions.tsx +0 -17
  45. package/docs/components/mdx/badge.tsx +0 -79
  46. package/docs/components/mdx/callout.tsx +0 -88
  47. package/docs/components/mdx/card.tsx +0 -110
  48. package/docs/components/mdx/code-block.tsx +0 -80
  49. package/docs/components/mdx/code-group.tsx +0 -203
  50. package/docs/components/mdx/color.tsx +0 -87
  51. package/docs/components/mdx/columns.tsx +0 -25
  52. package/docs/components/mdx/expandable.tsx +0 -45
  53. package/docs/components/mdx/field-layout.tsx +0 -77
  54. package/docs/components/mdx/frame.tsx +0 -23
  55. package/docs/components/mdx/get-text-content.ts +0 -18
  56. package/docs/components/mdx/icon.tsx +0 -12
  57. package/docs/components/mdx/iframe.tsx +0 -62
  58. package/docs/components/mdx/index.tsx +0 -121
  59. package/docs/components/mdx/installer.tsx +0 -20
  60. package/docs/components/mdx/panel.tsx +0 -11
  61. package/docs/components/mdx/param-field.tsx +0 -56
  62. package/docs/components/mdx/preview.tsx +0 -36
  63. package/docs/components/mdx/prompt.tsx +0 -63
  64. package/docs/components/mdx/request-example.tsx +0 -27
  65. package/docs/components/mdx/response-field.tsx +0 -42
  66. package/docs/components/mdx/steps.tsx +0 -92
  67. package/docs/components/mdx/tabs.tsx +0 -193
  68. package/docs/components/mdx/tile.tsx +0 -43
  69. package/docs/components/mdx/tooltip.tsx +0 -71
  70. package/docs/components/mdx/tree.tsx +0 -120
  71. package/docs/components/mdx/type-table.tsx +0 -71
  72. package/docs/components/mdx/update.tsx +0 -44
  73. package/docs/components/mdx/video.tsx +0 -45
  74. package/docs/components/mdx/view.tsx +0 -66
  75. package/docs/components/posthog-provider.tsx +0 -42
  76. package/docs/components/providers.tsx +0 -15
  77. package/docs/components/tenant-analytics.tsx +0 -49
  78. package/docs/components/third-parties.tsx +0 -32
  79. package/docs/components/ui/badge.tsx +0 -61
  80. package/docs/components/ui/breadcrumb.tsx +0 -112
  81. package/docs/components/ui/button-group.tsx +0 -83
  82. package/docs/components/ui/button.tsx +0 -65
  83. package/docs/components/ui/card.tsx +0 -92
  84. package/docs/components/ui/command.tsx +0 -167
  85. package/docs/components/ui/copy-button.tsx +0 -129
  86. package/docs/components/ui/dialog.tsx +0 -146
  87. package/docs/components/ui/field.tsx +0 -237
  88. package/docs/components/ui/input.tsx +0 -23
  89. package/docs/components/ui/kbd.tsx +0 -98
  90. package/docs/components/ui/label.tsx +0 -22
  91. package/docs/components/ui/morph-icon.tsx +0 -79
  92. package/docs/components/ui/popover.tsx +0 -267
  93. package/docs/components/ui/search-dialog.tsx +0 -431
  94. package/docs/components/ui/search.tsx +0 -101
  95. package/docs/components/ui/separator.tsx +0 -26
  96. package/docs/components/ui/sheet.tsx +0 -133
  97. package/docs/components/ui/sidebar.tsx +0 -758
  98. package/docs/components/ui/skeleton.tsx +0 -11
  99. package/docs/components/ui/switch.tsx +0 -32
  100. package/docs/components/ui/tabs.tsx +0 -138
  101. package/docs/components/ui/theme-toggle.tsx +0 -62
  102. package/docs/components/ui/tooltip.tsx +0 -53
  103. package/docs/components/web-mcp.tsx +0 -115
  104. package/docs/lib/agent-skills.ts +0 -48
  105. package/docs/lib/api-client.ts +0 -72
  106. package/docs/lib/config.ts +0 -6
  107. package/docs/lib/content-root.ts +0 -33
  108. package/docs/lib/content-source.ts +0 -70
  109. package/docs/lib/contextual-options.ts +0 -222
  110. package/docs/lib/dashboard-session.ts +0 -167
  111. package/docs/lib/db.ts +0 -13
  112. package/docs/lib/docs-collection.ts +0 -7
  113. package/docs/lib/docs-runtime.tsx +0 -745
  114. package/docs/lib/edge-config.ts +0 -95
  115. package/docs/lib/env.ts +0 -23
  116. package/docs/lib/etag.ts +0 -22
  117. package/docs/lib/github-install.ts +0 -33
  118. package/docs/lib/llms-full.ts +0 -82
  119. package/docs/lib/marketing-markdown.ts +0 -79
  120. package/docs/lib/marketing-site.ts +0 -31
  121. package/docs/lib/mdx.ts +0 -98
  122. package/docs/lib/navigation.ts +0 -288
  123. package/docs/lib/openapi-proxy.ts +0 -88
  124. package/docs/lib/openapi.ts +0 -158
  125. package/docs/lib/platform-config.ts +0 -6
  126. package/docs/lib/project-authz.ts +0 -46
  127. package/docs/lib/routes.ts +0 -103
  128. package/docs/lib/server-cache.ts +0 -83
  129. package/docs/lib/shiki.ts +0 -44
  130. package/docs/lib/supabase.ts +0 -37
  131. package/docs/lib/tenancy.ts +0 -364
  132. package/docs/lib/tenant-headers.ts +0 -43
  133. package/docs/lib/tenant-static.ts +0 -705
  134. package/docs/lib/tenant-utility-context.ts +0 -62
  135. package/docs/lib/tenants.ts +0 -72
  136. package/docs/lib/theme.ts +0 -29
  137. package/docs/lib/time-ago.ts +0 -24
  138. package/docs/lib/toc.ts +0 -2
  139. package/docs/lib/use-mobile.ts +0 -19
  140. package/docs/lib/use-tab-observer.ts +0 -71
  141. package/docs/lib/utils.ts +0 -5
  142. package/packages/@repo/common/dist/index.d.ts +0 -16
  143. package/packages/@repo/common/dist/index.d.ts.map +0 -1
  144. package/packages/@repo/common/dist/index.js +0 -84
  145. package/packages/@repo/common/package.json +0 -34
  146. package/packages/@repo/common/src/index.ts +0 -101
  147. package/packages/@repo/contracts/dist/analytics.d.ts +0 -21
  148. package/packages/@repo/contracts/dist/analytics.d.ts.map +0 -1
  149. package/packages/@repo/contracts/dist/analytics.js +0 -18
  150. package/packages/@repo/contracts/dist/dates.d.ts +0 -4
  151. package/packages/@repo/contracts/dist/dates.d.ts.map +0 -1
  152. package/packages/@repo/contracts/dist/dates.js +0 -2
  153. package/packages/@repo/contracts/dist/deployment.d.ts +0 -71
  154. package/packages/@repo/contracts/dist/deployment.d.ts.map +0 -1
  155. package/packages/@repo/contracts/dist/deployment.js +0 -46
  156. package/packages/@repo/contracts/dist/domain.d.ts +0 -94
  157. package/packages/@repo/contracts/dist/domain.d.ts.map +0 -1
  158. package/packages/@repo/contracts/dist/domain.js +0 -36
  159. package/packages/@repo/contracts/dist/git.d.ts +0 -28
  160. package/packages/@repo/contracts/dist/git.d.ts.map +0 -1
  161. package/packages/@repo/contracts/dist/git.js +0 -24
  162. package/packages/@repo/contracts/dist/ids.d.ts +0 -14
  163. package/packages/@repo/contracts/dist/ids.d.ts.map +0 -1
  164. package/packages/@repo/contracts/dist/ids.js +0 -11
  165. package/packages/@repo/contracts/dist/index.d.ts +0 -11
  166. package/packages/@repo/contracts/dist/index.d.ts.map +0 -1
  167. package/packages/@repo/contracts/dist/index.js +0 -12
  168. package/packages/@repo/contracts/dist/pagination.d.ts +0 -23
  169. package/packages/@repo/contracts/dist/pagination.d.ts.map +0 -1
  170. package/packages/@repo/contracts/dist/pagination.js +0 -15
  171. package/packages/@repo/contracts/dist/project.d.ts +0 -42
  172. package/packages/@repo/contracts/dist/project.d.ts.map +0 -1
  173. package/packages/@repo/contracts/dist/project.js +0 -25
  174. package/packages/@repo/contracts/dist/tenant.d.ts +0 -147
  175. package/packages/@repo/contracts/dist/tenant.d.ts.map +0 -1
  176. package/packages/@repo/contracts/dist/tenant.js +0 -58
  177. package/packages/@repo/contracts/dist/user.d.ts +0 -9
  178. package/packages/@repo/contracts/dist/user.d.ts.map +0 -1
  179. package/packages/@repo/contracts/dist/user.js +0 -9
  180. package/packages/@repo/contracts/package.json +0 -37
  181. package/packages/@repo/contracts/src/analytics.ts +0 -33
  182. package/packages/@repo/contracts/src/dates.ts +0 -4
  183. package/packages/@repo/contracts/src/deployment.ts +0 -73
  184. package/packages/@repo/contracts/src/domain.ts +0 -51
  185. package/packages/@repo/contracts/src/git.ts +0 -31
  186. package/packages/@repo/contracts/src/ids.ts +0 -23
  187. package/packages/@repo/contracts/src/index.ts +0 -12
  188. package/packages/@repo/contracts/src/pagination.ts +0 -21
  189. package/packages/@repo/contracts/src/project.ts +0 -32
  190. package/packages/@repo/contracts/src/tenant.ts +0 -94
  191. package/packages/@repo/contracts/src/user.ts +0 -12
  192. package/packages/@repo/models/dist/docs-config.d.ts +0 -961
  193. package/packages/@repo/models/dist/docs-config.d.ts.map +0 -1
  194. package/packages/@repo/models/dist/docs-config.js +0 -531
  195. package/packages/@repo/models/dist/index.d.ts +0 -3
  196. package/packages/@repo/models/dist/index.d.ts.map +0 -1
  197. package/packages/@repo/models/dist/index.js +0 -3
  198. package/packages/@repo/models/dist/tenant.d.ts +0 -37
  199. package/packages/@repo/models/dist/tenant.d.ts.map +0 -1
  200. package/packages/@repo/models/dist/tenant.js +0 -1
  201. package/packages/@repo/models/package.json +0 -37
  202. package/packages/@repo/models/src/docs-config.ts +0 -629
  203. package/packages/@repo/models/src/index.ts +0 -3
  204. package/packages/@repo/models/src/tenant.ts +0 -44
  205. package/packages/@repo/prebuild/dist/index.d.ts +0 -2
  206. package/packages/@repo/prebuild/dist/index.d.ts.map +0 -1
  207. package/packages/@repo/prebuild/dist/index.js +0 -2
  208. package/packages/@repo/prebuild/dist/openapi.d.ts +0 -43
  209. package/packages/@repo/prebuild/dist/openapi.d.ts.map +0 -1
  210. package/packages/@repo/prebuild/dist/openapi.js +0 -86
  211. package/packages/@repo/prebuild/package.json +0 -39
  212. package/packages/@repo/prebuild/src/index.ts +0 -2
  213. package/packages/@repo/prebuild/src/openapi.ts +0 -154
  214. package/packages/@repo/previewing/dist/blob-source.d.ts +0 -16
  215. package/packages/@repo/previewing/dist/blob-source.d.ts.map +0 -1
  216. package/packages/@repo/previewing/dist/blob-source.js +0 -128
  217. package/packages/@repo/previewing/dist/config-loader.d.ts +0 -134
  218. package/packages/@repo/previewing/dist/config-loader.d.ts.map +0 -1
  219. package/packages/@repo/previewing/dist/config-loader.js +0 -231
  220. package/packages/@repo/previewing/dist/constants.d.ts +0 -15
  221. package/packages/@repo/previewing/dist/constants.d.ts.map +0 -1
  222. package/packages/@repo/previewing/dist/constants.js +0 -14
  223. package/packages/@repo/previewing/dist/content-index.d.ts +0 -7
  224. package/packages/@repo/previewing/dist/content-index.d.ts.map +0 -1
  225. package/packages/@repo/previewing/dist/content-index.js +0 -291
  226. package/packages/@repo/previewing/dist/content-source.d.ts +0 -12
  227. package/packages/@repo/previewing/dist/content-source.d.ts.map +0 -1
  228. package/packages/@repo/previewing/dist/content-source.js +0 -1
  229. package/packages/@repo/previewing/dist/fs-source.d.ts +0 -11
  230. package/packages/@repo/previewing/dist/fs-source.d.ts.map +0 -1
  231. package/packages/@repo/previewing/dist/fs-source.js +0 -71
  232. package/packages/@repo/previewing/dist/index.d.ts +0 -16
  233. package/packages/@repo/previewing/dist/index.d.ts.map +0 -1
  234. package/packages/@repo/previewing/dist/index.js +0 -13
  235. package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts +0 -3
  236. package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts.map +0 -1
  237. package/packages/@repo/previewing/dist/markdown/agent-markdown.js +0 -176
  238. package/packages/@repo/previewing/dist/markdown/format.d.ts +0 -8
  239. package/packages/@repo/previewing/dist/markdown/format.d.ts.map +0 -1
  240. package/packages/@repo/previewing/dist/markdown/format.js +0 -43
  241. package/packages/@repo/previewing/dist/markdown/links.d.ts +0 -3
  242. package/packages/@repo/previewing/dist/markdown/links.d.ts.map +0 -1
  243. package/packages/@repo/previewing/dist/markdown/links.js +0 -31
  244. package/packages/@repo/previewing/dist/openapi-pages.d.ts +0 -7
  245. package/packages/@repo/previewing/dist/openapi-pages.d.ts.map +0 -1
  246. package/packages/@repo/previewing/dist/openapi-pages.js +0 -200
  247. package/packages/@repo/previewing/dist/search-index.d.ts +0 -4
  248. package/packages/@repo/previewing/dist/search-index.d.ts.map +0 -1
  249. package/packages/@repo/previewing/dist/search-index.js +0 -23
  250. package/packages/@repo/previewing/dist/serialization.d.ts +0 -13
  251. package/packages/@repo/previewing/dist/serialization.d.ts.map +0 -1
  252. package/packages/@repo/previewing/dist/serialization.js +0 -108
  253. package/packages/@repo/previewing/dist/toc-index.d.ts +0 -5
  254. package/packages/@repo/previewing/dist/toc-index.d.ts.map +0 -1
  255. package/packages/@repo/previewing/dist/toc-index.js +0 -53
  256. package/packages/@repo/previewing/dist/types.d.ts +0 -92
  257. package/packages/@repo/previewing/dist/types.d.ts.map +0 -1
  258. package/packages/@repo/previewing/dist/types.js +0 -1
  259. package/packages/@repo/previewing/dist/utility-index.d.ts +0 -7
  260. package/packages/@repo/previewing/dist/utility-index.d.ts.map +0 -1
  261. package/packages/@repo/previewing/dist/utility-index.js +0 -201
  262. package/packages/@repo/previewing/package.json +0 -41
  263. package/packages/@repo/previewing/src/blob-source.ts +0 -185
  264. package/packages/@repo/previewing/src/config-loader.ts +0 -316
  265. package/packages/@repo/previewing/src/constants.ts +0 -16
  266. package/packages/@repo/previewing/src/content-index.ts +0 -384
  267. package/packages/@repo/previewing/src/content-source.ts +0 -12
  268. package/packages/@repo/previewing/src/fs-source.ts +0 -103
  269. package/packages/@repo/previewing/src/index.ts +0 -71
  270. package/packages/@repo/previewing/src/markdown/agent-markdown.ts +0 -254
  271. package/packages/@repo/previewing/src/markdown/format.ts +0 -63
  272. package/packages/@repo/previewing/src/markdown/links.ts +0 -46
  273. package/packages/@repo/previewing/src/openapi-pages.ts +0 -319
  274. package/packages/@repo/previewing/src/search-index.ts +0 -38
  275. package/packages/@repo/previewing/src/serialization.ts +0 -191
  276. package/packages/@repo/previewing/src/toc-index.ts +0 -72
  277. package/packages/@repo/previewing/src/types.ts +0 -105
  278. package/packages/@repo/previewing/src/utility-index.ts +0 -304
  279. package/packages/@repo/validation/dist/index.d.ts +0 -12
  280. package/packages/@repo/validation/dist/index.d.ts.map +0 -1
  281. package/packages/@repo/validation/dist/index.js +0 -30
  282. package/packages/@repo/validation/package.json +0 -38
  283. package/packages/@repo/validation/src/blodemd-docs-schema.json +0 -3575
  284. package/packages/@repo/validation/src/index.ts +0 -59
  285. package/scripts/prepare-package.mjs +0 -53
  286. package/scripts/repo-packages.mjs +0 -8
@@ -1,431 +0,0 @@
1
- "use client";
2
-
3
- import { SearchIcon } from "blode-icons-react";
4
- import { useRouter } from "next/navigation";
5
- import {
6
- startTransition,
7
- useCallback,
8
- useDeferredValue,
9
- useEffect,
10
- useMemo,
11
- useReducer,
12
- useRef,
13
- } from "react";
14
- import type {
15
- ChangeEvent,
16
- KeyboardEvent as ReactKeyboardEvent,
17
- MouseEvent as ReactMouseEvent,
18
- } from "react";
19
-
20
- import {
21
- Dialog,
22
- DialogContent,
23
- DialogDescription,
24
- DialogTitle,
25
- } from "@/components/ui/dialog";
26
- import { isExternalHref, resolveHref, toDocHref } from "@/lib/routes";
27
-
28
- export interface SearchItem {
29
- href?: string;
30
- title: string;
31
- path: string;
32
- }
33
-
34
- interface SearchResponse {
35
- items: SearchItem[];
36
- }
37
-
38
- type SearchStatus = "idle" | "loading" | "ready" | "error";
39
-
40
- interface SearchState {
41
- activeIndex: number;
42
- items: SearchItem[];
43
- query: string;
44
- status: SearchStatus;
45
- }
46
-
47
- type SearchAction =
48
- | { type: "load-error" }
49
- | { type: "load-start" }
50
- | { items: SearchItem[]; type: "load-success" }
51
- | { type: "reset-query" }
52
- | { index: number; type: "set-active-index" }
53
- | { query: string; type: "set-query" };
54
-
55
- const MAX_RESULTS = 12;
56
- const INITIAL_SEARCH_STATE: SearchState = {
57
- activeIndex: 0,
58
- items: [],
59
- query: "",
60
- status: "idle",
61
- };
62
-
63
- const searchMatches = (item: SearchItem, query: string) => {
64
- if (!query) {
65
- return true;
66
- }
67
-
68
- const haystack =
69
- `${item.title} ${item.path} ${item.href ?? ""}`.toLowerCase();
70
- return haystack.includes(query);
71
- };
72
-
73
- const getWrappedNextIndex = (current: number, length: number) => {
74
- if (length === 0 || current >= length - 1) {
75
- return 0;
76
- }
77
-
78
- return current + 1;
79
- };
80
-
81
- const getWrappedPrevIndex = (current: number, length: number) => {
82
- if (length === 0 || current <= 0) {
83
- return length - 1;
84
- }
85
-
86
- return current - 1;
87
- };
88
-
89
- const searchReducer = (
90
- state: SearchState,
91
- action: SearchAction
92
- ): SearchState => {
93
- switch (action.type) {
94
- case "load-error": {
95
- return {
96
- ...state,
97
- status: "error",
98
- };
99
- }
100
- case "load-start": {
101
- return {
102
- ...state,
103
- status: "loading",
104
- };
105
- }
106
- case "load-success": {
107
- return {
108
- ...state,
109
- items: action.items,
110
- status: "ready",
111
- };
112
- }
113
- case "reset-query": {
114
- return {
115
- ...state,
116
- activeIndex: 0,
117
- query: "",
118
- };
119
- }
120
- case "set-active-index": {
121
- return {
122
- ...state,
123
- activeIndex: action.index,
124
- };
125
- }
126
- case "set-query": {
127
- return {
128
- ...state,
129
- activeIndex: 0,
130
- query: action.query,
131
- };
132
- }
133
- default: {
134
- return state;
135
- }
136
- }
137
- };
138
-
139
- const SearchResults = ({
140
- activeIndex,
141
- basePath,
142
- filteredItems,
143
- onResultClick,
144
- onResultMouseEnter,
145
- status,
146
- }: {
147
- activeIndex: number;
148
- basePath: string;
149
- filteredItems: SearchItem[];
150
- onResultClick: (event: ReactMouseEvent<HTMLButtonElement>) => void;
151
- onResultMouseEnter: (event: ReactMouseEvent<HTMLButtonElement>) => void;
152
- status: SearchStatus;
153
- }) => {
154
- if (status === "loading") {
155
- return (
156
- <div className="px-3 py-10 text-center text-sm text-muted-foreground">
157
- Loading search index...
158
- </div>
159
- );
160
- }
161
-
162
- if (status === "error") {
163
- return (
164
- <div className="px-3 py-10 text-center text-sm text-muted-foreground">
165
- Search is temporarily unavailable.
166
- </div>
167
- );
168
- }
169
-
170
- if (status === "ready" && filteredItems.length === 0) {
171
- return (
172
- <div className="px-3 py-10 text-center text-sm text-muted-foreground">
173
- No results found.
174
- </div>
175
- );
176
- }
177
-
178
- if (status !== "ready") {
179
- return null;
180
- }
181
-
182
- return (
183
- <div className="grid gap-1">
184
- {filteredItems.map((item, index) => {
185
- const href = item.href
186
- ? resolveHref(item.href, basePath)
187
- : toDocHref(item.path, basePath);
188
- const isActive = index === activeIndex;
189
-
190
- return (
191
- <button
192
- className={
193
- isActive
194
- ? "grid gap-1 rounded-xl bg-accent px-3 py-2 text-left text-foreground transition-colors"
195
- : "grid gap-1 rounded-xl px-3 py-2 text-left text-muted-foreground transition-colors hover:bg-accent/70 hover:text-foreground"
196
- }
197
- data-index={index}
198
- key={`${item.path}-${item.href ?? "internal"}`}
199
- onClick={onResultClick}
200
- onMouseEnter={onResultMouseEnter}
201
- type="button"
202
- >
203
- <span className="text-sm font-medium text-foreground">
204
- {item.title}
205
- </span>
206
- <span className="text-xs">{href}</span>
207
- </button>
208
- );
209
- })}
210
- </div>
211
- );
212
- };
213
-
214
- export const SearchDialog = ({
215
- basePath,
216
- open,
217
- onOpenChange,
218
- }: {
219
- basePath: string;
220
- open: boolean;
221
- onOpenChange: (open: boolean) => void;
222
- }) => {
223
- const router = useRouter();
224
- const inputRef = useRef<HTMLInputElement>(null);
225
- const requestRef = useRef<Promise<void> | null>(null);
226
- const loadedRef = useRef(false);
227
- const [state, dispatch] = useReducer(searchReducer, INITIAL_SEARCH_STATE);
228
- const { activeIndex, items, query, status } = state;
229
-
230
- const deferredQuery = useDeferredValue(query.trim().toLowerCase());
231
-
232
- const loadSearchItems = useCallback(() => {
233
- if (loadedRef.current) {
234
- return Promise.resolve();
235
- }
236
-
237
- if (requestRef.current) {
238
- return requestRef.current;
239
- }
240
-
241
- dispatch({ type: "load-start" });
242
- const request = (async () => {
243
- try {
244
- const response = await fetch(toDocHref("search", basePath), {
245
- headers: {
246
- accept: "application/json",
247
- },
248
- });
249
-
250
- if (!response.ok) {
251
- throw new Error(`Failed to load search index: ${response.status}`);
252
- }
253
-
254
- const payload = (await response.json()) as SearchResponse;
255
- const nextItems = Array.isArray(payload.items) ? payload.items : [];
256
- loadedRef.current = true;
257
- startTransition(() => {
258
- dispatch({ items: nextItems, type: "load-success" });
259
- });
260
- } catch {
261
- dispatch({ type: "load-error" });
262
- } finally {
263
- requestRef.current = null;
264
- }
265
- })();
266
-
267
- requestRef.current = request;
268
- return request;
269
- }, [basePath]);
270
-
271
- // Load the search index as soon as the dialog mounts.
272
- useEffect(() => {
273
- const run = async () => {
274
- try {
275
- await loadSearchItems();
276
- } catch {
277
- // Errors are surfaced via the reducer's "load-error" action.
278
- }
279
- };
280
-
281
- run();
282
- }, [loadSearchItems]);
283
-
284
- const filteredItems = useMemo(
285
- () =>
286
- items
287
- .filter((item) => searchMatches(item, deferredQuery))
288
- .slice(0, MAX_RESULTS),
289
- [deferredQuery, items]
290
- );
291
-
292
- const closeSearch = useCallback(() => {
293
- dispatch({ type: "reset-query" });
294
- onOpenChange(false);
295
- }, [onOpenChange]);
296
-
297
- const runSelection = useCallback(
298
- (item: SearchItem) => {
299
- closeSearch();
300
- const href = item.href
301
- ? resolveHref(item.href, basePath)
302
- : toDocHref(item.path, basePath);
303
-
304
- if (item.href && isExternalHref(item.href)) {
305
- window.open(href, "_blank", "noopener,noreferrer");
306
- return;
307
- }
308
-
309
- router.push(href);
310
- },
311
- [basePath, closeSearch, router]
312
- );
313
-
314
- const handleOpenChange = useCallback(
315
- (nextOpen: boolean) => {
316
- if (!nextOpen) {
317
- closeSearch();
318
- }
319
- },
320
- [closeSearch]
321
- );
322
-
323
- const handleQueryChange = useCallback(
324
- (event: ChangeEvent<HTMLInputElement>) => {
325
- dispatch({ query: event.target.value, type: "set-query" });
326
- },
327
- []
328
- );
329
-
330
- const handleResultClick = useCallback(
331
- (event: ReactMouseEvent<HTMLButtonElement>) => {
332
- const index = Number(event.currentTarget.dataset.index);
333
- const item = filteredItems[index];
334
- if (!item) {
335
- return;
336
- }
337
-
338
- runSelection(item);
339
- },
340
- [filteredItems, runSelection]
341
- );
342
-
343
- const handleResultMouseEnter = useCallback(
344
- (event: ReactMouseEvent<HTMLButtonElement>) => {
345
- const index = Number(event.currentTarget.dataset.index);
346
- if (Number.isNaN(index)) {
347
- return;
348
- }
349
-
350
- dispatch({ index, type: "set-active-index" });
351
- },
352
- []
353
- );
354
-
355
- const handleDialogKeyDown = useCallback(
356
- (event: ReactKeyboardEvent<HTMLDivElement>) => {
357
- if (event.key === "ArrowDown") {
358
- event.preventDefault();
359
- dispatch({
360
- index: getWrappedNextIndex(activeIndex, filteredItems.length),
361
- type: "set-active-index",
362
- });
363
- return;
364
- }
365
-
366
- if (event.key === "ArrowUp") {
367
- event.preventDefault();
368
- dispatch({
369
- index: getWrappedPrevIndex(activeIndex, filteredItems.length),
370
- type: "set-active-index",
371
- });
372
- return;
373
- }
374
-
375
- if (event.key === "Enter") {
376
- const activeItem = filteredItems[activeIndex];
377
- if (!activeItem) {
378
- return;
379
- }
380
-
381
- event.preventDefault();
382
- runSelection(activeItem);
383
- }
384
- },
385
- [activeIndex, filteredItems, runSelection]
386
- );
387
-
388
- return (
389
- <Dialog onOpenChange={handleOpenChange} open={open}>
390
- <DialogContent
391
- className="max-w-2xl gap-0 overflow-hidden p-0"
392
- onKeyDown={handleDialogKeyDown}
393
- showCloseButton={false}
394
- >
395
- <DialogTitle className="sr-only">Search documentation</DialogTitle>
396
- <DialogDescription className="sr-only">
397
- Search documentation pages and jump directly to a result.
398
- </DialogDescription>
399
- <div className="flex items-center gap-3 border-b border-border px-4 py-3">
400
- <SearchIcon className="size-4 text-muted-foreground" />
401
- <input
402
- aria-label="Search documentation"
403
- className="w-full bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground"
404
- onChange={handleQueryChange}
405
- placeholder="Search docs..."
406
- ref={inputRef}
407
- type="text"
408
- value={query}
409
- />
410
- <button
411
- className="rounded-md border border-border px-2 py-1 text-[11px] text-muted-foreground hover:bg-accent hover:text-foreground"
412
- onClick={closeSearch}
413
- type="button"
414
- >
415
- Esc
416
- </button>
417
- </div>
418
- <div className="max-h-[min(70vh,32rem)] overflow-y-auto p-2">
419
- <SearchResults
420
- activeIndex={activeIndex}
421
- basePath={basePath}
422
- filteredItems={filteredItems}
423
- onResultClick={handleResultClick}
424
- onResultMouseEnter={handleResultMouseEnter}
425
- status={status}
426
- />
427
- </div>
428
- </DialogContent>
429
- </Dialog>
430
- );
431
- };
@@ -1,101 +0,0 @@
1
- "use client";
2
-
3
- import { SearchIcon } from "blode-icons-react";
4
- import dynamic from "next/dynamic";
5
- import { useCallback, useEffect, useState } from "react";
6
-
7
- const SearchDialog = dynamic(
8
- async () => {
9
- const mod = await import("@/components/ui/search-dialog");
10
- return mod.SearchDialog;
11
- },
12
- { loading: () => null, ssr: false }
13
- );
14
-
15
- const preloadDialog = async () => {
16
- // Eagerly fetch the dialog chunk so it's warm by the time the user opens it.
17
- try {
18
- await import("@/components/ui/search-dialog");
19
- } catch {
20
- // Ignore preload failures; the dialog will retry on open.
21
- }
22
- };
23
-
24
- const isEditableTarget = (target: EventTarget | null) =>
25
- (target instanceof HTMLElement && target.isContentEditable) ||
26
- target instanceof HTMLInputElement ||
27
- target instanceof HTMLTextAreaElement ||
28
- target instanceof HTMLSelectElement;
29
-
30
- export const Search = ({ basePath }: { basePath: string }) => {
31
- const [open, setOpen] = useState(false);
32
- const [hasMounted, setHasMounted] = useState(false);
33
-
34
- const openSearch = useCallback(() => {
35
- preloadDialog();
36
- setHasMounted(true);
37
- setOpen(true);
38
- }, []);
39
-
40
- const handleOpenChange = useCallback((next: boolean) => {
41
- setOpen(next);
42
- }, []);
43
-
44
- useEffect(() => {
45
- const handleKeydown = (event: KeyboardEvent) => {
46
- if (
47
- (event.key === "k" && (event.metaKey || event.ctrlKey)) ||
48
- event.key === "/"
49
- ) {
50
- if (isEditableTarget(event.target)) {
51
- return;
52
- }
53
-
54
- event.preventDefault();
55
- if (open) {
56
- setOpen(false);
57
- return;
58
- }
59
-
60
- preloadDialog();
61
- setHasMounted(true);
62
- setOpen(true);
63
- }
64
- };
65
-
66
- document.addEventListener("keydown", handleKeydown);
67
- return () => document.removeEventListener("keydown", handleKeydown);
68
- }, [open]);
69
-
70
- return (
71
- <>
72
- <button
73
- aria-label="Search documentation"
74
- className="inline-flex size-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground md:hidden"
75
- onClick={openSearch}
76
- onFocus={preloadDialog}
77
- onMouseEnter={preloadDialog}
78
- type="button"
79
- >
80
- <SearchIcon className="size-4.5" />
81
- </button>
82
- <button
83
- className="relative hidden h-8 w-full items-center justify-start rounded-lg border border-border bg-muted/50 pl-3 text-sm font-normal text-foreground shadow-none transition-colors hover:bg-muted/80 md:flex md:w-48 lg:w-56 xl:w-64 dark:bg-card"
84
- onClick={openSearch}
85
- onFocus={preloadDialog}
86
- onMouseEnter={preloadDialog}
87
- type="button"
88
- >
89
- <span className="hidden lg:inline-flex">Search documentation...</span>
90
- <span className="inline-flex lg:hidden">Search...</span>
91
- </button>
92
- {hasMounted ? (
93
- <SearchDialog
94
- basePath={basePath}
95
- onOpenChange={handleOpenChange}
96
- open={open}
97
- />
98
- ) : null}
99
- </>
100
- );
101
- };
@@ -1,26 +0,0 @@
1
- "use client";
2
-
3
- import { Separator as SeparatorPrimitive } from "radix-ui";
4
- import * as React from "react";
5
-
6
- import { cn } from "@/lib/utils";
7
-
8
- const Separator = ({
9
- className,
10
- orientation = "horizontal",
11
- decorative = true,
12
- ...props
13
- }: React.ComponentProps<typeof SeparatorPrimitive.Root>) => (
14
- <SeparatorPrimitive.Root
15
- data-slot="separator"
16
- decorative={decorative}
17
- orientation={orientation}
18
- className={cn(
19
- "shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
20
- className
21
- )}
22
- {...props}
23
- />
24
- );
25
-
26
- export { Separator };
@@ -1,133 +0,0 @@
1
- "use client";
2
-
3
- import { XIcon } from "blode-icons-react";
4
- import { Dialog as SheetPrimitive } from "radix-ui";
5
- import * as React from "react";
6
-
7
- import { cn } from "@/lib/utils";
8
-
9
- const Sheet = ({
10
- ...props
11
- }: React.ComponentProps<typeof SheetPrimitive.Root>) => (
12
- <SheetPrimitive.Root data-slot="sheet" {...props} />
13
- );
14
-
15
- const SheetTrigger = ({
16
- ...props
17
- }: React.ComponentProps<typeof SheetPrimitive.Trigger>) => (
18
- <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
19
- );
20
-
21
- const SheetClose = ({
22
- ...props
23
- }: React.ComponentProps<typeof SheetPrimitive.Close>) => (
24
- <SheetPrimitive.Close data-slot="sheet-close" {...props} />
25
- );
26
-
27
- const SheetPortal = ({
28
- ...props
29
- }: React.ComponentProps<typeof SheetPrimitive.Portal>) => (
30
- <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
31
- );
32
-
33
- const SheetOverlay = ({
34
- className,
35
- ...props
36
- }: React.ComponentProps<typeof SheetPrimitive.Overlay>) => (
37
- <SheetPrimitive.Overlay
38
- data-slot="sheet-overlay"
39
- className={cn(
40
- "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
41
- className
42
- )}
43
- {...props}
44
- />
45
- );
46
-
47
- const SheetContent = ({
48
- className,
49
- children,
50
- side = "right",
51
- showCloseButton = true,
52
- ...props
53
- }: React.ComponentProps<typeof SheetPrimitive.Content> & {
54
- side?: "top" | "right" | "bottom" | "left";
55
- showCloseButton?: boolean;
56
- }) => (
57
- <SheetPortal>
58
- <SheetOverlay />
59
- <SheetPrimitive.Content
60
- data-slot="sheet-content"
61
- className={cn(
62
- "fixed z-50 flex flex-col gap-4 bg-background shadow-lg transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500",
63
- side === "right" &&
64
- "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
65
- side === "left" &&
66
- "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
67
- side === "top" &&
68
- "inset-x-0 top-0 h-auto border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
69
- side === "bottom" &&
70
- "inset-x-0 bottom-0 h-auto border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
71
- className
72
- )}
73
- {...props}
74
- >
75
- {children}
76
- {showCloseButton && (
77
- <SheetPrimitive.Close className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-secondary">
78
- <XIcon className="size-4" />
79
- <span className="sr-only">Close</span>
80
- </SheetPrimitive.Close>
81
- )}
82
- </SheetPrimitive.Content>
83
- </SheetPortal>
84
- );
85
-
86
- const SheetHeader = ({ className, ...props }: React.ComponentProps<"div">) => (
87
- <div
88
- data-slot="sheet-header"
89
- className={cn("flex flex-col gap-1.5 p-4", className)}
90
- {...props}
91
- />
92
- );
93
-
94
- const SheetFooter = ({ className, ...props }: React.ComponentProps<"div">) => (
95
- <div
96
- data-slot="sheet-footer"
97
- className={cn("mt-auto flex flex-col gap-2 p-4", className)}
98
- {...props}
99
- />
100
- );
101
-
102
- const SheetTitle = ({
103
- className,
104
- ...props
105
- }: React.ComponentProps<typeof SheetPrimitive.Title>) => (
106
- <SheetPrimitive.Title
107
- data-slot="sheet-title"
108
- className={cn("font-semibold text-foreground", className)}
109
- {...props}
110
- />
111
- );
112
-
113
- const SheetDescription = ({
114
- className,
115
- ...props
116
- }: React.ComponentProps<typeof SheetPrimitive.Description>) => (
117
- <SheetPrimitive.Description
118
- data-slot="sheet-description"
119
- className={cn("text-sm text-muted-foreground", className)}
120
- {...props}
121
- />
122
- );
123
-
124
- export {
125
- Sheet,
126
- SheetTrigger,
127
- SheetClose,
128
- SheetContent,
129
- SheetHeader,
130
- SheetFooter,
131
- SheetTitle,
132
- SheetDescription,
133
- };