livemark 0.25.0 → 0.26.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 (397) hide show
  1. package/README.md +3 -2
  2. package/build/actions/config/define.d.ts +6 -0
  3. package/build/actions/config/define.unit.js +8 -1
  4. package/build/actions/escape/copy.d.ts +11 -0
  5. package/build/actions/escape/copy.js +29 -0
  6. package/build/actions/escape/copy.unit.d.ts +1 -0
  7. package/build/actions/escape/copy.unit.js +37 -0
  8. package/build/actions/escape/list.d.ts +12 -0
  9. package/build/actions/escape/list.js +27 -0
  10. package/build/actions/escape/list.unit.d.ts +1 -0
  11. package/build/actions/escape/list.unit.js +36 -0
  12. package/build/actions/target/build.d.ts +9 -26
  13. package/build/actions/target/build.js +50 -71
  14. package/build/actions/target/build.unit.d.ts +1 -0
  15. package/build/actions/target/build.unit.js +76 -0
  16. package/build/actions/target/clear.d.ts +4 -0
  17. package/build/actions/target/clear.js +14 -0
  18. package/build/actions/target/clear.unit.d.ts +1 -0
  19. package/build/actions/target/clear.unit.js +23 -0
  20. package/build/commands/build.js +1 -2
  21. package/build/commands/clear.d.ts +5 -0
  22. package/build/commands/clear.js +15 -0
  23. package/build/commands/escape.d.ts +4 -3
  24. package/build/commands/escape.js +45 -48
  25. package/build/commands/preview.js +1 -2
  26. package/build/commands/start.js +1 -2
  27. package/build/components/Abbr.d.ts +1 -1
  28. package/build/components/Abbr.js +2 -4
  29. package/build/components/AnsiCode.d.ts +1 -1
  30. package/build/components/AnsiCode.js +2 -2
  31. package/build/components/Article.d.ts +2 -1
  32. package/build/components/Article.js +7 -14
  33. package/build/components/BackToTop.d.ts +1 -1
  34. package/build/components/Banner.d.ts +2 -2
  35. package/build/components/Banner.js +7 -3
  36. package/build/components/BlogIndex.d.ts +1 -1
  37. package/build/components/BlogIndex.js +2 -11
  38. package/build/components/Breadcrumbs.d.ts +1 -1
  39. package/build/components/Breadcrumbs.js +2 -3
  40. package/build/components/Callout.d.ts +1 -1
  41. package/build/components/Callout.js +5 -9
  42. package/build/components/Card.d.ts +1 -1
  43. package/build/components/Card.js +2 -3
  44. package/build/components/Cards.d.ts +1 -1
  45. package/build/components/ChangelogIndex.d.ts +1 -1
  46. package/build/components/ChangelogIndex.js +2 -11
  47. package/build/components/ChoiceList.d.ts +15 -0
  48. package/build/components/ChoiceList.js +13 -0
  49. package/build/components/CodeBlock.d.ts +1 -1
  50. package/build/components/CodeBlock.js +3 -16
  51. package/build/components/CodeTabs.d.ts +1 -1
  52. package/build/components/CodeTabs.js +2 -3
  53. package/build/components/Column.d.ts +1 -1
  54. package/build/components/Columns.d.ts +1 -1
  55. package/build/components/Content.d.ts +1 -1
  56. package/build/components/ContentTab.d.ts +1 -1
  57. package/build/components/ContentTabs.d.ts +1 -1
  58. package/build/components/ContentTabs.js +2 -3
  59. package/build/components/DefaultCatchBoundary.d.ts +1 -1
  60. package/build/components/DefaultCatchBoundary.js +5 -7
  61. package/build/components/DefinitionList.d.ts +3 -3
  62. package/build/components/Details.d.ts +1 -1
  63. package/build/components/Details.js +2 -5
  64. package/build/components/FileTree.d.ts +1 -1
  65. package/build/components/FileTree.js +3 -5
  66. package/build/components/Footer.d.ts +1 -1
  67. package/build/components/Footer.js +2 -5
  68. package/build/components/FootnoteRef.d.ts +1 -1
  69. package/build/components/FootnoteRef.js +2 -4
  70. package/build/components/Header.d.ts +6 -0
  71. package/build/components/Header.js +26 -0
  72. package/build/components/HeaderMenu.d.ts +2 -0
  73. package/build/components/HeaderMenu.js +27 -0
  74. package/build/components/HeaderNav.d.ts +6 -0
  75. package/build/components/HeaderNav.js +74 -0
  76. package/build/components/HeaderSearch.d.ts +4 -0
  77. package/build/components/HeaderSearch.js +33 -0
  78. package/build/components/Heading.d.ts +6 -6
  79. package/build/components/InlineBadge.d.ts +2 -2
  80. package/build/components/InlineBadge.js +1 -1
  81. package/build/components/InlineIcon.d.ts +1 -1
  82. package/build/components/InlineToc.d.ts +1 -1
  83. package/build/components/InlineToc.js +2 -4
  84. package/build/components/Layout.d.ts +2 -1
  85. package/build/components/Layout.js +5 -58
  86. package/build/components/LinkButton.d.ts +2 -2
  87. package/build/components/LinkButton.js +1 -1
  88. package/build/components/MenuSheet.d.ts +22 -0
  89. package/build/components/MenuSheet.js +27 -0
  90. package/build/components/Mermaid.d.ts +1 -1
  91. package/build/components/MermaidRenderer.d.ts +1 -1
  92. package/build/components/MermaidRenderer.js +20 -8
  93. package/build/components/NotFound.d.ts +1 -1
  94. package/build/components/NotFound.js +3 -6
  95. package/build/components/PackageTabs.d.ts +1 -1
  96. package/build/components/PackageTabs.js +3 -7
  97. package/build/components/PageToolbar.d.ts +1 -1
  98. package/build/components/PageToolbar.js +2 -10
  99. package/build/components/PrevNext.d.ts +1 -1
  100. package/build/components/PrevNext.js +2 -10
  101. package/build/components/Root.d.ts +4 -0
  102. package/build/components/Root.js +8 -0
  103. package/build/components/Search.d.ts +5 -2
  104. package/build/components/Search.js +11 -9
  105. package/build/components/SearchDialog.d.ts +1 -1
  106. package/build/components/SearchDialog.js +10 -133
  107. package/build/components/Section.d.ts +1 -1
  108. package/build/components/SectionHeader.d.ts +1 -1
  109. package/build/components/SheetPanel.d.ts +12 -0
  110. package/build/components/SheetPanel.js +19 -0
  111. package/build/components/Sidebar.d.ts +1 -1
  112. package/build/components/Sidebar.js +12 -14
  113. package/build/components/SidebarArticles.d.ts +4 -1
  114. package/build/components/SidebarArticles.js +5 -9
  115. package/build/components/SidebarLinks.d.ts +4 -1
  116. package/build/components/SidebarLinks.js +6 -9
  117. package/build/components/SidebarPosts.d.ts +4 -1
  118. package/build/components/SidebarPosts.js +7 -23
  119. package/build/components/SidebarReleases.d.ts +4 -1
  120. package/build/components/SidebarReleases.js +5 -15
  121. package/build/components/SidebarSectionPicker.d.ts +8 -0
  122. package/build/components/SidebarSectionPicker.js +31 -0
  123. package/build/components/SidebarSections.d.ts +1 -1
  124. package/build/components/SidebarSections.js +5 -9
  125. package/build/components/SiteLink.d.ts +1 -1
  126. package/build/components/SiteTitle.d.ts +1 -1
  127. package/build/components/SiteTitle.js +2 -6
  128. package/build/components/SortableTable.d.ts +1 -1
  129. package/build/components/SoundCloud.d.ts +1 -1
  130. package/build/components/SoundCloud.js +2 -2
  131. package/build/components/TagIndex.d.ts +1 -1
  132. package/build/components/TagIndex.js +2 -11
  133. package/build/components/Theme.d.ts +2 -1
  134. package/build/components/Theme.js +35 -15
  135. package/build/components/Toc.d.ts +5 -4
  136. package/build/components/Toc.js +35 -35
  137. package/build/components/YouTube.d.ts +1 -1
  138. package/build/components/YouTube.js +2 -2
  139. package/build/components/ZoomImage.d.ts +1 -1
  140. package/build/content-collections.js +5 -1
  141. package/build/elements/accordion.d.ts +4 -4
  142. package/build/elements/accordion.js +2 -3
  143. package/build/elements/alert-dialog.d.ts +12 -12
  144. package/build/elements/alert-dialog.js +2 -4
  145. package/build/elements/alert.d.ts +4 -4
  146. package/build/elements/alert.js +2 -2
  147. package/build/elements/aspect-ratio.d.ts +1 -1
  148. package/build/elements/avatar.d.ts +6 -6
  149. package/build/elements/badge.d.ts +1 -1
  150. package/build/elements/badge.js +3 -1
  151. package/build/elements/breadcrumb.d.ts +6 -6
  152. package/build/elements/breadcrumb.js +2 -4
  153. package/build/elements/button-group.d.ts +2 -2
  154. package/build/elements/button-group.js +5 -5
  155. package/build/elements/button.d.ts +2 -2
  156. package/build/elements/button.js +9 -7
  157. package/build/elements/calendar.d.ts +2 -2
  158. package/build/elements/calendar.js +2 -2
  159. package/build/elements/card.d.ts +7 -7
  160. package/build/elements/card.js +4 -4
  161. package/build/elements/carousel.d.ts +5 -5
  162. package/build/elements/carousel.js +3 -7
  163. package/build/elements/chart.d.ts +6 -6
  164. package/build/elements/chart.js +5 -11
  165. package/build/elements/checkbox.d.ts +1 -1
  166. package/build/elements/collapsible.d.ts +3 -3
  167. package/build/elements/command.d.ts +9 -9
  168. package/build/elements/command.js +5 -11
  169. package/build/elements/context-menu.d.ts +15 -15
  170. package/build/elements/context-menu.js +6 -9
  171. package/build/elements/dialog.d.ts +10 -10
  172. package/build/elements/dialog.js +2 -6
  173. package/build/elements/drawer.d.ts +14 -12
  174. package/build/elements/drawer.js +14 -15
  175. package/build/elements/dropdown-menu.d.ts +15 -15
  176. package/build/elements/dropdown-menu.js +7 -10
  177. package/build/elements/empty.d.ts +6 -6
  178. package/build/elements/empty.js +2 -2
  179. package/build/elements/field.d.ts +10 -10
  180. package/build/elements/field.js +3 -4
  181. package/build/elements/hover-card.d.ts +3 -3
  182. package/build/elements/hover-card.js +2 -2
  183. package/build/elements/input-group.d.ts +7 -7
  184. package/build/elements/input-group.js +5 -5
  185. package/build/elements/input-otp.d.ts +4 -4
  186. package/build/elements/input.d.ts +1 -1
  187. package/build/elements/input.js +2 -2
  188. package/build/elements/item.d.ts +9 -9
  189. package/build/elements/item.js +2 -2
  190. package/build/elements/kbd.d.ts +2 -2
  191. package/build/elements/label.d.ts +1 -1
  192. package/build/elements/menubar.d.ts +16 -16
  193. package/build/elements/menubar.js +9 -11
  194. package/build/elements/native-select.d.ts +3 -3
  195. package/build/elements/native-select.js +2 -4
  196. package/build/elements/navigation-menu.d.ts +8 -8
  197. package/build/elements/navigation-menu.js +3 -5
  198. package/build/elements/pagination.d.ts +7 -7
  199. package/build/elements/pagination.js +4 -10
  200. package/build/elements/popover.d.ts +6 -6
  201. package/build/elements/popover.js +2 -2
  202. package/build/elements/progress.d.ts +5 -5
  203. package/build/elements/progress.js +2 -3
  204. package/build/elements/radio-group.d.ts +2 -2
  205. package/build/elements/resizable.d.ts +3 -3
  206. package/build/elements/scroll-area.d.ts +2 -2
  207. package/build/elements/scroll-area.js +2 -4
  208. package/build/elements/select.d.ts +9 -9
  209. package/build/elements/select.js +4 -9
  210. package/build/elements/separator.d.ts +1 -1
  211. package/build/elements/sheet.d.ts +8 -8
  212. package/build/elements/sheet.js +2 -6
  213. package/build/elements/sidebar.d.ts +19 -19
  214. package/build/elements/sidebar.js +15 -37
  215. package/build/elements/skeleton.d.ts +1 -1
  216. package/build/elements/slider.d.ts +2 -1
  217. package/build/elements/slider.js +2 -3
  218. package/build/elements/sonner.d.ts +1 -1
  219. package/build/elements/spinner.d.ts +1 -1
  220. package/build/elements/switch.d.ts +1 -1
  221. package/build/elements/table.d.ts +8 -8
  222. package/build/elements/tabs.d.ts +4 -4
  223. package/build/elements/tabs.js +3 -3
  224. package/build/elements/textarea.d.ts +1 -1
  225. package/build/elements/textarea.js +2 -2
  226. package/build/elements/toggle-group.d.ts +3 -2
  227. package/build/elements/toggle-group.js +3 -3
  228. package/build/elements/toggle.d.ts +1 -1
  229. package/build/elements/toggle.js +2 -2
  230. package/build/elements/tooltip.d.ts +4 -4
  231. package/build/elements/tooltip.js +2 -3
  232. package/build/head.d.ts +4 -0
  233. package/build/head.js +6 -0
  234. package/build/helpers/article-search.d.ts +19 -0
  235. package/build/helpers/article-search.js +134 -0
  236. package/build/helpers/dependency-dir.d.ts +5 -0
  237. package/build/helpers/dependency-dir.js +20 -0
  238. package/build/helpers/dependency-dir.unit.d.ts +1 -0
  239. package/build/helpers/dependency-dir.unit.js +25 -0
  240. package/build/helpers/dynamic-icon-resolver.d.ts +1 -1
  241. package/build/helpers/dynamic-icon.d.ts +1 -1
  242. package/build/helpers/head.d.ts +53 -0
  243. package/build/helpers/head.js +69 -0
  244. package/build/helpers/head.unit.d.ts +1 -0
  245. package/build/helpers/head.unit.js +108 -0
  246. package/build/helpers/nav-items.d.ts +11 -0
  247. package/build/helpers/nav-items.js +65 -0
  248. package/build/helpers/render-inline-markdown.d.ts +1 -0
  249. package/build/helpers/render-inline-markdown.js +34 -0
  250. package/build/helpers/render-inline-markdown.unit.d.ts +1 -0
  251. package/build/helpers/render-inline-markdown.unit.js +20 -0
  252. package/build/helpers/search-highlight.d.ts +8 -0
  253. package/build/helpers/search-highlight.js +59 -0
  254. package/build/helpers/search-highlight.unit.d.ts +1 -0
  255. package/build/helpers/search-highlight.unit.js +36 -0
  256. package/build/helpers/target-export.d.ts +9 -0
  257. package/build/helpers/target-export.js +24 -0
  258. package/build/helpers/target-export.unit.d.ts +1 -0
  259. package/build/helpers/target-export.unit.js +25 -0
  260. package/build/helpers/theme.d.ts +6 -2
  261. package/build/helpers/theme.js +40 -7
  262. package/build/helpers/theme.unit.d.ts +1 -0
  263. package/build/helpers/theme.unit.js +30 -0
  264. package/build/hooks/hydrated.d.ts +2 -0
  265. package/build/hooks/hydrated.js +15 -0
  266. package/build/index.d.ts +1 -0
  267. package/build/index.js +1 -1
  268. package/build/models/config.d.ts +32 -6
  269. package/build/models/config.js +10 -1
  270. package/build/models/section.d.ts +4 -2
  271. package/build/models/section.js +1 -1
  272. package/build/plugins/vite-livemark.d.ts +4 -5
  273. package/build/plugins/vite-livemark.js +56 -90
  274. package/build/program.js +4 -2
  275. package/build/routes/$.d.ts +4 -1
  276. package/build/routes/$.js +20 -9
  277. package/build/routes/__root.js +29 -63
  278. package/build/settings.js +2 -1
  279. package/package.json +68 -66
  280. package/{.agents/skills → skills}/livemark-authoring/SKILL.md +2 -2
  281. package/{.agents/skills → skills}/livemark-configuration/SKILL.md +12 -5
  282. package/skills/livemark-customization/SKILL.md +145 -0
  283. package/source/actions/config/define.unit.ts +9 -0
  284. package/source/actions/escape/copy.ts +35 -0
  285. package/source/actions/escape/copy.unit.ts +51 -0
  286. package/source/actions/escape/list.ts +30 -0
  287. package/source/actions/escape/list.unit.ts +42 -0
  288. package/source/actions/target/build.ts +49 -69
  289. package/source/actions/target/build.unit.ts +95 -0
  290. package/source/actions/target/clear.ts +14 -0
  291. package/source/actions/target/clear.unit.ts +25 -0
  292. package/source/commands/build.ts +0 -1
  293. package/source/commands/clear.ts +15 -0
  294. package/source/commands/escape.ts +42 -59
  295. package/source/commands/preview.ts +0 -1
  296. package/source/commands/start.ts +0 -1
  297. package/source/components/AnsiCode.tsx +1 -1
  298. package/source/components/Article.tsx +8 -4
  299. package/source/components/Banner.tsx +12 -2
  300. package/source/components/BlogIndex.tsx +1 -1
  301. package/source/components/Callout.tsx +4 -6
  302. package/source/components/ChangelogIndex.tsx +1 -1
  303. package/source/components/ChoiceList.tsx +69 -0
  304. package/source/components/CodeBlock.tsx +6 -6
  305. package/source/components/CodeTabs.tsx +1 -1
  306. package/source/components/ContentTabs.tsx +1 -1
  307. package/source/components/DefaultCatchBoundary.tsx +4 -6
  308. package/source/components/Details.tsx +1 -1
  309. package/source/components/FileTree.tsx +1 -1
  310. package/source/components/Header.tsx +52 -0
  311. package/source/components/HeaderMenu.tsx +41 -0
  312. package/source/components/HeaderNav.tsx +145 -0
  313. package/source/components/HeaderSearch.tsx +77 -0
  314. package/source/components/InlineBadge.tsx +1 -1
  315. package/source/components/InlineToc.tsx +1 -1
  316. package/source/components/Layout.tsx +16 -160
  317. package/source/components/LinkButton.tsx +9 -1
  318. package/source/components/MenuSheet.tsx +92 -0
  319. package/source/components/MermaidRenderer.tsx +19 -8
  320. package/source/components/NotFound.tsx +3 -5
  321. package/source/components/PackageTabs.tsx +2 -2
  322. package/source/components/PageToolbar.tsx +11 -3
  323. package/source/components/PrevNext.tsx +2 -2
  324. package/source/components/Root.tsx +13 -0
  325. package/source/components/Search.tsx +28 -8
  326. package/source/components/SearchDialog.tsx +15 -189
  327. package/source/components/SheetPanel.tsx +69 -0
  328. package/source/components/Sidebar.tsx +27 -14
  329. package/source/components/SidebarArticles.tsx +4 -3
  330. package/source/components/SidebarLinks.tsx +3 -2
  331. package/source/components/SidebarPosts.tsx +3 -2
  332. package/source/components/SidebarReleases.tsx +3 -2
  333. package/source/components/SidebarSectionPicker.tsx +70 -0
  334. package/source/components/SiteTitle.tsx +5 -5
  335. package/source/components/SoundCloud.tsx +1 -1
  336. package/source/components/TagIndex.tsx +1 -1
  337. package/source/components/Theme.tsx +55 -29
  338. package/source/components/Toc.tsx +76 -55
  339. package/source/components/YouTube.tsx +1 -1
  340. package/source/content-collections.ts +4 -0
  341. package/source/elements/alert-dialog.tsx +1 -1
  342. package/source/elements/alert.tsx +1 -1
  343. package/source/elements/badge.tsx +4 -0
  344. package/source/elements/button-group.tsx +4 -4
  345. package/source/elements/button.tsx +10 -6
  346. package/source/elements/calendar.tsx +1 -1
  347. package/source/elements/card.tsx +3 -3
  348. package/source/elements/command.tsx +7 -4
  349. package/source/elements/context-menu.tsx +5 -5
  350. package/source/elements/dialog.tsx +1 -1
  351. package/source/elements/drawer.tsx +59 -43
  352. package/source/elements/dropdown-menu.tsx +6 -6
  353. package/source/elements/empty.tsx +1 -1
  354. package/source/elements/field.tsx +1 -1
  355. package/source/elements/hover-card.tsx +1 -1
  356. package/source/elements/input-group.tsx +4 -4
  357. package/source/elements/input.tsx +1 -1
  358. package/source/elements/item.tsx +1 -1
  359. package/source/elements/menubar.tsx +8 -8
  360. package/source/elements/native-select.tsx +1 -1
  361. package/source/elements/popover.tsx +1 -1
  362. package/source/elements/select.tsx +3 -3
  363. package/source/elements/sidebar.tsx +8 -21
  364. package/source/elements/tabs.tsx +2 -2
  365. package/source/elements/textarea.tsx +1 -1
  366. package/source/elements/toggle-group.tsx +2 -2
  367. package/source/elements/toggle.tsx +1 -1
  368. package/source/env.d.ts +1 -0
  369. package/source/head.ts +7 -0
  370. package/source/helpers/article-search.tsx +192 -0
  371. package/source/helpers/dependency-dir.ts +20 -0
  372. package/source/helpers/dependency-dir.unit.ts +39 -0
  373. package/source/helpers/head.ts +94 -0
  374. package/source/helpers/head.unit.ts +116 -0
  375. package/source/helpers/nav-items.tsx +102 -0
  376. package/source/helpers/render-inline-markdown.ts +44 -0
  377. package/source/helpers/render-inline-markdown.unit.ts +30 -0
  378. package/source/helpers/search-highlight.ts +73 -0
  379. package/source/helpers/search-highlight.unit.ts +42 -0
  380. package/source/helpers/target-export.ts +28 -0
  381. package/source/helpers/target-export.unit.ts +37 -0
  382. package/source/helpers/theme.ts +40 -6
  383. package/source/helpers/theme.unit.ts +32 -0
  384. package/source/hooks/hydrated.ts +18 -0
  385. package/source/index.ts +1 -0
  386. package/source/models/config.ts +13 -0
  387. package/source/models/section.ts +3 -0
  388. package/source/plugins/vite-livemark.ts +54 -95
  389. package/source/program.ts +2 -0
  390. package/source/routes/$.tsx +27 -9
  391. package/source/routes/__root.tsx +51 -71
  392. package/source/settings.ts +1 -0
  393. package/source/styles/general.css +59 -11
  394. package/source/styles/markdown.css +13 -7
  395. package/source/styles/shape.css +14 -0
  396. package/.agents/skills/change-review/SKILL.md +0 -47
  397. package/.agents/skills/livemark-customization/SKILL.md +0 -118
