livemark 0.2.0 → 0.7.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 (346) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +5 -1
  3. package/build/actions/changelog/build.d.ts +14 -0
  4. package/build/actions/changelog/build.js +158 -0
  5. package/build/actions/changelog/build.unit.js +66 -0
  6. package/build/actions/config/define.d.ts +6 -0
  7. package/build/actions/config/define.js +8 -0
  8. package/build/actions/config/define.unit.js +29 -0
  9. package/build/actions/config/load.d.ts +5 -0
  10. package/build/actions/config/load.js +25 -0
  11. package/build/actions/config/load.unit.js +23 -0
  12. package/build/commands/build.d.ts +5 -0
  13. package/build/commands/build.js +14 -0
  14. package/build/commands/escape.d.ts +9 -0
  15. package/build/commands/escape.js +56 -0
  16. package/build/commands/preview.d.ts +5 -0
  17. package/build/commands/preview.js +18 -0
  18. package/build/commands/start.d.ts +5 -0
  19. package/build/commands/start.js +19 -0
  20. package/build/docs/markdown/includes/example.d.ts +58 -0
  21. package/build/docs/markdown/includes/example.js +5 -0
  22. package/build/entrypoints/main.d.ts +2 -0
  23. package/build/entrypoints/main.js +12 -0
  24. package/build/helpers/program.d.ts +2 -0
  25. package/build/helpers/program.js +5 -0
  26. package/build/index.d.ts +1 -4
  27. package/build/index.js +2 -5
  28. package/build/livemark.config.d.ts +58 -0
  29. package/build/livemark.config.js +25 -0
  30. package/build/models/config.d.ts +340 -0
  31. package/build/models/config.js +34 -0
  32. package/build/models/link.d.ts +13 -0
  33. package/build/models/link.js +9 -0
  34. package/build/models/patch.d.ts +21 -0
  35. package/build/models/patch.js +7 -0
  36. package/build/models/section.d.ts +75 -0
  37. package/build/models/section.js +26 -0
  38. package/build/models/theme.d.ts +72 -0
  39. package/build/models/theme.js +73 -0
  40. package/build/program.d.ts +2 -0
  41. package/build/program.js +16 -0
  42. package/build/vite.config.d.ts +2 -0
  43. package/build/vite.config.js +48 -0
  44. package/build/website/assets/logo.svg +117 -0
  45. package/build/website/client.tsx +10 -0
  46. package/build/website/components/Abbr.tsx +17 -0
  47. package/build/website/components/AnsiCode.tsx +15 -0
  48. package/build/website/components/Article.tsx +172 -0
  49. package/build/website/components/BackToTop.tsx +32 -0
  50. package/build/website/components/Banner.tsx +32 -0
  51. package/build/website/components/BlogIndex.tsx +121 -0
  52. package/build/website/components/BlogSidebar.tsx +162 -0
  53. package/build/website/components/Breadcrumbs.tsx +22 -0
  54. package/build/website/components/Callout.tsx +72 -0
  55. package/build/website/components/Card.tsx +48 -0
  56. package/build/website/components/Cards.tsx +8 -0
  57. package/build/website/components/ChangelogIndex.tsx +111 -0
  58. package/build/website/components/ChangelogSidebar.tsx +120 -0
  59. package/build/website/components/CodeBlock.tsx +135 -0
  60. package/build/website/components/CodeTabs.tsx +83 -0
  61. package/build/website/components/Column.tsx +4 -0
  62. package/build/website/components/Columns.tsx +12 -0
  63. package/build/website/components/Content.tsx +7 -0
  64. package/build/website/components/ContentTab.tsx +7 -0
  65. package/build/website/components/ContentTabs.tsx +82 -0
  66. package/build/website/components/DefaultCatchBoundary.tsx +54 -0
  67. package/build/website/components/DefinitionList.tsx +21 -0
  68. package/build/website/components/Details.tsx +30 -0
  69. package/build/website/components/FileTree.tsx +52 -0
  70. package/build/website/components/Footer.tsx +16 -0
  71. package/build/website/components/FootnoteRef.tsx +52 -0
  72. package/build/website/components/Heading.tsx +20 -0
  73. package/build/website/components/InlineBadge.tsx +9 -0
  74. package/build/website/components/InlineIcon.tsx +10 -0
  75. package/build/website/components/InlineToc.tsx +31 -0
  76. package/build/website/components/Layout.tsx +190 -0
  77. package/build/website/components/LinkButton.tsx +31 -0
  78. package/build/website/components/Mermaid.tsx +18 -0
  79. package/build/website/components/MermaidRenderer.tsx +37 -0
  80. package/build/website/components/MiniSidebar.tsx +49 -0
  81. package/build/website/components/NotFound.tsx +27 -0
  82. package/build/website/components/PackageTabs.tsx +74 -0
  83. package/build/website/components/PageToolbar.tsx +75 -0
  84. package/build/website/components/PrevNext.tsx +60 -0
  85. package/build/website/components/Search.tsx +28 -0
  86. package/build/website/components/SearchDialog.tsx +245 -0
  87. package/build/website/components/Section.tsx +24 -0
  88. package/build/website/components/SectionHeader.tsx +35 -0
  89. package/build/website/components/Sidebar.tsx +160 -0
  90. package/build/website/components/SidebarLinks.tsx +70 -0
  91. package/build/website/components/SidebarSections.tsx +71 -0
  92. package/build/website/components/SiteTitle.tsx +21 -0
  93. package/build/website/components/SortableTable.tsx +81 -0
  94. package/build/website/components/SoundCloud.tsx +16 -0
  95. package/build/website/components/TagIndex.tsx +120 -0
  96. package/build/website/components/Theme.tsx +39 -0
  97. package/build/website/components/Toc.tsx +226 -0
  98. package/build/website/components/YouTube.tsx +16 -0
  99. package/build/website/components/ZoomImage.tsx +25 -0
  100. package/build/website/content/article.ts +78 -0
  101. package/build/website/content/tag.ts +29 -0
  102. package/build/website/content-collections.ts +208 -0
  103. package/build/website/elements/accordion.tsx +78 -0
  104. package/build/website/elements/alert-dialog.tsx +185 -0
  105. package/build/website/elements/alert.tsx +74 -0
  106. package/build/website/elements/aspect-ratio.tsx +22 -0
  107. package/build/website/elements/avatar.tsx +107 -0
  108. package/build/website/elements/badge.tsx +51 -0
  109. package/build/website/elements/breadcrumb.tsx +120 -0
  110. package/build/website/elements/button-group.tsx +87 -0
  111. package/build/website/elements/button.tsx +57 -0
  112. package/build/website/elements/calendar.tsx +229 -0
  113. package/build/website/elements/card.tsx +102 -0
  114. package/build/website/elements/carousel.tsx +240 -0
  115. package/build/website/elements/chart.tsx +372 -0
  116. package/build/website/elements/checkbox.tsx +26 -0
  117. package/build/website/elements/collapsible.tsx +19 -0
  118. package/build/website/elements/command.tsx +210 -0
  119. package/build/website/elements/context-menu.tsx +270 -0
  120. package/build/website/elements/dialog.tsx +152 -0
  121. package/build/website/elements/direction.tsx +4 -0
  122. package/build/website/elements/drawer.tsx +127 -0
  123. package/build/website/elements/dropdown-menu.tsx +260 -0
  124. package/build/website/elements/empty.tsx +104 -0
  125. package/build/website/elements/field.tsx +235 -0
  126. package/build/website/elements/hover-card.tsx +49 -0
  127. package/build/website/elements/input-group.tsx +171 -0
  128. package/build/website/elements/input-otp.tsx +84 -0
  129. package/build/website/elements/input.tsx +18 -0
  130. package/build/website/elements/item.tsx +199 -0
  131. package/build/website/elements/kbd.tsx +26 -0
  132. package/build/website/elements/label.tsx +17 -0
  133. package/build/website/elements/menubar.tsx +282 -0
  134. package/build/website/elements/native-select.tsx +56 -0
  135. package/build/website/elements/navigation-menu.tsx +171 -0
  136. package/build/website/elements/pagination.tsx +133 -0
  137. package/build/website/elements/popover.tsx +88 -0
  138. package/build/website/elements/progress.tsx +81 -0
  139. package/build/website/elements/radio-group.tsx +36 -0
  140. package/build/website/elements/resizable.tsx +48 -0
  141. package/build/website/elements/scroll-area.tsx +51 -0
  142. package/build/website/elements/select.tsx +200 -0
  143. package/build/website/elements/separator.tsx +22 -0
  144. package/build/website/elements/sheet.tsx +130 -0
  145. package/build/website/elements/sidebar.tsx +717 -0
  146. package/build/website/elements/skeleton.tsx +13 -0
  147. package/build/website/elements/slider.tsx +57 -0
  148. package/build/website/elements/sonner.tsx +40 -0
  149. package/build/website/elements/spinner.tsx +16 -0
  150. package/build/website/elements/switch.tsx +30 -0
  151. package/build/website/elements/table.tsx +112 -0
  152. package/build/website/elements/tabs.tsx +79 -0
  153. package/build/website/elements/textarea.tsx +16 -0
  154. package/build/website/elements/toggle-group.tsx +87 -0
  155. package/build/website/elements/toggle.tsx +43 -0
  156. package/build/website/elements/tooltip.tsx +67 -0
  157. package/build/website/env.d.ts +14 -0
  158. package/build/website/helpers/article-icon.ts +61 -0
  159. package/build/website/helpers/article.ts +90 -0
  160. package/build/website/helpers/changelog-source.ts +16 -0
  161. package/build/website/helpers/changelog-source.unit.ts +38 -0
  162. package/build/website/helpers/dynamic-icon-resolver.tsx +19 -0
  163. package/build/website/helpers/dynamic-icon.tsx +12 -0
  164. package/build/website/helpers/favicon.ts +7 -0
  165. package/build/website/helpers/model.ts +4 -0
  166. package/build/website/helpers/resolve-asset-path.ts +9 -0
  167. package/build/website/helpers/resolve-includes.ts +131 -0
  168. package/build/website/helpers/resolve-includes.unit.ts +126 -0
  169. package/build/website/helpers/search-text.ts +15 -0
  170. package/build/website/helpers/section.ts +50 -0
  171. package/build/website/helpers/section.unit.ts +71 -0
  172. package/build/website/helpers/style.ts +6 -0
  173. package/build/website/helpers/theme.ts +27 -0
  174. package/build/website/helpers/toc-context.ts +10 -0
  175. package/build/website/helpers/toc.ts +46 -0
  176. package/build/website/helpers/toc.unit.ts +74 -0
  177. package/build/website/hooks/in-view.ts +30 -0
  178. package/build/website/hooks/media.ts +19 -0
  179. package/build/website/models/article.ts +55 -0
  180. package/build/website/models/toc.ts +5 -0
  181. package/build/website/plugins/rehype-inline-code.ts +107 -0
  182. package/build/website/plugins/rehype-task-list-a11y.ts +33 -0
  183. package/build/website/plugins/remark-abbr.ts +46 -0
  184. package/build/website/plugins/remark-abbr.unit.ts +99 -0
  185. package/build/website/plugins/remark-ansi.ts +248 -0
  186. package/build/website/plugins/remark-ansi.unit.ts +197 -0
  187. package/build/website/plugins/remark-badge.ts +50 -0
  188. package/build/website/plugins/remark-badge.unit.ts +96 -0
  189. package/build/website/plugins/remark-button.ts +60 -0
  190. package/build/website/plugins/remark-button.unit.ts +147 -0
  191. package/build/website/plugins/remark-callout.ts +57 -0
  192. package/build/website/plugins/remark-card.ts +80 -0
  193. package/build/website/plugins/remark-code-tabs.ts +87 -0
  194. package/build/website/plugins/remark-columns.ts +66 -0
  195. package/build/website/plugins/remark-custom-heading-id.ts +70 -0
  196. package/build/website/plugins/remark-custom-heading-id.unit.ts +131 -0
  197. package/build/website/plugins/remark-deflist.ts +36 -0
  198. package/build/website/plugins/remark-details.ts +49 -0
  199. package/build/website/plugins/remark-filetree.ts +89 -0
  200. package/build/website/plugins/remark-filetree.unit.ts +137 -0
  201. package/build/website/plugins/remark-github-callout.ts +71 -0
  202. package/build/website/plugins/remark-icon.ts +42 -0
  203. package/build/website/plugins/remark-image.ts +34 -0
  204. package/build/website/plugins/remark-media.ts +62 -0
  205. package/build/website/plugins/remark-media.unit.ts +74 -0
  206. package/build/website/plugins/remark-mermaid.ts +23 -0
  207. package/build/website/plugins/remark-npm.ts +52 -0
  208. package/build/website/plugins/remark-steps.ts +36 -0
  209. package/build/website/plugins/remark-steps.unit.ts +97 -0
  210. package/build/website/plugins/remark-tab.ts +100 -0
  211. package/build/website/plugins/remark-tab.unit.ts +181 -0
  212. package/build/website/plugins/remark-toc.ts +39 -0
  213. package/build/website/plugins/remark-toc.unit.ts +82 -0
  214. package/build/website/plugins/shiki-icon.ts +82 -0
  215. package/build/website/plugins/shiki-line-highlight.ts +174 -0
  216. package/build/website/plugins/vite-livemark.ts +91 -0
  217. package/build/website/routeTree.gen.ts +86 -0
  218. package/build/website/router.tsx +34 -0
  219. package/build/website/routes/$.tsx +92 -0
  220. package/build/website/routes/__root.tsx +97 -0
  221. package/build/website/server.ts +7 -0
  222. package/build/website/styles/general.css +163 -0
  223. package/build/website/styles/markdown.css +214 -0
  224. package/build/website/vite.config.ts +71 -0
  225. package/entrypoints/main.ts +12 -0
  226. package/package.json +120 -12
  227. package/build/descriptor/index.d.ts +0 -3
  228. package/build/descriptor/index.js +0 -4
  229. package/build/descriptor/load.d.ts +0 -8
  230. package/build/descriptor/load.js +0 -40
  231. package/build/descriptor/node.d.ts +0 -125
  232. package/build/descriptor/node.js +0 -9
  233. package/build/descriptor/save.d.ts +0 -8
  234. package/build/descriptor/save.js +0 -17
  235. package/build/descriptor/save.spec.js +0 -80
  236. package/build/descriptor/validate.d.ts +0 -9
  237. package/build/descriptor/validate.js +0 -14
  238. package/build/descriptor/validate.spec.js +0 -124
  239. package/build/dialect/Dialect.d.ts +0 -88
  240. package/build/dialect/Dialect.js +0 -2
  241. package/build/dialect/index.d.ts +0 -3
  242. package/build/dialect/index.js +0 -3
  243. package/build/dialect/load.d.ts +0 -4
  244. package/build/dialect/load.js +0 -7
  245. package/build/dialect/save.d.ts +0 -9
  246. package/build/dialect/save.js +0 -13
  247. package/build/dialect/validate.d.ts +0 -1
  248. package/build/dialect/validate.js +0 -4
  249. package/build/metadata/index.d.ts +0 -3
  250. package/build/metadata/index.js +0 -4
  251. package/build/metadata/load.d.ts +0 -10
  252. package/build/metadata/load.js +0 -55
  253. package/build/metadata/node.d.ts +0 -125
  254. package/build/metadata/node.js +0 -9
  255. package/build/metadata/save.d.ts +0 -8
  256. package/build/metadata/save.js +0 -17
  257. package/build/metadata/save.spec.js +0 -80
  258. package/build/metadata/validate.d.ts +0 -9
  259. package/build/metadata/validate.js +0 -14
  260. package/build/metadata/validate.spec.d.ts +0 -1
  261. package/build/metadata/validate.spec.js +0 -124
  262. package/build/package/Contributor.d.ts +0 -21
  263. package/build/package/Contributor.js +0 -2
  264. package/build/package/Package.d.ts +0 -65
  265. package/build/package/Package.js +0 -2
  266. package/build/package/index.d.ts +0 -4
  267. package/build/package/index.js +0 -3
  268. package/build/package/load.d.ts +0 -4
  269. package/build/package/load.js +0 -7
  270. package/build/package/save.d.ts +0 -9
  271. package/build/package/save.js +0 -13
  272. package/build/package/validate.d.ts +0 -1
  273. package/build/package/validate.js +0 -4
  274. package/build/resource/License.d.ts +0 -18
  275. package/build/resource/License.js +0 -2
  276. package/build/resource/Resource.d.ts +0 -67
  277. package/build/resource/Resource.js +0 -2
  278. package/build/resource/Source.d.ts +0 -17
  279. package/build/resource/Source.js +0 -2
  280. package/build/resource/index.d.ts +0 -5
  281. package/build/resource/index.js +0 -2
  282. package/build/resource/load.d.ts +0 -1
  283. package/build/resource/load.js +0 -2
  284. package/build/resource/save.d.ts +0 -9
  285. package/build/resource/save.js +0 -13
  286. package/build/resource/types/index.d.ts +0 -1
  287. package/build/resource/types/index.js +0 -2
  288. package/build/resource/types/table.d.ts +0 -29
  289. package/build/resource/types/table.js +0 -2
  290. package/build/resource/validate.d.ts +0 -1
  291. package/build/resource/validate.js +0 -4
  292. package/build/schema/Field.d.ts +0 -5
  293. package/build/schema/Field.js +0 -2
  294. package/build/schema/Schema.d.ts +0 -55
  295. package/build/schema/Schema.js +0 -2
  296. package/build/schema/fields/any.d.ts +0 -20
  297. package/build/schema/fields/any.js +0 -2
  298. package/build/schema/fields/array.d.ts +0 -32
  299. package/build/schema/fields/array.js +0 -2
  300. package/build/schema/fields/base.d.ts +0 -42
  301. package/build/schema/fields/base.js +0 -2
  302. package/build/schema/fields/boolean.d.ts +0 -28
  303. package/build/schema/fields/boolean.js +0 -2
  304. package/build/schema/fields/date.d.ts +0 -35
  305. package/build/schema/fields/date.js +0 -2
  306. package/build/schema/fields/datetime.d.ts +0 -35
  307. package/build/schema/fields/datetime.js +0 -2
  308. package/build/schema/fields/duration.d.ts +0 -28
  309. package/build/schema/fields/duration.js +0 -2
  310. package/build/schema/fields/geojson.d.ts +0 -26
  311. package/build/schema/fields/geojson.js +0 -2
  312. package/build/schema/fields/geopoint.d.ts +0 -27
  313. package/build/schema/fields/geopoint.js +0 -2
  314. package/build/schema/fields/index.d.ts +0 -16
  315. package/build/schema/fields/index.js +0 -17
  316. package/build/schema/fields/integer.d.ts +0 -37
  317. package/build/schema/fields/integer.js +0 -2
  318. package/build/schema/fields/list.d.ts +0 -36
  319. package/build/schema/fields/list.js +0 -2
  320. package/build/schema/fields/number.d.ts +0 -40
  321. package/build/schema/fields/number.js +0 -2
  322. package/build/schema/fields/object.d.ts +0 -32
  323. package/build/schema/fields/object.js +0 -2
  324. package/build/schema/fields/string.d.ts +0 -40
  325. package/build/schema/fields/string.js +0 -2
  326. package/build/schema/fields/time.d.ts +0 -35
  327. package/build/schema/fields/time.js +0 -2
  328. package/build/schema/fields/year.d.ts +0 -28
  329. package/build/schema/fields/year.js +0 -2
  330. package/build/schema/fields/yearmonth.d.ts +0 -28
  331. package/build/schema/fields/yearmonth.js +0 -2
  332. package/build/schema/index.d.ts +0 -4
  333. package/build/schema/index.js +0 -2
  334. package/build/schema/load.d.ts +0 -1
  335. package/build/schema/load.js +0 -2
  336. package/build/schema/save.d.ts +0 -9
  337. package/build/schema/save.js +0 -13
  338. package/build/schema/validate.d.ts +0 -1
  339. package/build/schema/validate.js +0 -4
  340. package/build/tsconfig.tsbuildinfo +0 -1
  341. package/index.ts +0 -0
  342. package/tsconfig.json +0 -10
  343. package/typedoc.json +0 -4
  344. /package/build/{descriptor/save.spec.d.ts → actions/changelog/build.unit.d.ts} +0 -0
  345. /package/build/{descriptor/validate.spec.d.ts → actions/config/define.unit.d.ts} +0 -0
  346. /package/build/{metadata/save.spec.d.ts → actions/config/load.unit.d.ts} +0 -0
