@jant/core 0.6.16 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (508) hide show
  1. package/README.md +11 -11
  2. package/bin/commands/assets/upload.js +192 -15
  3. package/bin/commands/import-site.js +60 -4
  4. package/bin/commands/reset-password.js +21 -8
  5. package/bin/commands/site/snapshot/export.js +1 -1
  6. package/bin/commands/site/snapshot/import.js +1 -1
  7. package/bin/lib/d1-query.js +5 -16
  8. package/bin/lib/node-env.js +40 -4
  9. package/bin/lib/site-selection.js +85 -29
  10. package/bin/lib/wrangler-cli.js +28 -2
  11. package/bin/lib/wrangler-json.js +35 -0
  12. package/dist/{app-C7_4oab9.js → app-K_Aa1MMn.js} +52476 -13330
  13. package/dist/client/.vite/manifest.json +255 -90
  14. package/dist/client/_assets/chunks/confirm-D7GrwsCN.js +45 -0
  15. package/dist/client/_assets/chunks/create-editor-CD3FhrOB.js +257 -0
  16. package/dist/client/_assets/chunks/{native-DpcrFAPh.js → emoji-mart-C4RpRKcU.js} +716 -1
  17. package/dist/client/_assets/chunks/footnote-rail-CmeoVtnU.js +1 -0
  18. package/dist/client/_assets/chunks/heic-to-CuP2Qlsw.js +1 -0
  19. package/dist/client/_assets/chunks/jant-locale-picker-DL6mIOT5.js +69 -0
  20. package/dist/client/_assets/chunks/lit-DW8VmJAT.js +2 -0
  21. package/dist/client/_assets/chunks/mediabunny-DRaCQ1r-.js +31 -0
  22. package/dist/client/_assets/chunks/rolldown-runtime-hePW80VL.js +1 -0
  23. package/dist/client/_assets/chunks/settings-paths-BcdySNx6.js +84 -0
  24. package/dist/client/_assets/chunks/site-header-nav-DzXsFk05.js +1 -0
  25. package/dist/client/_assets/chunks/slug-format-CRXO1AL5.js +1 -0
  26. package/dist/client/_assets/chunks/slugify-373citbs.js +1 -0
  27. package/dist/client/_assets/chunks/sortable-list-CgaL2jCs.js +2 -0
  28. package/dist/client/_assets/chunks/types-D5iF3H1a.js +1 -0
  29. package/dist/client/_assets/chunks/unsafe-html-B5ZEXaxg.js +1 -0
  30. package/dist/client/_assets/chunks/unsafe-svg-0QCkP0vZ.js +2 -0
  31. package/dist/client/_assets/client-GiYENVw8.css +2 -0
  32. package/dist/client/_assets/client-VnFxJN7G.js +295 -0
  33. package/dist/client/_assets/client-auth-k8gJ6QJj.js +828 -0
  34. package/dist/client/_assets/client-author-DQ8R-8KR.css +2 -0
  35. package/dist/client/_assets/client-compose-B_kDtWkW.js +2004 -0
  36. package/dist/client/_assets/client-manage-M90aSTOk.js +2170 -0
  37. package/dist/client/_assets/client-settings-DfYs9n1F.js +1112 -0
  38. package/dist/{export-Dl5KCiEs.js → github-sync-BPAvT999.js} +2254 -107
  39. package/dist/index.js +2 -5
  40. package/dist/node.js +5 -7
  41. package/package.json +3 -3
  42. package/src/__tests__/auth-session-freshness.test.ts +57 -0
  43. package/src/__tests__/basecoat-variants.test.ts +121 -0
  44. package/src/__tests__/bin/assets-upload.test.ts +68 -0
  45. package/src/__tests__/export-hugo-build.test.ts +260 -0
  46. package/src/__tests__/export-service.test.ts +231 -0
  47. package/src/__tests__/helpers/component-css.ts +91 -0
  48. package/src/__tests__/helpers/db.ts +33 -0
  49. package/src/__tests__/helpers/export-fixtures.ts +3 -0
  50. package/src/__tests__/stylesheet-audience.test.ts +159 -0
  51. package/src/__tests__/stylesheet-breakpoints.test.ts +183 -0
  52. package/src/app.tsx +71 -16
  53. package/src/auth.ts +18 -1
  54. package/src/client/__tests__/collection-page-actions.test.ts +51 -2
  55. package/src/client/__tests__/compose-bridge-image-upload.test.ts +196 -0
  56. package/src/client/__tests__/compose-bridge-video-poster.test.ts +159 -0
  57. package/src/client/__tests__/compose-bridge.test.ts +272 -0
  58. package/src/client/__tests__/compose-launch.test.ts +62 -1
  59. package/src/client/__tests__/compose-shortcuts.test.ts +38 -9
  60. package/src/client/__tests__/compose-triggers.test.ts +90 -0
  61. package/src/client/__tests__/copy-field.test.ts +162 -0
  62. package/src/client/__tests__/custom-url-menu.test.ts +127 -6
  63. package/src/client/__tests__/image-processor.test.ts +324 -2
  64. package/src/client/__tests__/lazy-entries.test.ts +92 -0
  65. package/src/client/__tests__/media-scroll-hint.test.ts +155 -0
  66. package/src/client/__tests__/runtime-paths.test.ts +84 -0
  67. package/src/client/__tests__/smart-collection-page-actions.test.ts +158 -0
  68. package/src/client/__tests__/toast.test.ts +23 -0
  69. package/src/client/__tests__/video-processor-probe.test.ts +175 -0
  70. package/src/client/__tests__/video-processor.test.ts +181 -0
  71. package/src/client/audio-processor.ts +24 -15
  72. package/src/client/audio-waveform.ts +49 -0
  73. package/src/client/collection-dialog-host.ts +72 -0
  74. package/src/client/collection-navigation.ts +51 -16
  75. package/src/client/collection-page-actions.ts +26 -0
  76. package/src/client/components/__tests__/jant-collection-dialog.test.ts +329 -0
  77. package/src/client/components/__tests__/jant-collection-directory.test.ts +274 -10
  78. package/src/client/components/__tests__/jant-collection-form.test.ts +59 -178
  79. package/src/client/components/__tests__/jant-command-palette.test.ts +28 -0
  80. package/src/client/components/__tests__/jant-compose-dialog-draft-storage.test.ts +340 -0
  81. package/src/client/components/__tests__/jant-compose-dialog.test.ts +1250 -53
  82. package/src/client/components/__tests__/jant-compose-editor.test.ts +544 -40
  83. package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +0 -1
  84. package/src/client/components/__tests__/jant-locale-picker.test.ts +207 -0
  85. package/src/client/components/__tests__/jant-nav-manager.test.ts +234 -15
  86. package/src/client/components/__tests__/jant-post-menu.test.ts +413 -2
  87. package/src/client/components/__tests__/jant-post-picker.test.ts +197 -0
  88. package/src/client/components/__tests__/jant-settings-avatar.test.ts +15 -12
  89. package/src/client/components/__tests__/jant-settings-general.test.ts +541 -172
  90. package/src/client/components/__tests__/jant-settings-language.test.ts +851 -0
  91. package/src/client/components/__tests__/jant-smart-collection-dialog.test.ts +665 -0
  92. package/src/client/components/collection-dialog-types.ts +49 -0
  93. package/src/client/components/collection-manager-types.ts +32 -1
  94. package/src/client/components/collection-types.ts +1 -15
  95. package/src/client/components/compose-types.ts +75 -1
  96. package/src/client/components/jant-collection-dialog.ts +722 -0
  97. package/src/client/components/jant-collection-directory.ts +567 -182
  98. package/src/client/components/jant-collection-form.ts +53 -232
  99. package/src/client/components/jant-command-palette.ts +100 -49
  100. package/src/client/components/jant-compose-dialog.ts +1486 -707
  101. package/src/client/components/jant-compose-editor.ts +673 -336
  102. package/src/client/components/jant-compose-fullscreen.ts +51 -43
  103. package/src/client/components/jant-config-editor.ts +65 -53
  104. package/src/client/components/jant-confirm-dialog.ts +13 -11
  105. package/src/client/components/jant-locale-picker.ts +418 -0
  106. package/src/client/components/jant-media-lightbox.ts +146 -136
  107. package/src/client/components/jant-nav-manager.ts +690 -366
  108. package/src/client/components/jant-post-menu.ts +1086 -282
  109. package/src/client/components/jant-post-picker.ts +324 -0
  110. package/src/client/components/jant-repo-picker.ts +138 -106
  111. package/src/client/components/jant-settings-avatar.ts +31 -27
  112. package/src/client/components/jant-settings-general.ts +617 -543
  113. package/src/client/components/jant-settings-language.ts +1087 -0
  114. package/src/client/components/jant-smart-collection-dialog.ts +1021 -0
  115. package/src/client/components/jant-text-preview.ts +94 -86
  116. package/src/client/components/nav-manager-types.ts +62 -1
  117. package/src/client/components/settings-types.ts +14 -29
  118. package/src/client/components/smart-collection-conditions.ts +285 -0
  119. package/src/client/components/smart-collection-dialog-types.ts +68 -0
  120. package/src/client/compose-bridge.ts +214 -141
  121. package/src/client/compose-launch.ts +76 -2
  122. package/src/client/compose-shortcuts.ts +6 -8
  123. package/src/client/compose-triggers.ts +50 -0
  124. package/src/client/copy-field.ts +108 -0
  125. package/src/client/custom-url-menu.ts +60 -4
  126. package/src/client/icons.ts +14 -0
  127. package/src/client/image-plan.ts +165 -0
  128. package/src/client/image-processor.ts +195 -117
  129. package/src/client/image-worker-client.ts +45 -0
  130. package/src/client/image-worker.ts +135 -0
  131. package/src/client/lazy-entries.ts +95 -0
  132. package/src/client/lazy-slugify.ts +2 -2
  133. package/src/client/media-scroll-hint.ts +43 -2
  134. package/src/client/mediabunny.ts +29 -0
  135. package/src/client/post-picker.ts +41 -0
  136. package/src/client/runtime-paths.ts +74 -1
  137. package/src/client/settings-bridge.ts +4 -10
  138. package/src/client/site-header-nav.js +18 -6
  139. package/src/client/smart-collection-dialog-host.ts +116 -0
  140. package/src/client/smart-collection-page-actions.ts +208 -0
  141. package/src/client/tiptap/__tests__/bubble-menu.test.ts +110 -0
  142. package/src/client/tiptap/__tests__/floating-position.test.ts +136 -1
  143. package/src/client/tiptap/__tests__/inline-image-upload.test.ts +37 -0
  144. package/src/client/tiptap/bubble-menu.ts +47 -16
  145. package/src/client/tiptap/floating-position.ts +216 -2
  146. package/src/client/tiptap/inline-image-upload.ts +7 -3
  147. package/src/client/tiptap/link-toolbar.ts +22 -9
  148. package/src/client/toast.ts +13 -0
  149. package/src/client/types/vite-worker.d.ts +12 -0
  150. package/src/client/upload-with-metadata.ts +3 -13
  151. package/src/client/video-processor.ts +351 -107
  152. package/src/client-auth.ts +14 -31
  153. package/src/client-compose.ts +19 -0
  154. package/src/client-manage.ts +13 -0
  155. package/src/client-settings.ts +14 -0
  156. package/src/client-site.ts +10 -3
  157. package/src/client.ts +4 -0
  158. package/src/db/__tests__/backfill-nav-label-mirrors.test.ts +149 -0
  159. package/src/db/__tests__/schema-enum-sources.test.ts +33 -0
  160. package/src/db/__tests__/smart-collection-placement.test.ts +402 -0
  161. package/src/db/backfills/0006_clear_mirrored_page_nav_labels.sql +31 -0
  162. package/src/db/migrations/0032_married_tomas.sql +3 -0
  163. package/src/db/migrations/0033_busy_johnny_storm.sql +198 -0
  164. package/src/db/migrations/0034_cheerful_rumiko_fujikawa.sql +35 -0
  165. package/src/db/migrations/meta/0032_snapshot.json +2582 -0
  166. package/src/db/migrations/meta/0033_snapshot.json +2816 -0
  167. package/src/db/migrations/meta/0034_snapshot.json +2816 -0
  168. package/src/db/migrations/meta/_journal.json +21 -0
  169. package/src/db/migrations/pg/0030_abandoned_nighthawk.sql +3 -0
  170. package/src/db/migrations/pg/0031_strong_ultimatum.sql +128 -0
  171. package/src/db/migrations/pg/0032_furry_multiple_man.sql +6 -0
  172. package/src/db/migrations/pg/meta/0030_snapshot.json +3329 -0
  173. package/src/db/migrations/pg/meta/0031_snapshot.json +3660 -0
  174. package/src/db/migrations/pg/meta/0032_snapshot.json +3660 -0
  175. package/src/db/migrations/pg/meta/_journal.json +21 -0
  176. package/src/db/pg/schema.ts +195 -27
  177. package/src/db/post-visibility.ts +117 -0
  178. package/src/db/schema.ts +222 -27
  179. package/src/i18n/__tests__/detect.test.ts +26 -81
  180. package/src/i18n/__tests__/supported-locales.test.ts +83 -0
  181. package/src/i18n/context.tsx +12 -2
  182. package/src/i18n/detect.ts +7 -66
  183. package/src/i18n/locales/glossary.zh-Hans.yml +44 -4
  184. package/src/i18n/locales/glossary.zh-Hant.yml +44 -4
  185. package/src/i18n/locales/public/en.po +490 -158
  186. package/src/i18n/locales/public/en.ts +1 -1
  187. package/src/i18n/locales/public/zh-Hans.po +487 -155
  188. package/src/i18n/locales/public/zh-Hans.ts +1 -1
  189. package/src/i18n/locales/public/zh-Hant.po +487 -155
  190. package/src/i18n/locales/public/zh-Hant.ts +1 -1
  191. package/src/i18n/locales/settings/en.po +551 -69
  192. package/src/i18n/locales/settings/en.ts +1 -1
  193. package/src/i18n/locales/settings/zh-Hans.po +597 -115
  194. package/src/i18n/locales/settings/zh-Hans.ts +1 -1
  195. package/src/i18n/locales/settings/zh-Hant.po +610 -128
  196. package/src/i18n/locales/settings/zh-Hant.ts +1 -1
  197. package/src/i18n/locales.ts +94 -0
  198. package/src/i18n/middleware.ts +12 -2
  199. package/src/i18n/supported-locales.ts +80 -0
  200. package/src/lib/__tests__/api-settings.test.ts +11 -2
  201. package/src/lib/__tests__/asset-path.test.ts +92 -0
  202. package/src/lib/__tests__/deferred.test.ts +90 -0
  203. package/src/lib/__tests__/discover-ping.test.ts +89 -0
  204. package/src/lib/__tests__/discover.test.ts +410 -0
  205. package/src/lib/__tests__/feed-policy.test.ts +26 -0
  206. package/src/lib/__tests__/feed.test.ts +1526 -15
  207. package/src/lib/__tests__/filter-dimensions.test.ts +341 -0
  208. package/src/lib/__tests__/hosted-signin.test.ts +1 -1
  209. package/src/lib/__tests__/http-cache.test.ts +162 -0
  210. package/src/lib/__tests__/jant-docs-dev.test.ts +21 -0
  211. package/src/lib/__tests__/jant-docs.test.ts +23 -0
  212. package/src/lib/__tests__/lang-detect.test.ts +231 -0
  213. package/src/lib/__tests__/media-helpers.test.ts +81 -0
  214. package/src/lib/__tests__/navigation.test.ts +135 -1
  215. package/src/lib/__tests__/resolve-config.test.ts +64 -3
  216. package/src/lib/__tests__/schemas.test.ts +42 -4
  217. package/src/lib/__tests__/site-unavailable-page.test.ts +25 -0
  218. package/src/lib/__tests__/slug.test.ts +70 -0
  219. package/src/lib/__tests__/slugify.test.ts +85 -0
  220. package/src/lib/__tests__/storage.test.ts +32 -0
  221. package/src/lib/__tests__/thread-fold.test.ts +113 -0
  222. package/src/lib/__tests__/upload-sideload.test.ts +14 -0
  223. package/src/lib/__tests__/url-fetch.test.ts +1 -2
  224. package/src/lib/__tests__/url.test.ts +78 -72
  225. package/src/lib/__tests__/view-language.test.ts +413 -0
  226. package/src/lib/__tests__/worker-response-cache.test.ts +90 -0
  227. package/src/lib/address.ts +57 -0
  228. package/src/lib/api-posts.ts +12 -0
  229. package/src/lib/asset-path.ts +98 -1
  230. package/src/lib/build-env.ts +16 -0
  231. package/src/lib/collection-groups.ts +5 -1
  232. package/src/lib/collection-paths.ts +3 -10
  233. package/src/lib/constants.ts +28 -3
  234. package/src/lib/copy-field.ts +36 -0
  235. package/src/lib/crypto.ts +40 -0
  236. package/src/lib/csp-builder.ts +2 -1
  237. package/src/lib/deferred.ts +79 -0
  238. package/src/lib/discover-ping.ts +141 -0
  239. package/src/lib/discover.ts +437 -0
  240. package/src/lib/env.ts +134 -0
  241. package/src/lib/errors.ts +33 -0
  242. package/src/lib/feed-policy.ts +236 -2
  243. package/src/lib/feed.ts +926 -73
  244. package/src/lib/filter-dimensions.ts +1349 -0
  245. package/src/lib/github-sync-site-config.ts +3 -0
  246. package/src/lib/hosted-signin.ts +1 -1
  247. package/src/lib/http-cache.ts +148 -0
  248. package/src/lib/hugo-markdown.ts +16 -0
  249. package/src/lib/icons.ts +9 -2
  250. package/src/lib/ids.ts +3 -0
  251. package/src/lib/jant-docs.ts +42 -0
  252. package/src/lib/lang-detect.ts +308 -0
  253. package/src/lib/media-helpers.ts +13 -1
  254. package/src/lib/navigation.ts +78 -11
  255. package/src/lib/pagination.ts +28 -24
  256. package/src/lib/per-language-surfaces.ts +67 -0
  257. package/src/lib/post-meta.ts +19 -0
  258. package/src/lib/render.tsx +55 -7
  259. package/src/lib/resolve-config.ts +53 -5
  260. package/src/lib/schemas.ts +201 -10
  261. package/src/lib/site-header-fragment.tsx +2 -1
  262. package/src/lib/site-unavailable-page.ts +47 -0
  263. package/src/lib/slug.ts +51 -7
  264. package/src/lib/slugify.ts +113 -0
  265. package/src/lib/startup-config.ts +4 -6
  266. package/src/lib/storage.ts +7 -0
  267. package/src/lib/summary.ts +50 -0
  268. package/src/lib/thread-fold.ts +161 -0
  269. package/src/lib/time.ts +32 -0
  270. package/src/lib/timeline.ts +42 -1
  271. package/src/lib/tiptap-render.ts +1 -2
  272. package/src/lib/upload.ts +16 -13
  273. package/src/lib/url.ts +139 -86
  274. package/src/lib/version.ts +10 -8
  275. package/src/lib/view-language.ts +436 -0
  276. package/src/lib/view.ts +51 -23
  277. package/src/lib/viewer-context.ts +62 -0
  278. package/src/middleware/__tests__/auth.test.ts +70 -2
  279. package/src/middleware/__tests__/cache-control.test.ts +71 -3
  280. package/src/middleware/__tests__/onboarding.test.ts +76 -5
  281. package/src/middleware/__tests__/secure-headers.test.ts +1 -1
  282. package/src/middleware/__tests__/session.test.ts +181 -33
  283. package/src/middleware/auth.ts +50 -31
  284. package/src/middleware/cache-control.ts +75 -10
  285. package/src/middleware/config.ts +6 -6
  286. package/src/middleware/error-handler.ts +12 -0
  287. package/src/middleware/onboarding.ts +32 -10
  288. package/src/middleware/secure-headers.ts +1 -1
  289. package/src/middleware/session.ts +96 -8
  290. package/src/node/__tests__/cli-migrate.test.ts +21 -19
  291. package/src/node/__tests__/cli-reset-password.test.ts +81 -8
  292. package/src/node/__tests__/cli-runtime-target.test.ts +48 -1
  293. package/src/node/__tests__/cli-site-selection.test.ts +128 -38
  294. package/src/node/__tests__/runtime.test.ts +37 -0
  295. package/src/node/index.ts +1 -0
  296. package/src/preset.css +76 -22
  297. package/src/routes/__tests__/feed-validator.test.ts +156 -0
  298. package/src/routes/api/__tests__/collections.test.ts +114 -0
  299. package/src/routes/api/__tests__/discover.test.ts +222 -0
  300. package/src/routes/api/__tests__/nav-items.test.ts +212 -2
  301. package/src/routes/api/__tests__/post-translations.test.ts +829 -0
  302. package/src/routes/api/__tests__/settings.test.ts +24 -3
  303. package/src/routes/api/__tests__/telegram.test.ts +6 -5
  304. package/src/routes/api/collections.ts +49 -6
  305. package/src/routes/api/custom-urls.ts +0 -1
  306. package/src/routes/api/discover.ts +95 -0
  307. package/src/routes/api/export.ts +3 -0
  308. package/src/routes/api/internal/__tests__/sites.test.ts +42 -2
  309. package/src/routes/api/nav-items.ts +55 -8
  310. package/src/routes/api/posts.ts +159 -0
  311. package/src/routes/api/public/__tests__/archive.test.ts +111 -0
  312. package/src/routes/api/public/archive.ts +77 -81
  313. package/src/routes/api/public/posts.ts +23 -6
  314. package/src/routes/api/smart-collections.ts +132 -0
  315. package/src/routes/api/telegram.ts +2 -40
  316. package/src/routes/api/uploads.ts +1 -2
  317. package/src/routes/auth/__tests__/setup-auth.test.ts +137 -0
  318. package/src/routes/auth/__tests__/setup-discover.test.ts +204 -0
  319. package/src/routes/auth/__tests__/setup-flow.test.ts +270 -0
  320. package/src/routes/auth/__tests__/setup-page.test.tsx +329 -0
  321. package/src/routes/auth/__tests__/setup-steps.test.ts +310 -0
  322. package/src/routes/auth/__tests__/setup.test.ts +278 -26
  323. package/src/routes/auth/__tests__/signin.test.ts +135 -0
  324. package/src/routes/auth/setup.tsx +934 -186
  325. package/src/routes/auth/signin.tsx +10 -8
  326. package/src/routes/compose.tsx +5 -0
  327. package/src/routes/dash/__tests__/custom-urls-archive.test.ts +44 -0
  328. package/src/routes/dash/__tests__/custom-urls-page.test.ts +49 -0
  329. package/src/routes/dash/__tests__/delete-account.test.ts +106 -0
  330. package/src/routes/dash/__tests__/settings-discover.test.ts +213 -0
  331. package/src/routes/dash/custom-urls.tsx +1 -37
  332. package/src/routes/dash/settings.tsx +502 -41
  333. package/src/routes/discover-announce.ts +96 -0
  334. package/src/routes/feed/__tests__/feed.test.ts +165 -2
  335. package/src/routes/feed/feed.ts +69 -40
  336. package/src/routes/feed/sitemap.ts +95 -11
  337. package/src/routes/pages/__tests__/archive-indexing.test.ts +200 -0
  338. package/src/routes/pages/__tests__/archive-params.test.ts +370 -6
  339. package/src/routes/pages/__tests__/collection-routing.test.ts +16 -0
  340. package/src/routes/pages/__tests__/collections-feed-links.test.ts +72 -0
  341. package/src/routes/pages/__tests__/collections.test.ts +9 -3
  342. package/src/routes/pages/__tests__/custom-archive-url.test.ts +119 -0
  343. package/src/routes/pages/__tests__/feed-autodiscovery.test.ts +148 -0
  344. package/src/routes/pages/__tests__/language-routing.test.ts +679 -0
  345. package/src/routes/pages/__tests__/post-preview-partial.test.ts +96 -0
  346. package/src/routes/pages/__tests__/smart-collection.test.ts +298 -0
  347. package/src/routes/pages/__tests__/subscribe.test.ts +248 -0
  348. package/src/routes/pages/archive.tsx +471 -369
  349. package/src/routes/pages/collection.tsx +94 -96
  350. package/src/routes/pages/collections.tsx +38 -50
  351. package/src/routes/pages/featured.tsx +32 -13
  352. package/src/routes/pages/home.tsx +25 -6
  353. package/src/routes/pages/language.tsx +113 -0
  354. package/src/routes/pages/latest.tsx +26 -16
  355. package/src/routes/pages/new.tsx +3 -0
  356. package/src/routes/pages/page.tsx +178 -17
  357. package/src/routes/pages/partials.tsx +41 -0
  358. package/src/routes/pages/search.tsx +18 -3
  359. package/src/routes/pages/smart-collection.tsx +340 -0
  360. package/src/routes/pages/subscribe.tsx +182 -0
  361. package/src/runtime/__tests__/index.test.ts +19 -0
  362. package/src/runtime/__tests__/node.test.ts +129 -4
  363. package/src/runtime/cloudflare.ts +21 -2
  364. package/src/runtime/index.ts +27 -1
  365. package/src/runtime/node.ts +18 -1
  366. package/src/runtime/site.ts +95 -24
  367. package/src/services/__tests__/auth.test.ts +116 -7
  368. package/src/services/__tests__/collection.test.ts +108 -4
  369. package/src/services/__tests__/language.test.ts +495 -0
  370. package/src/services/__tests__/navigation.test.ts +213 -10
  371. package/src/services/__tests__/path.test.ts +180 -0
  372. package/src/services/__tests__/post-language.test.ts +830 -0
  373. package/src/services/__tests__/post.test.ts +46 -9
  374. package/src/services/__tests__/settings.test.ts +228 -17
  375. package/src/services/__tests__/site-admin.test.ts +5 -5
  376. package/src/services/__tests__/smart-collection.test.ts +651 -0
  377. package/src/services/about-page.ts +22 -1
  378. package/src/services/auth.ts +51 -49
  379. package/src/services/bootstrap.ts +188 -38
  380. package/src/services/collection-directory-position.ts +76 -0
  381. package/src/services/collection.ts +331 -46
  382. package/src/services/custom-url.ts +27 -22
  383. package/src/services/export-theme/assets/client-site.css +1 -1
  384. package/src/services/export-theme/assets/client-site.js +123 -123
  385. package/src/services/export-theme/layouts/_default/rss.xml +77 -1
  386. package/src/services/export-theme/layouts/partials/feed-post-content.xml +105 -2
  387. package/src/services/export-theme/layouts/partials/media-gallery.html +35 -21
  388. package/src/services/export-theme/layouts/partials/pagination.html +14 -13
  389. package/src/services/export-theme/layouts/partials/post-card.html +8 -4
  390. package/src/services/export-theme/layouts/partials/reply.html +2 -1
  391. package/src/services/export-theme/layouts/partials/thread-preview.html +40 -30
  392. package/src/services/export-theme/styles/main.css +13 -1
  393. package/src/services/export.ts +278 -19
  394. package/src/services/index.ts +34 -3
  395. package/src/services/language.ts +412 -0
  396. package/src/services/mcp.ts +3 -1
  397. package/src/services/media.ts +14 -6
  398. package/src/services/navigation.ts +429 -67
  399. package/src/services/path.ts +221 -6
  400. package/src/services/post.ts +1021 -152
  401. package/src/services/search.ts +39 -2
  402. package/src/services/settings.ts +238 -43
  403. package/src/services/site-admin.ts +24 -7
  404. package/src/services/site.ts +77 -1
  405. package/src/services/smart-collection.ts +636 -0
  406. package/src/services/telegram.ts +20 -22
  407. package/src/services/upload-session.ts +1 -3
  408. package/src/style-author.css +27 -0
  409. package/src/styles/components-author.css +1622 -0
  410. package/src/styles/components.css +24 -1571
  411. package/src/styles/site-media.css +16 -2
  412. package/src/styles/tokens.css +82 -12
  413. package/src/styles/ui-author.css +7602 -0
  414. package/src/styles/ui.css +1087 -7219
  415. package/src/types/app-context.ts +7 -0
  416. package/src/types/bindings.ts +3 -0
  417. package/src/types/config.ts +94 -15
  418. package/src/types/constants.ts +188 -16
  419. package/src/types/entities.ts +87 -1
  420. package/src/types/operations.ts +64 -2
  421. package/src/types/props.ts +157 -31
  422. package/src/types/views.ts +55 -1
  423. package/src/ui/__tests__/font-themes.test.ts +52 -12
  424. package/src/ui/compose/ComposeDialog.tsx +201 -7
  425. package/src/ui/compose/ComposePrompt.tsx +1 -5
  426. package/src/ui/compose/__tests__/ComposeDialog.test.tsx +125 -0
  427. package/src/ui/dash/appearance/AdvancedContent.tsx +2 -2
  428. package/src/ui/dash/appearance/CodeInjectionContent.tsx +12 -16
  429. package/src/ui/dash/appearance/NavigationContent.tsx +117 -16
  430. package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +33 -11
  431. package/src/ui/dash/appearance/__tests__/system-nav-descriptions.test.ts +44 -0
  432. package/src/ui/dash/appearance/system-nav-descriptions.ts +75 -0
  433. package/src/ui/dash/settings/AccountMenuContent.tsx +2 -2
  434. package/src/ui/dash/settings/ApiTokensContent.tsx +2 -1
  435. package/src/ui/dash/settings/ConfigEditorContent.tsx +35 -16
  436. package/src/ui/dash/settings/GeneralContent.tsx +275 -113
  437. package/src/ui/dash/settings/LanguageContent.tsx +409 -0
  438. package/src/ui/dash/settings/SettingsRootContent.tsx +19 -1
  439. package/src/ui/dash/settings/__tests__/GeneralContent.test.tsx +324 -4
  440. package/src/ui/dash/settings/__tests__/LanguageContent.test.tsx +144 -0
  441. package/src/ui/dash/settings/__tests__/discover-copy.test.ts +66 -0
  442. package/src/ui/dash/settings/discover-copy.ts +116 -0
  443. package/src/ui/feed/LinkCard.tsx +55 -45
  444. package/src/ui/feed/NoteCard.tsx +9 -4
  445. package/src/ui/feed/PostStatusBadges.tsx +90 -43
  446. package/src/ui/feed/QuoteCard.tsx +55 -30
  447. package/src/ui/feed/ThreadPreview.tsx +6 -2
  448. package/src/ui/feed/__tests__/thread-preview.test.ts +13 -16
  449. package/src/ui/feed/__tests__/timeline-cards.test.ts +314 -49
  450. package/src/ui/feed/thread-preview-state.ts +20 -6
  451. package/src/ui/font-themes.ts +39 -29
  452. package/src/ui/layouts/BaseLayout.tsx +155 -10
  453. package/src/ui/layouts/SiteLayout.tsx +192 -34
  454. package/src/ui/layouts/__tests__/BaseLayout.test.tsx +196 -17
  455. package/src/ui/layouts/__tests__/SiteLayout.test.tsx +109 -85
  456. package/src/ui/pages/ArchivePage.tsx +282 -289
  457. package/src/ui/pages/CollectionPage.tsx +86 -76
  458. package/src/ui/pages/CollectionsPage.tsx +5 -0
  459. package/src/ui/pages/ComposePage.tsx +8 -0
  460. package/src/ui/pages/PostPage.tsx +47 -0
  461. package/src/ui/pages/SearchPage.tsx +3 -3
  462. package/src/ui/pages/SmartCollectionPage.tsx +434 -0
  463. package/src/ui/pages/SubscribePage.tsx +236 -0
  464. package/src/ui/pages/__tests__/ArchivePage.test.tsx +65 -9
  465. package/src/ui/pages/__tests__/collections-directory-rows.test.tsx +92 -0
  466. package/src/ui/pages/__tests__/collections-view-links.test.tsx +81 -0
  467. package/src/ui/shared/CollectionDirectory.tsx +178 -3
  468. package/src/ui/shared/CollectionsManager.tsx +70 -17
  469. package/src/ui/shared/CopyField.tsx +127 -0
  470. package/src/ui/shared/EmptyPostContent.tsx +23 -0
  471. package/src/ui/shared/MediaGallery.tsx +125 -46
  472. package/src/ui/shared/Pagination.tsx +20 -5
  473. package/src/ui/shared/PostFooter.tsx +20 -11
  474. package/src/ui/shared/__tests__/archive-labels.test.ts +100 -0
  475. package/src/ui/shared/__tests__/media-gallery.test.ts +210 -2
  476. package/src/ui/shared/__tests__/navigation-labels.test.ts +16 -22
  477. package/src/ui/shared/__tests__/pagination.test.ts +38 -24
  478. package/src/ui/shared/__tests__/post-footer.test.ts +32 -0
  479. package/src/ui/shared/archive-labels.ts +98 -0
  480. package/src/ui/shared/collection-management-labels.ts +94 -16
  481. package/src/ui/shared/navigation-labels.ts +45 -71
  482. package/src/ui/shared/post-article-attributes.ts +2 -0
  483. package/src/ui/shared/smart-collection-labels.ts +343 -0
  484. package/dist/app-C75Zc8dD.js +0 -6
  485. package/dist/client/_assets/chunks/heic-to-DUUaO23q.js +0 -1
  486. package/dist/client/_assets/chunks/module-DcsAZQZ_.js +0 -716
  487. package/dist/client/_assets/chunks/url-CU9pEbk5.js +0 -1
  488. package/dist/client/_assets/client-Bq0vre8Y.js +0 -296
  489. package/dist/client/_assets/client-D3VZyG4L.css +0 -2
  490. package/dist/client/_assets/client-auth-F2rb9WfF.js +0 -5571
  491. package/dist/env-BPYViDJJ.js +0 -281
  492. package/dist/github-api-BNF35Lkx.js +0 -176
  493. package/dist/github-app-DdiD-bC4.js +0 -275
  494. package/dist/github-sync-Bqg62IvV.js +0 -4
  495. package/dist/github-sync-HdK2EgvJ.js +0 -431
  496. package/dist/url-CbLAtlZe.js +0 -900
  497. package/src/client/__tests__/collection-created-notice.test.ts +0 -36
  498. package/src/client/__tests__/collection-form-bridge.test.ts +0 -216
  499. package/src/client/__tests__/post-form-bridge.test.ts +0 -82
  500. package/src/client/collection-created-notice.ts +0 -66
  501. package/src/client/collection-form-bridge.ts +0 -191
  502. package/src/client/components/__tests__/jant-post-form.test.ts +0 -193
  503. package/src/client/components/jant-post-form.ts +0 -422
  504. package/src/client/components/post-form-template.ts +0 -352
  505. package/src/client/components/post-form-types.ts +0 -96
  506. package/src/client/media-metadata.ts +0 -247
  507. package/src/client/post-form-bridge.ts +0 -193
  508. package/src/ui/pages/CollectionEditorPage.tsx +0 -175
