@jant/core 0.6.14 → 0.6.16

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 (350) hide show
  1. package/bin/commands/import-site.js +88 -13
  2. package/bin/commands/migrate.js +55 -0
  3. package/bin/commands/posts/rebuild-html.js +184 -0
  4. package/bin/commands/site/snapshot/import.js +14 -10
  5. package/bin/lib/d1-query.js +23 -5
  6. package/bin/lib/migration-runner.js +29 -7
  7. package/bin/lib/node-database.js +32 -0
  8. package/bin/lib/site-snapshot.js +347 -46
  9. package/bin/lib/sql-export.js +1 -1
  10. package/bin/lib/thread-collection-migration.js +326 -0
  11. package/dist/app-C75Zc8dD.js +6 -0
  12. package/dist/{app-2i7-WQHg.js → app-C7_4oab9.js} +7774 -6425
  13. package/dist/client/.vite/manifest.json +8 -8
  14. package/dist/client/_assets/chunks/{url-pLre2DM_.js → url-CU9pEbk5.js} +1 -1
  15. package/dist/client/_assets/{client-BvID5ucz.js → client-Bq0vre8Y.js} +59 -38
  16. package/dist/client/_assets/client-D3VZyG4L.css +2 -0
  17. package/dist/client/_assets/client-auth-F2rb9WfF.js +5571 -0
  18. package/dist/{env-OHRKGcMj.js → env-BPYViDJJ.js} +1 -1
  19. package/dist/{export-DWn149b7.js → export-Dl5KCiEs.js} +1348 -128
  20. package/dist/{github-api-BgSiE71w.js → github-api-BNF35Lkx.js} +1 -1
  21. package/dist/{github-app-BbklkFmU.js → github-app-DdiD-bC4.js} +1 -1
  22. package/dist/{github-sync-C0zyF6XS.js → github-sync-Bqg62IvV.js} +3 -3
  23. package/dist/{github-sync-Ckk0sJxK.js → github-sync-HdK2EgvJ.js} +3 -3
  24. package/dist/index.js +5 -5
  25. package/dist/node.js +7 -7
  26. package/dist/{url-BMYO-Zlt.js → url-CbLAtlZe.js} +517 -12
  27. package/package.json +11 -10
  28. package/src/__tests__/bin/posts-rebuild-html.test.ts +137 -0
  29. package/src/__tests__/dev-navigation-defaults.test.ts +22 -0
  30. package/src/__tests__/export-hugo-build.test.ts +63 -4
  31. package/src/__tests__/export-import-roundtrip.test.ts +6 -4
  32. package/src/__tests__/export-service.test.ts +142 -9
  33. package/src/__tests__/helpers/app.ts +3 -0
  34. package/src/__tests__/helpers/export-fixtures.ts +2 -0
  35. package/src/__tests__/import-site-command.test.ts +65 -0
  36. package/src/__tests__/mise-config.test.ts +22 -0
  37. package/src/__tests__/vite-config.test.ts +45 -0
  38. package/src/app.tsx +16 -3
  39. package/src/client/__tests__/collection-created-notice.test.ts +36 -0
  40. package/src/client/__tests__/collection-form-bridge.test.ts +10 -1
  41. package/src/client/__tests__/collection-page-actions.test.ts +71 -2
  42. package/src/client/__tests__/compose-bridge.test.ts +316 -2
  43. package/src/client/__tests__/compose-shortcuts.test.ts +20 -0
  44. package/src/client/__tests__/feed-video-player.test.ts +16 -1
  45. package/src/client/__tests__/footnote-rail.test.ts +472 -0
  46. package/src/client/__tests__/hydrate-partial.test.ts +3 -0
  47. package/src/client/__tests__/toast.test.ts +82 -1
  48. package/src/client/collection-created-notice.ts +66 -0
  49. package/src/client/collection-form-bridge.ts +17 -0
  50. package/src/client/collection-navigation.ts +44 -0
  51. package/src/client/collection-page-actions.ts +57 -1
  52. package/src/client/components/__tests__/compose-format-convert.test.ts +0 -19
  53. package/src/client/components/__tests__/jant-collection-directory.test.ts +155 -6
  54. package/src/client/components/__tests__/jant-command-palette.test.ts +51 -0
  55. package/src/client/components/__tests__/jant-compose-dialog.test.ts +2268 -206
  56. package/src/client/components/__tests__/jant-compose-editor.test.ts +147 -59
  57. package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +114 -64
  58. package/src/client/components/__tests__/jant-config-editor.test.ts +405 -0
  59. package/src/client/components/__tests__/jant-media-lightbox.test.ts +121 -0
  60. package/src/client/components/__tests__/jant-nav-manager.test.ts +538 -2
  61. package/src/client/components/__tests__/jant-post-form.test.ts +2 -2
  62. package/src/client/components/__tests__/jant-post-menu.test.ts +47 -5
  63. package/src/client/components/__tests__/jant-settings-avatar.test.ts +2 -2
  64. package/src/client/components/__tests__/jant-settings-general.test.ts +3 -3
  65. package/src/client/components/collection-manager-types.ts +9 -3
  66. package/src/client/components/compose-format-convert.ts +5 -1
  67. package/src/client/components/compose-types.ts +55 -3
  68. package/src/client/components/jant-collection-directory.ts +165 -30
  69. package/src/client/components/jant-command-palette.ts +14 -7
  70. package/src/client/components/jant-compose-dialog.ts +1542 -694
  71. package/src/client/components/jant-compose-editor.ts +237 -99
  72. package/src/client/components/jant-compose-fullscreen.ts +27 -9
  73. package/src/client/components/jant-config-editor.ts +722 -0
  74. package/src/client/components/jant-media-lightbox.ts +100 -18
  75. package/src/client/components/jant-nav-manager.ts +1283 -54
  76. package/src/client/components/jant-post-form.ts +3 -3
  77. package/src/client/components/jant-post-menu.ts +177 -95
  78. package/src/client/components/nav-manager-types.ts +51 -2
  79. package/src/client/components/post-form-types.ts +1 -1
  80. package/src/client/compose-bridge.ts +147 -123
  81. package/src/client/compose-launch.ts +13 -0
  82. package/src/client/compose-shortcuts.ts +5 -1
  83. package/src/client/feed-video-player.ts +62 -2
  84. package/src/client/footnote-rail.ts +478 -0
  85. package/src/client/hydrate-partial.ts +2 -0
  86. package/src/client/media-lightbox-events.ts +63 -0
  87. package/src/client/post-refresh.ts +135 -0
  88. package/src/client/site-header-fragment.ts +38 -0
  89. package/src/client/tiptap/__tests__/blockquote-editing.test.ts +201 -0
  90. package/src/client/tiptap/__tests__/clear-formatting.test.ts +168 -0
  91. package/src/client/tiptap/__tests__/link-input-rules.test.ts +121 -0
  92. package/src/client/tiptap/__tests__/list-editing.test.ts +447 -0
  93. package/src/client/tiptap/__tests__/markdown-clipboard.test.ts +727 -4
  94. package/src/client/tiptap/__tests__/table-controls.test.ts +263 -0
  95. package/src/client/tiptap/__tests__/table-size-picker.test.ts +179 -0
  96. package/src/client/tiptap/bubble-menu.ts +88 -10
  97. package/src/client/tiptap/continuous-lists.ts +102 -0
  98. package/src/client/tiptap/create-editor.ts +3 -0
  99. package/src/client/tiptap/extensions.ts +14 -5
  100. package/src/client/tiptap/link-input-rules.ts +4 -4
  101. package/src/client/tiptap/markdown-clipboard.ts +608 -11
  102. package/src/client/tiptap/slash-commands.ts +8 -1
  103. package/src/client/tiptap/structural-keymap.ts +211 -0
  104. package/src/client/tiptap/tab-indent.ts +8 -22
  105. package/src/client/tiptap/table-control-labels.ts +30 -0
  106. package/src/client/tiptap/table-controls.ts +537 -0
  107. package/src/client/tiptap/table-size-picker.ts +254 -0
  108. package/src/client/toast.ts +133 -39
  109. package/src/client-auth.ts +1 -0
  110. package/src/client.ts +1 -0
  111. package/src/db/__tests__/backfill-thread-activity.test.ts +234 -0
  112. package/src/db/__tests__/d1-query.test.ts +43 -1
  113. package/src/db/__tests__/migration-runner.test.ts +63 -0
  114. package/src/db/__tests__/migrations.test.ts +469 -0
  115. package/src/db/__tests__/thread-activity.test.ts +113 -0
  116. package/src/db/__tests__/thread-collection-migration.test.ts +364 -0
  117. package/src/db/backfills/0005_split_thread_activity_from_quiet_replies.sql +68 -0
  118. package/src/db/migrations/0027_old_blue_blade.sql +39 -0
  119. package/src/db/migrations/0028_superb_post.sql +2 -0
  120. package/src/db/migrations/0029_boring_magma.sql +1 -0
  121. package/src/db/migrations/0030_typical_vivisector.sql +50 -0
  122. package/src/db/migrations/0031_many_ego.sql +3 -0
  123. package/src/db/migrations/meta/0027_snapshot.json +2511 -0
  124. package/src/db/migrations/meta/0028_snapshot.json +2511 -0
  125. package/src/db/migrations/meta/0029_snapshot.json +2519 -0
  126. package/src/db/migrations/meta/0030_snapshot.json +2541 -0
  127. package/src/db/migrations/meta/0031_snapshot.json +2562 -0
  128. package/src/db/migrations/meta/_journal.json +35 -0
  129. package/src/db/migrations/pg/0025_moaning_epoch.sql +39 -0
  130. package/src/db/migrations/pg/0026_talented_killer_shrike.sql +2 -0
  131. package/src/db/migrations/pg/0027_short_cannonball.sql +1 -0
  132. package/src/db/migrations/pg/0028_perfect_sharon_carter.sql +27 -0
  133. package/src/db/migrations/pg/0029_rare_hairball.sql +3 -0
  134. package/src/db/migrations/pg/meta/0025_snapshot.json +3204 -0
  135. package/src/db/migrations/pg/meta/0026_snapshot.json +3204 -0
  136. package/src/db/migrations/pg/meta/0027_snapshot.json +3211 -0
  137. package/src/db/migrations/pg/meta/0028_snapshot.json +3248 -0
  138. package/src/db/migrations/pg/meta/0029_snapshot.json +3289 -0
  139. package/src/db/migrations/pg/meta/_journal.json +35 -0
  140. package/src/db/pg/schema.ts +46 -20
  141. package/src/db/rehearsal-fixtures/demo-current.json +39 -4
  142. package/src/db/rehearsal-fixtures/demo-current.sql +121 -6
  143. package/src/db/schema.ts +48 -20
  144. package/src/db/thread-activity.ts +101 -0
  145. package/src/i18n/__tests__/detect.test.ts +8 -2
  146. package/src/i18n/detect.ts +14 -5
  147. package/src/i18n/locales/public/en.po +222 -51
  148. package/src/i18n/locales/public/en.ts +1 -1
  149. package/src/i18n/locales/public/zh-Hans.po +216 -45
  150. package/src/i18n/locales/public/zh-Hans.ts +1 -1
  151. package/src/i18n/locales/public/zh-Hant.po +216 -45
  152. package/src/i18n/locales/public/zh-Hant.ts +1 -1
  153. package/src/i18n/locales/settings/en.po +513 -10
  154. package/src/i18n/locales/settings/en.ts +1 -1
  155. package/src/i18n/locales/settings/zh-Hans.po +515 -12
  156. package/src/i18n/locales/settings/zh-Hans.ts +1 -1
  157. package/src/i18n/locales/settings/zh-Hant.po +515 -12
  158. package/src/i18n/locales/settings/zh-Hant.ts +1 -1
  159. package/src/lib/__tests__/api-settings.test.ts +299 -0
  160. package/src/lib/__tests__/constants.test.ts +5 -0
  161. package/src/lib/__tests__/feed-policy.test.ts +25 -0
  162. package/src/lib/__tests__/feed.test.ts +168 -0
  163. package/src/lib/__tests__/footnotes-upgrade.test.ts +181 -0
  164. package/src/lib/__tests__/markdown-roundtrip-embed.test.ts +61 -0
  165. package/src/lib/__tests__/markdown-to-tiptap.test.ts +32 -4
  166. package/src/lib/__tests__/markdown.test.ts +24 -6
  167. package/src/lib/__tests__/navigation.test.ts +59 -2
  168. package/src/lib/__tests__/post-body-html.test.ts +176 -0
  169. package/src/lib/__tests__/post-display.test.ts +64 -0
  170. package/src/lib/__tests__/resolve-config.test.ts +113 -1
  171. package/src/lib/__tests__/slug.test.ts +18 -0
  172. package/src/lib/__tests__/summary.test.ts +82 -0
  173. package/src/lib/__tests__/timeline.test.ts +109 -70
  174. package/src/lib/__tests__/timezones.test.ts +31 -3
  175. package/src/lib/__tests__/tiptap-render.test.ts +268 -9
  176. package/src/lib/__tests__/tiptap-to-markdown.test.ts +6 -0
  177. package/src/lib/__tests__/translit.test.ts +87 -0
  178. package/src/lib/__tests__/url.test.ts +53 -0
  179. package/src/lib/__tests__/view.test.ts +53 -0
  180. package/src/lib/__tests__/worker-response-cache.test.ts +18 -1
  181. package/src/lib/api-settings.ts +239 -12
  182. package/src/lib/collection-sort.ts +7 -5
  183. package/src/lib/constants.ts +2 -0
  184. package/src/lib/feed-path.ts +25 -0
  185. package/src/lib/feed-policy.ts +64 -0
  186. package/src/lib/feed.ts +113 -11
  187. package/src/lib/footnotes.ts +264 -0
  188. package/src/lib/github-sync-site-config.ts +2 -0
  189. package/src/lib/hugo-markdown.ts +15 -3
  190. package/src/lib/jant-branding.ts +1 -0
  191. package/src/lib/link-preview.ts +25 -0
  192. package/src/lib/markdown-manager.ts +193 -5
  193. package/src/lib/markdown.ts +10 -3
  194. package/src/lib/navigation.ts +16 -3
  195. package/src/lib/post-body-html.ts +131 -0
  196. package/src/lib/post-display.ts +47 -8
  197. package/src/lib/render.tsx +9 -2
  198. package/src/lib/resolve-config.ts +100 -16
  199. package/src/lib/schemas.ts +133 -1
  200. package/src/lib/settings-paths.ts +5 -0
  201. package/src/lib/site-skill.ts +78 -0
  202. package/src/lib/summary.ts +16 -5
  203. package/src/lib/timeline.ts +137 -131
  204. package/src/lib/timezones.ts +54 -14
  205. package/src/lib/tiptap-render.ts +359 -83
  206. package/src/lib/translit.ts +288 -0
  207. package/src/lib/url.ts +123 -12
  208. package/src/lib/view.ts +58 -20
  209. package/src/lib/worker-response-cache.ts +11 -18
  210. package/src/middleware/__tests__/public-content-access.test.ts +91 -0
  211. package/src/middleware/config.ts +2 -2
  212. package/src/middleware/public-content-access.ts +87 -0
  213. package/src/node/__tests__/cli-export.test.ts +14 -0
  214. package/src/node/__tests__/cli-migrate.test.ts +6 -0
  215. package/src/node/__tests__/cli-site-snapshot.test.ts +205 -2
  216. package/src/node/__tests__/cli-snapshot-meta.test.ts +100 -0
  217. package/src/node/index.ts +2 -1
  218. package/src/preset.css +16 -2
  219. package/src/routes/__tests__/compose.test.ts +51 -0
  220. package/src/routes/__tests__/site-skill.test.ts +112 -0
  221. package/src/routes/api/__tests__/collections.test.ts +91 -19
  222. package/src/routes/api/__tests__/mcp.test.ts +65 -1
  223. package/src/routes/api/__tests__/nav-items.test.ts +91 -0
  224. package/src/routes/api/__tests__/palette.test.ts +44 -0
  225. package/src/routes/api/__tests__/public-access.test.ts +81 -0
  226. package/src/routes/api/__tests__/settings.test.ts +217 -0
  227. package/src/routes/api/collections.ts +22 -26
  228. package/src/routes/api/export.ts +2 -0
  229. package/src/routes/api/internal/__tests__/post-body-html.test.ts +163 -0
  230. package/src/routes/api/internal/__tests__/sites.test.ts +35 -2
  231. package/src/routes/api/internal/post-body-html.ts +43 -0
  232. package/src/routes/api/internal/sites.ts +24 -0
  233. package/src/routes/api/nav-items.ts +24 -1
  234. package/src/routes/api/posts.ts +14 -10
  235. package/src/routes/api/public/__tests__/archive.test.ts +35 -0
  236. package/src/routes/api/public/__tests__/posts.test.ts +246 -0
  237. package/src/routes/api/public/archive.ts +4 -0
  238. package/src/routes/api/public/posts.ts +48 -24
  239. package/src/routes/api/search.ts +3 -0
  240. package/src/routes/api/settings.ts +33 -0
  241. package/src/routes/auth/__tests__/setup.test.ts +7 -4
  242. package/src/routes/compose.tsx +8 -3
  243. package/src/routes/dash/settings.tsx +45 -2
  244. package/src/routes/feed/__tests__/feed.test.ts +210 -6
  245. package/src/routes/feed/__tests__/sitemap.test.ts +68 -1
  246. package/src/routes/feed/feed.ts +23 -14
  247. package/src/routes/pages/__tests__/archive-params.test.ts +384 -3
  248. package/src/routes/pages/__tests__/collection-routing.test.ts +63 -5
  249. package/src/routes/pages/__tests__/collections.test.ts +9 -9
  250. package/src/routes/pages/__tests__/featured.test.ts +6 -2
  251. package/src/routes/pages/__tests__/preview.test.ts +176 -0
  252. package/src/routes/pages/__tests__/search.test.ts +69 -0
  253. package/src/routes/pages/archive.tsx +90 -22
  254. package/src/routes/pages/collection.tsx +32 -19
  255. package/src/routes/pages/collections.tsx +6 -1
  256. package/src/routes/pages/page.tsx +86 -11
  257. package/src/routes/site-skill.ts +18 -0
  258. package/src/services/__tests__/auth.test.ts +7 -5
  259. package/src/services/__tests__/collection.test.ts +190 -44
  260. package/src/services/__tests__/navigation.test.ts +229 -21
  261. package/src/services/__tests__/post-timeline.test.ts +249 -39
  262. package/src/services/__tests__/post.test.ts +844 -5
  263. package/src/services/__tests__/search.test.ts +48 -1
  264. package/src/services/__tests__/settings.test.ts +8 -0
  265. package/src/services/__tests__/site-admin.test.ts +121 -1
  266. package/src/services/auth.ts +2 -2
  267. package/src/services/bootstrap.ts +3 -2
  268. package/src/services/collection.ts +224 -167
  269. package/src/services/export-theme/assets/client-site.css +1 -1
  270. package/src/services/export-theme/assets/client-site.js +46 -25
  271. package/src/services/export-theme/layouts/_default/list.html +18 -4
  272. package/src/services/export-theme/layouts/_default/rss.xml +8 -12
  273. package/src/services/export-theme/layouts/featured/list.html +5 -4
  274. package/src/services/export-theme/layouts/partials/featured-thread.html +56 -0
  275. package/src/services/export-theme/layouts/partials/footer.html +1 -1
  276. package/src/services/export-theme/layouts/partials/media-gallery.html +1 -0
  277. package/src/services/export-theme/styles/main.css +30 -2
  278. package/src/services/export.ts +94 -85
  279. package/src/services/mcp.ts +37 -27
  280. package/src/services/media.ts +1 -1
  281. package/src/services/navigation.ts +185 -46
  282. package/src/services/path.ts +4 -1
  283. package/src/services/post.ts +1142 -342
  284. package/src/services/search.ts +17 -2
  285. package/src/services/settings.ts +2 -10
  286. package/src/services/site-admin.ts +63 -43
  287. package/src/style-cjk-jp.css +1 -1
  288. package/src/style-cjk-kr.css +1 -1
  289. package/src/style-cjk-tc.css +1 -1
  290. package/src/style-cjk.css +1 -1
  291. package/src/styles/components.css +540 -14
  292. package/src/styles/site-media.css +111 -19
  293. package/src/styles/tokens.css +76 -10
  294. package/src/styles/ui.css +2227 -1347
  295. package/src/types/bindings.ts +3 -0
  296. package/src/types/config.ts +243 -12
  297. package/src/types/constants.ts +22 -1
  298. package/src/types/entities.ts +14 -8
  299. package/src/types/operations.ts +18 -10
  300. package/src/types/props.ts +20 -2
  301. package/src/types/raw-assets.d.ts +5 -0
  302. package/src/types/views.ts +22 -4
  303. package/src/ui/__tests__/font-themes.test.ts +42 -30
  304. package/src/ui/compose/ComposeDialog.tsx +109 -19
  305. package/src/ui/dash/appearance/NavigationContent.tsx +332 -4
  306. package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +23 -0
  307. package/src/ui/dash/settings/ConfigEditorContent.tsx +578 -0
  308. package/src/ui/dash/settings/GeneralContent.tsx +15 -5
  309. package/src/ui/dash/settings/SettingsRootContent.tsx +21 -1
  310. package/src/ui/dash/settings/__tests__/ConfigEditorContent.test.tsx +98 -0
  311. package/src/ui/dash/settings/__tests__/SettingsRootContent.test.tsx +15 -0
  312. package/src/ui/feed/CuratedThreadPreview.tsx +16 -4
  313. package/src/ui/feed/LinkCard.tsx +2 -12
  314. package/src/ui/feed/LinkPreview.tsx +2 -7
  315. package/src/ui/feed/NoteCard.tsx +10 -20
  316. package/src/ui/feed/PostStatusBadges.tsx +42 -3
  317. package/src/ui/feed/QuoteCard.tsx +2 -12
  318. package/src/ui/feed/ThreadPreview.tsx +26 -34
  319. package/src/ui/feed/TimelineFeed.tsx +2 -2
  320. package/src/ui/feed/__tests__/thread-preview.test.ts +197 -56
  321. package/src/ui/feed/__tests__/timeline-cards.test.ts +178 -3
  322. package/src/ui/feed/thread-preview-state.ts +5 -7
  323. package/src/ui/font-themes.ts +74 -26
  324. package/src/ui/layouts/BaseLayout.tsx +22 -8
  325. package/src/ui/layouts/__tests__/BaseLayout.test.tsx +64 -1
  326. package/src/ui/pages/ArchivePage.tsx +131 -24
  327. package/src/ui/pages/CollectionPage.tsx +101 -22
  328. package/src/ui/pages/CollectionsPage.tsx +3 -1
  329. package/src/ui/pages/PostPage.tsx +39 -12
  330. package/src/ui/pages/SearchPage.tsx +6 -14
  331. package/src/ui/pages/__tests__/ArchivePage.test.tsx +70 -0
  332. package/src/ui/pages/__tests__/PostPage.test.tsx +88 -0
  333. package/src/ui/shared/CollectionDirectory.tsx +13 -9
  334. package/src/ui/shared/CollectionsManager.tsx +17 -7
  335. package/src/ui/shared/DraftPreviewBar.tsx +49 -0
  336. package/src/ui/shared/HomePageBranding.tsx +2 -2
  337. package/src/ui/shared/MediaGallery.tsx +1 -0
  338. package/src/ui/shared/PostFooter.tsx +38 -13
  339. package/src/ui/shared/__tests__/home-page-branding.test.tsx +1 -1
  340. package/src/ui/shared/__tests__/media-gallery.test.ts +1 -0
  341. package/src/ui/shared/__tests__/navigation-labels.test.ts +2 -2
  342. package/src/ui/shared/__tests__/post-footer.test.ts +15 -0
  343. package/src/ui/shared/collection-management-labels.ts +33 -2
  344. package/src/ui/shared/custom-icons.ts +5 -0
  345. package/src/ui/shared/navigation-labels.ts +2 -4
  346. package/src/ui/shared/post-article-attributes.ts +52 -0
  347. package/dist/app-DZDlmh7C.js +0 -6
  348. package/dist/client/_assets/client-Cevfpm8H.css +0 -2
  349. package/dist/client/_assets/client-auth-v3yvhbgZ.js +0 -4736
  350. package/src/client/tiptap/wrapping-input-rules.ts +0 -102
