livemark 0.2.0 → 0.7.1

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 (348) 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/package.json +120 -12
  226. package/skills/authoring/SKILL.md +97 -0
  227. package/skills/configuration/SKILL.md +120 -0
  228. package/skills/customization/SKILL.md +118 -0
  229. package/build/descriptor/index.d.ts +0 -3
  230. package/build/descriptor/index.js +0 -4
  231. package/build/descriptor/load.d.ts +0 -8
  232. package/build/descriptor/load.js +0 -40
  233. package/build/descriptor/node.d.ts +0 -125
  234. package/build/descriptor/node.js +0 -9
  235. package/build/descriptor/save.d.ts +0 -8
  236. package/build/descriptor/save.js +0 -17
  237. package/build/descriptor/save.spec.js +0 -80
  238. package/build/descriptor/validate.d.ts +0 -9
  239. package/build/descriptor/validate.js +0 -14
  240. package/build/descriptor/validate.spec.js +0 -124
  241. package/build/dialect/Dialect.d.ts +0 -88
  242. package/build/dialect/Dialect.js +0 -2
  243. package/build/dialect/index.d.ts +0 -3
  244. package/build/dialect/index.js +0 -3
  245. package/build/dialect/load.d.ts +0 -4
  246. package/build/dialect/load.js +0 -7
  247. package/build/dialect/save.d.ts +0 -9
  248. package/build/dialect/save.js +0 -13
  249. package/build/dialect/validate.d.ts +0 -1
  250. package/build/dialect/validate.js +0 -4
  251. package/build/metadata/index.d.ts +0 -3
  252. package/build/metadata/index.js +0 -4
  253. package/build/metadata/load.d.ts +0 -10
  254. package/build/metadata/load.js +0 -55
  255. package/build/metadata/node.d.ts +0 -125
  256. package/build/metadata/node.js +0 -9
  257. package/build/metadata/save.d.ts +0 -8
  258. package/build/metadata/save.js +0 -17
  259. package/build/metadata/save.spec.js +0 -80
  260. package/build/metadata/validate.d.ts +0 -9
  261. package/build/metadata/validate.js +0 -14
  262. package/build/metadata/validate.spec.d.ts +0 -1
  263. package/build/metadata/validate.spec.js +0 -124
  264. package/build/package/Contributor.d.ts +0 -21
  265. package/build/package/Contributor.js +0 -2
  266. package/build/package/Package.d.ts +0 -65
  267. package/build/package/Package.js +0 -2
  268. package/build/package/index.d.ts +0 -4
  269. package/build/package/index.js +0 -3
  270. package/build/package/load.d.ts +0 -4
  271. package/build/package/load.js +0 -7
  272. package/build/package/save.d.ts +0 -9
  273. package/build/package/save.js +0 -13
  274. package/build/package/validate.d.ts +0 -1
  275. package/build/package/validate.js +0 -4
  276. package/build/resource/License.d.ts +0 -18
  277. package/build/resource/License.js +0 -2
  278. package/build/resource/Resource.d.ts +0 -67
  279. package/build/resource/Resource.js +0 -2
  280. package/build/resource/Source.d.ts +0 -17
  281. package/build/resource/Source.js +0 -2
  282. package/build/resource/index.d.ts +0 -5
  283. package/build/resource/index.js +0 -2
  284. package/build/resource/load.d.ts +0 -1
  285. package/build/resource/load.js +0 -2
  286. package/build/resource/save.d.ts +0 -9
  287. package/build/resource/save.js +0 -13
  288. package/build/resource/types/index.d.ts +0 -1
  289. package/build/resource/types/index.js +0 -2
  290. package/build/resource/types/table.d.ts +0 -29
  291. package/build/resource/types/table.js +0 -2
  292. package/build/resource/validate.d.ts +0 -1
  293. package/build/resource/validate.js +0 -4
  294. package/build/schema/Field.d.ts +0 -5
  295. package/build/schema/Field.js +0 -2
  296. package/build/schema/Schema.d.ts +0 -55
  297. package/build/schema/Schema.js +0 -2
  298. package/build/schema/fields/any.d.ts +0 -20
  299. package/build/schema/fields/any.js +0 -2
  300. package/build/schema/fields/array.d.ts +0 -32
  301. package/build/schema/fields/array.js +0 -2
  302. package/build/schema/fields/base.d.ts +0 -42
  303. package/build/schema/fields/base.js +0 -2
  304. package/build/schema/fields/boolean.d.ts +0 -28
  305. package/build/schema/fields/boolean.js +0 -2
  306. package/build/schema/fields/date.d.ts +0 -35
  307. package/build/schema/fields/date.js +0 -2
  308. package/build/schema/fields/datetime.d.ts +0 -35
  309. package/build/schema/fields/datetime.js +0 -2
  310. package/build/schema/fields/duration.d.ts +0 -28
  311. package/build/schema/fields/duration.js +0 -2
  312. package/build/schema/fields/geojson.d.ts +0 -26
  313. package/build/schema/fields/geojson.js +0 -2
  314. package/build/schema/fields/geopoint.d.ts +0 -27
  315. package/build/schema/fields/geopoint.js +0 -2
  316. package/build/schema/fields/index.d.ts +0 -16
  317. package/build/schema/fields/index.js +0 -17
  318. package/build/schema/fields/integer.d.ts +0 -37
  319. package/build/schema/fields/integer.js +0 -2
  320. package/build/schema/fields/list.d.ts +0 -36
  321. package/build/schema/fields/list.js +0 -2
  322. package/build/schema/fields/number.d.ts +0 -40
  323. package/build/schema/fields/number.js +0 -2
  324. package/build/schema/fields/object.d.ts +0 -32
  325. package/build/schema/fields/object.js +0 -2
  326. package/build/schema/fields/string.d.ts +0 -40
  327. package/build/schema/fields/string.js +0 -2
  328. package/build/schema/fields/time.d.ts +0 -35
  329. package/build/schema/fields/time.js +0 -2
  330. package/build/schema/fields/year.d.ts +0 -28
  331. package/build/schema/fields/year.js +0 -2
  332. package/build/schema/fields/yearmonth.d.ts +0 -28
  333. package/build/schema/fields/yearmonth.js +0 -2
  334. package/build/schema/index.d.ts +0 -4
  335. package/build/schema/index.js +0 -2
  336. package/build/schema/load.d.ts +0 -1
  337. package/build/schema/load.js +0 -2
  338. package/build/schema/save.d.ts +0 -9
  339. package/build/schema/save.js +0 -13
  340. package/build/schema/validate.d.ts +0 -1
  341. package/build/schema/validate.js +0 -4
  342. package/build/tsconfig.tsbuildinfo +0 -1
  343. package/index.ts +0 -0
  344. package/tsconfig.json +0 -10
  345. package/typedoc.json +0 -4
  346. /package/build/{descriptor/save.spec.d.ts → actions/changelog/build.unit.d.ts} +0 -0
  347. /package/build/{descriptor/validate.spec.d.ts → actions/config/define.unit.d.ts} +0 -0
  348. /package/build/{metadata/save.spec.d.ts → actions/config/load.unit.d.ts} +0 -0