@@ -11,6 +11,8 @@ import type {
11
11
  SystemNavKey,
12
12
  } from "../../../types.js";
13
13
  import { SYSTEM_NAV_KEYS } from "../../../types.js";
14
+ import { getSystemNavDescription } from "./system-nav-descriptions.js";
15
+ import { getSmartCollectionLabels } from "../../shared/smart-collection-labels.js";
14
16
  import type {
15
17
  NavManagerCollection,
16
18
  NavManagerLabels,
@@ -19,10 +21,12 @@ import type {
19
21
  } from "../../../client/components/nav-manager-types.js";
20
22
  import type { CollectionFormLabels } from "../../../client/components/collection-types.js";
21
23
  import { toPublicHref, toPublicPath } from "../../../lib/url.js";
22
- import { getCollectionFormLabels } from "../../shared/collection-management-labels.js";
24
+ import {
25
+ getCollectionDialogLabels,
26
+ getCollectionFormLabels,
27
+ } from "../../shared/collection-management-labels.js";
23
28
  import {
24
29
  getNavItemDisplayLabel,
25
- getSystemNavDescription,
26
30
  getSystemNavDisplayLabel,
27
31
  NAV_MORE_LABEL,
28
32
  } from "../../shared/navigation-labels.js";
@@ -210,16 +214,35 @@ export function NavigationContent({
210
214
  slug: item.collection.slug,
211
215
  group: currentGroup,
212
216
  });
217
+ } else if (item.type === "smart_collection" && item.smartCollection) {
218
+ result.push({
219
+ id: item.smartCollection.id,
220
+ title: item.smartCollection.title,
221
+ slug: item.smartCollection.slug,
222
+ group: currentGroup,
223
+ isSmart: true,
224
+ });
213
225
  }