@@ -28,7 +28,7 @@ export function CodeBlock(props: React.ComponentProps<"pre">) {
28
28
 
29
29
  return (
30
30
  <figure
31
- className="shiki not-prose my-4 relative rounded-xl border shadow-sm overflow-hidden text-sm bg-sidebar dark:bg-sidebar"
31
+ className="shiki not-prose my-4 relative rounded-card border shadow-sm overflow-hidden text-sm bg-sidebar dark:bg-sidebar"
32
32
  style={{ ...style, backgroundColor: undefined }}
33
33
  >
34
34
  {title ? (
@@ -44,7 +44,7 @@ export function CodeBlock(props: React.ComponentProps<"pre">) {
44
44
  <TooltipTrigger
45
45
  onClick={handleWrapToggle}
46
46
  aria-label={wrap ? "Disable wrap" : "Enable wrap"}
47
- className={`-me-2 p-1.5 rounded-md hover:text-foreground transition-colors ${wrap ? "text-foreground" : ""}`}
47
+ className={`-me-2 p-1.5 rounded-control hover:text-foreground transition-colors ${wrap ? "text-foreground" : ""}`}
48
48
  >
49
49
  <WrapText className="size-3.5" />
50
50
  </TooltipTrigger>
@@ -54,7 +54,7 @@ export function CodeBlock(props: React.ComponentProps<"pre">) {
54
54
  <TooltipTrigger
55
55
  onClick={handleCopy}
56
56
  aria-label={copied ? "Copied" : "Copy code"}
57
- className="-me-2 p-1.5 rounded-md hover:text-foreground transition-colors"
57
+ className="-me-2 p-1.5 rounded-control hover:text-foreground transition-colors"
58
58
  >
59
59
  {copied ? (
60
60
  <Check className="size-3.5" />
@@ -66,12 +66,12 @@ export function CodeBlock(props: React.ComponentProps<"pre">) {
66
66
  </Tooltip>
67
67
  </div>
68
68
  ) : (
69
- <div className="empty:hidden absolute top-2 right-2 z-10 backdrop-blur-lg rounded-lg text-muted-foreground">
69
+ <div className="empty:hidden absolute top-2 right-2 z-10 backdrop-blur-lg rounded-control text-muted-foreground">
70
70
  <Tooltip>
71
71
  <TooltipTrigger
72
72
  onClick={handleWrapToggle}
73
73
  aria-label={wrap ? "Disable wrap" : "Enable wrap"}
74
- className={`p-1.5 rounded-md hover:text-foreground transition-colors ${wrap ? "text-foreground" : ""}`}
74
+ className={`p-1.5 rounded-control hover:text-foreground transition-colors ${wrap ? "text-foreground" : ""}`}
75
75
  >
76
76
  <WrapText className="size-3.5" />
77
77
  </TooltipTrigger>
@@ -81,7 +81,7 @@ export function CodeBlock(props: React.ComponentProps<"pre">) {
81
81
  <TooltipTrigger
82
82
  onClick={handleCopy}
83
83
  aria-label={copied ? "Copied" : "Copy code"}
84
- className="p-1.5 rounded-md hover:text-foreground transition-colors"
84
+ className="p-1.5 rounded-control hover:text-foreground transition-colors"
85
85
  >
86
86
  {copied ? (
87
87
  <Check className="size-3.5" />
@@ -47,7 +47,7 @@ export function CodeTabs(props: {
47
47
  }, [props.sync, names])
48
48
 
49
49
  return (
50
- <div className="not-prose my-4 rounded-xl border shadow-sm overflow-hidden text-sm bg-sidebar dark:bg-sidebar">
50
+ <div className="not-prose my-4 rounded-card border shadow-sm overflow-hidden text-sm bg-sidebar dark:bg-sidebar">
51
51
  <div className="flex border-b">
52
52
  {names.map((name, i) => (
53
53
  <button
@@ -45,7 +45,7 @@ export function ContentTabs(props: { sync?: string; children: React.ReactNode })
45
45
  }, [props.sync, titles])
46
46
 
47
47
  return (
48
- <div className="not-prose my-4 rounded-xl border bg-card">
48
+ <div className="not-prose my-4 rounded-card border bg-card">
49
49
  <div className="flex border-b">
50
50
  {titles.map((title, i) => (
51
51
  <button
@@ -6,6 +6,7 @@ import {
6
6
  useMatch,
7
7
  useRouter,
8
8
  } from "@tanstack/react-router"
9
+ import { buttonVariants } from "../elements/button.tsx"
9
10
 
10
11
  export function DefaultCatchBoundary({ error }: ErrorComponentProps) {
11
12
  const router = useRouter()
@@ -25,21 +26,18 @@ export function DefaultCatchBoundary({ error }: ErrorComponentProps) {
25
26
  onClick={() => {
26
27
  router.invalidate()
27
28
  }}
28
- className="bg-primary text-primary-foreground px-4 py-2 text-sm font-medium hover:bg-primary/80 transition-colors"
29
+ className={buttonVariants({ size: "lg" })}
29
30
  >
30
31
  Try Again
31
32
  </button>
32
33
  {isRoot ? (
33
- <Link
34
- to="/"
35
- className="border border-border px-4 py-2 text-sm font-medium hover:bg-card transition-colors"
36
- >
34
+ <Link to="/" className={buttonVariants({ variant: "outline", size: "lg" })}>
37
35
  Home
38
36
  </Link>
39
37
  ) : (
40
38
  <Link
41
39
  to="/"
42
- className="border border-border px-4 py-2 text-sm font-medium hover:bg-card transition-colors"
40
+ className={buttonVariants({ variant: "outline", size: "lg" })}
43
41
  onClick={(e: any) => {
44
42
  e.preventDefault()
45
43
  window.history.back()
@@ -14,7 +14,7 @@ export function Details(props: { summary: string; children: React.ReactNode }) {
14
14
  <Collapsible
15
15
  open={open}
16
16
  onOpenChange={setOpen}
17
- className="not-prose my-4 rounded-xl border border-border bg-card px-4 py-3"
17
+ className="not-prose my-4 rounded-card border border-border bg-card px-4 py-3"
18
18
  >
19
19
  <CollapsibleTrigger className="flex w-full cursor-pointer items-center gap-2 text-sm font-semibold select-none">
20
20
  <ChevronRight
@@ -11,7 +11,7 @@ export function FileTree(props: { tree: string }) {
11
11
  const items: TreeItem[] = JSON.parse(props.tree)
12
12
 
13
13
  return (
14
- <div className="not-prose my-4 rounded-xl border border-border bg-card p-4 font-mono text-sm">
14
+ <div className="not-prose my-4 rounded-card border border-border bg-card p-4 font-mono text-sm">
15
15
  <TreeItems items={items} depth={0} />
16
16
  </div>
17
17
  )
@@ -0,0 +1,52 @@
1
+ import { config } from "livemark:virtual"
2
+ import { useLocation, useMatch } from "@tanstack/react-router"
3
+ import { useState } from "react"
4
+ import { cn } from "cn"
5
+ import { currentSection } from "../content/article.ts"
6
+ import { activeSiteLink } from "../helpers/section.ts"
7
+ import { HeaderMenu } from "./HeaderMenu.tsx"
8
+ import { HeaderNav } from "./HeaderNav.tsx"
9
+ import { Search } from "./Search.tsx"
10
+ import { SiteLink } from "./SiteLink.tsx"
11
+ import { SiteTitle } from "./SiteTitle.tsx"
12
+ import { Theme } from "./Theme.tsx"
13
+
14
+ /** Sticky site header: title, header sections and links, search and theme. `toggle`
15
+ * sits before the title from `lg`; `menu` opens the phone navigation */
16
+ export function Header(props: { toggle?: React.ReactNode; menu?: React.ReactNode }) {
17
+ const pathname = useLocation({ select: l => l.pathname })
18
+ const articleRoute = useMatch({ from: "/$", shouldThrow: false })
19
+ const activeSection = articleRoute
20
+ ? currentSection(`/${pathname.replace(/^\/|\/$/g, "")}/`)
21
+ : undefined
22
+ const siteLinkTarget = activeSiteLink(pathname, config.sections ?? [])
23
+ const [compactSearch, setCompactSearch] = useState(false)
24
+
25
+ return (
26
+ <header className="sticky top-0 z-20 flex has-[[data-header-search]]:z-40 h-16 shrink-0 items-center border-b bg-background">
27
+ <div
28
+ className={cn(
29
+ "flex min-w-0 items-center self-stretch pl-4 lg:shrink-0",
30
+ props.toggle ? "pr-4" : "lg:w-[calc(var(--sidebar-width,16rem)+4rem)]",
31
+ )}
32
+ >
33
+ {props.toggle && <div className="hidden lg:flex">{props.toggle}</div>}
34
+ <SiteLink
35
+ to={siteLinkTarget}
36
+ className={cn("flex min-w-0 items-center gap-2", props.toggle && "lg:hidden")}
37
+ >
38
+ <SiteTitle />
39
+ </SiteLink>
40
+ </div>
41
+ <HeaderNav
42
+ activePrefix={activeSection?.prefix}
43
+ onCompactChange={setCompactSearch}
44
+ />
45
+ <div className="ml-auto flex shrink-0 items-center gap-1 pr-2 lg:pr-1">
46
+ <Search compact={compactSearch} />
47
+ <Theme />
48
+ <div className="lg:hidden">{props.menu ?? <HeaderMenu />}</div>
49
+ </div>
50
+ </header>
51
+ )
52
+ }
@@ -0,0 +1,41 @@
1
+ import { config } from "livemark:virtual"
2
+ import { useNavigate } from "@tanstack/react-router"
3
+ import { Menu } from "lucide-react"
4
+ import { Button } from "../elements/button.tsx"
5
+ import { DynamicIcon } from "../helpers/dynamic-icon.tsx"
6
+ import { useNavItems } from "../helpers/nav-items.tsx"
7
+ import { prefixUrl } from "../helpers/prefix-url.ts"
8
+ import { MenuSheet } from "./MenuSheet.tsx"
9
+
10
+ /** Phone navigation for a `Header` without a sidebar: the header sections and links */
11
+ export function HeaderMenu() {
12
+ const items = useNavItems()
13
+ const navigate = useNavigate()
14
+
15
+ return (
16
+ <MenuSheet
17
+ title="Navigation"
18
+ items={items.map(item => ({
19
+ id: item.key,
20
+ label: item.suffix ? `${item.title} (${item.suffix})` : item.title,
21
+ icon: item.icon && <DynamicIcon name={item.icon} className="size-4 shrink-0" />,
22
+ active: item.active,
23
+ onSelect: () => {
24
+ if (item.href) window.location.assign(prefixUrl(item.href, config.base))
25
+ else if (item.target) navigate({ to: item.target })
26
+ },
27
+ }))}
28
+ trigger={
29
+ <Button
30
+ variant="ghost"
31
+ size="icon-sm"
32
+ title="Navigation"
33
+ aria-label="Navigation"
34
+ className="cursor-pointer"
35
+ />
36
+ }
37
+ >
38
+ <Menu />
39
+ </MenuSheet>
40
+ )
41
+ }
@@ -0,0 +1,145 @@
1
+ import { ChevronDown } from "lucide-react"
2
+ import { useLayoutEffect, useRef, useState } from "react"
3
+ import { cn } from "cn"
4
+ import { type NavItem, renderNavAnchor, useNavItems } from "../helpers/nav-items.tsx"
5
+ import {
6
+ DropdownMenu,
7
+ DropdownMenuContent,
8
+ DropdownMenuItem,
9
+ DropdownMenuTrigger,
10
+ } from "../elements/dropdown-menu.tsx"
11
+
12
+ // The `lg:w-56` Search field minus its 36px icon-only form
13
+ const SEARCH_COMPACT_SAVING = 188
14
+
15
+ /** Header sections and links from `lg`: once they outgrow the bar, Search turns
16
+ * compact and the rest fold into a "More" menu */
17
+ export function HeaderNav(props: {
18
+ activePrefix?: string
19
+ onCompactChange: (compact: boolean) => void
20
+ }) {
21
+ const items = useNavItems(props.activePrefix)
22
+ const strip = useRef<HTMLElement>(null)
23
+ const measure = useRef<HTMLDivElement>(null)
24
+ const [visibleCount, setVisibleCount] = useState(items.length)
25
+ const onCompactChange = useRef(props.onCompactChange)
26
+ onCompactChange.current = props.onCompactChange
27
+
28
+ useLayoutEffect(() => {
29
+ let compact = false
30
+ const fit = () => {
31
+ if (!strip.current || !measure.current) return
32
+ const style = getComputedStyle(strip.current)
33
+ const width =
34
+ strip.current.clientWidth -
35
+ parseFloat(style.paddingLeft) -
36
+ parseFloat(style.paddingRight)
37
+ if (width <= 0) return
38
+ // Measured as if Search were full, so toggling it never feeds back into the fit
39
+ const room = width - (compact ? SEARCH_COMPACT_SAVING : 0)
40
+ const gap = parseFloat(getComputedStyle(measure.current).columnGap) || 0
41
+ const widths = [...measure.current.children].map(
42
+ child => child.getBoundingClientRect().width,
43
+ )
44
+ const more = widths.pop() ?? 0
45
+ const total = widths.reduce((sum, w) => sum + w, 0) + gap * (widths.length - 1)
46
+
47
+ compact = total > room
48
+ let count = widths.length
49
+ if (total > room + SEARCH_COMPACT_SAVING) {
50
+ let used = more
51
+ count = 0
52
+ for (const w of widths) {
53
+ if (used + gap + w > room + SEARCH_COMPACT_SAVING) break
54
+ used += gap + w
55
+ count++
56
+ }
57
+ }
58
+ onCompactChange.current(compact)
59
+ setVisibleCount(count)
60
+ }
61
+ fit()
62
+ const observer = new ResizeObserver(fit)
63
+ if (strip.current) observer.observe(strip.current)
64
+ if (measure.current) observer.observe(measure.current)
65
+ return () => observer.disconnect()
66
+ }, [])
67
+
68
+ const shown = items.slice(0, visibleCount)
69
+ const folded = items.slice(visibleCount)
70
+
71
+ return (
72
+ <nav
73
+ ref={strip}
74
+ className="relative hidden w-0 min-w-0 flex-1 items-center gap-6 self-stretch overflow-hidden px-6 text-sm lg:flex xl:gap-8"
75
+ >
76
+ {shown.map(item => (
77
+ <HeaderNavLink key={item.key} item={item} />
78
+ ))}
79
+ {folded.length > 0 && <HeaderNavMore items={folded} />}
80
+ <div
81
+ ref={measure}
82
+ aria-hidden
83
+ inert
84
+ className="invisible absolute left-0 flex gap-6 whitespace-nowrap xl:gap-8"
85
+ >
86
+ {items.map(item => (
87
+ <HeaderNavLink key={item.key} item={item} />
88
+ ))}
89
+ <HeaderNavMoreTrigger active={false} />
90
+ </div>
91
+ </nav>
92
+ )
93
+ }
94
+
95
+ function HeaderNavLink(props: { item: NavItem }) {
96
+ return renderNavAnchor(
97
+ props.item,
98
+ cn(
99
+ "inline-flex shrink-0 items-center gap-1.5 whitespace-nowrap text-foreground",
100
+ props.item.active ? ACTIVE : IDLE,
101
+ ),
102
+ )
103
+ }
104
+
105
+ function HeaderNavMore(props: { items: NavItem[] }) {
106
+ return (
107
+ <DropdownMenu>
108
+ <DropdownMenuTrigger
109
+ render={<HeaderNavMoreTrigger active={props.items.some(item => item.active)} />}
110
+ />
111
+ <DropdownMenuContent align="end" className="w-auto">
112
+ {props.items.map(item => (
113
+ <DropdownMenuItem
114
+ key={item.key}
115
+ className={cn("cursor-pointer", item.active && "font-medium")}
116
+ render={renderNavAnchor(item)}
117
+ />
118
+ ))}
119
+ </DropdownMenuContent>
120
+ </DropdownMenu>
121
+ )
122
+ }
123
+
124
+ function HeaderNavMoreTrigger(
125
+ props: React.ComponentProps<"button"> & { active: boolean },
126
+ ) {
127
+ const { active, className, ...rest } = props
128
+ return (
129
+ <button
130
+ type="button"
131
+ {...rest}
132
+ className={cn(
133
+ "inline-flex shrink-0 cursor-pointer items-center gap-1 whitespace-nowrap text-foreground",
134
+ active ? ACTIVE : IDLE,
135
+ className,
136
+ )}
137
+ >
138
+ More
139
+ <ChevronDown className="size-3.5" />
140
+ </button>
141
+ )
142
+ }
143
+
144
+ const ACTIVE = "font-medium border-b-2 border-foreground pb-0.5 -mb-0.5"
145
+ const IDLE = "opacity-80 hover:opacity-100 transition-opacity"
@@ -0,0 +1,77 @@
1
+ import { useLayoutEffect, useRef, useState } from "react"
2
+ import { X } from "lucide-react"
3
+ import { SearchResultGroups, useArticleSearch } from "../helpers/article-search.tsx"
4
+ import { Command, CommandEmpty, CommandInput, CommandList } from "../elements/command.tsx"
5
+
6
+ /** Search field that takes over the header below `lg`, with results dropping under it */
7
+ export function HeaderSearch(props: { onClose: () => void }) {
8
+ const search = useArticleSearch()
9
+ const bar = useRef<HTMLDivElement>(null)
10
+ const [panelTop, setPanelTop] = useState<number>()
11
+
12
+ // Measured, not `top-16`: while the Banner is in view it pushes the header down.
13
+ useLayoutEffect(() => {
14
+ const measure = () => setPanelTop(bar.current?.getBoundingClientRect().bottom)
15
+ measure()
16
+ window.addEventListener("scroll", measure, { passive: true })
17
+ window.addEventListener("resize", measure)
18
+ return () => {
19
+ window.removeEventListener("scroll", measure)
20
+ window.removeEventListener("resize", measure)
21
+ }
22
+ }, [])
23
+
24
+ // `data-header-search` lifts the header over the Toc bar and BackToTop (Layout).
25
+ return (
26
+ <Command
27
+ ref={bar}
28
+ data-header-search
29
+ shouldFilter={false}
30
+ loop
31
+ onKeyDown={event => {
32
+ if (event.key === "Escape") props.onClose()
33
+ }}
34
+ className="absolute inset-0 z-10 overflow-visible rounded-none! bg-background p-0 lg:hidden"
35
+ >
36
+ <div className="flex h-full items-center gap-1 pl-1 pr-2">
37
+ <div className="flex-1 [&_[data-slot=command-input-wrapper]]:p-0 [&_[data-slot=input-group]]:border-transparent! [&_[data-slot=input-group]]:bg-transparent! [&_[data-slot=input-group]]:ring-0!">
38
+ <CommandInput
39
+ autoFocus
40
+ placeholder="Search docs..."
41
+ value={search.query}
42
+ onValueChange={search.searchArticles}
43
+ />
44
+ </div>
45
+ <button
46
+ type="button"
47
+ onClick={props.onClose}
48
+ aria-label="Close search"
49
+ title="Close search"
50
+ className="flex size-9 shrink-0 items-center justify-center rounded-control text-muted-foreground hover:bg-muted hover:text-foreground transition-colors cursor-pointer"
51
+ >
52
+ <X className="size-5" />
53
+ </button>
54
+ </div>
55
+ <div
56
+ style={{ top: panelTop }}
57
+ className="fixed inset-x-0 bottom-0 flex flex-col border-t bg-background p-1"
58
+ >
59
+ <CommandList className="max-h-none flex-1 overscroll-contain">
60
+ <CommandEmpty>
61
+ {search.query.trim()
62
+ ? "No results found."
63
+ : "Type to search across all contents."}
64
+ </CommandEmpty>
65
+ <SearchResultGroups
66
+ query={search.query}
67
+ grouped={search.grouped}
68
+ onSelect={path => {
69
+ props.onClose()
70
+ search.selectArticle(path)
71
+ }}
72
+ />
73
+ </CommandList>
74
+ </div>
75
+ </Command>
76
+ )
77
+ }
@@ -3,7 +3,7 @@ import { Badge } from "../elements/badge.tsx"
3
3
  /** Inline badge rendered from :badge text directives */
4
4
  export function InlineBadge(props: {
5
5
  label: string
6
- variant?: "default" | "secondary" | "destructive" | "outline"
6
+ variant?: "default" | "secondary" | "positive" | "warning" | "destructive" | "outline"
7
7
  }) {
8
8
  return <Badge variant={props.variant}>{props.label}</Badge>
9
9
  }
@@ -9,7 +9,7 @@ export function InlineToc(props: { maxLevel?: string }) {
9
9
  if (items.length === 0) return null
10
10
 
11
11
  return (
12
- <nav className="not-prose my-8 rounded-xl border border-border bg-card p-6">
12
+ <nav className="not-prose my-8 rounded-card border border-border bg-card p-6">
13
13
  <p className="text-base font-semibold mb-4">Table of Contents</p>
14
14
  <ul className="text-base space-y-2.5">
15
15
  {items.map(item => (
@@ -1,15 +1,3 @@
1
- import { config } from "livemark:virtual"
2
- import { Link, useLocation, useMatch } from "@tanstack/react-router"
3
- import { useHotkey } from "@tanstack/react-hotkeys"
4
- import {
5
- currentSection,
6
- sectionFirstArticle,
7
- sectionFlatArticles,
8
- sortedArticles,
9
- } from "../content/article.ts"
10
- import { DynamicIcon } from "../helpers/dynamic-icon.tsx"
11
- import { prefixUrl } from "../helpers/prefix-url.ts"
12
- import { activeSiteLink, customSectionActive } from "../helpers/section.ts"
13
1
  import {
14
2
  SidebarInset,
15
3
  SidebarProvider,
@@ -18,160 +6,25 @@ import {
18
6
  } from "../elements/sidebar.tsx"
19
7
  import { BackToTop } from "./BackToTop.tsx"
20
8
  import { Banner } from "./Banner.tsx"
9
+ import { Header } from "./Header.tsx"
21
10
  import { Sidebar } from "./Sidebar.tsx"
22
- import { SiteLink } from "./SiteLink.tsx"
23
- import { SiteTitle } from "./SiteTitle.tsx"
24
-
25
- function splatFor(pathname: string) {
26
- return { _splat: pathname.replace(/^\/|\/$/g, "") }
27
- }
28
11
 
12
+ /** Site chrome around a page: banner, header, sidebar and back-to-top */
29
13
  export function Layout(props: { withSidebar?: boolean; children?: React.ReactNode }) {
30
- const pathname = useLocation({ select: l => l.pathname })
31
- const articleRoute = useMatch({ from: "/$", shouldThrow: false })
32
- const activeSection = articleRoute
33
- ? currentSection(`/${pathname.replace(/^\/|\/$/g, "")}/`)
34
- : undefined
35
- const siteLinkTarget = activeSiteLink(pathname, config.sections ?? [])
36
-
37
- useHotkey("J", () =>
38
- window.scrollBy({ top: window.innerHeight * 0.8, behavior: "smooth" }),
39
- )
40
- useHotkey("K", () =>
41
- window.scrollBy({ top: -window.innerHeight * 0.8, behavior: "smooth" }),
42
- )
43
-
44
- const sections = config.sections
45
-
46
- const header = (
47
- <header className="sticky top-0 z-20 flex h-16 shrink-0 items-center border-b bg-background">
48
- <div
49
- className={`flex items-center self-stretch pl-4 ${props.withSidebar ? "pr-4" : "lg:pr-20"}`}
50
- >
51
- {props.withSidebar ? (
52
- <>
53
- <div className="hidden lg:flex">
54
- <SidebarTrigger />
55
- </div>
56
- <SiteLink to={siteLinkTarget} className="lg:hidden flex items-center gap-2">
57
- <SiteTitle />
58
- </SiteLink>
59
- </>
60
- ) : (
61
- <SiteLink to={siteLinkTarget} className="flex items-center gap-2">
62
- <SiteTitle />
63
- </SiteLink>
64
- )}
65
- </div>
66
- <div className="hidden lg:flex flex-1 items-center gap-8 self-stretch px-6 text-sm">
67
- {sections?.length ? (
68
- sections
69
- .filter(section => section.position === "header")
70
- .map(section => {
71
- const icon = section.icon
72
- if (section.type === "custom") {
73
- const isActive = customSectionActive(section.url, pathname)
74
- return (
75
- <a
76
- key={section.url}
77
- href={prefixUrl(section.url, config.base)}
78
- className={`inline-flex items-center gap-1.5 text-foreground ${
79
- isActive
80
- ? "font-medium border-b-2 border-foreground pb-0.5 -mb-0.5"
81
- : "opacity-80 hover:opacity-100 transition-opacity"
82
- }`}
83
- >
84
- {icon && <DynamicIcon name={icon} className="size-3.5" />}
85
- <span>{section.title}</span>
86
- </a>
87
- )
88
- }
89
- const isActive = activeSection?.prefix === section.prefix
90
- const target =
91
- section.type === "blog" || section.type === "changelog"
92
- ? section.prefix
93
- : sectionFirstArticle.get(section.prefix)
94
- const latestVersion =
95
- section.type === "changelog" && section.version
96
- ? sortedArticles.find(
97
- a => a.path === sectionFlatArticles.get(section.prefix)?.[0],
98
- )?.title
99
- : undefined
100
- return (
101
- <Link
102
- key={section.prefix}
103
- to={target === "/" ? "/" : "/$"}
104
- params={target && target !== "/" ? splatFor(target) : {}}
105
- className={`inline-flex items-center gap-1.5 text-foreground ${
106
- isActive
107
- ? "font-medium border-b-2 border-foreground pb-0.5 -mb-0.5"
108
- : "opacity-80 hover:opacity-100 transition-opacity"
109
- }`}
110
- >
111
- {icon && <DynamicIcon name={icon} className="size-3.5" />}
112
- <span>
113
- {section.title}
114
- {latestVersion && (
115
- <span className="opacity-80"> ({latestVersion})</span>
116
- )}
117
- </span>
118
- </Link>
119
- )
120
- })
121
- ) : (
122
- <Link
123
- to="/"
124
- className="text-foreground font-medium underline underline-offset-4"
125
- >
126
- Docs
127
- </Link>
128
- )}
129
- {config.links
130
- ?.filter(
131
- link =>
132
- link.position === "header" &&
133
- (!link.prefix || link.prefix === activeSection?.prefix),
134
- )
135
- .map(link => (
136
- <a
137
- key={link.url}
138
- href={prefixUrl(link.url, config.base)}
139
- className="text-foreground opacity-80 hover:opacity-100 transition-opacity"
140
- >
141
- {link.icon && (
142
- <DynamicIcon
143
- name={link.icon}
144
- className="inline size-3.5 align-[-0.125em]"
145
- />
146
- )}{" "}
147
- {link.title}
148
- </a>
149
- ))}
150
- <Banner />
151
- </div>
152
- <div className="lg:hidden ml-auto pr-2">
153
- <SidebarTrigger />
154
- </div>
155
- </header>
156
- )
157
-
158
14
  return (
159
- <SidebarProvider
160
- key={props.withSidebar ? "sidebar" : "mini"}
161
- defaultOpen={!!props.withSidebar}
162
- >
163
- <SidebarShell withSidebar={props.withSidebar} header={header}>
164
- {props.children}
165
- </SidebarShell>
166
- </SidebarProvider>
15
+ <>
16
+ <Banner />
17
+ <SidebarProvider
18
+ key={props.withSidebar ? "sidebar" : "mini"}
19
+ defaultOpen={!!props.withSidebar}
20
+ >
21
+ <SidebarShell withSidebar={props.withSidebar}>{props.children}</SidebarShell>
22
+ </SidebarProvider>
23
+ </>
167
24
  )
168
25
  }
169
26
 
170
- function SidebarShell(props: {
171
- withSidebar?: boolean
172
- header: React.ReactNode
173
- children?: React.ReactNode
174
- }) {
27
+ function SidebarShell(props: { withSidebar?: boolean; children?: React.ReactNode }) {
175
28
  const { isMobile, setOpenMobile } = useSidebar()
176
29
  const onClick = (event: React.MouseEvent<HTMLDivElement>) => {
177
30
  if (!isMobile) return
@@ -181,7 +34,10 @@ function SidebarShell(props: {
181
34
  <div style={{ display: "contents" }} onClick={onClick}>
182
35
  <Sidebar withSidebar={props.withSidebar} />
183
36
  <SidebarInset>
184
- {props.header}
37
+ <Header
38
+ toggle={props.withSidebar && <SidebarTrigger />}
39
+ menu={<SidebarTrigger />}
40
+ />
185
41
  <main className="flex-1">{props.children}</main>
186
42
  <BackToTop />
187
43
  </SidebarInset>