livemark 0.0.0-dev

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 (187) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +3 -0
  3. package/build/actions/config/define.d.ts +6 -0
  4. package/build/actions/config/define.js +8 -0
  5. package/build/actions/config/define.unit.d.ts +1 -0
  6. package/build/actions/config/define.unit.js +34 -0
  7. package/build/actions/config/load.d.ts +5 -0
  8. package/build/actions/config/load.js +22 -0
  9. package/build/actions/config/load.unit.d.ts +1 -0
  10. package/build/actions/config/load.unit.js +23 -0
  11. package/build/commands/build.d.ts +5 -0
  12. package/build/commands/build.js +13 -0
  13. package/build/commands/preview.d.ts +5 -0
  14. package/build/commands/preview.js +18 -0
  15. package/build/commands/start.d.ts +5 -0
  16. package/build/commands/start.js +19 -0
  17. package/build/docs/markdown/includes/example.d.ts +9 -0
  18. package/build/docs/markdown/includes/example.js +5 -0
  19. package/build/entrypoints/main.d.ts +2 -0
  20. package/build/entrypoints/main.js +12 -0
  21. package/build/helpers/program.d.ts +2 -0
  22. package/build/helpers/program.js +5 -0
  23. package/build/index.d.ts +1 -0
  24. package/build/index.js +2 -0
  25. package/build/livemark.config.d.ts +9 -0
  26. package/build/livemark.config.js +5 -0
  27. package/build/models/config.d.ts +33 -0
  28. package/build/models/config.js +14 -0
  29. package/build/program.d.ts +2 -0
  30. package/build/program.js +14 -0
  31. package/build/vite.config.d.ts +2 -0
  32. package/build/vite.config.js +48 -0
  33. package/build/website/client.tsx +10 -0
  34. package/build/website/components/Abbr.tsx +17 -0
  35. package/build/website/components/AnsiCode.tsx +15 -0
  36. package/build/website/components/Banner.tsx +32 -0
  37. package/build/website/components/Breadcrumbs.tsx +19 -0
  38. package/build/website/components/Callout.tsx +72 -0
  39. package/build/website/components/Cards.tsx +66 -0
  40. package/build/website/components/CodeBlock.tsx +118 -0
  41. package/build/website/components/CodeTabs.tsx +83 -0
  42. package/build/website/components/Columns.tsx +17 -0
  43. package/build/website/components/Content.tsx +7 -0
  44. package/build/website/components/ContentTab.tsx +7 -0
  45. package/build/website/components/ContentTabs.tsx +82 -0
  46. package/build/website/components/DefaultCatchBoundary.tsx +54 -0
  47. package/build/website/components/DefinitionList.tsx +21 -0
  48. package/build/website/components/Details.tsx +30 -0
  49. package/build/website/components/FileTree.tsx +52 -0
  50. package/build/website/components/Footer.tsx +9 -0
  51. package/build/website/components/FootnoteRef.tsx +52 -0
  52. package/build/website/components/Heading.tsx +20 -0
  53. package/build/website/components/InlineBadge.tsx +9 -0
  54. package/build/website/components/InlineIcon.tsx +21 -0
  55. package/build/website/components/InlineToc.tsx +31 -0
  56. package/build/website/components/Layout.tsx +220 -0
  57. package/build/website/components/LinkButton.tsx +31 -0
  58. package/build/website/components/Mermaid.tsx +37 -0
  59. package/build/website/components/NotFound.tsx +27 -0
  60. package/build/website/components/PackageTabs.tsx +74 -0
  61. package/build/website/components/PageToolbar.tsx +65 -0
  62. package/build/website/components/PrevNext.tsx +52 -0
  63. package/build/website/components/SearchDialog.tsx +245 -0
  64. package/build/website/components/Section.tsx +24 -0
  65. package/build/website/components/SectionHeader.tsx +35 -0
  66. package/build/website/components/SiteTitle.tsx +16 -0
  67. package/build/website/components/SortableTable.tsx +81 -0
  68. package/build/website/components/SoundCloud.tsx +16 -0
  69. package/build/website/components/Theme.tsx +40 -0
  70. package/build/website/components/Toc.tsx +99 -0
  71. package/build/website/components/YouTube.tsx +16 -0
  72. package/build/website/components/ZoomImage.tsx +30 -0
  73. package/build/website/content-collections.ts +181 -0
  74. package/build/website/elements/accordion.tsx +78 -0
  75. package/build/website/elements/alert-dialog.tsx +185 -0
  76. package/build/website/elements/alert.tsx +74 -0
  77. package/build/website/elements/aspect-ratio.tsx +22 -0
  78. package/build/website/elements/avatar.tsx +107 -0
  79. package/build/website/elements/badge.tsx +51 -0
  80. package/build/website/elements/breadcrumb.tsx +120 -0
  81. package/build/website/elements/button-group.tsx +87 -0
  82. package/build/website/elements/button.tsx +57 -0
  83. package/build/website/elements/calendar.tsx +229 -0
  84. package/build/website/elements/card.tsx +102 -0
  85. package/build/website/elements/carousel.tsx +240 -0
  86. package/build/website/elements/chart.tsx +372 -0
  87. package/build/website/elements/checkbox.tsx +26 -0
  88. package/build/website/elements/collapsible.tsx +19 -0
  89. package/build/website/elements/command.tsx +210 -0
  90. package/build/website/elements/context-menu.tsx +270 -0
  91. package/build/website/elements/dialog.tsx +152 -0
  92. package/build/website/elements/direction.tsx +4 -0
  93. package/build/website/elements/drawer.tsx +127 -0
  94. package/build/website/elements/dropdown-menu.tsx +260 -0
  95. package/build/website/elements/empty.tsx +104 -0
  96. package/build/website/elements/field.tsx +235 -0
  97. package/build/website/elements/hover-card.tsx +49 -0
  98. package/build/website/elements/input-group.tsx +171 -0
  99. package/build/website/elements/input-otp.tsx +84 -0
  100. package/build/website/elements/input.tsx +18 -0
  101. package/build/website/elements/item.tsx +199 -0
  102. package/build/website/elements/kbd.tsx +26 -0
  103. package/build/website/elements/label.tsx +17 -0
  104. package/build/website/elements/menubar.tsx +282 -0
  105. package/build/website/elements/native-select.tsx +56 -0
  106. package/build/website/elements/navigation-menu.tsx +171 -0
  107. package/build/website/elements/pagination.tsx +133 -0
  108. package/build/website/elements/popover.tsx +88 -0
  109. package/build/website/elements/progress.tsx +81 -0
  110. package/build/website/elements/radio-group.tsx +36 -0
  111. package/build/website/elements/resizable.tsx +48 -0
  112. package/build/website/elements/scroll-area.tsx +51 -0
  113. package/build/website/elements/select.tsx +200 -0
  114. package/build/website/elements/separator.tsx +22 -0
  115. package/build/website/elements/sheet.tsx +130 -0
  116. package/build/website/elements/sidebar.tsx +717 -0
  117. package/build/website/elements/skeleton.tsx +13 -0
  118. package/build/website/elements/slider.tsx +57 -0
  119. package/build/website/elements/sonner.tsx +40 -0
  120. package/build/website/elements/spinner.tsx +16 -0
  121. package/build/website/elements/switch.tsx +30 -0
  122. package/build/website/elements/table.tsx +112 -0
  123. package/build/website/elements/tabs.tsx +79 -0
  124. package/build/website/elements/textarea.tsx +16 -0
  125. package/build/website/elements/toggle-group.tsx +87 -0
  126. package/build/website/elements/toggle.tsx +43 -0
  127. package/build/website/elements/tooltip.tsx +67 -0
  128. package/build/website/env.d.ts +10 -0
  129. package/build/website/globals.d.ts +8 -0
  130. package/build/website/helpers/article-icon.ts +59 -0
  131. package/build/website/helpers/articles.ts +24 -0
  132. package/build/website/helpers/resolve-includes.ts +131 -0
  133. package/build/website/helpers/resolve-includes.unit.ts +126 -0
  134. package/build/website/helpers/search-text.ts +15 -0
  135. package/build/website/helpers/style.ts +6 -0
  136. package/build/website/helpers/theme.ts +27 -0
  137. package/build/website/helpers/toc-context.ts +10 -0
  138. package/build/website/helpers/toc.ts +51 -0
  139. package/build/website/helpers/toc.unit.ts +74 -0
  140. package/build/website/hooks/in-view.ts +30 -0
  141. package/build/website/hooks/media.ts +19 -0
  142. package/build/website/models/article.ts +40 -0
  143. package/build/website/plugins/rehype-inline-code.ts +107 -0
  144. package/build/website/plugins/remark-abbr.ts +46 -0
  145. package/build/website/plugins/remark-abbr.unit.ts +99 -0
  146. package/build/website/plugins/remark-ansi.ts +247 -0
  147. package/build/website/plugins/remark-ansi.unit.ts +197 -0
  148. package/build/website/plugins/remark-badge.ts +50 -0
  149. package/build/website/plugins/remark-badge.unit.ts +96 -0
  150. package/build/website/plugins/remark-button.ts +60 -0
  151. package/build/website/plugins/remark-button.unit.ts +147 -0
  152. package/build/website/plugins/remark-callout.ts +57 -0
  153. package/build/website/plugins/remark-card.ts +80 -0
  154. package/build/website/plugins/remark-code-tabs.ts +87 -0
  155. package/build/website/plugins/remark-columns.ts +66 -0
  156. package/build/website/plugins/remark-custom-heading-id.ts +70 -0
  157. package/build/website/plugins/remark-custom-heading-id.unit.ts +131 -0
  158. package/build/website/plugins/remark-deflist.ts +36 -0
  159. package/build/website/plugins/remark-details.ts +49 -0
  160. package/build/website/plugins/remark-filetree.ts +89 -0
  161. package/build/website/plugins/remark-filetree.unit.ts +137 -0
  162. package/build/website/plugins/remark-github-callout.ts +71 -0
  163. package/build/website/plugins/remark-icon.ts +42 -0
  164. package/build/website/plugins/remark-image.ts +25 -0
  165. package/build/website/plugins/remark-media.ts +62 -0
  166. package/build/website/plugins/remark-media.unit.ts +74 -0
  167. package/build/website/plugins/remark-mermaid.ts +23 -0
  168. package/build/website/plugins/remark-npm.ts +52 -0
  169. package/build/website/plugins/remark-steps.ts +36 -0
  170. package/build/website/plugins/remark-steps.unit.ts +97 -0
  171. package/build/website/plugins/remark-tab.ts +100 -0
  172. package/build/website/plugins/remark-tab.unit.ts +181 -0
  173. package/build/website/plugins/remark-toc.ts +39 -0
  174. package/build/website/plugins/remark-toc.unit.ts +82 -0
  175. package/build/website/plugins/shiki-icon.ts +82 -0
  176. package/build/website/plugins/shiki-line-highlight.ts +174 -0
  177. package/build/website/public/logo.svg +72 -0
  178. package/build/website/routeTree.gen.ts +86 -0
  179. package/build/website/router.tsx +34 -0
  180. package/build/website/routes/$.tsx +149 -0
  181. package/build/website/routes/__root.tsx +84 -0
  182. package/build/website/routes/index.tsx +13 -0
  183. package/build/website/server.ts +7 -0
  184. package/build/website/styles/general.css +347 -0
  185. package/build/website/vite.config.ts +36 -0
  186. package/entrypoints/main.ts +12 -0
  187. package/package.json +120 -0