214
226
  }
215
227
 
216
- // Append collections not in directory items
228
+ // Append anything with no directory row, both kinds alike.
217
229
  const includedIds = new Set(result.map((c) => c.id));
218
230
  for (const c of directoryData.collections) {
219
231
  if (!includedIds.has(c.id)) {
220
232
  result.push({ id: c.id, title: c.title, slug: c.slug, group: null });
221
233
  }
222
234
  }
235
+ for (const c of directoryData.smartCollections) {
236
+ if (!includedIds.has(c.id)) {
237
+ result.push({
238
+ id: c.id,
239
+ title: c.title,
240
+ slug: c.slug,
241
+ group: null,
242
+ isSmart: true,
243
+ });
244
+ }
245
+ }
223
246
 
224
247
  return result;
225
248
  })();
@@ -237,20 +260,17 @@ export function NavigationContent({
237
260
  ).map((key) => ({
238
261
  key,
239
262
  label: getSystemNavDisplayLabel(key, i18n),
240
- description:
263
+ // Only the RSS line takes a value: it names which end /feed currently
264
+ // returns. The strings live in `system-nav-descriptions.ts` so the RSS and
265
+ // Subscribe pair stays written — and edited — together, and so they land in
266
+ // the translated catalog rather than the English-only public one.
267
+ description: getSystemNavDescription(
268
+ key,
269
+ i18n,
241
270
  key === "rss"
242
- ? i18n._(
243
- msg({
244
- message:
245
- "Header RSS points to your {feed} feed (/feed). Change what /feed returns in General.",
246
- comment:
247
- "@context: Description for the RSS system navigation toggle. {feed} is either Latest or Featured.",
248
- }),
249
- {
250
- feed: mainRssFeed === "latest" ? latestLabel : featuredLabel,
251
- },
252
- )
253
- : getSystemNavDescription(key, i18n),
271
+ ? { feed: mainRssFeed === "latest" ? latestLabel : featuredLabel }
272
+ : undefined,
273
+ ),
254
274
  }));
255
275
 
256
276
  const labels: NavManagerLabels = {
@@ -406,6 +426,7 @@ export function NavigationContent({
406
426
  "@context: Section label for nav items hidden under More dropdown",
407
427
  }),
408
428
  ),
429
+ previewMore: moreLabel,
409
430
  moreEmptyHint: i18n._(
410
431
  msg({
411
432
  message: "Drag links here to show them under the More menu",
@@ -480,12 +501,83 @@ export function NavigationContent({
480
501
  comment: "@context: Placeholder for the navigation page search",
481
502
  }),
482
503
  ),
504
+ searchPagesHint: i18n._(
505
+ msg({
506
+ message: "Search pages, or paste an address",
507
+ comment:
508
+ "@context: Placeholder for the navigation page search, which also accepts a pasted URL or path",
509
+ }),
510
+ ),
483
511
  recentPages: i18n._(
484
512
  msg({
485
513
  message: "Recently updated",
486
514
  comment: "@context: Heading above recent pages in the page picker",
487
515
  }),
488
516
  ),
517
+ addressMatch: i18n._(
518
+ msg({
519
+ message: "At that address",
520
+ comment:
521
+ "@context: Heading above the page a pasted address resolved to",
522
+ }),
523
+ ),
524
+ addressAlreadyAdded: i18n._(
525
+ msg({
526
+ message: "Already in navigation. Drag it in the list above to move it.",
527
+ comment:
528
+ "@context: Shown when a pasted address is already a navigation item",
529
+ }),
530
+ ),
531
+ addressNotFound: i18n._(
532
+ msg({
533
+ message: "Nothing at {address}. Check it, or search by title.",
534
+ comment:
535
+ "@context: Shown when a pasted address matches no page on the site",
536
+ }),
537
+ // Filled in the browser with the address that was looked up.
538
+ { address: "{address}" },
539
+ ),
540
+ addressUnpublished: i18n._(
541
+ msg({
542
+ message: "That page is a draft. Publish it, then add it.",
543
+ comment: "@context: Shown when a pasted address resolves to a draft",
544
+ }),
545
+ ),
546
+ addressPrivate: i18n._(
547
+ msg({
548
+ message: "That page is private, so nobody could open it from a menu.",
549
+ comment:
550
+ "@context: Shown when a pasted address resolves to a private page",
551
+ }),
552
+ ),
553
+ addressUntitled: i18n._(
554
+ msg({
555
+ message: "That page has no title yet, so a menu has nothing to show.",
556
+ comment:
557
+ "@context: Shown when a pasted address resolves to an untitled post",
558
+ }),
559
+ ),
560
+ addressExternal: i18n._(
561
+ msg({
562
+ message:
563
+ "That address is on another site. Navigation holds it as a link.",
564
+ comment: "@context: Shown when a pasted address points off the site",
565
+ }),
566
+ ),
567
+ addressLinkOnly: i18n._(
568
+ msg({
569
+ message: "Navigation holds that address as a link.",
570
+ comment:
571
+ "@context: Shown for a page on the site that can only be a link, such as an archive URL",
572
+ }),
573
+ ),
574
+ addressAddAsLink: i18n._(
575
+ msg({
576
+ message: "Add as link",
577
+ comment:
578
+ "@context: Button that opens the link form with the pasted address filled in",
579
+ }),
580
+ ),
489
581
  searchingPages: i18n._(
490
582
  msg({
491
583
  message: "Searching pages…",
@@ -643,6 +735,7 @@ export function NavigationContent({
643
735
  comment: "@context: Button for adding a collection to nav",
644
736
  }),
645
737
  ),
738
+ smartCollectionLabel: getSmartCollectionLabels(i18n).noun,
646
739
  addCollectionToNavigation: i18n._(
647
740
  msg({
648
741
  message: "Add collection to navigation",
@@ -729,6 +822,14 @@ export function NavigationContent({
729
822
 
730
823
  return (
731
824
  <div class="max-w-3xl flex flex-col gap-8">
825
+ {/* The dialog is a Lit component and cannot reach the i18n catalogs, so
826
+ the page that can open it carries its strings. */}
827
+ <div
828
+ hidden
829
+ data-collection-dialog-labels={escapeJson(
830
+ getCollectionDialogLabels(i18n),
831
+ )}
832
+ />
732
833
  <jant-nav-manager
733
834
  items={escapeJson(itemsData)}
734
835
  labels={escapeJson(labels)}
@@ -1,6 +1,7 @@
1
1
  import type { Context } from "hono";
2
2
  import { renderToString } from "hono/jsx/dom/server";
3
3
  import { describe, expect, it } from "vitest";
4
+ import { readComponentCss } from "../../../../__tests__/helpers/component-css.js";
4
5
  import { I18nProvider } from "../../../../i18n/context.js";
5
6
  import { createI18n } from "../../../../i18n/i18n.js";
6
7
  import { NavigationContent } from "../NavigationContent.js";
@@ -21,7 +22,12 @@ function renderNavigationContent(
21
22
  return renderToString(
22
23
  NavigationContent({
23
24
  navItems: [],
24
- directoryData: { collections: [], items: [], directoryItems: [] },
25
+ directoryData: {
26
+ collections: [],
27
+ smartCollections: [],
28
+ items: [],
29
+ directoryItems: [],
30
+ },
25
31
  suggestedLinks: [],
26
32
  mainRssFeed: "latest",
27
33
  rssFeedsEnabled: true,
@@ -32,20 +38,24 @@ function renderNavigationContent(
32
38
  }
33
39
 
34
40
  describe("NavigationContent", () => {
35
- it("interpolates the latest feed label in the RSS system link description", () => {
36
- const html = renderNavigationContent({ mainRssFeed: "latest" });
37
-
38
- expect(html).toContain(
39
- "Header RSS points to your Latest feed (/feed). Change what /feed returns in General.",
41
+ it("names which end the RSS entry currently points at", () => {
42
+ expect(renderNavigationContent({ mainRssFeed: "latest" })).toContain(
43
+ "currently your Latest feed",
44
+ );
45
+ expect(renderNavigationContent({ mainRssFeed: "featured" })).toContain(
46
+ "currently your Featured feed",
40
47
  );
41
48
  });
42
49
 
43
- it("interpolates the featured feed label in the RSS system link description", () => {
44
- const html = renderNavigationContent({ mainRssFeed: "featured" });
50
+ // RSS and Subscribe are the only pair an author has to choose between, and
51
+ // they are adjacent switches. Each has to say who it is for, or the choice is
52
+ // two near-identical toggles.
53
+ it("offers RSS and Subscribe as a legible choice", () => {
54
+ const html = renderNavigationContent({ mainRssFeed: "latest" });
45
55
 
46
- expect(html).toContain(
47
- "Header RSS points to your Featured feed (/feed). Change what /feed returns in General.",
48
- );
56
+ expect(html).toContain("already use a feed reader");
57
+ expect(html).toContain("a page listing your feeds with copy buttons");
58
+ expect(html).toContain("don&#39;t already use one");
49
59
  });
50
60
 
51
61
  it("renders the built-in links heading", () => {
@@ -93,4 +103,16 @@ describe("NavigationContent", () => {
93
103
  expect(html).toContain("suggested-links=");
94
104
  expect(html).toContain("&quot;targetLabel&quot;:&quot;Collection&quot;");
95
105
  });
106
+
107
+ it("leaves the preview frame unclipped so the More menu can escape it", () => {
108
+ const css = readComponentCss();
109
+ const frame = css.match(/\.nav-preview \{[^}]*\}/)?.[0] ?? "";
110
+
111
+ // The menu opens below the frame's own bottom edge. Clipping here cuts it
112
+ // off entirely — a stacking order cannot escape an ancestor's overflow.
113
+ expect(frame).not.toContain("overflow-hidden");
114
+ expect(css).toMatch(
115
+ /\.nav-preview-chrome \{[\s\S]*?border-top-left-radius/,
116
+ );
117
+ });
96
118
  });
@@ -0,0 +1,44 @@
1
+ import type { I18n, MessageDescriptor } from "@lingui/core";
2
+ import { describe, expect, it } from "vitest";
3
+ import { getSystemNavDescription } from "../system-nav-descriptions.js";
4
+
5
+ const i18n = {
6
+ _(descriptor: MessageDescriptor, values?: Record<string, unknown>) {
7
+ const message = descriptor.message ?? "";
8
+ return values
9
+ ? message.replace(/\{(\w+)\}/g, (_, key: string) => String(values[key]))
10
+ : message;
11
+ },
12
+ } satisfies Pick<I18n, "_">;
13
+
14
+ describe("getSystemNavDescription", () => {
15
+ it("describes each system nav toggle", () => {
16
+ expect(getSystemNavDescription("latest", i18n)).toBe(
17
+ "Link to your latest posts. Your homepage shows this feed.",
18
+ );
19
+ expect(getSystemNavDescription("featured", i18n)).toBe(
20
+ "Link to posts you've marked as featured.",
21
+ );
22
+ expect(getSystemNavDescription("archive", i18n)).toBe(
23
+ "Link to the post archive",
24
+ );
25
+ });
26
+
27
+ it("names which end the RSS entry currently points at", () => {
28
+ expect(getSystemNavDescription("rss", i18n, { feed: "Latest" })).toContain(
29
+ "currently your Latest feed",
30
+ );
31
+ });
32
+
33
+ // The two feed entries are the only pair an author has to choose between, so
34
+ // each has to say who it is for. Losing either half loses the choice.
35
+ it("tells the two feed entries apart by who they are for", () => {
36
+ const rss = getSystemNavDescription("rss", i18n, { feed: "Latest" });
37
+ const subscribe = getSystemNavDescription("subscribe", i18n);
38
+
39
+ expect(rss).toContain("/feed");
40
+ expect(rss).toContain("already use a feed reader");
41
+ expect(subscribe).toContain("/subscribe");
42
+ expect(subscribe).toContain("don't already use one");
43
+ });
44
+ });
@@ -0,0 +1,75 @@
1
+ /**
2
+ * The line under each system nav toggle in Appearance, saying what turning it
3
+ * on does.
4
+ *
5
+ * These live under `ui/dash/` rather than beside the nav labels in `ui/shared/`
6
+ * because that is what puts them in the translated catalog: `lingui.config`
7
+ * splits by path, and only `routes/dash/**`, `ui/dash/**` and the setup page
8
+ * are translated. The labels themselves stay in `ui/shared/` — they render in
9
+ * the public site nav, which is English in every view.
10
+ */
11
+
12
+ import { msg } from "@lingui/core/macro";
13
+ import type { MessageDescriptor } from "@lingui/core";
14
+ import type { I18n, TranslationValues } from "../../../i18n/i18n.js";
15
+ import type { SystemNavKey } from "../../../types.js";
16
+
17
+ type Translator = Pick<I18n, "_">;
18
+
19
+ const SYSTEM_NAV_DESCRIPTIONS: Record<SystemNavKey, MessageDescriptor> = {
20
+ latest: msg({
21
+ message: "Link to your latest posts. Your homepage shows this feed.",
22
+ comment: "@context: Description for the latest system navigation toggle",
23
+ }),
24
+ featured: msg({
25
+ message: "Link to posts you've marked as featured.",
26
+ comment: "@context: Description for the featured system navigation toggle",
27
+ }),
28
+ // These two sit next to each other in the same list and are the only pair an
29
+ // author has to choose between, so they are written as a contrast: the raw
30
+ // file versus the page about it, readers who already have a feed reader
31
+ // versus readers who do not. Change one and change the other.
32
+ rss: msg({
33
+ message:
34
+ "Links straight to /feed — the raw Atom file, currently your {feed} feed. Best for readers who already use a feed reader.",
35
+ comment:
36
+ "@context: Description for the RSS system navigation toggle. {feed} is either Latest or Featured. Pairs with the Subscribe toggle's description.",
37
+ }),
38
+ subscribe: msg({
39
+ message:
40
+ "Links to /subscribe, a page listing your feeds with copy buttons. Best for readers who don't already use one.",
41
+ comment:
42
+ "@context: Description for the Subscribe system navigation toggle. Pairs with the RSS toggle's description.",
43
+ }),
44
+ settings: msg({
45
+ message: "Shows 'Settings' when logged in, 'Sign in' when logged out",
46
+ comment: "@context: Description for the settings system navigation toggle",
47
+ }),
48
+ collections: msg({
49
+ message: "Link to your collections page",
50
+ comment:
51
+ "@context: Description for the collections system navigation toggle",
52
+ }),
53
+ archive: msg({
54
+ message: "Link to the post archive",
55
+ comment: "@context: Description for the archive system navigation toggle",
56
+ }),
57
+ };
58
+
59
+ /**
60
+ * The description for one system nav toggle.
61
+ *
62
+ * @param key - Which system nav entry
63
+ * @param i18n - Translator for the current request
64
+ * @param values - Placeholder values, for the descriptions that carry one
65
+ * @returns The description text
66
+ * @example
67
+ * getSystemNavDescription("rss", i18n, { feed: "Latest" });
68
+ */
69
+ export function getSystemNavDescription(
70
+ key: SystemNavKey,
71
+ i18n: Translator,
72
+ values?: TranslationValues,
73
+ ): string {
74
+ return i18n._(SYSTEM_NAV_DESCRIPTIONS[key], values);
75
+ }
@@ -5,6 +5,7 @@
5
5
  import { msg } from "@lingui/core/macro";
6
6
  import { coalesceDisplayText } from "../../../lib/display-text.js";
7
7
  import { useLingui } from "../../../i18n/context.js";
8
+ import { getJantDocsUrl } from "../../../lib/jant-docs.js";
8
9
  import { extractDomain, toPublicPath } from "../../../lib/url.js";
9
10
  import { CORE_VERSION } from "../../../lib/version.js";
10
11
  import {
@@ -13,8 +14,7 @@ import {
13
14
  SettingsDirectorySection,
14
15
  } from "./SettingsDirectory.js";
15
16
 
16
- const BACKUPS_DOCS_URL =
17
- "https://github.com/jant-me/jant/blob/main/docs/backups.md";
17
+ const BACKUPS_DOCS_URL = getJantDocsUrl("backups");
18
18
  const GITHUB_COMMIT_BASE = "https://github.com/jant-me/jant/tree";
19
19
 
20
20
  const ICONS = {
@@ -9,10 +9,11 @@ import { msg } from "@lingui/core/macro";
9
9
  import { useLingui } from "../../../i18n/context.js";
10
10
  import type { ApiToken } from "../../../types/entities.js";
11
11
  import { buildConfirmActionExpression } from "../../../lib/confirm.js";
12
+ import { getJantDocsUrl } from "../../../lib/jant-docs.js";
12
13
  import { formatDate } from "../../../lib/time.js";
13
14
  import { toPublicPath } from "../../../lib/url.js";
14
15
 
15
- const API_DOCS_URL = "https://github.com/jant-me/jant/blob/main/docs/API.md";
16
+ const API_DOCS_URL = getJantDocsUrl("api");
16
17
 
17
18
  function TokenRow({
18
19
  token,
@@ -76,27 +76,23 @@ export function ConfigEditorContent({
76
76
  "zh-Hant": "繁體中文",
77
77
  },
78
78
  },
79
- CJK_SERIF_FONT: {
79
+ MULTILINGUAL_ENABLED: {
80
80
  description: i18n._(
81
81
  msg({
82
82
  message:
83
- "The serif fallback used when the content language has no built-in profile.",
84
- comment: "@context: Config Editor setting description",
83
+ "Whether each language gets its own home page, archive, and feed. Managed on the Language page.",
84
+ comment: "@context: Config Editor linked setting description",
85
+ }),
86
+ ),
87
+ },
88
+ ADDITIONAL_LANGUAGES: {
89
+ description: i18n._(
90
+ msg({
91
+ message:
92
+ "The languages served under a URL prefix. Managed on the Language page.",
93
+ comment: "@context: Config Editor linked setting description",
85
94
  }),
86
95
  ),
87
- optionLabels: {
88
- off: i18n._(
89
- msg({
90
- message: "Follow content language",
91
- comment:
92
- "@context: Config Editor enum option for automatic CJK font fallback",
93
- }),
94
- ),
95
- "zh-Hans": "简体中文",
96
- "zh-Hant": "繁體中文",
97
- ja: "日本語",
98
- ko: "한국어",
99
- },
100
96
  },
101
97
  MAIN_RSS_FEED: {
102
98
  description: i18n._(
@@ -120,6 +116,29 @@ export function ConfigEditorContent({
120
116
  ),
121
117
  },
122
118
  },
119
+ ARCHIVE_DEFAULT_LAYOUT: {
120
+ description: i18n._(
121
+ msg({
122
+ message:
123
+ "Which layout /archive opens with. Readers can switch layouts from the page.",
124
+ comment: "@context: Config Editor setting description",
125
+ }),
126
+ ),
127
+ optionLabels: {
128
+ list: i18n._(
129
+ msg({
130
+ message: "Full posts",
131
+ comment: "@context: Config Editor archive layout enum option",
132
+ }),
133
+ ),
134
+ grid: i18n._(
135
+ msg({
136
+ message: "Tile grid",
137
+ comment: "@context: Config Editor archive layout enum option",
138
+ }),
139
+ ),
140
+ },
141
+ },
123
142
  PAGE_SIZE: {
124
143
  description: i18n._(
125
144
  msg({