@@ -26,6 +26,11 @@ declare module "*.js?raw" {
26
26
  export default content;
27
27
  }
28
28
 
29
+ declare module "*.md?raw" {
30
+ const content: string;
31
+ export default content;
32
+ }
33
+
29
34
  declare module "*.xml?raw" {
30
35
  const content: string;
31
36
  export default content;
@@ -92,7 +92,7 @@ export interface PostView {
92
92
  // Media -- URLs pre-computed
93
93
  media: MediaView[];
94
94
 
95
- // Collections this post belongs to
95
+ // Thread-level Collections projected onto this post
96
96
  collections: CollectionTagView[];
97
97
 
98
98
  // Thread context
@@ -102,6 +102,12 @@ export interface PostView {
102
102
  threadRootId?: string;
103
103
  /** Whether this post is the last (most recent) in its thread. Controls reply button visibility. */
104
104
  isLastInThread: boolean;
105
+ /**
106
+ * TypeID of an unpublished draft that already ends this thread, set only for
107
+ * the signed-in author on surfaces that do not render drafts. Replying here
108
+ * would fork the chain, so the reply affordance resumes that draft instead.
109
+ */
110
+ draftTailId?: string;
105
111
  /** Number of published replies in this thread when relevant to the current view. */
106
112
  replyCount?: number;
107
113
 
@@ -157,6 +163,7 @@ export interface NavItemView {
157
163
  type: NavItemType;
158
164
  systemKey?: SystemNavKey;
159
165
  collectionId?: string;
166
+ postId?: string;
160
167
  label: string;
161
168
  url: string;
162
169
  /** "header" = visible in nav bar, "more" = under More dropdown */
@@ -173,7 +180,7 @@ export interface NavItemView {
173
180
 
174
181
  export type SuggestedNavLinkTargetType = "page" | "collection" | "archive";
175
182
 
176
- export type SuggestedNavLinkNavItemType = "link" | "collection";
183
+ export type SuggestedNavLinkNavItemType = "link" | "collection" | "page";
177
184
 
178
185
  export interface SuggestedNavLink {
179
186
  key: string;
@@ -182,6 +189,15 @@ export interface SuggestedNavLink {
182
189
  targetType: SuggestedNavLinkTargetType;
183
190
  navItemType: SuggestedNavLinkNavItemType;
184
191
  collectionId?: string;
192
+ postId?: string;
193
+ }
194
+
195
+ /** A published titled note eligible to be added to site navigation. */
196
+ export interface NavigationPageCandidate {
197
+ id: string;
198
+ title: string;
199
+ slug: string;
200
+ updatedAt: number;
185
201
  }
186
202
 
187
203
  /**
@@ -215,13 +231,15 @@ export interface SearchResultView {
215
231
  export interface TimelineItemView {
216
232
  post: PostView;
217
233
  threadPreview?: {
218
- secondReply?: PostView;
219
- penultimateReply?: PostView;
234
+ leadingReplies: PostView[];
235
+ trailingReplies: PostView[];
220
236
  latestReply: PostView;
221
237
  totalReplyCount: number;
222
238
  };
223
239
  curatedThread?: {
224
240
  rootPost: PostView;
241
+ /** Show ratings on non-highlighted context posts (complete Collection Threads). */
242
+ showContextRatings: boolean;
225
243
  segments: {
226
244
  post: PostView;
227
245
  hiddenBeforeCount: number;
@@ -1,9 +1,11 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
  import {
3
3
  BUILTIN_FONT_THEMES,
4
+ DEFAULT_FONT_CJK_SANS_FALLBACK,
4
5
  DEFAULT_FONT_CJK_SERIF_FALLBACK,
5
- getCjkSerifCssVariables,
6
+ getCjkFontCssVariables,
6
7
  getFontThemeCssVariables,
8
+ resolveCjkFontProfile,
7
9
  } from "../font-themes.js";
8
10
 
9
11
  describe("BUILTIN_FONT_THEMES", () => {
@@ -90,52 +92,62 @@ describe("BUILTIN_FONT_THEMES", () => {
90
92
  expect(variables["--type-label-weight"]).toBe("var(--fw-semibold)");
91
93
  });
92
94
 
93
- it("routes zh-Hans to the simplified CJK serif fallback first", () => {
94
- const variables = getCjkSerifCssVariables("zh-Hans");
95
- const stack = variables["--font-cjk-serif-fallback"];
95
+ it("routes zh-Hans content to simplified serif and sans fallbacks", () => {
96
+ const variables = getCjkFontCssVariables("zh-Hans", "off");
97
+ const serif = variables["--font-cjk-serif-fallback"];
98
+ const sans = variables["--font-cjk-sans-fallback"];
96
99
 
97
- expect(stack).toContain('"Songti SC"');
98
- expect(stack).toContain('"Noto Serif SC"');
99
- expect(stack.indexOf('"Songti SC"')).toBeLessThan(
100
- stack.indexOf('"Noto Serif SC"'),
100
+ expect(serif).toContain('"Songti SC"');
101
+ expect(serif).toContain('"Noto Serif SC"');
102
+ expect(sans.indexOf('"PingFang SC"')).toBeLessThan(
103
+ sans.indexOf('"PingFang TC"'),
101
104
  );
102
105
  });
103
106
 
104
- it("routes zh-Hant to the traditional CJK serif fallback first", () => {
105
- const variables = getCjkSerifCssVariables("zh-Hant");
106
- const stack = variables["--font-cjk-serif-fallback"];
107
+ it("routes zh-Hant content to traditional serif and sans fallbacks", () => {
108
+ const variables = getCjkFontCssVariables("zh-Hant", "off");
109
+ const serif = variables["--font-cjk-serif-fallback"];
110
+ const sans = variables["--font-cjk-sans-fallback"];
107
111
 
108
- expect(stack).toContain('"Songti TC"');
109
- expect(stack).toContain('"Noto Serif TC"');
110
- expect(stack.indexOf('"Songti TC"')).toBeLessThan(
111
- stack.indexOf('"Noto Serif TC"'),
112
+ expect(serif).toContain('"Songti TC"');
113
+ expect(serif).toContain('"Noto Serif TC"');
114
+ expect(sans.indexOf('"PingFang TC"')).toBeLessThan(
115
+ sans.indexOf('"PingFang SC"'),
112
116
  );
113
117
  });
114
118
 
115
- it("routes ja to the Japanese CJK serif fallback", () => {
116
- const variables = getCjkSerifCssVariables("ja");
117
- const stack = variables["--font-cjk-serif-fallback"];
119
+ it("routes Japanese content to the Japanese font profile", () => {
120
+ const variables = getCjkFontCssVariables("ja", "off");
118
121
 
119
- expect(stack).toContain('"Noto Serif JP"');
122
+ expect(variables["--font-cjk-serif-fallback"]).toContain('"Noto Serif JP"');
123
+ expect(variables["--font-cjk-sans-fallback"]).toContain('"Noto Sans JP"');
120
124
  });
121
125
 
122
- it("routes ko to the Korean CJK serif fallback", () => {
123
- const variables = getCjkSerifCssVariables("ko");
124
- const stack = variables["--font-cjk-serif-fallback"];
126
+ it("routes Korean content to the Korean font profile", () => {
127
+ const variables = getCjkFontCssVariables("ko", "off");
125
128
 
126
- expect(stack).toContain('"Noto Serif KR"');
129
+ expect(variables["--font-cjk-serif-fallback"]).toContain('"Noto Serif KR"');
130
+ expect(variables["--font-cjk-sans-fallback"]).toContain('"Noto Sans KR"');
127
131
  });
128
132
 
129
- it("does not inject a runtime override when CJK is off", () => {
130
- expect(getCjkSerifCssVariables("off")).toEqual({});
133
+ it("uses the explicit CJK fallback for an unadapted content language", () => {
134
+ expect(resolveCjkFontProfile("en", "zh-Hans")).toBe("zh-Hans");
131
135
  });
132
136
 
133
- it("does not inject a runtime override for unrecognized values", () => {
134
- expect(getCjkSerifCssVariables("en")).toEqual({});
137
+ it("lets an adapted content language override the manual fallback", () => {
138
+ expect(resolveCjkFontProfile("zh-Hant", "zh-Hans")).toBe("zh-Hant");
135
139
  });
136
140
 
137
- it("keeps a default CJK serif fallback for the base tokens", () => {
138
- expect(DEFAULT_FONT_CJK_SERIF_FALLBACK).toContain('"Songti SC"');
139
- expect(DEFAULT_FONT_CJK_SERIF_FALLBACK).toContain('"Noto Serif SC"');
141
+ it("keeps the default profile neutral", () => {
142
+ expect(getCjkFontCssVariables("en", "off")).toEqual({});
143
+ expect(DEFAULT_FONT_CJK_SERIF_FALLBACK).toBe('"Jant Language Fallback"');
144
+ expect(DEFAULT_FONT_CJK_SANS_FALLBACK).toBe('"Jant Language Fallback"');
145
+ });
146
+
147
+ it("puts language slots into every serif and sans theme stack", () => {
148
+ for (const theme of BUILTIN_FONT_THEMES) {
149
+ const combined = `${theme.headingFontFamily} ${theme.bodyFontFamily}`;
150
+ expect(combined).toMatch(/var\(--font-cjk-(?:serif|sans)-fallback\)/);
151
+ }
140
152
  });
141
153
  });
@@ -13,6 +13,7 @@ import type { FC } from "hono/jsx";
13
13
  import { MAX_THREAD_POSTS, type Collection } from "../../types.js";
14
14
  import { useLingui } from "../../i18n/context.js";
15
15
  import { getCollectionFormLabels } from "../shared/collection-management-labels.js";
16
+ import type { ComposeLabels } from "../../client/components/compose-types.js";
16
17
 
17
18
  export interface ComposeDialogProps {
18
19
  collections?: Collection[];
@@ -36,7 +37,7 @@ export const ComposeForm: FC<ComposeFormProps> = ({
36
37
  }) => {
37
38
  const { i18n } = useLingui();
38
39
 
39
- const labels = JSON.stringify({
40
+ const labelsObject = {
40
41
  cancel: i18n._(
41
42
  msg({
42
43
  message: "Cancel",
@@ -125,8 +126,9 @@ export const ComposeForm: FC<ComposeFormProps> = ({
125
126
  ),
126
127
  titlePlaceholder: i18n._(
127
128
  msg({
128
- message: "Title",
129
- comment: "@context: Compose note title placeholder",
129
+ message: "Untitled",
130
+ comment:
131
+ "@context: Compose note title placeholder. States what the note is while the field is empty rather than asking for a title — untitled notes are a normal kind of note here, and Archive files them under this same word.",
130
132
  }),
131
133
  ),
132
134
  bodyPlaceholder: i18n._(
@@ -236,7 +238,7 @@ export const ComposeForm: FC<ComposeFormProps> = ({
236
238
  title: i18n._(
237
239
  msg({
238
240
  message: "Title",
239
- comment: "@context: Compose toolbar - title tooltip",
241
+ comment: "@context: Compose toolbar - show or hide the title field",
240
242
  }),
241
243
  ),
242
244
  fullscreen: i18n._(
@@ -476,6 +478,19 @@ export const ComposeForm: FC<ComposeFormProps> = ({
476
478
  comment: "@context: Drafts panel empty state",
477
479
  }),
478
480
  ),
481
+ previewDraft: i18n._(
482
+ msg({
483
+ message: "Preview",
484
+ comment: "@context: Draft item action that opens its rendered preview",
485
+ }),
486
+ ),
487
+ draftActions: i18n._(
488
+ msg({
489
+ message: "Draft actions",
490
+ comment:
491
+ "@context: Accessible label for a draft item's more-actions button",
492
+ }),
493
+ ),
479
494
  deleteDraft: i18n._(
480
495
  msg({
481
496
  message: "Delete Draft",
@@ -635,9 +650,9 @@ export const ComposeForm: FC<ComposeFormProps> = ({
635
650
  ),
636
651
  publishDateSummaryNow: i18n._(
637
652
  msg({
638
- message: "Publish now",
653
+ message: "Now",
639
654
  comment:
640
- "@context: Compose summary shown near the submit controls when an edited post no longer has a custom publish date",
655
+ "@context: Value shown on a post's date control when it will publish at the current time",
641
656
  }),
642
657
  ),
643
658
  publishDateSummaryAction: i18n._(
@@ -674,9 +689,9 @@ export const ComposeForm: FC<ComposeFormProps> = ({
674
689
  ),
675
690
  publishSlugSummaryAuto: i18n._(
676
691
  msg({
677
- message: "Auto link",
692
+ message: "/…",
678
693
  comment:
679
- "@context: Compose summary shown near the submit controls when a manual custom link is cleared",
694
+ "@context: Value shown on a post's permalink control when the link is generated automatically — a stand-in for the path the server will assign. Sits next to real permalinks rendered as /my-post, so keep the leading slash",
680
695
  }),
681
696
  ),
682
697
  publishSlugSummaryAction: i18n._(
@@ -780,24 +795,24 @@ export const ComposeForm: FC<ComposeFormProps> = ({
780
795
  "@context: Toast shown when a local draft is restored on compose open",
781
796
  }),
782
797
  ),
783
- newThread: i18n._(
798
+ closeCompose: i18n._(
784
799
  msg({
785
- message: "New Thread",
800
+ message: "Close compose",
786
801
  comment:
787
- "@context: Compose dialog header title when composing a thread",
802
+ "@context: Post options row that leaves the composer; prompts to save a draft first if there is unsaved work",
788
803
  }),
789
804
  ),
790
- replyTitle: i18n._(
805
+ editing: i18n._(
791
806
  msg({
792
- message: "Reply",
807
+ message: "Editing",
793
808
  comment:
794
- "@context: Compose dialog header title when replying to a post",
809
+ "@context: Marker above the composer when changing a post that is already published",
795
810
  }),
796
811
  ),
797
- editTitle: i18n._(
812
+ composeDialogLabel: i18n._(
798
813
  msg({
799
- message: "Edit",
800
- comment: "@context: Compose dialog header title when editing a post",
814
+ message: "Compose",
815
+ comment: "@context: Accessible name for the compose dialog",
801
816
  }),
802
817
  ),
803
818
  slashHint: i18n._(
@@ -807,8 +822,84 @@ export const ComposeForm: FC<ComposeFormProps> = ({
807
822
  "@context: First-use hint shown over the compose editor to surface the slash command menu",
808
823
  }),
809
824
  ),
825
+ tableControls: {
826
+ toolbarLabel: i18n._(
827
+ msg({
828
+ message: "Table controls",
829
+ comment: "@context: Accessible label for the compose table toolbar",
830
+ }),
831
+ ),
832
+ addRowAbove: i18n._(
833
+ msg({
834
+ message: "Add row above",
835
+ comment: "@context: Compose table action",
836
+ }),
837
+ ),
838
+ addRowBelow: i18n._(
839
+ msg({
840
+ message: "Add row below",
841
+ comment: "@context: Compose table action",
842
+ }),
843
+ ),
844
+ addColumnBefore: i18n._(
845
+ msg({
846
+ message: "Add column before",
847
+ comment: "@context: Compose table action",
848
+ }),
849
+ ),
850
+ addColumnAfter: i18n._(
851
+ msg({
852
+ message: "Add column after",
853
+ comment: "@context: Compose table action",
854
+ }),
855
+ ),
856
+ options: i18n._(
857
+ msg({
858
+ message: "Table options",
859
+ comment: "@context: Compose table menu button label",
860
+ }),
861
+ ),
862
+ deleteRow: i18n._(
863
+ msg({
864
+ message: "Delete row",
865
+ comment: "@context: Compose table action",
866
+ }),
867
+ ),
868
+ deleteColumn: i18n._(
869
+ msg({
870
+ message: "Delete column",
871
+ comment: "@context: Compose table action",
872
+ }),
873
+ ),
874
+ toggleHeaderRow: i18n._(
875
+ msg({
876
+ message: "Toggle header row",
877
+ comment: "@context: Compose table action",
878
+ }),
879
+ ),
880
+ deleteTable: i18n._(
881
+ msg({
882
+ message: "Delete table",
883
+ comment: "@context: Destructive compose table action",
884
+ }),
885
+ ),
886
+ sizePickerLabel: i18n._(
887
+ msg({
888
+ message: "Choose table size",
889
+ comment: "@context: Accessible title for the table dimension picker",
890
+ }),
891
+ ),
892
+ insertTableSize: i18n._(
893
+ msg({
894
+ message: "Insert %rows% by %cols% table",
895
+ comment:
896
+ "@context: Accessible label for a table size option. %rows% and %cols% are replaced with dimensions",
897
+ }),
898
+ ),
899
+ },
810
900
  collectionFormLabels: getCollectionFormLabels(i18n),
811
- }).replace(/</g, "\\u003c");
901
+ } satisfies ComposeLabels;
902
+ const labels = JSON.stringify(labelsObject).replace(/</g, "\\u003c");
812
903
 
813
904
  const collectionsJson = JSON.stringify(
814
905
  (collections ?? []).map((c) => ({
@@ -830,7 +921,6 @@ export const ComposeForm: FC<ComposeFormProps> = ({
830
921
  >
831
922
  {/* SSR fallback skeleton */}
832
923
  <div class="compose-dialog-inner">
833
- <div class="compose-dialog-header" />
834
924
  <div class="compose-body skel-section-md" />
835
925
  </div>
836
926
  </jant-compose-dialog>