@@ -0,0 +1,174 @@
1
+ interface HastText {
2
+ type: "text"
3
+ value: string
4
+ }
5
+
6
+ interface HastElement {
7
+ type: "element"
8
+ properties: Record<string, unknown>
9
+ children: (HastElement | HastText)[]
10
+ }
11
+
12
+ interface ShikiTransformer {
13
+ name: string
14
+ preprocess?: (
15
+ this: { options: { meta?: { __raw?: string } } },
16
+ code: string,
17
+ ) => void
18
+ pre?: (pre: HastElement) => HastElement | void
19
+ line?: (line: HastElement, lineNumber: number) => HastElement | void
20
+ span?: (span: HastElement) => HastElement | void
21
+ }
22
+
23
+ function parseLineRanges(meta: string): Set<number> {
24
+ const lines = new Set<number>()
25
+ const match = meta.match(/\{([\d,\s-]+)\}/)
26
+ if (!match) return lines
27
+
28
+ const parts = match[1]!.split(",")
29
+ for (const part of parts) {
30
+ const trimmed = part.trim()
31
+ const rangeMatch = trimmed.match(/^(\d+)-(\d+)$/)
32
+ if (rangeMatch) {
33
+ const start = Number(rangeMatch[1])
34
+ const end = Number(rangeMatch[2])
35
+ for (let i = start; i <= end; i++) {
36
+ lines.add(i)
37
+ }
38
+ } else {
39
+ const num = Number(trimmed)
40
+ if (!Number.isNaN(num)) {
41
+ lines.add(num)
42
+ }
43
+ }
44
+ }
45
+
46
+ return lines
47
+ }
48
+
49
+ function parseLineNumbers(meta: string): { enabled: boolean; start: number } {
50
+ const match = meta.match(/\blineNumbers(?:=(\d+))?\b/)
51
+ if (!match) return { enabled: false, start: 1 }
52
+ const start = match[1] ? Number(match[1]) : 1
53
+ return { enabled: true, start }
54
+ }
55
+
56
+ function parseWordHighlight(meta: string): string | undefined {
57
+ const match = meta.match(/\{word:([^}]+)\}/)
58
+ return match ? match[1] : undefined
59
+ }
60
+
61
+ function spanContainsWord(span: HastElement, word: string): boolean {
62
+ for (const child of span.children) {
63
+ if (child.type === "text" && child.value.includes(word)) {
64
+ return true
65
+ }
66
+ }
67
+ return false
68
+ }
69
+
70
+ const NOTATION_RE =
71
+ /\/\/\s*\[!code\s+(highlight|focus|\+\+|--|error|warning)\]\s*$/
72
+ const NOTATION_BLOCK_RE =
73
+ /\/\*\s*\[!code\s+(highlight|focus|\+\+|--|error|warning)\]\s*\*\/\s*$/
74
+
75
+ function stripNotationFromLine(line: HastElement): string | undefined {
76
+ for (const child of line.children) {
77
+ if (child.type === "element") {
78
+ const result = stripNotationFromLine(child)
79
+ if (result !== undefined) return result
80
+ }
81
+ if (child.type === "text") {
82
+ const match =
83
+ child.value.match(NOTATION_RE) ?? child.value.match(NOTATION_BLOCK_RE)
84
+ if (match) {
85
+ child.value = child.value.slice(0, match.index).trimEnd()
86
+ return match[1]!
87
+ }
88
+ }
89
+ }
90
+ return undefined
91
+ }
92
+
93
+ /** Shiki transformer that handles comment-based code annotations for highlighting, diffs, and focus effects. */
94
+ export function transformerNotations(): ShikiTransformer {
95
+ let hasFocus = false
96
+ let preElement: HastElement | undefined
97
+
98
+ return {
99
+ name: "livemark:notations",
100
+ preprocess() {
101
+ hasFocus = false
102
+ preElement = undefined
103
+ },
104
+ line(line) {
105
+ const notation = stripNotationFromLine(line)
106
+ if (!notation) return line
107
+
108
+ switch (notation) {
109
+ case "highlight":
110
+ line.properties["data-highlighted"] = ""
111
+ break
112
+ case "++":
113
+ line.properties["data-diff"] = "add"
114
+ break
115
+ case "--":
116
+ line.properties["data-diff"] = "remove"
117
+ break
118
+ case "focus":
119
+ line.properties["data-focus"] = ""
120
+ hasFocus = true
121
+ break
122
+ case "error":
123
+ line.properties["data-line-status"] = "error"
124
+ break
125
+ case "warning":
126
+ line.properties["data-line-status"] = "warning"
127
+ break
128
+ }
129
+
130
+ return line
131
+ },
132
+ pre(pre) {
133
+ preElement = pre
134
+ if (hasFocus && preElement) {
135
+ preElement.properties["data-has-focus"] = ""
136
+ }
137
+ return pre
138
+ },
139
+ }
140
+ }
141
+
142
+ /** Shiki transformer that highlights specific lines and words based on the code block meta string. */
143
+ export function transformerLineHighlight(): ShikiTransformer {
144
+ let highlightedLines = new Set<number>()
145
+ let lineNumbers = { enabled: false, start: 1 }
146
+ let highlightedWord: string | undefined
147
+
148
+ return {
149
+ name: "livemark:line-highlight",
150
+ preprocess() {
151
+ const raw = this.options.meta?.__raw ?? ""
152
+ highlightedLines = parseLineRanges(raw)
153
+ lineNumbers = parseLineNumbers(raw)
154
+ highlightedWord = parseWordHighlight(raw)
155
+ },
156
+ line(line, lineNumber) {
157
+ if (highlightedLines.has(lineNumber)) {
158
+ line.properties["data-highlighted"] = ""
159
+ }
160
+ if (lineNumbers.enabled) {
161
+ line.properties["data-line-number"] = String(
162
+ lineNumber - 1 + lineNumbers.start,
163
+ )
164
+ }
165
+ return line
166
+ },
167
+ span(span) {
168
+ if (highlightedWord && spanContainsWord(span, highlightedWord)) {
169
+ span.properties["data-word-highlighted"] = ""
170
+ }
171
+ return span
172
+ },
173
+ }
174
+ }
@@ -0,0 +1,72 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg
3
+ data-v-0dd9719b=""
4
+ version="1.0"
5
+ viewBox="0 0 200 200"
6
+ preserveAspectRatio="xMidYMid"
7
+ color-interpolation-filters="sRGB"
8
+ id="svg14"
9
+ sodipodi:docname="fairspec-logo.svg"
10
+ inkscape:version="1.4.2 (1:1.4.2+202505120737+ebf0e940d0)"
11
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
13
+ xmlns="http://www.w3.org/2000/svg"
14
+ xmlns:svg="http://www.w3.org/2000/svg">
15
+ <sodipodi:namedview
16
+ id="namedview14"
17
+ pagecolor="#ffffff"
18
+ bordercolor="#000000"
19
+ borderopacity="0.25"
20
+ inkscape:showpageshadow="2"
21
+ inkscape:pageopacity="0.0"
22
+ inkscape:pagecheckerboard="0"
23
+ inkscape:deskcolor="#d1d1d1"
24
+ inkscape:zoom="2.4555556"
25
+ inkscape:cx="92.239817"
26
+ inkscape:cy="110.56561"
27
+ inkscape:window-width="1920"
28
+ inkscape:window-height="1108"
29
+ inkscape:window-x="0"
30
+ inkscape:window-y="53"
31
+ inkscape:window-maximized="1"
32
+ inkscape:current-layer="svg14" />
33
+ <!---->
34
+ <g
35
+ id="g7"
36
+ style="overflow:visible"
37
+ transform="matrix(1.9217834,0,0,1.9217834,-1.7872586,9.8749299)">
38
+ <polygon
39
+ fill="#0067b5"
40
+ points="16.19,19.77 29.19,42.29 3.19,42.29 0.93,46.2 44.32,46.2 22.63,8.63 "
41
+ id="polygon2"
42
+ style="fill:#2c7cfd;fill-opacity:1" />
43
+ <polygon
44
+ fill="#009fe8"
45
+ points="57.31,1.18 44.31,23.69 31.31,1.18 26.8,1.18 48.49,38.75 70.18,1.18 "
46
+ id="polygon3"
47
+ style="fill:#8ec5ff;fill-opacity:1" />
48
+ <polygon
49
+ fill="#009fe8"
50
+ points="94.44,27.66 68.43,27.66 81.44,5.15 79.18,1.24 57.49,38.81 100.87,38.81 "
51
+ id="polygon4"
52
+ style="fill:#8ec5ff;fill-opacity:1" />
53
+ <polygon
54
+ fill="#009fe8"
55
+ points="89.74,72.81 76.74,50.3 102.74,50.3 105,46.39 61.62,46.39 83.31,83.96 "
56
+ id="polygon5"
57
+ style="fill:#8ec5ff;fill-opacity:1" />
58
+ <polygon
59
+ fill="#0067b5"
60
+ points="48.62,91.41 61.62,68.89 74.62,91.41 79.13,91.41 57.45,53.83 35.75,91.41 "
61
+ id="polygon6"
62
+ style="fill:#2c7cfd;fill-opacity:1" />
63
+ <polygon
64
+ fill="#0067b5"
65
+ points="11.49,64.92 37.49,64.92 24.5,87.43 26.75,91.34 48.44,53.78 5.05,53.78 "
66
+ id="polygon7"
67
+ style="fill:#2c7cfd;fill-opacity:1" />
68
+ </g>
69
+ <defs
70
+ v-gra="od"
71
+ id="defs14" />
72
+ </svg>
@@ -0,0 +1,86 @@
1
+ /* eslint-disable */
2
+
3
+ // @ts-nocheck
4
+
5
+ // noinspection JSUnusedGlobalSymbols
6
+
7
+ // This file was automatically generated by TanStack Router.
8
+ // You should NOT make any changes in this file as it will be overwritten.
9
+ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10
+
11
+ import { Route as rootRouteImport } from './routes/__root'
12
+ import { Route as SplatRouteImport } from './routes/$'
13
+ import { Route as IndexRouteImport } from './routes/index'
14
+
15
+ const SplatRoute = SplatRouteImport.update({
16
+ id: '/$',
17
+ path: '/$',
18
+ getParentRoute: () => rootRouteImport,
19
+ } as any)
20
+ const IndexRoute = IndexRouteImport.update({
21
+ id: '/',
22
+ path: '/',
23
+ getParentRoute: () => rootRouteImport,
24
+ } as any)
25
+
26
+ export interface FileRoutesByFullPath {
27
+ '/': typeof IndexRoute
28
+ '/$': typeof SplatRoute
29
+ }
30
+ export interface FileRoutesByTo {
31
+ '/': typeof IndexRoute
32
+ '/$': typeof SplatRoute
33
+ }
34
+ export interface FileRoutesById {
35
+ __root__: typeof rootRouteImport
36
+ '/': typeof IndexRoute
37
+ '/$': typeof SplatRoute
38
+ }
39
+ export interface FileRouteTypes {
40
+ fileRoutesByFullPath: FileRoutesByFullPath
41
+ fullPaths: '/' | '/$'
42
+ fileRoutesByTo: FileRoutesByTo
43
+ to: '/' | '/$'
44
+ id: '__root__' | '/' | '/$'
45
+ fileRoutesById: FileRoutesById
46
+ }
47
+ export interface RootRouteChildren {
48
+ IndexRoute: typeof IndexRoute
49
+ SplatRoute: typeof SplatRoute
50
+ }
51
+
52
+ declare module '@tanstack/react-router' {
53
+ interface FileRoutesByPath {
54
+ '/$': {
55
+ id: '/$'
56
+ path: '/$'
57
+ fullPath: '/$'
58
+ preLoaderRoute: typeof SplatRouteImport
59
+ parentRoute: typeof rootRouteImport
60
+ }
61
+ '/': {
62
+ id: '/'
63
+ path: '/'
64
+ fullPath: '/'
65
+ preLoaderRoute: typeof IndexRouteImport
66
+ parentRoute: typeof rootRouteImport
67
+ }
68
+ }
69
+ }
70
+
71
+ const rootRouteChildren: RootRouteChildren = {
72
+ IndexRoute: IndexRoute,
73
+ SplatRoute: SplatRoute,
74
+ }
75
+ export const routeTree = rootRouteImport
76
+ ._addFileChildren(rootRouteChildren)
77
+ ._addFileTypes<FileRouteTypes>()
78
+
79
+ import type { getRouter } from './router.tsx'
80
+ import type { createStart } from '@tanstack/react-start'
81
+ declare module '@tanstack/react-start' {
82
+ interface Register {
83
+ ssr: true
84
+ router: Awaited<ReturnType<typeof getRouter>>
85
+ }
86
+ }
@@ -0,0 +1,34 @@
1
+ import { QueryClient } from "@tanstack/react-query"
2
+ import { createRouter } from "@tanstack/react-router"
3
+ import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query"
4
+ import { DefaultCatchBoundary } from "./components/DefaultCatchBoundary.tsx"
5
+ import { NotFound } from "./components/NotFound.tsx"
6
+ import { routeTree } from "./routeTree.gen.ts"
7
+
8
+ export function getRouter() {
9
+ const queryClient = new QueryClient()
10
+
11
+ const router = createRouter({
12
+ routeTree,
13
+ context: { queryClient },
14
+ trailingSlash: "always",
15
+ defaultPreload: "intent",
16
+ defaultViewTransition: true,
17
+ defaultErrorComponent: DefaultCatchBoundary,
18
+ defaultNotFoundComponent: () => <NotFound />,
19
+ scrollRestoration: true,
20
+ })
21
+
22
+ setupRouterSsrQueryIntegration({
23
+ router,
24
+ queryClient,
25
+ })
26
+
27
+ return router
28
+ }
29
+
30
+ declare module "@tanstack/react-router" {
31
+ interface Register {
32
+ router: ReturnType<typeof getRouter>
33
+ }
34
+ }
@@ -0,0 +1,149 @@
1
+ import { MDXContent } from "@content-collections/mdx/react"
2
+ import { createFileRoute, notFound } from "@tanstack/react-router"
3
+ import { sortedArticles } from "../helpers/articles.ts"
4
+ import { Callout } from "../components/Callout.tsx"
5
+ import { Columns, Column } from "../components/Columns.tsx"
6
+ import { Card, Cards } from "../components/Cards.tsx"
7
+ import { CodeBlock } from "../components/CodeBlock.tsx"
8
+ import { headingComponents } from "../components/Heading.tsx"
9
+ import { Calendar } from "lucide-react"
10
+ import { CodeTabs } from "../components/CodeTabs.tsx"
11
+ import { ContentTab } from "../components/ContentTab.tsx"
12
+ import { ContentTabs } from "../components/ContentTabs.tsx"
13
+ import { Details } from "../components/Details.tsx"
14
+ import { FileTree } from "../components/FileTree.tsx"
15
+ import { InlineIcon } from "../components/InlineIcon.tsx"
16
+ import { Abbr } from "../components/Abbr.tsx"
17
+ import { FootnoteRef } from "../components/FootnoteRef.tsx"
18
+ import {
19
+ DefinitionList,
20
+ DefinitionTerm,
21
+ DefinitionDetail,
22
+ } from "../components/DefinitionList.tsx"
23
+ import { AnsiCode } from "../components/AnsiCode.tsx"
24
+ import { InlineBadge } from "../components/InlineBadge.tsx"
25
+ import { LinkButton } from "../components/LinkButton.tsx"
26
+ import { Mermaid } from "../components/Mermaid.tsx"
27
+ import { PackageTabs } from "../components/PackageTabs.tsx"
28
+ import { SoundCloud } from "../components/SoundCloud.tsx"
29
+ import { YouTube } from "../components/YouTube.tsx"
30
+ import { InlineToc } from "../components/InlineToc.tsx"
31
+ import { PageToolbar } from "../components/PageToolbar.tsx"
32
+ import { PrevNext } from "../components/PrevNext.tsx"
33
+ import { Toc } from "../components/Toc.tsx"
34
+ import { ZoomImage } from "../components/ZoomImage.tsx"
35
+ import { Separator } from "../elements/separator.tsx"
36
+ import { TocContext } from "../helpers/toc-context.ts"
37
+ import {
38
+ SortableTable,
39
+ TableHeader,
40
+ TableBody,
41
+ TableRow,
42
+ TableHead,
43
+ TableCell,
44
+ } from "../components/SortableTable.tsx"
45
+
46
+ export const Route = createFileRoute("/$")({
47
+ loader: ({ params }) => {
48
+ const splat = `/${params._splat}/`
49
+ const article = sortedArticles.find(a => a.pathname === splat)
50
+ if (!article) throw notFound()
51
+ return article
52
+ },
53
+ head: ({ loaderData }) => ({
54
+ meta: [
55
+ ...(loaderData ? [{ title: loaderData.title }] : []),
56
+ ...(loaderData?.description
57
+ ? [{ name: "description", content: loaderData.description }]
58
+ : []),
59
+ ],
60
+ }),
61
+ component: Component,
62
+ })
63
+
64
+ function Component() {
65
+ const article = Route.useLoaderData()
66
+ const lastUpdated = formatDate(article.lastUpdated)
67
+
68
+ const H1 = (props: React.HTMLAttributes<HTMLHeadingElement>) => (
69
+ <>
70
+ <h1 {...props}>
71
+ {props.id ? (
72
+ <a href={`#${props.id}`}>{props.children}</a>
73
+ ) : (
74
+ props.children
75
+ )}
76
+ </h1>
77
+ {lastUpdated && (
78
+ <p className="flex items-center gap-1.5 text-sm text-muted-foreground !-mt-4 !mb-6">
79
+ <Calendar className="size-3.5" />
80
+ Last updated {lastUpdated}
81
+ </p>
82
+ )}
83
+ </>
84
+ )
85
+
86
+ return (
87
+ <TocContext.Provider value={article.toc}>
88
+ <div className="flex flex-1 gap-10 p-6 md:p-10">
89
+ <div className="flex-1 min-w-0 mx-auto max-w-3xl">
90
+ <div className="prose dark:prose-invert max-w-none">
91
+ <MDXContent
92
+ code={article.mdx}
93
+ components={{
94
+ hr: Separator,
95
+ img: ZoomImage,
96
+ pre: CodeBlock,
97
+ table: SortableTable,
98
+ thead: TableHeader,
99
+ tbody: TableBody,
100
+ tr: TableRow,
101
+ th: TableHead,
102
+ td: TableCell,
103
+ a: FootnoteRef,
104
+ Abbr,
105
+ AnsiCode,
106
+ Callout,
107
+ Card,
108
+ Cards,
109
+ Column,
110
+ Columns,
111
+ CodeTabs,
112
+ ContentTab,
113
+ ContentTabs,
114
+ DefinitionDetail,
115
+ DefinitionList,
116
+ DefinitionTerm,
117
+ Details,
118
+ FileTree,
119
+ InlineBadge,
120
+ InlineIcon,
121
+ InlineToc,
122
+ LinkButton,
123
+ Mermaid,
124
+ PackageTabs,
125
+ SoundCloud,
126
+ YouTube,
127
+ ...headingComponents,
128
+ h1: H1,
129
+ }}
130
+ />
131
+ </div>
132
+ <PrevNext pathname={article.pathname} />
133
+ </div>
134
+ <Toc items={article.toc}>
135
+ <PageToolbar filePath={article.filePath} content={article.content} />
136
+ </Toc>
137
+ </div>
138
+ </TocContext.Provider>
139
+ )
140
+ }
141
+
142
+ function formatDate(iso?: string) {
143
+ if (!iso) return undefined
144
+ return new Date(iso).toLocaleDateString("en-US", {
145
+ year: "numeric",
146
+ month: "short",
147
+ day: "numeric",
148
+ })
149
+ }
@@ -0,0 +1,84 @@
1
+ import { TanStackDevtools } from "@tanstack/react-devtools"
2
+ import { ReactQueryDevtoolsPanel } from "@tanstack/react-query-devtools"
3
+ import {
4
+ createRootRoute,
5
+ HeadContent,
6
+ Outlet,
7
+ Scripts,
8
+ } from "@tanstack/react-router"
9
+ import { TanStackRouterDevtoolsPanel } from "@tanstack/react-router-devtools"
10
+ import type * as React from "react"
11
+ import { Layout } from "../components/Layout.tsx"
12
+ import { DefaultCatchBoundary } from "../components/DefaultCatchBoundary.tsx"
13
+ import { NotFound } from "../components/NotFound.tsx"
14
+ import { Toaster } from "../elements/sonner.tsx"
15
+ import generalCss from "../styles/general.css?url"
16
+
17
+ export const Route = createRootRoute({
18
+ head: () => ({
19
+ meta: [
20
+ { charSet: "utf-8" },
21
+ { title: "Title" },
22
+ { name: "description", content: "Description" },
23
+ { property: "og:title", content: "Title" },
24
+ { property: "og:description", content: "Description" },
25
+ { property: "og:site_name", content: "Title" },
26
+ { property: "og:type", content: "website" },
27
+ {
28
+ name: "viewport",
29
+ content: "width=device-width, initial-scale=1",
30
+ },
31
+ ],
32
+ links: [
33
+ { rel: "icon", href: "/logo.svg", type: "image/svg+xml" },
34
+ { rel: "stylesheet", href: generalCss },
35
+ // TODO: recover
36
+ // { rel: "canonical", href: settings.HOST },
37
+ ],
38
+ }),
39
+ notFoundComponent: () => <NotFound />,
40
+ errorComponent: props => {
41
+ return (
42
+ <Document>
43
+ <DefaultCatchBoundary {...props} />
44
+ </Document>
45
+ )
46
+ },
47
+ component: () => {
48
+ return (
49
+ <Document>
50
+ <Outlet />
51
+ </Document>
52
+ )
53
+ },
54
+ })
55
+
56
+ function Document(props: { children: React.ReactNode }) {
57
+ return (
58
+ <html lang="en">
59
+ <head>
60
+ <HeadContent />
61
+ </head>
62
+ <body>
63
+ <Layout>{props.children}</Layout>
64
+ <Toaster position="top-center" />
65
+ <TanStackDevtools
66
+ config={{ hideUntilHover: true }}
67
+ plugins={[
68
+ {
69
+ name: "TanStack Query",
70
+ render: <ReactQueryDevtoolsPanel />,
71
+ defaultOpen: true,
72
+ },
73
+ {
74
+ name: "TanStack Router",
75
+ render: <TanStackRouterDevtoolsPanel />,
76
+ defaultOpen: false,
77
+ },
78
+ ]}
79
+ />
80
+ <Scripts />
81
+ </body>
82
+ </html>
83
+ )
84
+ }
@@ -0,0 +1,13 @@
1
+ import { createFileRoute, notFound, redirect } from "@tanstack/react-router"
2
+ import { sortedArticles } from "../helpers/articles.ts"
3
+
4
+ export const Route = createFileRoute("/")({
5
+ beforeLoad: () => {
6
+ const first = sortedArticles[0]
7
+ if (!first) throw notFound()
8
+ throw redirect({
9
+ to: "/$",
10
+ params: { _splat: first.pathname.replace(/^\/|\/$/g, "") },
11
+ })
12
+ },
13
+ })
@@ -0,0 +1,7 @@
1
+ import handler, { createServerEntry } from "@tanstack/react-start/server-entry"
2
+
3
+ export default createServerEntry({
4
+ fetch(request) {
5
+ return handler.fetch(request)
6
+ },
7
+ })