@@ -0,0 +1,172 @@
1
+ import { MDXContent } from "@content-collections/mdx/react"
2
+ import { Calendar, History, User } from "lucide-react"
3
+ import type { ArticleView } from "../models/article.ts"
4
+ import { TocContext } from "../helpers/toc-context.ts"
5
+ import { Abbr } from "./Abbr.tsx"
6
+ import { AnsiCode } from "./AnsiCode.tsx"
7
+ import { Callout } from "./Callout.tsx"
8
+ import { Card } from "./Card.tsx"
9
+ import { Cards } from "./Cards.tsx"
10
+ import { CodeBlock } from "./CodeBlock.tsx"
11
+ import { CodeTabs } from "./CodeTabs.tsx"
12
+ import { Column } from "./Column.tsx"
13
+ import { Columns } from "./Columns.tsx"
14
+ import { ContentTab } from "./ContentTab.tsx"
15
+ import { ContentTabs } from "./ContentTabs.tsx"
16
+ import {
17
+ DefinitionDetail,
18
+ DefinitionList,
19
+ DefinitionTerm,
20
+ } from "./DefinitionList.tsx"
21
+ import { Details } from "./Details.tsx"
22
+ import { FileTree } from "./FileTree.tsx"
23
+ import { Footer } from "./Footer.tsx"
24
+ import { FootnoteRef } from "./FootnoteRef.tsx"
25
+ import { headingComponents } from "./Heading.tsx"
26
+ import { InlineBadge } from "./InlineBadge.tsx"
27
+ import { InlineIcon } from "./InlineIcon.tsx"
28
+ import { InlineToc } from "./InlineToc.tsx"
29
+ import { LinkButton } from "./LinkButton.tsx"
30
+ import { Mermaid } from "./Mermaid.tsx"
31
+ import { PackageTabs } from "./PackageTabs.tsx"
32
+ import { PageToolbar } from "./PageToolbar.tsx"
33
+ import { PrevNext } from "./PrevNext.tsx"
34
+ import {
35
+ SortableTable,
36
+ TableBody,
37
+ TableCell,
38
+ TableHead,
39
+ TableHeader,
40
+ TableRow,
41
+ } from "./SortableTable.tsx"
42
+ import { SoundCloud } from "./SoundCloud.tsx"
43
+ import { MobileToc, Toc } from "./Toc.tsx"
44
+ import { YouTube } from "./YouTube.tsx"
45
+ import { ZoomImage } from "./ZoomImage.tsx"
46
+ import { Separator } from "../elements/separator.tsx"
47
+
48
+ /** Full-page article layout: MDX content, table of contents, toolbar, prev/next, footer */
49
+ export function Article(props: { article: ArticleView }) {
50
+ const { article } = props
51
+ const lastUpdated = formatDate(article.lastUpdated)
52
+ const publishedDate = formatDate(article.date)
53
+ const authors = article.author
54
+ ? Array.isArray(article.author)
55
+ ? article.author
56
+ : [article.author]
57
+ : []
58
+ const hasMeta = publishedDate || authors.length > 0 || lastUpdated
59
+
60
+ const H1 = (headingProps: React.HTMLAttributes<HTMLHeadingElement>) => (
61
+ <>
62
+ <h1 {...headingProps}>
63
+ {headingProps.id ? (
64
+ <a href={`#${headingProps.id}`}>{headingProps.children}</a>
65
+ ) : (
66
+ headingProps.children
67
+ )}
68
+ </h1>
69
+ {hasMeta && (
70
+ <p className="flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-muted-foreground !-mt-4 !mb-6">
71
+ {authors.length > 0 && (
72
+ <span className="flex items-center gap-1.5">
73
+ <User className="size-3.5" />
74
+ {authors.join(", ")}
75
+ </span>
76
+ )}
77
+ {publishedDate && (
78
+ <span className="flex items-center gap-1.5">
79
+ <Calendar className="size-3.5" />
80
+ Published {publishedDate}
81
+ </span>
82
+ )}
83
+ {lastUpdated && (
84
+ <span className="flex items-center gap-1.5">
85
+ <History className="size-3.5" />
86
+ Updated {lastUpdated}
87
+ </span>
88
+ )}
89
+ </p>
90
+ )}
91
+ {article.image && (
92
+ <img
93
+ src={article.image}
94
+ alt=""
95
+ className="!mt-0 !mb-6 w-full rounded-xl border shadow-sm"
96
+ />
97
+ )}
98
+ </>
99
+ )
100
+
101
+ return (
102
+ <TocContext.Provider value={article.tocItems}>
103
+ {article.toc !== false && (
104
+ <MobileToc items={article.tocItems}>
105
+ <PageToolbar file={article.file} content={article.content} />
106
+ </MobileToc>
107
+ )}
108
+ <div className="flex flex-1 gap-10 p-4 pt-8 md:p-10">
109
+ <div className="flex-1 min-w-0 mx-auto max-w-3xl">
110
+ <div className="prose dark:prose-invert max-w-none">
111
+ <MDXContent
112
+ code={article.mdx}
113
+ components={{
114
+ hr: Separator,
115
+ img: ZoomImage,
116
+ pre: CodeBlock,
117
+ table: SortableTable,
118
+ thead: TableHeader,
119
+ tbody: TableBody,
120
+ tr: TableRow,
121
+ th: TableHead,
122
+ td: TableCell,
123
+ a: FootnoteRef,
124
+ Abbr,
125
+ AnsiCode,
126
+ Callout,
127
+ Card,
128
+ Cards,
129
+ Column,
130
+ Columns,
131
+ CodeTabs,
132
+ ContentTab,
133
+ ContentTabs,
134
+ DefinitionDetail,
135
+ DefinitionList,
136
+ DefinitionTerm,
137
+ Details,
138
+ FileTree,
139
+ InlineBadge,
140
+ InlineIcon,
141
+ InlineToc,
142
+ LinkButton,
143
+ Mermaid,
144
+ PackageTabs,
145
+ SoundCloud,
146
+ YouTube,
147
+ ...headingComponents,
148
+ h1: H1,
149
+ }}
150
+ />
151
+ </div>
152
+ <PrevNext path={article.path} />
153
+ <Footer />
154
+ </div>
155
+ {article.toc !== false && (
156
+ <Toc items={article.tocItems}>
157
+ <PageToolbar file={article.file} content={article.content} />
158
+ </Toc>
159
+ )}
160
+ </div>
161
+ </TocContext.Provider>
162
+ )
163
+ }
164
+
165
+ function formatDate(iso?: string) {
166
+ if (!iso) return undefined
167
+ return new Date(iso).toLocaleDateString("en-US", {
168
+ year: "numeric",
169
+ month: "short",
170
+ day: "numeric",
171
+ })
172
+ }
@@ -0,0 +1,32 @@
1
+ import { ArrowUp } from "lucide-react"
2
+ import { useEffect, useState } from "react"
3
+ import { Button } from "../elements/button.tsx"
4
+
5
+ /** Floating button that scrolls the page back to the top once the user
6
+ * has scrolled past a threshold. */
7
+ export function BackToTop() {
8
+ const [visible, setVisible] = useState(false)
9
+
10
+ useEffect(() => {
11
+ const onScroll = () => setVisible(window.scrollY > 400)
12
+ onScroll()
13
+ window.addEventListener("scroll", onScroll, { passive: true })
14
+ return () => window.removeEventListener("scroll", onScroll)
15
+ }, [])
16
+
17
+ return (
18
+ <Button
19
+ type="button"
20
+ variant="outline"
21
+ aria-label="Back to top"
22
+ onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
23
+ className={`fixed bottom-6 right-6 z-30 size-10 rounded-full shadow-md transition-all duration-200 ${
24
+ visible
25
+ ? "opacity-100 translate-y-0 pointer-events-auto"
26
+ : "opacity-0 translate-y-2 pointer-events-none"
27
+ }`}
28
+ >
29
+ <ArrowUp className="size-4" />
30
+ </Button>
31
+ )
32
+ }
@@ -0,0 +1,32 @@
1
+ import { Star, MessageCircle } from "lucide-react"
2
+
3
+ /** Technical preview banner displayed in the header */
4
+ export function Banner() {
5
+ return (
6
+ <div className="hidden md:flex flex-1 items-center justify-end">
7
+ <div className="rounded-xl border border-primary/20 bg-primary/2 dark:bg-primary/5 shadow-xs px-3 py-1.5 text-sm text-primary">
8
+ <span>
9
+ This project is in technical preview.{" "}
10
+ <a
11
+ href="https://github.com/datisthq/livemark"
12
+ target="_blank"
13
+ rel="noopener noreferrer"
14
+ className="font-semibold hover:underline underline-offset-2"
15
+ >
16
+ <Star className="inline size-3.5 align-[-0.125em]" /> Star on GitHub
17
+ </a>{" "}
18
+ and{" "}
19
+ <a
20
+ href="https://github.com/datisthq/livemark/discussions"
21
+ target="_blank"
22
+ rel="noopener noreferrer"
23
+ className="font-semibold hover:underline underline-offset-2"
24
+ >
25
+ <MessageCircle className="inline size-3.5 align-[-0.125em]" /> share
26
+ feedback!
27
+ </a>
28
+ </span>
29
+ </div>
30
+ </div>
31
+ )
32
+ }
@@ -0,0 +1,121 @@
1
+ import { Link } from "@tanstack/react-router"
2
+ import { History } from "lucide-react"
3
+ import {
4
+ currentSection,
5
+ sectionFlatArticles,
6
+ sortedArticles,
7
+ } from "../content/article.ts"
8
+ import { Separator } from "../elements/separator.tsx"
9
+ import { TocContext } from "../helpers/toc-context.ts"
10
+ import { Footer } from "./Footer.tsx"
11
+ import { PageToolbar } from "./PageToolbar.tsx"
12
+ import { MobileToc, Toc } from "./Toc.tsx"
13
+
14
+ /** Auto-generated blog index listing all posts by date */
15
+ export function BlogIndex(props: { sectionPrefix: string }) {
16
+ const section = currentSection(props.sectionPrefix)
17
+ const flat = sectionFlatArticles.get(props.sectionPrefix) ?? []
18
+ const posts = flat
19
+ .map(p => sortedArticles.find(a => a.path === p))
20
+ .filter(a => a !== undefined)
21
+
22
+ const tocItems = posts.map(post => ({
23
+ url: `#${slugOf(post.path)}`,
24
+ title: post.title,
25
+ depth: 2,
26
+ }))
27
+
28
+ const content = [
29
+ `# ${section?.title ?? "Blog"}`,
30
+ ...posts.map(post => {
31
+ const parts = [`## ${post.title}`]
32
+ if (post.date) parts.push(formatDate(post.date))
33
+ if (post.author) {
34
+ parts.push(
35
+ Array.isArray(post.author) ? post.author.join(", ") : post.author,
36
+ )
37
+ }
38
+ if (post.description) parts.push("", post.description)
39
+ return parts.join("\n")
40
+ }),
41
+ ].join("\n\n")
42
+
43
+ return (
44
+ <TocContext.Provider value={tocItems}>
45
+ <MobileToc items={tocItems}>
46
+ <PageToolbar content={content} />
47
+ </MobileToc>
48
+ <div className="flex flex-1 gap-10 p-4 pt-8 md:p-10">
49
+ <div className="flex-1 min-w-0 mx-auto max-w-3xl">
50
+ <div className="prose dark:prose-invert max-w-none mb-8">
51
+ <h1 id="top">
52
+ <a href="#top">{section?.title ?? "Blog"}</a>
53
+ </h1>
54
+ {posts[0]?.date && (
55
+ <p className="flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-muted-foreground !-mt-4 !mb-0">
56
+ <span className="flex items-center gap-1.5">
57
+ <History className="size-3.5" />
58
+ Updated {formatDate(posts[0].date)}
59
+ </span>
60
+ </p>
61
+ )}
62
+ </div>
63
+ <div className="space-y-6">
64
+ {posts.map((post, i) => (
65
+ <article key={post.path} id={slugOf(post.path)}>
66
+ {i > 0 && <Separator className="mb-6" />}
67
+ <h2 className="text-2xl">
68
+ <Link
69
+ to="/$"
70
+ params={{ _splat: post.path.replace(/^\/|\/$/g, "") }}
71
+ className="font-medium hover:text-primary transition-colors"
72
+ >
73
+ {post.title}
74
+ </Link>
75
+ </h2>
76
+ <p className="text-sm text-muted-foreground mt-1 flex gap-3">
77
+ {post.date && <span>{formatDate(post.date)}</span>}
78
+ {post.author && (
79
+ <span>
80
+ {Array.isArray(post.author)
81
+ ? post.author.join(", ")
82
+ : post.author}
83
+ </span>
84
+ )}
85
+ </p>
86
+ {post.description && (
87
+ <p className="text-muted-foreground mt-2">
88
+ {post.description}
89
+ </p>
90
+ )}
91
+ </article>
92
+ ))}
93
+ </div>
94
+ <div className="mt-10">
95
+ <Footer />
96
+ </div>
97
+ </div>
98
+ <Toc items={tocItems}>
99
+ <PageToolbar content={content} />
100
+ </Toc>
101
+ </div>
102
+ </TocContext.Provider>
103
+ )
104
+ }
105
+
106
+ function slugOf(path: string) {
107
+ return (
108
+ path
109
+ .replace(/^\/|\/$/g, "")
110
+ .split("/")
111
+ .pop() ?? ""
112
+ )
113
+ }
114
+
115
+ function formatDate(iso: string) {
116
+ return new Date(iso).toLocaleDateString("en-US", {
117
+ year: "numeric",
118
+ month: "short",
119
+ day: "numeric",
120
+ })
121
+ }
@@ -0,0 +1,162 @@
1
+ import { Link, useLocation } from "@tanstack/react-router"
2
+ import { useHotkey } from "@tanstack/react-hotkeys"
3
+ import { Clock, List, Rss, Tag } from "lucide-react"
4
+ import {
5
+ currentSection,
6
+ sectionFlatArticles,
7
+ sortedArticles,
8
+ } from "../content/article.ts"
9
+ import {
10
+ Sidebar as SidebarRoot,
11
+ SidebarContent,
12
+ SidebarFooter,
13
+ SidebarGroup,
14
+ SidebarGroupContent,
15
+ SidebarGroupLabel,
16
+ SidebarHeader,
17
+ SidebarMenu,
18
+ SidebarMenuButton,
19
+ SidebarMenuItem,
20
+ SidebarMenuSub,
21
+ SidebarMenuSubButton,
22
+ SidebarMenuSubItem,
23
+ SidebarRail,
24
+ useSidebar,
25
+ } from "../elements/sidebar.tsx"
26
+ import { Search } from "./Search.tsx"
27
+ import { SidebarLinks } from "./SidebarLinks.tsx"
28
+ import { SidebarSections } from "./SidebarSections.tsx"
29
+ import { SiteTitle } from "./SiteTitle.tsx"
30
+ import { Theme } from "./Theme.tsx"
31
+
32
+ /** Blog-specific sidebar with Posts, Tags, and Links */
33
+ export function BlogSidebar() {
34
+ const pathname = useLocation({ select: l => l.pathname })
35
+ const { toggleSidebar } = useSidebar()
36
+
37
+ useHotkey("S", toggleSidebar)
38
+
39
+ const section = currentSection(`/${pathname.replace(/^\/|\/$/g, "")}/`)
40
+ const flat = section ? (sectionFlatArticles.get(section.prefix) ?? []) : []
41
+ const posts = flat
42
+ .map(p => sortedArticles.find(a => a.path === p))
43
+ .filter(a => a !== undefined)
44
+ const recentPosts = posts.slice(0, 5)
45
+
46
+ const allTags = new Set<string>()
47
+ for (const post of posts) {
48
+ for (const tag of post.tags ?? []) {
49
+ allTags.add(tag)
50
+ }
51
+ }
52
+ const tags = [...allTags].sort()
53
+
54
+ const normalized = `/${pathname.replace(/^\/|\/$/g, "")}/`
55
+ const isIndex = section ? normalized === section.prefix : false
56
+ const sectionPath = (section?.prefix ?? "/blog/").replace(/^\/|\/$/g, "")
57
+
58
+ return (
59
+ <SidebarRoot>
60
+ <SidebarHeader>
61
+ <SidebarMenu>
62
+ <SidebarMenuItem>
63
+ <SidebarMenuButton size="lg" render={<Link to="/" />}>
64
+ <SiteTitle />
65
+ </SidebarMenuButton>
66
+ </SidebarMenuItem>
67
+ </SidebarMenu>
68
+ </SidebarHeader>
69
+ <SidebarContent>
70
+ <SidebarSections />
71
+ <SidebarGroup>
72
+ <SidebarGroupLabel className="uppercase font-mono text-xs tracking-widest">
73
+ Posts
74
+ </SidebarGroupLabel>
75
+ <SidebarGroupContent>
76
+ <SidebarMenu>
77
+ <SidebarMenuItem>
78
+ <SidebarMenuButton
79
+ isActive={isIndex}
80
+ className={isIndex ? "" : "opacity-75"}
81
+ render={<Link to="/$" params={{ _splat: sectionPath }} />}
82
+ >
83
+ <List className="size-4" />
84
+ <span>All Posts</span>
85
+ </SidebarMenuButton>
86
+ </SidebarMenuItem>
87
+ <SidebarMenuItem>
88
+ <SidebarMenuButton className="opacity-75">
89
+ <Clock className="size-4" />
90
+ <span>Recent Posts</span>
91
+ </SidebarMenuButton>
92
+ <SidebarMenuSub>
93
+ {recentPosts.map(post => {
94
+ const active = normalized === post.path
95
+ return (
96
+ <SidebarMenuSubItem key={post.path}>
97
+ <SidebarMenuSubButton
98
+ isActive={active}
99
+ className={active ? "" : "opacity-75"}
100
+ render={
101
+ <Link
102
+ to="/$"
103
+ params={{
104
+ _splat: post.path.replace(/^\/|\/$/g, ""),
105
+ }}
106
+ />
107
+ }
108
+ >
109
+ <span>{post.title}</span>
110
+ </SidebarMenuSubButton>
111
+ </SidebarMenuSubItem>
112
+ )
113
+ })}
114
+ </SidebarMenuSub>
115
+ </SidebarMenuItem>
116
+ <SidebarMenuItem>
117
+ <SidebarMenuButton className="opacity-75">
118
+ <Rss className="size-4" />
119
+ <span>RSS Feed</span>
120
+ </SidebarMenuButton>
121
+ </SidebarMenuItem>
122
+ </SidebarMenu>
123
+ </SidebarGroupContent>
124
+ </SidebarGroup>
125
+
126
+ {tags.length > 0 && (
127
+ <SidebarGroup>
128
+ <SidebarGroupLabel className="uppercase font-mono text-xs tracking-widest">
129
+ Tags
130
+ </SidebarGroupLabel>
131
+ <SidebarGroupContent>
132
+ <SidebarMenu>
133
+ {tags.map(tag => {
134
+ const tagPath = `${sectionPath}/tags/${tag}`
135
+ const tagActive = normalized === `/${tagPath}/`
136
+ return (
137
+ <SidebarMenuItem key={tag}>
138
+ <SidebarMenuButton
139
+ isActive={tagActive}
140
+ className={tagActive ? "" : "opacity-75"}
141
+ render={<Link to="/$" params={{ _splat: tagPath }} />}
142
+ >
143
+ <Tag className="size-3.5" />
144
+ <span>{tag}</span>
145
+ </SidebarMenuButton>
146
+ </SidebarMenuItem>
147
+ )
148
+ })}
149
+ </SidebarMenu>
150
+ </SidebarGroupContent>
151
+ </SidebarGroup>
152
+ )}
153
+ <SidebarLinks />
154
+ </SidebarContent>
155
+ <SidebarFooter className="p-4 space-y-2">
156
+ <Search />
157
+ <Theme />
158
+ </SidebarFooter>
159
+ <SidebarRail />
160
+ </SidebarRoot>
161
+ )
162
+ }
@@ -0,0 +1,22 @@
1
+ import { Link, useLocation, useMatches } from "@tanstack/react-router"
2
+ import { currentSection } from "../content/article.ts"
3
+
4
+ export function Breadcrumbs() {
5
+ const matches = useMatches()
6
+ const last = matches[matches.length - 1]
7
+ const loaderData = last?.loaderData as { title?: string } | undefined
8
+ const pathname = useLocation({ select: l => l.pathname })
9
+ const section = currentSection(`/${pathname.replace(/^\/|\/$/g, "")}/`)
10
+
11
+ return (
12
+ <nav className="flex items-center gap-1.5 text-sm text-muted-foreground">
13
+ <Link to="/" className="hover:text-foreground transition-colors">
14
+ {section?.title ?? import.meta.env.CONFIG.title}
15
+ </Link>
16
+ <span>/</span>
17
+ {loaderData?.title && (
18
+ <span className="text-foreground font-medium">{loaderData.title}</span>
19
+ )}
20
+ </nav>
21
+ )
22
+ }
@@ -0,0 +1,72 @@
1
+ import { AlertTriangle, Flame, Info, Lightbulb } from "lucide-react"
2
+ import { cn } from "../helpers/style.ts"
3
+
4
+ type CalloutType = "note" | "tip" | "info" | "warning" | "danger"
5
+
6
+ interface CalloutConfig {
7
+ icon: React.ElementType
8
+ label: string
9
+ classes: string
10
+ }
11
+
12
+ const configs: Record<CalloutType, CalloutConfig> = {
13
+ note: {
14
+ icon: Info,
15
+ label: "Note",
16
+ classes:
17
+ "border-blue-500/30 bg-blue-50/50 text-blue-900 dark:bg-blue-950/30 dark:text-blue-200",
18
+ },
19
+ info: {
20
+ icon: Info,
21
+ label: "Info",
22
+ classes:
23
+ "border-blue-500/30 bg-blue-50/50 text-blue-900 dark:bg-blue-950/30 dark:text-blue-200",
24
+ },
25
+ tip: {
26
+ icon: Lightbulb,
27
+ label: "Tip",
28
+ classes:
29
+ "border-green-500/30 bg-green-50/50 text-green-900 dark:bg-green-950/30 dark:text-green-200",
30
+ },
31
+ warning: {
32
+ icon: AlertTriangle,
33
+ label: "Warning",
34
+ classes:
35
+ "border-yellow-500/30 bg-yellow-50/50 text-yellow-900 dark:bg-yellow-950/30 dark:text-yellow-200",
36
+ },
37
+ danger: {
38
+ icon: Flame,
39
+ label: "Danger",
40
+ classes:
41
+ "border-red-500/30 bg-red-50/50 text-red-900 dark:bg-red-950/30 dark:text-red-200",
42
+ },
43
+ }
44
+
45
+ /** Styled callout block for notes, tips, warnings, and other admonitions */
46
+ export function Callout(props: {
47
+ type?: CalloutType
48
+ title?: string
49
+ children: React.ReactNode
50
+ }) {
51
+ const type = props.type ?? "note"
52
+ const config = configs[type]
53
+ const Icon = config.icon
54
+ const title = props.title ?? config.label
55
+
56
+ return (
57
+ <aside
58
+ className={cn(
59
+ "not-prose my-4 rounded-xl border px-4 py-3",
60
+ config.classes,
61
+ )}
62
+ >
63
+ <div className="flex items-center gap-2 font-semibold text-sm mb-2">
64
+ <Icon className="size-4 shrink-0" />
65
+ <span>{title}</span>
66
+ </div>
67
+ <div className="text-sm [&>p]:my-1 [&>p:first-child]:mt-0 [&>p:last-child]:mb-0">
68
+ {props.children}
69
+ </div>
70
+ </aside>
71
+ )
72
+ }
@@ -0,0 +1,48 @@
1
+ import { Link } from "@tanstack/react-router"
2
+ import { DynamicIcon } from "../helpers/dynamic-icon.tsx"
3
+ import {
4
+ Card as CardElement,
5
+ CardContent,
6
+ CardHeader,
7
+ CardTitle,
8
+ } from "../elements/card.tsx"
9
+
10
+ /** Card component with optional icon, title, description, and link */
11
+ export function Card(props: {
12
+ title: string
13
+ href?: string
14
+ icon?: string
15
+ children?: React.ReactNode
16
+ }) {
17
+ const card = (
18
+ <CardElement size="sm" className="transition-colors hover:bg-accent">
19
+ <CardHeader>
20
+ <CardTitle className="flex items-center gap-2">
21
+ {props.icon && (
22
+ <DynamicIcon name={props.icon} className="size-5 text-primary" />
23
+ )}
24
+ {props.title}
25
+ </CardTitle>
26
+ </CardHeader>
27
+ {props.children && (
28
+ <CardContent>
29
+ <div className="text-muted-foreground text-sm">{props.children}</div>
30
+ </CardContent>
31
+ )}
32
+ </CardElement>
33
+ )
34
+
35
+ if (props.href?.startsWith("http")) {
36
+ return (
37
+ <a href={props.href} target="_blank" rel="noopener noreferrer">
38
+ {card}
39
+ </a>
40
+ )
41
+ }
42
+
43
+ if (props.href) {
44
+ return <Link to={props.href}>{card}</Link>
45
+ }
46
+
47
+ return card
48
+ }
@@ -0,0 +1,8 @@
1
+ /** Grid container for card components */
2
+ export function Cards(props: { children: React.ReactNode }) {
3
+ return (
4
+ <div className="not-prose grid grid-cols-1 gap-4 my-4 sm:grid-cols-2">
5
+ {props.children}
6
+ </div>
7
+ )
8
+ }