blodemd 0.1.0 → 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 (289) hide show
  1. package/dist/cli.mjs +50 -174
  2. package/dist/cli.mjs.map +1 -1
  3. package/package.json +3 -36
  4. package/dev-server/app/[[...slug]]/page.tsx +0 -140
  5. package/dev-server/app/blodemd-dev/invalidate/route.ts +0 -12
  6. package/dev-server/app/blodemd-dev/static/[...path]/route.ts +0 -32
  7. package/dev-server/app/blodemd-dev/version/route.ts +0 -14
  8. package/dev-server/app/blodemd-internal/proxy/route.ts +0 -86
  9. package/dev-server/app/error.tsx +0 -24
  10. package/dev-server/app/favicon.ico +0 -0
  11. package/dev-server/app/globals.css +0 -4
  12. package/dev-server/app/layout.tsx +0 -38
  13. package/dev-server/app/not-found.tsx +0 -18
  14. package/dev-server/app/search/route.ts +0 -17
  15. package/dev-server/components/dev-reload-script.tsx +0 -86
  16. package/dev-server/components/providers.tsx +0 -15
  17. package/dev-server/lib/dev-state.ts +0 -8
  18. package/dev-server/lib/local-content-source.ts +0 -103
  19. package/dev-server/lib/local-runtime.tsx +0 -555
  20. package/dev-server/next-env.d.ts +0 -5
  21. package/dev-server/next.config.js +0 -54
  22. package/dev-server/package.json +0 -61
  23. package/dev-server/postcss.config.mjs +0 -7
  24. package/dev-server/public/glide-variable.woff2 +0 -0
  25. package/dev-server/tsconfig.json +0 -50
  26. package/docs/app/globals.css +0 -471
  27. package/docs/components/animate-ui/primitives/buttons/button.tsx +0 -14
  28. package/docs/components/api/api-playground.tsx +0 -467
  29. package/docs/components/api/api-reference.tsx +0 -157
  30. package/docs/components/content/collection-index.tsx +0 -114
  31. package/docs/components/docs/contextual-menu.tsx +0 -495
  32. package/docs/components/docs/copy-page-menu.tsx +0 -364
  33. package/docs/components/docs/doc-header.tsx +0 -223
  34. package/docs/components/docs/doc-shell.tsx +0 -355
  35. package/docs/components/docs/doc-sidebar.tsx +0 -256
  36. package/docs/components/docs/doc-toc.tsx +0 -46
  37. package/docs/components/docs/mobile-nav.tsx +0 -195
  38. package/docs/components/docs/sidebar-active-highlight.tsx +0 -34
  39. package/docs/components/docs/sidebar-scroll-area.tsx +0 -63
  40. package/docs/components/git/repo-picker.tsx +0 -529
  41. package/docs/components/icons/doc-icon.tsx +0 -96
  42. package/docs/components/mdx/accordion.tsx +0 -83
  43. package/docs/components/mdx/agent-instructions.tsx +0 -17
  44. package/docs/components/mdx/badge.tsx +0 -79
  45. package/docs/components/mdx/callout.tsx +0 -88
  46. package/docs/components/mdx/card.tsx +0 -110
  47. package/docs/components/mdx/code-block.tsx +0 -80
  48. package/docs/components/mdx/code-group.tsx +0 -203
  49. package/docs/components/mdx/color.tsx +0 -87
  50. package/docs/components/mdx/columns.tsx +0 -25
  51. package/docs/components/mdx/expandable.tsx +0 -45
  52. package/docs/components/mdx/field-layout.tsx +0 -77
  53. package/docs/components/mdx/frame.tsx +0 -23
  54. package/docs/components/mdx/get-text-content.ts +0 -18
  55. package/docs/components/mdx/icon.tsx +0 -12
  56. package/docs/components/mdx/iframe.tsx +0 -62
  57. package/docs/components/mdx/index.tsx +0 -121
  58. package/docs/components/mdx/installer.tsx +0 -20
  59. package/docs/components/mdx/panel.tsx +0 -11
  60. package/docs/components/mdx/param-field.tsx +0 -56
  61. package/docs/components/mdx/preview.tsx +0 -36
  62. package/docs/components/mdx/prompt.tsx +0 -63
  63. package/docs/components/mdx/request-example.tsx +0 -27
  64. package/docs/components/mdx/response-field.tsx +0 -42
  65. package/docs/components/mdx/steps.tsx +0 -92
  66. package/docs/components/mdx/tabs.tsx +0 -193
  67. package/docs/components/mdx/tile.tsx +0 -43
  68. package/docs/components/mdx/tooltip.tsx +0 -71
  69. package/docs/components/mdx/tree.tsx +0 -120
  70. package/docs/components/mdx/type-table.tsx +0 -71
  71. package/docs/components/mdx/update.tsx +0 -44
  72. package/docs/components/mdx/video.tsx +0 -45
  73. package/docs/components/mdx/view.tsx +0 -66
  74. package/docs/components/posthog-provider.tsx +0 -42
  75. package/docs/components/providers.tsx +0 -15
  76. package/docs/components/tenant-analytics.tsx +0 -49
  77. package/docs/components/third-parties.tsx +0 -32
  78. package/docs/components/ui/badge.tsx +0 -61
  79. package/docs/components/ui/breadcrumb.tsx +0 -112
  80. package/docs/components/ui/button-group.tsx +0 -83
  81. package/docs/components/ui/button.tsx +0 -65
  82. package/docs/components/ui/card.tsx +0 -92
  83. package/docs/components/ui/command.tsx +0 -167
  84. package/docs/components/ui/copy-button.tsx +0 -129
  85. package/docs/components/ui/dialog.tsx +0 -146
  86. package/docs/components/ui/field.tsx +0 -237
  87. package/docs/components/ui/input.tsx +0 -23
  88. package/docs/components/ui/kbd.tsx +0 -98
  89. package/docs/components/ui/label.tsx +0 -22
  90. package/docs/components/ui/morph-icon.tsx +0 -79
  91. package/docs/components/ui/popover.tsx +0 -267
  92. package/docs/components/ui/search-dialog.tsx +0 -431
  93. package/docs/components/ui/search.tsx +0 -101
  94. package/docs/components/ui/separator.tsx +0 -26
  95. package/docs/components/ui/sheet.tsx +0 -133
  96. package/docs/components/ui/sidebar.tsx +0 -758
  97. package/docs/components/ui/skeleton.tsx +0 -11
  98. package/docs/components/ui/switch.tsx +0 -32
  99. package/docs/components/ui/tabs.tsx +0 -138
  100. package/docs/components/ui/theme-toggle.tsx +0 -62
  101. package/docs/components/ui/tooltip.tsx +0 -53
  102. package/docs/components/web-mcp.tsx +0 -115
  103. package/docs/lib/agent-skills.ts +0 -48
  104. package/docs/lib/api-client.ts +0 -72
  105. package/docs/lib/config.ts +0 -6
  106. package/docs/lib/content-root.ts +0 -33
  107. package/docs/lib/content-source.ts +0 -70
  108. package/docs/lib/contextual-options.ts +0 -222
  109. package/docs/lib/dashboard-session.ts +0 -167
  110. package/docs/lib/db.ts +0 -13
  111. package/docs/lib/docs-collection.ts +0 -7
  112. package/docs/lib/docs-runtime.tsx +0 -745
  113. package/docs/lib/edge-config.ts +0 -95
  114. package/docs/lib/env.ts +0 -23
  115. package/docs/lib/etag.ts +0 -22
  116. package/docs/lib/github-install.ts +0 -33
  117. package/docs/lib/llms-full.ts +0 -82
  118. package/docs/lib/marketing-markdown.ts +0 -79
  119. package/docs/lib/marketing-site.ts +0 -31
  120. package/docs/lib/mdx.ts +0 -98
  121. package/docs/lib/navigation.ts +0 -288
  122. package/docs/lib/openapi-proxy.ts +0 -88
  123. package/docs/lib/openapi.ts +0 -158
  124. package/docs/lib/platform-config.ts +0 -6
  125. package/docs/lib/project-authz.ts +0 -46
  126. package/docs/lib/routes.ts +0 -103
  127. package/docs/lib/server-cache.ts +0 -83
  128. package/docs/lib/shiki.ts +0 -44
  129. package/docs/lib/supabase.ts +0 -37
  130. package/docs/lib/tenancy.ts +0 -364
  131. package/docs/lib/tenant-headers.ts +0 -43
  132. package/docs/lib/tenant-static.ts +0 -705
  133. package/docs/lib/tenant-utility-context.ts +0 -62
  134. package/docs/lib/tenants.ts +0 -72
  135. package/docs/lib/theme.ts +0 -29
  136. package/docs/lib/time-ago.ts +0 -24
  137. package/docs/lib/toc.ts +0 -2
  138. package/docs/lib/use-mobile.ts +0 -19
  139. package/docs/lib/use-tab-observer.ts +0 -71
  140. package/docs/lib/utils.ts +0 -5
  141. package/packages/@repo/common/dist/index.d.ts +0 -16
  142. package/packages/@repo/common/dist/index.d.ts.map +0 -1
  143. package/packages/@repo/common/dist/index.js +0 -84
  144. package/packages/@repo/common/package.json +0 -34
  145. package/packages/@repo/common/src/index.ts +0 -101
  146. package/packages/@repo/contracts/dist/analytics.d.ts +0 -21
  147. package/packages/@repo/contracts/dist/analytics.d.ts.map +0 -1
  148. package/packages/@repo/contracts/dist/analytics.js +0 -18
  149. package/packages/@repo/contracts/dist/api-key.d.ts +0 -27
  150. package/packages/@repo/contracts/dist/api-key.d.ts.map +0 -1
  151. package/packages/@repo/contracts/dist/api-key.js +0 -20
  152. package/packages/@repo/contracts/dist/dates.d.ts +0 -4
  153. package/packages/@repo/contracts/dist/dates.d.ts.map +0 -1
  154. package/packages/@repo/contracts/dist/dates.js +0 -2
  155. package/packages/@repo/contracts/dist/deployment.d.ts +0 -71
  156. package/packages/@repo/contracts/dist/deployment.d.ts.map +0 -1
  157. package/packages/@repo/contracts/dist/deployment.js +0 -46
  158. package/packages/@repo/contracts/dist/domain.d.ts +0 -94
  159. package/packages/@repo/contracts/dist/domain.d.ts.map +0 -1
  160. package/packages/@repo/contracts/dist/domain.js +0 -36
  161. package/packages/@repo/contracts/dist/git.d.ts +0 -28
  162. package/packages/@repo/contracts/dist/git.d.ts.map +0 -1
  163. package/packages/@repo/contracts/dist/git.js +0 -24
  164. package/packages/@repo/contracts/dist/ids.d.ts +0 -14
  165. package/packages/@repo/contracts/dist/ids.d.ts.map +0 -1
  166. package/packages/@repo/contracts/dist/ids.js +0 -11
  167. package/packages/@repo/contracts/dist/index.d.ts +0 -12
  168. package/packages/@repo/contracts/dist/index.d.ts.map +0 -1
  169. package/packages/@repo/contracts/dist/index.js +0 -13
  170. package/packages/@repo/contracts/dist/pagination.d.ts +0 -23
  171. package/packages/@repo/contracts/dist/pagination.d.ts.map +0 -1
  172. package/packages/@repo/contracts/dist/pagination.js +0 -15
  173. package/packages/@repo/contracts/dist/project.d.ts +0 -42
  174. package/packages/@repo/contracts/dist/project.d.ts.map +0 -1
  175. package/packages/@repo/contracts/dist/project.js +0 -25
  176. package/packages/@repo/contracts/dist/tenant.d.ts +0 -147
  177. package/packages/@repo/contracts/dist/tenant.d.ts.map +0 -1
  178. package/packages/@repo/contracts/dist/tenant.js +0 -58
  179. package/packages/@repo/contracts/dist/user.d.ts +0 -9
  180. package/packages/@repo/contracts/dist/user.d.ts.map +0 -1
  181. package/packages/@repo/contracts/dist/user.js +0 -9
  182. package/packages/@repo/contracts/package.json +0 -37
  183. package/packages/@repo/contracts/src/analytics.ts +0 -33
  184. package/packages/@repo/contracts/src/api-key.ts +0 -27
  185. package/packages/@repo/contracts/src/dates.ts +0 -4
  186. package/packages/@repo/contracts/src/deployment.ts +0 -73
  187. package/packages/@repo/contracts/src/domain.ts +0 -51
  188. package/packages/@repo/contracts/src/git.ts +0 -31
  189. package/packages/@repo/contracts/src/ids.ts +0 -23
  190. package/packages/@repo/contracts/src/index.ts +0 -13
  191. package/packages/@repo/contracts/src/pagination.ts +0 -21
  192. package/packages/@repo/contracts/src/project.ts +0 -32
  193. package/packages/@repo/contracts/src/tenant.ts +0 -94
  194. package/packages/@repo/contracts/src/user.ts +0 -12
  195. package/packages/@repo/models/dist/docs-config.d.ts +0 -961
  196. package/packages/@repo/models/dist/docs-config.d.ts.map +0 -1
  197. package/packages/@repo/models/dist/docs-config.js +0 -531
  198. package/packages/@repo/models/dist/index.d.ts +0 -3
  199. package/packages/@repo/models/dist/index.d.ts.map +0 -1
  200. package/packages/@repo/models/dist/index.js +0 -3
  201. package/packages/@repo/models/dist/tenant.d.ts +0 -37
  202. package/packages/@repo/models/dist/tenant.d.ts.map +0 -1
  203. package/packages/@repo/models/dist/tenant.js +0 -1
  204. package/packages/@repo/models/package.json +0 -37
  205. package/packages/@repo/models/src/docs-config.ts +0 -629
  206. package/packages/@repo/models/src/index.ts +0 -3
  207. package/packages/@repo/models/src/tenant.ts +0 -44
  208. package/packages/@repo/prebuild/dist/index.d.ts +0 -2
  209. package/packages/@repo/prebuild/dist/index.d.ts.map +0 -1
  210. package/packages/@repo/prebuild/dist/index.js +0 -2
  211. package/packages/@repo/prebuild/dist/openapi.d.ts +0 -43
  212. package/packages/@repo/prebuild/dist/openapi.d.ts.map +0 -1
  213. package/packages/@repo/prebuild/dist/openapi.js +0 -86
  214. package/packages/@repo/prebuild/package.json +0 -39
  215. package/packages/@repo/prebuild/src/index.ts +0 -2
  216. package/packages/@repo/prebuild/src/openapi.ts +0 -154
  217. package/packages/@repo/previewing/dist/blob-source.d.ts +0 -16
  218. package/packages/@repo/previewing/dist/blob-source.d.ts.map +0 -1
  219. package/packages/@repo/previewing/dist/blob-source.js +0 -128
  220. package/packages/@repo/previewing/dist/config-loader.d.ts +0 -134
  221. package/packages/@repo/previewing/dist/config-loader.d.ts.map +0 -1
  222. package/packages/@repo/previewing/dist/config-loader.js +0 -231
  223. package/packages/@repo/previewing/dist/constants.d.ts +0 -15
  224. package/packages/@repo/previewing/dist/constants.d.ts.map +0 -1
  225. package/packages/@repo/previewing/dist/constants.js +0 -14
  226. package/packages/@repo/previewing/dist/content-index.d.ts +0 -7
  227. package/packages/@repo/previewing/dist/content-index.d.ts.map +0 -1
  228. package/packages/@repo/previewing/dist/content-index.js +0 -291
  229. package/packages/@repo/previewing/dist/content-source.d.ts +0 -12
  230. package/packages/@repo/previewing/dist/content-source.d.ts.map +0 -1
  231. package/packages/@repo/previewing/dist/content-source.js +0 -1
  232. package/packages/@repo/previewing/dist/fs-source.d.ts +0 -11
  233. package/packages/@repo/previewing/dist/fs-source.d.ts.map +0 -1
  234. package/packages/@repo/previewing/dist/fs-source.js +0 -71
  235. package/packages/@repo/previewing/dist/index.d.ts +0 -16
  236. package/packages/@repo/previewing/dist/index.d.ts.map +0 -1
  237. package/packages/@repo/previewing/dist/index.js +0 -13
  238. package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts +0 -3
  239. package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts.map +0 -1
  240. package/packages/@repo/previewing/dist/markdown/agent-markdown.js +0 -176
  241. package/packages/@repo/previewing/dist/markdown/format.d.ts +0 -8
  242. package/packages/@repo/previewing/dist/markdown/format.d.ts.map +0 -1
  243. package/packages/@repo/previewing/dist/markdown/format.js +0 -43
  244. package/packages/@repo/previewing/dist/markdown/links.d.ts +0 -3
  245. package/packages/@repo/previewing/dist/markdown/links.d.ts.map +0 -1
  246. package/packages/@repo/previewing/dist/markdown/links.js +0 -31
  247. package/packages/@repo/previewing/dist/openapi-pages.d.ts +0 -7
  248. package/packages/@repo/previewing/dist/openapi-pages.d.ts.map +0 -1
  249. package/packages/@repo/previewing/dist/openapi-pages.js +0 -200
  250. package/packages/@repo/previewing/dist/search-index.d.ts +0 -4
  251. package/packages/@repo/previewing/dist/search-index.d.ts.map +0 -1
  252. package/packages/@repo/previewing/dist/search-index.js +0 -23
  253. package/packages/@repo/previewing/dist/serialization.d.ts +0 -13
  254. package/packages/@repo/previewing/dist/serialization.d.ts.map +0 -1
  255. package/packages/@repo/previewing/dist/serialization.js +0 -108
  256. package/packages/@repo/previewing/dist/toc-index.d.ts +0 -5
  257. package/packages/@repo/previewing/dist/toc-index.d.ts.map +0 -1
  258. package/packages/@repo/previewing/dist/toc-index.js +0 -53
  259. package/packages/@repo/previewing/dist/types.d.ts +0 -92
  260. package/packages/@repo/previewing/dist/types.d.ts.map +0 -1
  261. package/packages/@repo/previewing/dist/types.js +0 -1
  262. package/packages/@repo/previewing/dist/utility-index.d.ts +0 -7
  263. package/packages/@repo/previewing/dist/utility-index.d.ts.map +0 -1
  264. package/packages/@repo/previewing/dist/utility-index.js +0 -201
  265. package/packages/@repo/previewing/package.json +0 -41
  266. package/packages/@repo/previewing/src/blob-source.ts +0 -185
  267. package/packages/@repo/previewing/src/config-loader.ts +0 -316
  268. package/packages/@repo/previewing/src/constants.ts +0 -16
  269. package/packages/@repo/previewing/src/content-index.ts +0 -384
  270. package/packages/@repo/previewing/src/content-source.ts +0 -12
  271. package/packages/@repo/previewing/src/fs-source.ts +0 -103
  272. package/packages/@repo/previewing/src/index.ts +0 -71
  273. package/packages/@repo/previewing/src/markdown/agent-markdown.ts +0 -254
  274. package/packages/@repo/previewing/src/markdown/format.ts +0 -63
  275. package/packages/@repo/previewing/src/markdown/links.ts +0 -46
  276. package/packages/@repo/previewing/src/openapi-pages.ts +0 -319
  277. package/packages/@repo/previewing/src/search-index.ts +0 -38
  278. package/packages/@repo/previewing/src/serialization.ts +0 -191
  279. package/packages/@repo/previewing/src/toc-index.ts +0 -72
  280. package/packages/@repo/previewing/src/types.ts +0 -105
  281. package/packages/@repo/previewing/src/utility-index.ts +0 -304
  282. package/packages/@repo/validation/dist/index.d.ts +0 -12
  283. package/packages/@repo/validation/dist/index.d.ts.map +0 -1
  284. package/packages/@repo/validation/dist/index.js +0 -30
  285. package/packages/@repo/validation/package.json +0 -38
  286. package/packages/@repo/validation/src/blodemd-docs-schema.json +0 -3575
  287. package/packages/@repo/validation/src/index.ts +0 -59
  288. package/scripts/prepare-package.mjs +0 -53
  289. 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
- };