@@ -0,0 +1,78 @@
1
+ import { allArticles } from "content-collections"
2
+ import type { ArticleGroup } from "../models/article.ts"
3
+ import {
4
+ buildArticleTree,
5
+ flattenArticleTree,
6
+ groupArticleTree,
7
+ } from "../helpers/article.ts"
8
+ import { matchSection, partitionBySection } from "../helpers/section.ts"
9
+
10
+ /**
11
+ * Articles sorted by frontmatter `order`:
12
+ * positive values first (ascending), then unordered, then negative values
13
+ * (so `order: -1` lands at the very end, `-2` just before it, and so on).
14
+ */
15
+ export const sortedArticles = [...allArticles].sort(
16
+ (a, b) => orderKey(a.order) - orderKey(b.order),
17
+ )
18
+
19
+ /** The article whose path is `/`, if any (rendered in place at the root) */
20
+ export const homeArticle = sortedArticles.find(a => a.path === "/")
21
+
22
+ /** Sidebar sections derived from the path tree, partitioned by `group` */
23
+ export const articleGroups = groupArticleTree(
24
+ buildArticleTree(sortedArticles),
25
+ sortedArticles,
26
+ )
27
+
28
+ /** Articles in depth-first order across all sections (matches sidebar walk) */
29
+ export const flatArticles = articleGroups.flatMap(group =>
30
+ flattenArticleTree(group.nodes),
31
+ )
32
+
33
+ /** The first article in sidebar order, used as the default landing page */
34
+ export const firstArticle = sortedArticles.find(a => a.path === flatArticles[0])
35
+
36
+ function orderKey(order?: number) {
37
+ if (order === undefined) return Number.MAX_SAFE_INTEGER / 2
38
+ if (order < 0) return Number.MAX_SAFE_INTEGER + order
39
+ return order
40
+ }
41
+
42
+ const configSections = import.meta.env.CONFIG.sections
43
+
44
+ /** Per-section article groups, keyed by section prefix */
45
+ export const sectionArticleGroups = new Map<string, ArticleGroup[]>()
46
+
47
+ /** Per-section flat article lists, keyed by section prefix */
48
+ export const sectionFlatArticles = new Map<string, string[]>()
49
+
50
+ /** Per-section first article path, keyed by section prefix */
51
+ export const sectionFirstArticle = new Map<string, string | undefined>()
52
+
53
+ if (configSections?.length) {
54
+ const sectionByPrefix = new Map(configSections.map(s => [s.prefix, s]))
55
+ const buckets = partitionBySection(sortedArticles, configSections)
56
+ for (const [key, bucket] of buckets) {
57
+ const section = sectionByPrefix.get(key)
58
+ const sorted =
59
+ section?.type === "blog" || section?.type === "changelog"
60
+ ? [...bucket].sort(
61
+ (a, b) =>
62
+ new Date(b.date ?? 0).getTime() - new Date(a.date ?? 0).getTime(),
63
+ )
64
+ : bucket
65
+ const tree = buildArticleTree(sorted)
66
+ const groups = groupArticleTree(tree, sorted)
67
+ const flat = groups.flatMap(g => flattenArticleTree(g.nodes))
68
+ sectionArticleGroups.set(key, groups)
69
+ sectionFlatArticles.set(key, flat)
70
+ sectionFirstArticle.set(key, flat[0])
71
+ }
72
+ }
73
+
74
+ /** Find which config section an article path belongs to */
75
+ export function currentSection(path: string) {
76
+ if (!configSections?.length) return undefined
77
+ return matchSection(path, configSections)
78
+ }
@@ -0,0 +1,29 @@
1
+ import { sectionFlatArticles, sortedArticles } from "./article.ts"
2
+
3
+ const configSections = import.meta.env.CONFIG.sections
4
+
5
+ /** Per-section tag → article paths mapping. Articles sorted by date descending. */
6
+ export const sectionTags = new Map<string, Map<string, string[]>>()
7
+
8
+ if (configSections?.length) {
9
+ for (const section of configSections) {
10
+ if (section.type !== "blog") continue
11
+ const flat = sectionFlatArticles.get(section.prefix) ?? []
12
+ const tagMap = new Map<string, string[]>()
13
+ for (const path of flat) {
14
+ const article = sortedArticles.find(a => a.path === path)
15
+ if (!article?.tags) continue
16
+ for (const tag of article.tags) {
17
+ const list = tagMap.get(tag)
18
+ if (list) {
19
+ list.push(path)
20
+ } else {
21
+ tagMap.set(tag, [path])
22
+ }
23
+ }
24
+ }
25
+ if (tagMap.size > 0) {
26
+ sectionTags.set(section.prefix, tagMap)
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,208 @@
1
+ import { execSync } from "node:child_process"
2
+ import { basename, relative, resolve } from "node:path"
3
+ import { defineCollection, defineConfig } from "@content-collections/core"
4
+ import { compileMDX } from "@content-collections/mdx"
5
+ import rehypeShiki from "@shikijs/rehype"
6
+ import { transformerTwoslash } from "@shikijs/twoslash"
7
+ import rehypeKatex from "rehype-katex"
8
+ import rehypeSlug from "rehype-slug"
9
+ import remarkDefinitionList from "remark-definition-list"
10
+ import remarkDirective from "remark-directive"
11
+ import remarkGemoji from "remark-gemoji"
12
+ import remarkGfm from "remark-gfm"
13
+ import remarkMath from "remark-math"
14
+ import { loadConfig } from "../actions/config/load.ts"
15
+ import { buildChangelog, cacheIncludeGlob } from "../actions/changelog/build.ts"
16
+ import { Article } from "./models/article.ts"
17
+ import { pickDefaultIcon } from "./helpers/article-icon.ts"
18
+ import slugify from "@sindresorhus/slugify"
19
+ import remarkCustomHeadingId from "./plugins/remark-custom-heading-id.ts"
20
+ import { remarkCallout } from "./plugins/remark-callout.ts"
21
+ import { remarkCard } from "./plugins/remark-card.ts"
22
+ import { remarkColumns } from "./plugins/remark-columns.ts"
23
+ import { remarkTab } from "./plugins/remark-tab.ts"
24
+ import { remarkBadge } from "./plugins/remark-badge.ts"
25
+ import { remarkButton } from "./plugins/remark-button.ts"
26
+ import { remarkAbbr } from "./plugins/remark-abbr.ts"
27
+ import { remarkDeflist } from "./plugins/remark-deflist.ts"
28
+ import { remarkDetails } from "./plugins/remark-details.ts"
29
+ import { remarkFiletree } from "./plugins/remark-filetree.ts"
30
+ import { remarkIcon } from "./plugins/remark-icon.ts"
31
+ import { remarkCodeTabs } from "./plugins/remark-code-tabs.ts"
32
+ import { remarkGithubCallout } from "./plugins/remark-github-callout.ts"
33
+ import { remarkImage } from "./plugins/remark-image.ts"
34
+ import { remarkMedia } from "./plugins/remark-media.ts"
35
+ import { remarkAnsi } from "./plugins/remark-ansi.ts"
36
+ import { remarkMermaid } from "./plugins/remark-mermaid.ts"
37
+ import { remarkToc } from "./plugins/remark-toc.ts"
38
+ import { remarkNpm } from "./plugins/remark-npm.ts"
39
+ import { remarkSteps } from "./plugins/remark-steps.ts"
40
+ import {
41
+ transformerLineHighlight,
42
+ transformerNotations,
43
+ } from "./plugins/shiki-line-highlight.ts"
44
+ import { rehypeInlineCode } from "./plugins/rehype-inline-code.ts"
45
+ import { rehypeTaskListA11y } from "./plugins/rehype-task-list-a11y.ts"
46
+ import { transformerIcon } from "./plugins/shiki-icon.ts"
47
+ import { resolveAssetPath } from "./helpers/resolve-asset-path.ts"
48
+ import { resolveIncludes } from "./helpers/resolve-includes.ts"
49
+ import { extractSearchText } from "./helpers/search-text.ts"
50
+ import { extractToc } from "./helpers/toc.ts"
51
+
52
+ const config = await loadConfig()
53
+
54
+ const changelogSections =
55
+ config.sections?.filter(s => s.type === "changelog") ?? []
56
+ for (const section of changelogSections) {
57
+ await buildChangelog(section, config)
58
+ }
59
+
60
+ const configInclude = Array.isArray(config.include)
61
+ ? config.include
62
+ : [config.include]
63
+ const include = changelogSections.length
64
+ ? [...configInclude, cacheIncludeGlob()]
65
+ : configInclude
66
+
67
+ // content-collections compiles this file to .content-collections/cache/;
68
+ // going up 2 levels reconstructs the baseDirectory it uses for path resolution
69
+ const baseDir = resolve(import.meta.dirname, "../..")
70
+ const directory = relative(baseDir, config.root) || "."
71
+
72
+ function toPath(filePath: string) {
73
+ const name = basename(filePath).replace(/\.\w+$/, "")
74
+ return slugify(name)
75
+ }
76
+
77
+ function getLastUpdated(filePath: string) {
78
+ try {
79
+ const timestamp = execSync(`git log -1 --format=%cI -- "${filePath}"`, {
80
+ cwd: config.root,
81
+ encoding: "utf-8",
82
+ }).trim()
83
+ return timestamp || undefined
84
+ } catch {
85
+ return undefined
86
+ }
87
+ }
88
+
89
+ function extractTitle(content: string, path: string) {
90
+ const match = /^#\s+(.+)$/m.exec(content)
91
+ if (match) return match[1]!
92
+ return (
93
+ path
94
+ .split("/")
95
+ .pop()
96
+ ?.replace(/\.\w+$/, "") ?? path
97
+ )
98
+ }
99
+
100
+ const articles = defineCollection({
101
+ name: "articles",
102
+ directory,
103
+ include,
104
+ exclude: config.exclude,
105
+ schema: Article,
106
+ transform: async (document, context) => {
107
+ const patch = config.patches?.find(p => p.file === document._meta.filePath)
108
+ const doc = patch ? { ...document, ...patch.article } : document
109
+ const filePath = resolve(config.root, doc._meta.filePath)
110
+ const content = resolveIncludes(doc.content, filePath)
111
+ const title = doc.title ?? extractTitle(content, doc._meta.path)
112
+ const icon = doc.icon ?? pickDefaultIcon(doc._meta.path)
113
+ const path = doc.path ?? toPath(doc._meta.filePath)
114
+ const mdx = await compileMDX(
115
+ context,
116
+ { ...doc, content },
117
+ {
118
+ remarkPlugins: [
119
+ remarkGfm,
120
+ remarkGemoji,
121
+ remarkDefinitionList,
122
+ remarkDeflist,
123
+ remarkMath,
124
+ remarkDirective,
125
+ remarkCallout,
126
+ remarkCard,
127
+ remarkColumns,
128
+ remarkTab,
129
+ remarkDetails,
130
+ remarkFiletree,
131
+ remarkIcon,
132
+ remarkBadge,
133
+ remarkButton,
134
+ remarkAbbr,
135
+ remarkGithubCallout,
136
+ [
137
+ remarkImage,
138
+ {
139
+ filePath: resolve(config.root, doc._meta.filePath),
140
+ root: config.root,
141
+ },
142
+ ],
143
+ remarkAnsi,
144
+ remarkMermaid,
145
+ remarkMedia,
146
+ remarkToc,
147
+ remarkNpm,
148
+ remarkCodeTabs,
149
+ remarkSteps,
150
+ remarkCustomHeadingId,
151
+ ],
152
+ rehypePlugins: [
153
+ [
154
+ rehypeShiki,
155
+ {
156
+ themes: {
157
+ light: config.codeThemeLight,
158
+ dark: config.codeThemeDark,
159
+ },
160
+ // Darken catppuccin-latte's green (the colour used for strings and
161
+ // some comments) — the theme default #40A02B lands at 3.2:1 on the
162
+ // code-block background, below the WCAG AA 4.5:1 threshold.
163
+ colorReplacements: {
164
+ "catppuccin-latte": {
165
+ "#40a02b": "#2a7e16",
166
+ },
167
+ },
168
+ transformers: [
169
+ transformerTwoslash({ explicitTrigger: true }),
170
+ transformerIcon(),
171
+ transformerNotations(),
172
+ transformerLineHighlight(),
173
+ ],
174
+ parseMetaString: (meta: string) => ({ "data-meta": meta }),
175
+ },
176
+ ],
177
+ rehypeInlineCode,
178
+ rehypeSlug,
179
+ rehypeKatex,
180
+ rehypeTaskListA11y,
181
+ ],
182
+ },
183
+ )
184
+ const tocItems = extractToc(content)
185
+ const searchText = extractSearchText(content)
186
+ const lastUpdated = getLastUpdated(doc._meta.filePath)
187
+ const image = doc.image
188
+ ? resolveAssetPath(doc.image, filePath, config.root)
189
+ : undefined
190
+ return {
191
+ ...doc,
192
+ file: doc._meta.filePath,
193
+ lastUpdated,
194
+ image,
195
+ title,
196
+ icon,
197
+ path,
198
+ tocItems,
199
+ searchText,
200
+ mdx,
201
+ }
202
+ },
203
+ })
204
+
205
+ export default defineConfig({
206
+ // @ts-expect-error tsgo picks wrong overload when rehype-slug augments unified types
207
+ content: [articles],
208
+ })
@@ -0,0 +1,78 @@
1
+ import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"
2
+ import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
3
+
4
+ import { cn } from "../helpers/style.ts"
5
+
6
+ function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
7
+ return (
8
+ <AccordionPrimitive.Root
9
+ data-slot="accordion"
10
+ className={cn("flex w-full flex-col", className)}
11
+ {...props}
12
+ />
13
+ )
14
+ }
15
+
16
+ function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
17
+ return (
18
+ <AccordionPrimitive.Item
19
+ data-slot="accordion-item"
20
+ className={cn("not-last:border-b", className)}
21
+ {...props}
22
+ />
23
+ )
24
+ }
25
+
26
+ function AccordionTrigger({
27
+ className,
28
+ children,
29
+ ...props
30
+ }: AccordionPrimitive.Trigger.Props) {
31
+ return (
32
+ <AccordionPrimitive.Header className="flex">
33
+ <AccordionPrimitive.Trigger
34
+ data-slot="accordion-trigger"
35
+ className={cn(
36
+ "group/accordion-trigger relative flex flex-1 items-start justify-between rounded-md border border-transparent py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
37
+ className,
38
+ )}
39
+ {...props}
40
+ >
41
+ {children}
42
+ <ChevronDownIcon
43
+ data-slot="accordion-trigger-icon"
44
+ className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden"
45
+ />
46
+ <ChevronUpIcon
47
+ data-slot="accordion-trigger-icon"
48
+ className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline"
49
+ />
50
+ </AccordionPrimitive.Trigger>
51
+ </AccordionPrimitive.Header>
52
+ )
53
+ }
54
+
55
+ function AccordionContent({
56
+ className,
57
+ children,
58
+ ...props
59
+ }: AccordionPrimitive.Panel.Props) {
60
+ return (
61
+ <AccordionPrimitive.Panel
62
+ data-slot="accordion-content"
63
+ className="overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up"
64
+ {...props}
65
+ >
66
+ <div
67
+ className={cn(
68
+ "h-(--accordion-panel-height) pt-0 pb-4 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4",
69
+ className,
70
+ )}
71
+ >
72
+ {children}
73
+ </div>
74
+ </AccordionPrimitive.Panel>
75
+ )
76
+ }
77
+
78
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
@@ -0,0 +1,185 @@
1
+ import * as React from "react"
2
+ import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog"
3
+
4
+ import { cn } from "../helpers/style.ts"
5
+ import { Button } from "./button.tsx"
6
+
7
+ function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
8
+ return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
9
+ }
10
+
11
+ function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {
12
+ return (
13
+ <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
14
+ )
15
+ }
16
+
17
+ function AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {
18
+ return (
19
+ <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
20
+ )
21
+ }
22
+
23
+ function AlertDialogOverlay({
24
+ className,
25
+ ...props
26
+ }: AlertDialogPrimitive.Backdrop.Props) {
27
+ return (
28
+ <AlertDialogPrimitive.Backdrop
29
+ data-slot="alert-dialog-overlay"
30
+ className={cn(
31
+ "fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
32
+ className,
33
+ )}
34
+ {...props}
35
+ />
36
+ )
37
+ }
38
+
39
+ function AlertDialogContent({
40
+ className,
41
+ size = "default",
42
+ ...props
43
+ }: AlertDialogPrimitive.Popup.Props & {
44
+ size?: "default" | "sm"
45
+ }) {
46
+ return (
47
+ <AlertDialogPortal>
48
+ <AlertDialogOverlay />
49
+ <AlertDialogPrimitive.Popup
50
+ data-slot="alert-dialog-content"
51
+ data-size={size}
52
+ className={cn(
53
+ "group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-6 rounded-xl bg-popover p-6 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-lg data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
54
+ className,
55
+ )}
56
+ {...props}
57
+ />
58
+ </AlertDialogPortal>
59
+ )
60
+ }
61
+
62
+ function AlertDialogHeader({
63
+ className,
64
+ ...props
65
+ }: React.ComponentProps<"div">) {
66
+ return (
67
+ <div
68
+ data-slot="alert-dialog-header"
69
+ className={cn(
70
+ "grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
71
+ className,
72
+ )}
73
+ {...props}
74
+ />
75
+ )
76
+ }
77
+
78
+ function AlertDialogFooter({
79
+ className,
80
+ ...props
81
+ }: React.ComponentProps<"div">) {
82
+ return (
83
+ <div
84
+ data-slot="alert-dialog-footer"
85
+ className={cn(
86
+ "flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
87
+ className,
88
+ )}
89
+ {...props}
90
+ />
91
+ )
92
+ }
93
+
94
+ function AlertDialogMedia({
95
+ className,
96
+ ...props
97
+ }: React.ComponentProps<"div">) {
98
+ return (
99
+ <div
100
+ data-slot="alert-dialog-media"
101
+ className={cn(
102
+ "mb-2 inline-flex size-16 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8",
103
+ className,
104
+ )}
105
+ {...props}
106
+ />
107
+ )
108
+ }
109
+
110
+ function AlertDialogTitle({
111
+ className,
112
+ ...props
113
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
114
+ return (
115
+ <AlertDialogPrimitive.Title
116
+ data-slot="alert-dialog-title"
117
+ className={cn(
118
+ "cn-font-heading text-lg font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
119
+ className,
120
+ )}
121
+ {...props}
122
+ />
123
+ )
124
+ }
125
+
126
+ function AlertDialogDescription({
127
+ className,
128
+ ...props
129
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
130
+ return (
131
+ <AlertDialogPrimitive.Description
132
+ data-slot="alert-dialog-description"
133
+ className={cn(
134
+ "text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
135
+ className,
136
+ )}
137
+ {...props}
138
+ />
139
+ )
140
+ }
141
+
142
+ function AlertDialogAction({
143
+ className,
144
+ ...props
145
+ }: React.ComponentProps<typeof Button>) {
146
+ return (
147
+ <Button
148
+ data-slot="alert-dialog-action"
149
+ className={cn(className)}
150
+ {...props}
151
+ />
152
+ )
153
+ }
154
+
155
+ function AlertDialogCancel({
156
+ className,
157
+ variant = "outline",
158
+ size = "default",
159
+ ...props
160
+ }: AlertDialogPrimitive.Close.Props &
161
+ Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
162
+ return (
163
+ <AlertDialogPrimitive.Close
164
+ data-slot="alert-dialog-cancel"
165
+ className={cn(className)}
166
+ render={<Button variant={variant} size={size} />}
167
+ {...props}
168
+ />
169
+ )
170
+ }
171
+
172
+ export {
173
+ AlertDialog,
174
+ AlertDialogAction,
175
+ AlertDialogCancel,
176
+ AlertDialogContent,
177
+ AlertDialogDescription,
178
+ AlertDialogFooter,
179
+ AlertDialogHeader,
180
+ AlertDialogMedia,
181
+ AlertDialogOverlay,
182
+ AlertDialogPortal,
183
+ AlertDialogTitle,
184
+ AlertDialogTrigger,
185
+ }
@@ -0,0 +1,74 @@
1
+ import { cva, type VariantProps } from "class-variance-authority"
2
+ import { cn } from "../helpers/style.ts"
3
+
4
+ const alertVariants = cva(
5
+ "grid gap-0.5 rounded-lg border px-4 py-3 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4 w-full relative group/alert",
6
+ {
7
+ variants: {
8
+ variant: {
9
+ default: "bg-card text-card-foreground",
10
+ destructive:
11
+ "text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current",
12
+ },
13
+ },
14
+ defaultVariants: {
15
+ variant: "default",
16
+ },
17
+ },
18
+ )
19
+
20
+ function Alert({
21
+ className,
22
+ variant,
23
+ ...props
24
+ }: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
25
+ return (
26
+ <div
27
+ data-slot="alert"
28
+ role="alert"
29
+ className={cn(alertVariants({ variant }), className)}
30
+ {...props}
31
+ />
32
+ )
33
+ }
34
+
35
+ function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
36
+ return (
37
+ <div
38
+ data-slot="alert-title"
39
+ className={cn(
40
+ "font-medium group-has-[>svg]/alert:col-start-2 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3",
41
+ className,
42
+ )}
43
+ {...props}
44
+ />
45
+ )
46
+ }
47
+
48
+ function AlertDescription({
49
+ className,
50
+ ...props
51
+ }: React.ComponentProps<"div">) {
52
+ return (
53
+ <div
54
+ data-slot="alert-description"
55
+ className={cn(
56
+ "text-muted-foreground text-sm text-balance md:text-pretty [&_p:not(:last-child)]:mb-4 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3",
57
+ className,
58
+ )}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
65
+ return (
66
+ <div
67
+ data-slot="alert-action"
68
+ className={cn("absolute top-2.5 right-3", className)}
69
+ {...props}
70
+ />
71
+ )
72
+ }
73
+
74
+ export { Alert, AlertTitle, AlertDescription, AlertAction }
@@ -0,0 +1,22 @@
1
+ import { cn } from "../helpers/style.ts"
2
+
3
+ function AspectRatio({
4
+ ratio,
5
+ className,
6
+ ...props
7
+ }: React.ComponentProps<"div"> & { ratio: number }) {
8
+ return (
9
+ <div
10
+ data-slot="aspect-ratio"
11
+ style={
12
+ {
13
+ "--ratio": ratio,
14
+ } as React.CSSProperties
15
+ }
16
+ className={cn("relative aspect-(--ratio)", className)}
17
+ {...props}
18
+ />
19
+ )
20
+ }
21
+
22
+ export { AspectRatio }