@geekity/cms 0.31.0 → 0.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (759) hide show
  1. package/admin/components/badge.njk +4 -0
  2. package/admin/components/fields.njk +41 -24
  3. package/admin/components/job-status.njk +45 -0
  4. package/admin/components/setting-fields.njk +38 -0
  5. package/admin/layouts/settings-page.njk +16 -0
  6. package/admin/pages/comments/all.njk +1 -2
  7. package/admin/pages/documents/editor.njk +17 -15
  8. package/admin/pages/documents/syndication.njk +4 -4
  9. package/admin/pages/federation/followers.njk +56 -6
  10. package/admin/pages/federation/settings.njk +1 -1
  11. package/admin/pages/media/library.njk +52 -3
  12. package/admin/pages/navigation/menus.njk +2 -2
  13. package/admin/pages/plugins/screen.njk +5 -46
  14. package/admin/pages/settings/discussion.njk +76 -47
  15. package/admin/pages/settings/email.njk +75 -47
  16. package/admin/pages/settings/general.njk +15 -15
  17. package/admin/pages/settings/permalinks.njk +8 -8
  18. package/admin/pages/settings/privacy.njk +6 -6
  19. package/admin/pages/settings/reading.njk +36 -36
  20. package/admin/pages/tools/dev-mode.njk +29 -3
  21. package/admin/pages/tools/export.njk +89 -0
  22. package/admin/pages/tools/maintenance.njk +51 -0
  23. package/admin/pages/users/apps.njk +2 -2
  24. package/admin/pages/users/edit.njk +3 -3
  25. package/admin/pages/users/new.njk +2 -2
  26. package/admin/static/admin.css +80 -0
  27. package/dist/admin/app-activity.d.ts.map +1 -1
  28. package/dist/admin/app-activity.js +2 -3
  29. package/dist/admin/app-activity.js.map +1 -1
  30. package/dist/admin/appearance.d.ts +1 -5
  31. package/dist/admin/appearance.d.ts.map +1 -1
  32. package/dist/admin/appearance.js +9 -16
  33. package/dist/admin/appearance.js.map +1 -1
  34. package/dist/admin/comments.d.ts.map +1 -1
  35. package/dist/admin/comments.js +2 -3
  36. package/dist/admin/comments.js.map +1 -1
  37. package/dist/admin/confirm-password.d.ts +4 -0
  38. package/dist/admin/confirm-password.d.ts.map +1 -0
  39. package/dist/admin/confirm-password.js +11 -0
  40. package/dist/admin/confirm-password.js.map +1 -0
  41. package/dist/admin/connected-apps.d.ts.map +1 -1
  42. package/dist/admin/connected-apps.js +17 -22
  43. package/dist/admin/connected-apps.js.map +1 -1
  44. package/dist/admin/dev-mode.d.ts.map +1 -1
  45. package/dist/admin/dev-mode.js +35 -10
  46. package/dist/admin/dev-mode.js.map +1 -1
  47. package/dist/admin/documents.d.ts.map +1 -1
  48. package/dist/admin/documents.js +22 -10
  49. package/dist/admin/documents.js.map +1 -1
  50. package/dist/admin/editor-actions.d.ts.map +1 -1
  51. package/dist/admin/editor-actions.js +1 -2
  52. package/dist/admin/editor-actions.js.map +1 -1
  53. package/dist/admin/editor-layout.js +1 -1
  54. package/dist/admin/editor-layout.js.map +1 -1
  55. package/dist/admin/export.d.ts +10 -0
  56. package/dist/admin/export.d.ts.map +1 -0
  57. package/dist/admin/export.js +72 -0
  58. package/dist/admin/export.js.map +1 -0
  59. package/dist/admin/federation.d.ts +7 -14
  60. package/dist/admin/federation.d.ts.map +1 -1
  61. package/dist/admin/federation.js +48 -94
  62. package/dist/admin/federation.js.map +1 -1
  63. package/dist/admin/index.d.ts +2 -5
  64. package/dist/admin/index.d.ts.map +1 -1
  65. package/dist/admin/index.js +2 -4
  66. package/dist/admin/index.js.map +1 -1
  67. package/dist/admin/indieauth-consent.d.ts.map +1 -1
  68. package/dist/admin/indieauth-consent.js +5 -7
  69. package/dist/admin/indieauth-consent.js.map +1 -1
  70. package/dist/admin/job-status.d.ts +25 -0
  71. package/dist/admin/job-status.d.ts.map +1 -0
  72. package/dist/admin/job-status.js +53 -0
  73. package/dist/admin/job-status.js.map +1 -0
  74. package/dist/admin/legacy-migrations.d.ts.map +1 -1
  75. package/dist/admin/legacy-migrations.js +7 -6
  76. package/dist/admin/legacy-migrations.js.map +1 -1
  77. package/dist/admin/maintenance.d.ts +9 -0
  78. package/dist/admin/maintenance.d.ts.map +1 -0
  79. package/dist/admin/maintenance.js +42 -0
  80. package/dist/admin/maintenance.js.map +1 -0
  81. package/dist/admin/media.d.ts +4 -1
  82. package/dist/admin/media.d.ts.map +1 -1
  83. package/dist/admin/media.js +16 -1
  84. package/dist/admin/media.js.map +1 -1
  85. package/dist/admin/menu.d.ts.map +1 -1
  86. package/dist/admin/menu.js +4 -0
  87. package/dist/admin/menu.js.map +1 -1
  88. package/dist/admin/messages.d.ts.map +1 -1
  89. package/dist/admin/messages.js +2 -3
  90. package/dist/admin/messages.js.map +1 -1
  91. package/dist/admin/navigation.d.ts.map +1 -1
  92. package/dist/admin/navigation.js +27 -23
  93. package/dist/admin/navigation.js.map +1 -1
  94. package/dist/admin/plugins.d.ts.map +1 -1
  95. package/dist/admin/plugins.js +19 -66
  96. package/dist/admin/plugins.js.map +1 -1
  97. package/dist/admin/preview.d.ts.map +1 -1
  98. package/dist/admin/preview.js +5 -6
  99. package/dist/admin/preview.js.map +1 -1
  100. package/dist/admin/recovery.js +2 -2
  101. package/dist/admin/recovery.js.map +1 -1
  102. package/dist/admin/routes.d.ts.map +1 -1
  103. package/dist/admin/routes.js +6 -3
  104. package/dist/admin/routes.js.map +1 -1
  105. package/dist/admin/setting-overrides.d.ts +4 -0
  106. package/dist/admin/setting-overrides.d.ts.map +1 -0
  107. package/dist/admin/setting-overrides.js +24 -0
  108. package/dist/admin/setting-overrides.js.map +1 -0
  109. package/dist/admin/settings-discussion.d.ts +6 -4
  110. package/dist/admin/settings-discussion.d.ts.map +1 -1
  111. package/dist/admin/settings-discussion.js +75 -45
  112. package/dist/admin/settings-discussion.js.map +1 -1
  113. package/dist/admin/settings-email.d.ts +11 -8
  114. package/dist/admin/settings-email.d.ts.map +1 -1
  115. package/dist/admin/settings-email.js +88 -77
  116. package/dist/admin/settings-email.js.map +1 -1
  117. package/dist/admin/settings-federation.d.ts +0 -7
  118. package/dist/admin/settings-federation.d.ts.map +1 -1
  119. package/dist/admin/settings-federation.js +0 -36
  120. package/dist/admin/settings-federation.js.map +1 -1
  121. package/dist/admin/settings-fields.d.ts +32 -0
  122. package/dist/admin/settings-fields.d.ts.map +1 -0
  123. package/dist/admin/settings-fields.js +368 -0
  124. package/dist/admin/settings-fields.js.map +1 -0
  125. package/dist/admin/settings-general.d.ts.map +1 -1
  126. package/dist/admin/settings-general.js +10 -19
  127. package/dist/admin/settings-general.js.map +1 -1
  128. package/dist/admin/settings-page.d.ts +3 -29
  129. package/dist/admin/settings-page.d.ts.map +1 -1
  130. package/dist/admin/settings-page.js +38 -53
  131. package/dist/admin/settings-page.js.map +1 -1
  132. package/dist/admin/settings-permalinks.js +2 -2
  133. package/dist/admin/settings-permalinks.js.map +1 -1
  134. package/dist/admin/settings-privacy.js +1 -1
  135. package/dist/admin/settings-privacy.js.map +1 -1
  136. package/dist/admin/settings-reading.js +13 -13
  137. package/dist/admin/settings-reading.js.map +1 -1
  138. package/dist/admin/settings-renderer.d.ts +32 -0
  139. package/dist/admin/settings-renderer.d.ts.map +1 -0
  140. package/dist/admin/settings-renderer.js +79 -0
  141. package/dist/admin/settings-renderer.js.map +1 -0
  142. package/dist/admin/site-setting-edit.d.ts +4 -0
  143. package/dist/admin/site-setting-edit.d.ts.map +1 -0
  144. package/dist/admin/site-setting-edit.js +20 -0
  145. package/dist/admin/site-setting-edit.js.map +1 -0
  146. package/dist/admin/taxonomy.d.ts.map +1 -1
  147. package/dist/admin/taxonomy.js +10 -19
  148. package/dist/admin/taxonomy.js.map +1 -1
  149. package/dist/admin/templates.d.ts +2 -0
  150. package/dist/admin/templates.d.ts.map +1 -1
  151. package/dist/admin/templates.js +2 -0
  152. package/dist/admin/templates.js.map +1 -1
  153. package/dist/admin/users.js +1 -1
  154. package/dist/admin/users.js.map +1 -1
  155. package/dist/avatars/avatars.d.ts +0 -2
  156. package/dist/avatars/avatars.d.ts.map +1 -1
  157. package/dist/avatars/avatars.js +9 -10
  158. package/dist/avatars/avatars.js.map +1 -1
  159. package/dist/avatars/index.d.ts +1 -1
  160. package/dist/avatars/index.d.ts.map +1 -1
  161. package/dist/avatars/index.js +1 -1
  162. package/dist/avatars/index.js.map +1 -1
  163. package/dist/cache.d.ts +0 -2
  164. package/dist/cache.d.ts.map +1 -1
  165. package/dist/cache.js +2 -4
  166. package/dist/cache.js.map +1 -1
  167. package/dist/cli.d.ts +1 -1
  168. package/dist/cli.d.ts.map +1 -1
  169. package/dist/cli.js +500 -86
  170. package/dist/cli.js.map +1 -1
  171. package/dist/cms/app.d.ts +1 -1
  172. package/dist/cms/app.d.ts.map +1 -1
  173. package/dist/cms/app.js +13 -2
  174. package/dist/cms/app.js.map +1 -1
  175. package/dist/cms/boot.d.ts +12 -0
  176. package/dist/cms/boot.d.ts.map +1 -1
  177. package/dist/cms/boot.js +43 -17
  178. package/dist/cms/boot.js.map +1 -1
  179. package/dist/cms/create.d.ts +24 -0
  180. package/dist/cms/create.d.ts.map +1 -1
  181. package/dist/cms/create.js +14 -0
  182. package/dist/cms/create.js.map +1 -1
  183. package/dist/cms/services.d.ts +3 -1
  184. package/dist/cms/services.d.ts.map +1 -1
  185. package/dist/cms/services.js +83 -26
  186. package/dist/cms/services.js.map +1 -1
  187. package/dist/cms/site-records.d.ts.map +1 -1
  188. package/dist/cms/site-records.js +0 -2
  189. package/dist/cms/site-records.js.map +1 -1
  190. package/dist/comments/akismet.d.ts +13 -46
  191. package/dist/comments/akismet.d.ts.map +1 -1
  192. package/dist/comments/akismet.js +29 -68
  193. package/dist/comments/akismet.js.map +1 -1
  194. package/dist/comments/conversation.d.ts +14 -8
  195. package/dist/comments/conversation.d.ts.map +1 -1
  196. package/dist/comments/conversation.js.map +1 -1
  197. package/dist/comments/index.d.ts +4 -4
  198. package/dist/comments/index.d.ts.map +1 -1
  199. package/dist/comments/index.js +3 -3
  200. package/dist/comments/index.js.map +1 -1
  201. package/dist/comments/policy.d.ts +23 -26
  202. package/dist/comments/policy.d.ts.map +1 -1
  203. package/dist/comments/policy.js +13 -20
  204. package/dist/comments/policy.js.map +1 -1
  205. package/dist/comments/records.d.ts +0 -2
  206. package/dist/comments/records.d.ts.map +1 -1
  207. package/dist/comments/records.js +2 -3
  208. package/dist/comments/records.js.map +1 -1
  209. package/dist/comments/reply-notices.d.ts +5 -6
  210. package/dist/comments/reply-notices.d.ts.map +1 -1
  211. package/dist/comments/reply-notices.js +27 -15
  212. package/dist/comments/reply-notices.js.map +1 -1
  213. package/dist/comments/reply-post.d.ts.map +1 -1
  214. package/dist/comments/reply-post.js +2 -3
  215. package/dist/comments/reply-post.js.map +1 -1
  216. package/dist/comments/submission.d.ts +0 -2
  217. package/dist/comments/submission.d.ts.map +1 -1
  218. package/dist/comments/submission.js +1 -3
  219. package/dist/comments/submission.js.map +1 -1
  220. package/dist/config-loader.d.ts.map +1 -1
  221. package/dist/config-loader.js +2 -1
  222. package/dist/config-loader.js.map +1 -1
  223. package/dist/config.d.ts +27 -1
  224. package/dist/config.d.ts.map +1 -1
  225. package/dist/config.js +5 -1
  226. package/dist/config.js.map +1 -1
  227. package/dist/contact/delivery.d.ts +2 -4
  228. package/dist/contact/delivery.d.ts.map +1 -1
  229. package/dist/contact/delivery.js +1 -2
  230. package/dist/contact/delivery.js.map +1 -1
  231. package/dist/contact/index.d.ts +1 -1
  232. package/dist/contact/index.d.ts.map +1 -1
  233. package/dist/contact/index.js +1 -1
  234. package/dist/contact/index.js.map +1 -1
  235. package/dist/contact/records.d.ts +0 -2
  236. package/dist/contact/records.d.ts.map +1 -1
  237. package/dist/contact/records.js +3 -5
  238. package/dist/contact/records.js.map +1 -1
  239. package/dist/content/citation.d.ts +1 -0
  240. package/dist/content/citation.d.ts.map +1 -1
  241. package/dist/content/citation.js.map +1 -1
  242. package/dist/content/document-form.d.ts +3 -1
  243. package/dist/content/document-form.d.ts.map +1 -1
  244. package/dist/content/document-form.js.map +1 -1
  245. package/dist/content/enclosure-form.d.ts.map +1 -1
  246. package/dist/content/enclosure-form.js +5 -6
  247. package/dist/content/enclosure-form.js.map +1 -1
  248. package/dist/content/excerpt.d.ts +1 -0
  249. package/dist/content/excerpt.d.ts.map +1 -1
  250. package/dist/content/excerpt.js +3 -0
  251. package/dist/content/excerpt.js.map +1 -1
  252. package/dist/content/index.d.ts +3 -3
  253. package/dist/content/index.d.ts.map +1 -1
  254. package/dist/content/index.js +2 -2
  255. package/dist/content/index.js.map +1 -1
  256. package/dist/content/kept-properties.d.ts +0 -1
  257. package/dist/content/kept-properties.d.ts.map +1 -1
  258. package/dist/content/kept-properties.js +2 -2
  259. package/dist/content/kept-properties.js.map +1 -1
  260. package/dist/content/locations.d.ts +0 -1
  261. package/dist/content/locations.d.ts.map +1 -1
  262. package/dist/content/locations.js +2 -2
  263. package/dist/content/locations.js.map +1 -1
  264. package/dist/content/media.d.ts +7 -0
  265. package/dist/content/media.d.ts.map +1 -1
  266. package/dist/content/media.js +12 -1
  267. package/dist/content/media.js.map +1 -1
  268. package/dist/content/metadata/strip-job.d.ts +16 -0
  269. package/dist/content/metadata/strip-job.d.ts.map +1 -0
  270. package/dist/content/metadata/strip-job.js +24 -0
  271. package/dist/content/metadata/strip-job.js.map +1 -0
  272. package/dist/content/metadata/sweep.d.ts +13 -1
  273. package/dist/content/metadata/sweep.d.ts.map +1 -1
  274. package/dist/content/metadata/sweep.js +47 -25
  275. package/dist/content/metadata/sweep.js.map +1 -1
  276. package/dist/content/permalink-file.d.ts +2 -1
  277. package/dist/content/permalink-file.d.ts.map +1 -1
  278. package/dist/content/permalink-file.js +3 -3
  279. package/dist/content/permalink-file.js.map +1 -1
  280. package/dist/content/photo-form.d.ts +1 -0
  281. package/dist/content/photo-form.d.ts.map +1 -1
  282. package/dist/content/photo-form.js +8 -5
  283. package/dist/content/photo-form.js.map +1 -1
  284. package/dist/content/photo.d.ts +1 -0
  285. package/dist/content/photo.d.ts.map +1 -1
  286. package/dist/content/photo.js +1 -1
  287. package/dist/content/photo.js.map +1 -1
  288. package/dist/content/post-fields.d.ts.map +1 -1
  289. package/dist/content/post-fields.js +5 -9
  290. package/dist/content/post-fields.js.map +1 -1
  291. package/dist/content/read-form.d.ts +10 -3
  292. package/dist/content/read-form.d.ts.map +1 -1
  293. package/dist/content/read-form.js +67 -9
  294. package/dist/content/read-form.js.map +1 -1
  295. package/dist/content/read.d.ts +9 -2
  296. package/dist/content/read.d.ts.map +1 -1
  297. package/dist/content/read.js +22 -3
  298. package/dist/content/read.js.map +1 -1
  299. package/dist/content/store.d.ts +0 -1
  300. package/dist/content/store.d.ts.map +1 -1
  301. package/dist/content/store.js +0 -1
  302. package/dist/content/store.js.map +1 -1
  303. package/dist/content/uploads.d.ts +1 -1
  304. package/dist/content/uploads.d.ts.map +1 -1
  305. package/dist/content/uploads.js +6 -1
  306. package/dist/content/uploads.js.map +1 -1
  307. package/dist/content/write.d.ts +1 -1
  308. package/dist/content/write.d.ts.map +1 -1
  309. package/dist/content/write.js +7 -3
  310. package/dist/content/write.js.map +1 -1
  311. package/dist/dev-mode.d.ts +4 -26
  312. package/dist/dev-mode.d.ts.map +1 -1
  313. package/dist/dev-mode.js +4 -53
  314. package/dist/dev-mode.js.map +1 -1
  315. package/dist/export/export-archives.d.ts +29 -0
  316. package/dist/export/export-archives.d.ts.map +1 -0
  317. package/dist/export/export-archives.js +88 -0
  318. package/dist/export/export-archives.js.map +1 -0
  319. package/dist/export/export-job.d.ts +21 -0
  320. package/dist/export/export-job.d.ts.map +1 -0
  321. package/dist/export/export-job.js +63 -0
  322. package/dist/export/export-job.js.map +1 -0
  323. package/dist/export/site-export.d.ts +101 -0
  324. package/dist/export/site-export.d.ts.map +1 -0
  325. package/dist/export/site-export.js +243 -0
  326. package/dist/export/site-export.js.map +1 -0
  327. package/dist/export/site-import.d.ts +75 -0
  328. package/dist/export/site-import.d.ts.map +1 -0
  329. package/dist/export/site-import.js +492 -0
  330. package/dist/export/site-import.js.map +1 -0
  331. package/dist/exports.d.ts +9 -4
  332. package/dist/exports.d.ts.map +1 -1
  333. package/dist/exports.js +3 -1
  334. package/dist/exports.js.map +1 -1
  335. package/dist/federation/article.d.ts +5 -11
  336. package/dist/federation/article.d.ts.map +1 -1
  337. package/dist/federation/article.js +67 -35
  338. package/dist/federation/article.js.map +1 -1
  339. package/dist/federation/backfill.d.ts +3 -1
  340. package/dist/federation/backfill.d.ts.map +1 -1
  341. package/dist/federation/backfill.js +5 -3
  342. package/dist/federation/backfill.js.map +1 -1
  343. package/dist/federation/cited-post.d.ts +1 -1
  344. package/dist/federation/cited-post.d.ts.map +1 -1
  345. package/dist/federation/cited-post.js +1 -1
  346. package/dist/federation/cited-post.js.map +1 -1
  347. package/dist/federation/delivery.d.ts +5 -2
  348. package/dist/federation/delivery.d.ts.map +1 -1
  349. package/dist/federation/delivery.js +30 -14
  350. package/dist/federation/delivery.js.map +1 -1
  351. package/dist/federation/federation.d.ts +7 -7
  352. package/dist/federation/federation.d.ts.map +1 -1
  353. package/dist/federation/federation.js +6 -13
  354. package/dist/federation/federation.js.map +1 -1
  355. package/dist/federation/handles.d.ts +1 -1
  356. package/dist/federation/handles.d.ts.map +1 -1
  357. package/dist/federation/handles.js +1 -1
  358. package/dist/federation/handles.js.map +1 -1
  359. package/dist/federation/inbox.d.ts.map +1 -1
  360. package/dist/federation/inbox.js +5 -8
  361. package/dist/federation/inbox.js.map +1 -1
  362. package/dist/federation/index.d.ts +1 -0
  363. package/dist/federation/index.d.ts.map +1 -1
  364. package/dist/federation/index.js +1 -0
  365. package/dist/federation/index.js.map +1 -1
  366. package/dist/federation/keys.js +3 -3
  367. package/dist/federation/keys.js.map +1 -1
  368. package/dist/federation/object-ids.d.ts +50 -0
  369. package/dist/federation/object-ids.d.ts.map +1 -0
  370. package/dist/federation/object-ids.js +134 -0
  371. package/dist/federation/object-ids.js.map +1 -0
  372. package/dist/federation/profiles.d.ts +1 -1
  373. package/dist/federation/profiles.d.ts.map +1 -1
  374. package/dist/federation/profiles.js +1 -1
  375. package/dist/federation/profiles.js.map +1 -1
  376. package/dist/federation/queue.d.ts +32 -17
  377. package/dist/federation/queue.d.ts.map +1 -1
  378. package/dist/federation/queue.js +173 -39
  379. package/dist/federation/queue.js.map +1 -1
  380. package/dist/federation/relays.d.ts +6 -2
  381. package/dist/federation/relays.d.ts.map +1 -1
  382. package/dist/federation/relays.js +43 -36
  383. package/dist/federation/relays.js.map +1 -1
  384. package/dist/federation/resend-job.d.ts +44 -0
  385. package/dist/federation/resend-job.d.ts.map +1 -0
  386. package/dist/federation/resend-job.js +59 -0
  387. package/dist/federation/resend-job.js.map +1 -0
  388. package/dist/files/atomic.d.ts +9 -0
  389. package/dist/files/atomic.d.ts.map +1 -1
  390. package/dist/files/atomic.js +1 -1
  391. package/dist/files/atomic.js.map +1 -1
  392. package/dist/files/data-files.d.ts +104 -0
  393. package/dist/files/data-files.d.ts.map +1 -0
  394. package/dist/files/data-files.js +330 -0
  395. package/dist/files/data-files.js.map +1 -0
  396. package/dist/files/export-archives.d.ts +12 -0
  397. package/dist/files/export-archives.d.ts.map +1 -0
  398. package/dist/files/export-archives.js +67 -0
  399. package/dist/files/export-archives.js.map +1 -0
  400. package/dist/files/static-files.d.ts.map +1 -1
  401. package/dist/files/static-files.js +7 -22
  402. package/dist/files/static-files.js.map +1 -1
  403. package/dist/files/tar.d.ts +29 -0
  404. package/dist/files/tar.d.ts.map +1 -0
  405. package/dist/files/tar.js +206 -0
  406. package/dist/files/tar.js.map +1 -0
  407. package/dist/files/upload-types.d.ts +81 -0
  408. package/dist/files/upload-types.d.ts.map +1 -0
  409. package/dist/files/upload-types.js +234 -0
  410. package/dist/files/upload-types.js.map +1 -0
  411. package/dist/forms/protection.d.ts +0 -8
  412. package/dist/forms/protection.d.ts.map +1 -1
  413. package/dist/forms/protection.js +2 -10
  414. package/dist/forms/protection.js.map +1 -1
  415. package/dist/images/icons.d.ts.map +1 -1
  416. package/dist/images/icons.js +2 -0
  417. package/dist/images/icons.js.map +1 -1
  418. package/dist/images/index.d.ts +1 -1
  419. package/dist/images/index.d.ts.map +1 -1
  420. package/dist/images/index.js +1 -1
  421. package/dist/images/index.js.map +1 -1
  422. package/dist/images/markup.d.ts +4 -1
  423. package/dist/images/markup.d.ts.map +1 -1
  424. package/dist/images/markup.js +10 -6
  425. package/dist/images/markup.js.map +1 -1
  426. package/dist/images/paths.d.ts +1 -4
  427. package/dist/images/paths.d.ts.map +1 -1
  428. package/dist/images/paths.js +6 -12
  429. package/dist/images/paths.js.map +1 -1
  430. package/dist/images/variants.d.ts +4 -2
  431. package/dist/images/variants.d.ts.map +1 -1
  432. package/dist/images/variants.js +21 -21
  433. package/dist/images/variants.js.map +1 -1
  434. package/dist/index.d.ts +1 -0
  435. package/dist/index.d.ts.map +1 -1
  436. package/dist/index.js +1 -0
  437. package/dist/index.js.map +1 -1
  438. package/dist/indexnow.d.ts +4 -2
  439. package/dist/indexnow.d.ts.map +1 -1
  440. package/dist/indexnow.js +32 -20
  441. package/dist/indexnow.js.map +1 -1
  442. package/dist/indieauth/tokens.d.ts +0 -2
  443. package/dist/indieauth/tokens.d.ts.map +1 -1
  444. package/dist/indieauth/tokens.js +2 -4
  445. package/dist/indieauth/tokens.js.map +1 -1
  446. package/dist/jobs/file-records.d.ts +13 -0
  447. package/dist/jobs/file-records.d.ts.map +1 -0
  448. package/dist/jobs/file-records.js +104 -0
  449. package/dist/jobs/file-records.js.map +1 -0
  450. package/dist/jobs/in-process.d.ts +10 -0
  451. package/dist/jobs/in-process.d.ts.map +1 -0
  452. package/dist/jobs/in-process.js +45 -0
  453. package/dist/jobs/in-process.js.map +1 -0
  454. package/dist/jobs/lock-file.d.ts +13 -0
  455. package/dist/jobs/lock-file.d.ts.map +1 -0
  456. package/dist/jobs/lock-file.js +107 -0
  457. package/dist/jobs/lock-file.js.map +1 -0
  458. package/dist/jobs/processes.d.ts +11 -0
  459. package/dist/jobs/processes.d.ts.map +1 -0
  460. package/dist/jobs/processes.js +50 -0
  461. package/dist/jobs/processes.js.map +1 -0
  462. package/dist/jobs/queue.d.ts +18 -0
  463. package/dist/jobs/queue.d.ts.map +1 -0
  464. package/dist/jobs/queue.js +220 -0
  465. package/dist/jobs/queue.js.map +1 -0
  466. package/dist/jobs/types.d.ts +159 -0
  467. package/dist/jobs/types.d.ts.map +1 -0
  468. package/dist/jobs/types.js +22 -0
  469. package/dist/jobs/types.js.map +1 -0
  470. package/dist/mail/index.d.ts +0 -2
  471. package/dist/mail/index.d.ts.map +1 -1
  472. package/dist/mail/index.js +0 -1
  473. package/dist/mail/index.js.map +1 -1
  474. package/dist/maintenance.d.ts +5 -42
  475. package/dist/maintenance.d.ts.map +1 -1
  476. package/dist/maintenance.js +4 -67
  477. package/dist/maintenance.js.map +1 -1
  478. package/dist/media/library.d.ts +1 -1
  479. package/dist/media/library.d.ts.map +1 -1
  480. package/dist/media/library.js +4 -1
  481. package/dist/media/library.js.map +1 -1
  482. package/dist/media/uploads.d.ts +1 -1
  483. package/dist/media/uploads.d.ts.map +1 -1
  484. package/dist/media/uploads.js +1 -1
  485. package/dist/media/uploads.js.map +1 -1
  486. package/dist/micropub/endpoint.js +10 -10
  487. package/dist/micropub/endpoint.js.map +1 -1
  488. package/dist/micropub/media.d.ts +0 -2
  489. package/dist/micropub/media.d.ts.map +1 -1
  490. package/dist/micropub/media.js +5 -7
  491. package/dist/micropub/media.js.map +1 -1
  492. package/dist/notifications/comments.d.ts +4 -2
  493. package/dist/notifications/comments.d.ts.map +1 -1
  494. package/dist/notifications/comments.js +77 -65
  495. package/dist/notifications/comments.js.map +1 -1
  496. package/dist/notifications/digest.d.ts +2 -4
  497. package/dist/notifications/digest.d.ts.map +1 -1
  498. package/dist/notifications/digest.js +9 -10
  499. package/dist/notifications/digest.js.map +1 -1
  500. package/dist/notifications/index.d.ts +3 -3
  501. package/dist/notifications/index.d.ts.map +1 -1
  502. package/dist/notifications/index.js +3 -3
  503. package/dist/notifications/index.js.map +1 -1
  504. package/dist/notifications/mail-service.d.ts +10 -8
  505. package/dist/notifications/mail-service.d.ts.map +1 -1
  506. package/dist/notifications/mail-service.js +70 -70
  507. package/dist/notifications/mail-service.js.map +1 -1
  508. package/dist/notifications/optouts.d.ts +0 -2
  509. package/dist/notifications/optouts.d.ts.map +1 -1
  510. package/dist/notifications/optouts.js +2 -4
  511. package/dist/notifications/optouts.js.map +1 -1
  512. package/dist/notifications/tokens.d.ts +0 -2
  513. package/dist/notifications/tokens.d.ts.map +1 -1
  514. package/dist/notifications/tokens.js +2 -28
  515. package/dist/notifications/tokens.js.map +1 -1
  516. package/dist/notify.d.ts +4 -2
  517. package/dist/notify.d.ts.map +1 -1
  518. package/dist/notify.js +27 -15
  519. package/dist/notify.js.map +1 -1
  520. package/dist/plugin.d.ts +36 -16
  521. package/dist/plugin.d.ts.map +1 -1
  522. package/dist/plugin.js +1 -1
  523. package/dist/plugin.js.map +1 -1
  524. package/dist/plugins/changes.d.ts +0 -1
  525. package/dist/plugins/changes.d.ts.map +1 -1
  526. package/dist/plugins/changes.js +2 -3
  527. package/dist/plugins/changes.js.map +1 -1
  528. package/dist/plugins/data.d.ts +19 -0
  529. package/dist/plugins/data.d.ts.map +1 -0
  530. package/dist/plugins/data.js +117 -0
  531. package/dist/plugins/data.js.map +1 -0
  532. package/dist/plugins/enabled.d.ts +1 -13
  533. package/dist/plugins/enabled.d.ts.map +1 -1
  534. package/dist/plugins/enabled.js +11 -23
  535. package/dist/plugins/enabled.js.map +1 -1
  536. package/dist/plugins/install.d.ts +1 -1
  537. package/dist/plugins/install.d.ts.map +1 -1
  538. package/dist/plugins/install.js +7 -42
  539. package/dist/plugins/install.js.map +1 -1
  540. package/dist/plugins/migrate-settings.d.ts +7 -0
  541. package/dist/plugins/migrate-settings.d.ts.map +1 -0
  542. package/dist/plugins/migrate-settings.js +41 -0
  543. package/dist/plugins/migrate-settings.js.map +1 -0
  544. package/dist/plugins/registry.d.ts +10 -14
  545. package/dist/plugins/registry.d.ts.map +1 -1
  546. package/dist/plugins/registry.js +56 -36
  547. package/dist/plugins/registry.js.map +1 -1
  548. package/dist/plugins/settings.d.ts +5 -57
  549. package/dist/plugins/settings.d.ts.map +1 -1
  550. package/dist/plugins/settings.js +47 -180
  551. package/dist/plugins/settings.js.map +1 -1
  552. package/dist/plugins/site.d.ts +2 -1
  553. package/dist/plugins/site.d.ts.map +1 -1
  554. package/dist/plugins/site.js +5 -5
  555. package/dist/plugins/site.js.map +1 -1
  556. package/dist/privacy/retention.d.ts +4 -0
  557. package/dist/privacy/retention.d.ts.map +1 -1
  558. package/dist/privacy/retention.js +12 -5
  559. package/dist/privacy/retention.js.map +1 -1
  560. package/dist/settings/akismet.d.ts +9 -0
  561. package/dist/settings/akismet.d.ts.map +1 -0
  562. package/dist/settings/akismet.js +46 -0
  563. package/dist/settings/akismet.js.map +1 -0
  564. package/dist/settings/declare.d.ts +15 -0
  565. package/dist/settings/declare.d.ts.map +1 -0
  566. package/dist/settings/declare.js +20 -0
  567. package/dist/settings/declare.js.map +1 -0
  568. package/dist/settings/dev-mode.d.ts +29 -0
  569. package/dist/settings/dev-mode.d.ts.map +1 -0
  570. package/dist/settings/dev-mode.js +77 -0
  571. package/dist/settings/dev-mode.js.map +1 -0
  572. package/dist/settings/kinds.d.ts +13 -0
  573. package/dist/settings/kinds.d.ts.map +1 -0
  574. package/dist/settings/kinds.js +108 -0
  575. package/dist/settings/kinds.js.map +1 -0
  576. package/dist/settings/mail.d.ts +10 -0
  577. package/dist/settings/mail.d.ts.map +1 -0
  578. package/dist/settings/mail.js +92 -0
  579. package/dist/settings/mail.js.map +1 -0
  580. package/dist/settings/maintenance.d.ts +6 -0
  581. package/dist/settings/maintenance.d.ts.map +1 -0
  582. package/dist/settings/maintenance.js +33 -0
  583. package/dist/settings/maintenance.js.map +1 -0
  584. package/dist/settings/names.d.ts +7 -0
  585. package/dist/settings/names.d.ts.map +1 -0
  586. package/dist/settings/names.js +31 -0
  587. package/dist/settings/names.js.map +1 -0
  588. package/dist/settings/presence.d.ts +2 -0
  589. package/dist/settings/presence.d.ts.map +1 -0
  590. package/dist/settings/presence.js +7 -0
  591. package/dist/settings/presence.js.map +1 -0
  592. package/dist/settings/registry.d.ts +14 -0
  593. package/dist/settings/registry.d.ts.map +1 -0
  594. package/dist/settings/registry.js +369 -0
  595. package/dist/settings/registry.js.map +1 -0
  596. package/dist/settings/types.d.ts +176 -0
  597. package/dist/settings/types.d.ts.map +1 -0
  598. package/dist/settings/types.js +2 -0
  599. package/dist/settings/types.js.map +1 -0
  600. package/dist/site/namespace.d.ts +88 -0
  601. package/dist/site/namespace.d.ts.map +1 -0
  602. package/dist/site/namespace.js +471 -0
  603. package/dist/site/namespace.js.map +1 -0
  604. package/dist/site/setting-rows.d.ts +9 -10
  605. package/dist/site/setting-rows.d.ts.map +1 -1
  606. package/dist/site/setting-rows.js +109 -228
  607. package/dist/site/setting-rows.js.map +1 -1
  608. package/dist/site/settings-form.d.ts.map +1 -1
  609. package/dist/site/settings-form.js +6 -10
  610. package/dist/site/settings-form.js.map +1 -1
  611. package/dist/site/settings.d.ts +6 -322
  612. package/dist/site/settings.d.ts.map +1 -1
  613. package/dist/site/settings.js +13 -76
  614. package/dist/site/settings.js.map +1 -1
  615. package/dist/site/site-json.d.ts +0 -31
  616. package/dist/site/site-json.d.ts.map +1 -1
  617. package/dist/site/site-json.js +5 -49
  618. package/dist/site/site-json.js.map +1 -1
  619. package/dist/site/users.d.ts +0 -9
  620. package/dist/site/users.d.ts.map +1 -1
  621. package/dist/site/users.js +2 -11
  622. package/dist/site/users.js.map +1 -1
  623. package/dist/store/deliveries.d.ts +2 -0
  624. package/dist/store/deliveries.d.ts.map +1 -1
  625. package/dist/store/deliveries.js +7 -0
  626. package/dist/store/deliveries.js.map +1 -1
  627. package/dist/store/queue-database.d.ts +11 -0
  628. package/dist/store/queue-database.d.ts.map +1 -0
  629. package/dist/store/queue-database.js +39 -0
  630. package/dist/store/queue-database.js.map +1 -0
  631. package/dist/supervisor/control.d.ts +1 -0
  632. package/dist/supervisor/control.d.ts.map +1 -1
  633. package/dist/supervisor/control.js +10 -0
  634. package/dist/supervisor/control.js.map +1 -1
  635. package/dist/supervisor/primary.d.ts.map +1 -1
  636. package/dist/supervisor/primary.js +15 -3
  637. package/dist/supervisor/primary.js.map +1 -1
  638. package/dist/testing.d.ts +1 -1
  639. package/dist/testing.d.ts.map +1 -1
  640. package/dist/testing.js +1 -1
  641. package/dist/testing.js.map +1 -1
  642. package/dist/theme/site-data.d.ts +1 -1
  643. package/dist/theme/site-data.d.ts.map +1 -1
  644. package/dist/theme/site-data.js.map +1 -1
  645. package/dist/web/asset-routes.d.ts +6 -2
  646. package/dist/web/asset-routes.d.ts.map +1 -1
  647. package/dist/web/asset-routes.js +12 -4
  648. package/dist/web/asset-routes.js.map +1 -1
  649. package/dist/web/comment-routes.d.ts.map +1 -1
  650. package/dist/web/comment-routes.js +4 -4
  651. package/dist/web/comment-routes.js.map +1 -1
  652. package/dist/web/contact-routes.js +1 -1
  653. package/dist/web/contact-routes.js.map +1 -1
  654. package/dist/web/context.d.ts +5 -0
  655. package/dist/web/context.d.ts.map +1 -1
  656. package/dist/web/context.js +9 -4
  657. package/dist/web/context.js.map +1 -1
  658. package/dist/web/conversation.d.ts +1 -1
  659. package/dist/web/conversation.d.ts.map +1 -1
  660. package/dist/web/conversation.js +59 -43
  661. package/dist/web/conversation.js.map +1 -1
  662. package/dist/web/document-page.d.ts.map +1 -1
  663. package/dist/web/document-page.js +5 -4
  664. package/dist/web/document-page.js.map +1 -1
  665. package/dist/web/document-site.d.ts +1 -1
  666. package/dist/web/document-site.d.ts.map +1 -1
  667. package/dist/web/document-site.js +2 -1
  668. package/dist/web/document-site.js.map +1 -1
  669. package/dist/web/embed.js +1 -1
  670. package/dist/web/embed.js.map +1 -1
  671. package/dist/web/env.d.ts +9 -0
  672. package/dist/web/env.d.ts.map +1 -1
  673. package/dist/web/federation-routes.d.ts.map +1 -1
  674. package/dist/web/federation-routes.js +5 -2
  675. package/dist/web/federation-routes.js.map +1 -1
  676. package/dist/web/feed-item.js +1 -1
  677. package/dist/web/feed-item.js.map +1 -1
  678. package/dist/web/feed-routes.d.ts +3 -4
  679. package/dist/web/feed-routes.d.ts.map +1 -1
  680. package/dist/web/feed-routes.js +17 -15
  681. package/dist/web/feed-routes.js.map +1 -1
  682. package/dist/web/health.js +1 -1
  683. package/dist/web/health.js.map +1 -1
  684. package/dist/web/index.d.ts +1 -1
  685. package/dist/web/index.d.ts.map +1 -1
  686. package/dist/web/index.js.map +1 -1
  687. package/dist/web/indieauth-activity-log.d.ts +0 -2
  688. package/dist/web/indieauth-activity-log.d.ts.map +1 -1
  689. package/dist/web/indieauth-activity-log.js +2 -4
  690. package/dist/web/indieauth-activity-log.js.map +1 -1
  691. package/dist/web/indieauth-bearer.js +2 -2
  692. package/dist/web/indieauth-bearer.js.map +1 -1
  693. package/dist/web/indieauth-discovery.d.ts +0 -4
  694. package/dist/web/indieauth-discovery.d.ts.map +1 -1
  695. package/dist/web/indieauth-discovery.js +3 -10
  696. package/dist/web/indieauth-discovery.js.map +1 -1
  697. package/dist/web/indieauth-token.d.ts.map +1 -1
  698. package/dist/web/indieauth-token.js +3 -3
  699. package/dist/web/indieauth-token.js.map +1 -1
  700. package/dist/web/listing-pages.d.ts.map +1 -1
  701. package/dist/web/listing-pages.js +1 -2
  702. package/dist/web/listing-pages.js.map +1 -1
  703. package/dist/web/maintenance.js +3 -3
  704. package/dist/web/maintenance.js.map +1 -1
  705. package/dist/web/page-sources.d.ts +1 -2
  706. package/dist/web/page-sources.d.ts.map +1 -1
  707. package/dist/web/page-sources.js +6 -7
  708. package/dist/web/page-sources.js.map +1 -1
  709. package/dist/web/paths.js +1 -1
  710. package/dist/web/paths.js.map +1 -1
  711. package/dist/web/pingback-routes.d.ts.map +1 -1
  712. package/dist/web/pingback-routes.js +3 -3
  713. package/dist/web/pingback-routes.js.map +1 -1
  714. package/dist/web/plugin-federation.js +50 -40
  715. package/dist/web/plugin-federation.js.map +1 -1
  716. package/dist/web/render.d.ts +12 -5
  717. package/dist/web/render.d.ts.map +1 -1
  718. package/dist/web/render.js +36 -22
  719. package/dist/web/render.js.map +1 -1
  720. package/dist/web/request.js +1 -1
  721. package/dist/web/request.js.map +1 -1
  722. package/dist/web/routes.d.ts.map +1 -1
  723. package/dist/web/routes.js +8 -9
  724. package/dist/web/routes.js.map +1 -1
  725. package/dist/web/site-index.d.ts.map +1 -1
  726. package/dist/web/site-index.js +1 -2
  727. package/dist/web/site-index.js.map +1 -1
  728. package/dist/web/site-view.d.ts +0 -2
  729. package/dist/web/site-view.d.ts.map +1 -1
  730. package/dist/web/site-view.js +0 -2
  731. package/dist/web/site-view.js.map +1 -1
  732. package/dist/web/webmention-routes.d.ts.map +1 -1
  733. package/dist/web/webmention-routes.js +2 -2
  734. package/dist/web/webmention-routes.js.map +1 -1
  735. package/dist/web/well-known.d.ts.map +1 -1
  736. package/dist/web/well-known.js +6 -7
  737. package/dist/web/well-known.js.map +1 -1
  738. package/dist/webmention/cited-picture.js +1 -1
  739. package/dist/webmention/cited-picture.js.map +1 -1
  740. package/dist/webmention/pingback.d.ts +1 -8
  741. package/dist/webmention/pingback.d.ts.map +1 -1
  742. package/dist/webmention/pingback.js +2 -11
  743. package/dist/webmention/pingback.js.map +1 -1
  744. package/dist/webmention/receive.d.ts +3 -1
  745. package/dist/webmention/receive.d.ts.map +1 -1
  746. package/dist/webmention/receive.js +5 -3
  747. package/dist/webmention/receive.js.map +1 -1
  748. package/dist/webmention/reply-contexts.d.ts +14 -3
  749. package/dist/webmention/reply-contexts.d.ts.map +1 -1
  750. package/dist/webmention/reply-contexts.js +12 -10
  751. package/dist/webmention/reply-contexts.js.map +1 -1
  752. package/dist/webmention/service.d.ts +3 -1
  753. package/dist/webmention/service.d.ts.map +1 -1
  754. package/dist/webmention/service.js +66 -53
  755. package/dist/webmention/service.js.map +1 -1
  756. package/package.json +13 -11
  757. package/themes/default/partials/post-list.njk +19 -14
  758. package/themes/default/src/style.css +12 -0
  759. package/themes/default/static/style.css +19 -0
@@ -37,14 +37,18 @@
37
37
  accepted: 'badge-outline',
38
38
  described: 'badge-outline',
39
39
  decorative: 'badge-outline',
40
+ finished: 'badge-outline',
40
41
  active: 'badge-primary',
42
+ running: 'badge-primary',
41
43
  unread: 'badge-primary',
42
44
  connected: 'badge-success',
43
45
  scheduled: 'badge-info',
46
+ queued: 'badge-info',
44
47
  draft: 'badge-warning',
45
48
  pending: 'badge-warning',
46
49
  missing: 'badge-warning',
47
50
  unreachable: 'badge-warning',
51
+ interrupted: 'badge-warning',
48
52
  failed: 'badge-error',
49
53
  rejected: 'badge-error',
50
54
  spam: 'badge-error',
@@ -36,12 +36,13 @@
36
36
  reads the explanation with the box rather than leaving it to be found. A
37
37
  textarea given no `name` only shows something and posts nothing.
38
38
 
39
- `label` and `hint` are written into the page as markup, because the admin's
40
- labels and hints carry `<code>`, `<em>` and links. They are template
41
- literals, never anything a visitor typed; a hint that interpolates a value
42
- should be captured with `{% set … %}…{% endset %}`, which escapes what it
43
- interpolates before this ever sees it. `error` is a message from the server
44
- and is escaped. #}
39
+ `label` and `hint` are plain text and always escaped, even a value marked
40
+ safe, so a plugin's or a user's words can go straight in. `labelHtml`,
41
+ `hintHtml` and `errorHtml` are markup the admin's own templates write, such
42
+ as a `<code>` or a link, and are printed as given; a hint that interpolates
43
+ a value is captured with `{% set … %}…{% endset %}`, which escapes what it
44
+ interpolates. Either one wins over its plain-text twin, and an empty hint
45
+ writes no paragraph. #}
45
46
 
46
47
  {% from "components/alert.njk" import alert %}
47
48
 
@@ -53,18 +54,24 @@
53
54
  already written as its own paragraph, and drawn in the error colour whether
54
55
  or not the form was refused. The hint is a `label` made `block` and
55
56
  `whitespace-normal`: DaisyUI's is `inline-flex` and `nowrap`. #}
56
- {% macro _below(id, hint, error, errorHtml, hintId='') %}
57
+ {% macro _below(id, hint, hintHtml, error, errorHtml, hintId='') %}
57
58
  {% if error %}
58
59
  <p class="validator-hint" id="{{ id }}-error">{{ error }}</p>
59
60
  {% endif %}
60
61
  {% if errorHtml %}
61
62
  <div class="text-error">{{ errorHtml | safe }}</div>
62
63
  {% endif %}
63
- {% if hint %}
64
- <p class="label block whitespace-normal"{% if hintId %} id="{{ hintId }}"{% endif %}>{{ hint | safe }}</p>
64
+ {% if hintHtml | length %}
65
+ <p class="label block whitespace-normal"{% if hintId %} id="{{ hintId }}"{% endif %}>{{ hintHtml | safe }}</p>
66
+ {% elif hint | length %}
67
+ <p class="label block whitespace-normal"{% if hintId %} id="{{ hintId }}"{% endif %}>{{ hint ~ '' }}</p>
65
68
  {% endif %}
66
69
  {% endmacro %}
67
70
 
71
+ {% macro _label(label, labelHtml) -%}
72
+ {{ labelHtml | safe if labelHtml | length else label | default('') ~ '' }}
73
+ {%- endmacro %}
74
+
68
75
  {# What a control says about itself when the form refused it: that it is
69
76
  invalid, and which paragraph says why, so a screen reader reads the message
70
77
  with the field rather than leaving it to be found. `errorHtml` is not named
@@ -98,12 +105,14 @@
98
105
  required=false,
99
106
  autofocus=false,
100
107
  readonly=false,
101
- disabled=false
108
+ disabled=false,
109
+ labelHtml='',
110
+ hintHtml=''
102
111
  ) %}
103
112
  <div class="fieldset">
104
- <label class="fieldset-legend" for="{{ id }}">{{ label | safe }}</label>
113
+ <label class="fieldset-legend" for="{{ id }}">{{ _label(label, labelHtml) }}</label>
105
114
  <input id="{{ id }}" name="{{ name }}" type="{{ type }}"{% if min %} min="{{ min }}"{% endif %}{% if step %} step="{{ step }}"{% endif %}{% if inputmode %} inputmode="{{ inputmode }}"{% endif %}{% if autocomplete %} autocomplete="{{ autocomplete }}"{% endif %} value="{{ value }}"{% if list %} list="{{ list }}"{% endif %}{% if maxlength %} maxlength="{{ maxlength }}"{% endif %}{% if placeholder %} placeholder="{{ placeholder }}"{% endif %}{% if spellcheck %} spellcheck="{{ spellcheck }}"{% endif %}{% if required %} required{% endif %}{% if autofocus %} autofocus{% endif %}{% if readonly %} readonly{% endif %}{% if disabled %} disabled{% endif %}{{ _invalid(id, error, hintId) }} class="input input-sm w-full read-only:bg-base-200 read-only:border-dashed{% if error %} validator{% endif %}" />
106
- {{ _below(id, hint, error, errorHtml, hintId) }}
115
+ {{ _below(id, hint, hintHtml, error, errorHtml, hintId) }}
107
116
  </div>
108
117
  {%- endmacro %}
109
118
 
@@ -122,12 +131,14 @@
122
131
  placeholder='',
123
132
  spellcheck='',
124
133
  required=false,
125
- autofocus=false
134
+ autofocus=false,
135
+ labelHtml='',
136
+ hintHtml=''
126
137
  ) %}
127
138
  <div class="fieldset">
128
- <label class="fieldset-legend" for="{{ id }}">{{ label | safe }}</label>
139
+ <label class="fieldset-legend" for="{{ id }}">{{ _label(label, labelHtml) }}</label>
129
140
  <input id="{{ id }}" name="{{ name }}" type="password" value=""{% if autocomplete %} autocomplete="{{ autocomplete }}"{% endif %}{% if spellcheck %} spellcheck="{{ spellcheck }}"{% endif %}{% if placeholder %} placeholder="{{ placeholder }}"{% endif %}{% if required %} required{% endif %}{% if autofocus %} autofocus{% endif %}{{ _invalid(id, error) }} class="input input-sm w-full{% if error %} validator{% endif %}" />
130
- {{ _below(id, hint, error, errorHtml) }}
141
+ {{ _below(id, hint, hintHtml, error, errorHtml) }}
131
142
  </div>
132
143
  {%- endmacro %}
133
144
 
@@ -146,12 +157,14 @@
146
157
  required=false,
147
158
  autofocus=false,
148
159
  readonly=false,
149
- disabled=false
160
+ disabled=false,
161
+ labelHtml='',
162
+ hintHtml=''
150
163
  ) %}
151
164
  <div class="fieldset">
152
- <label class="fieldset-legend" for="{{ id }}">{{ label | safe }}</label>
165
+ <label class="fieldset-legend" for="{{ id }}">{{ _label(label, labelHtml) }}</label>
153
166
  <textarea id="{{ id }}"{% if name %} name="{{ name }}"{% endif %}{% if rows %} rows="{{ rows }}"{% endif %}{% if spellcheck %} spellcheck="{{ spellcheck }}"{% endif %}{% if required %} required{% endif %}{% if autofocus %} autofocus{% endif %}{% if readonly %} readonly{% endif %}{% if disabled %} disabled{% endif %}{{ _invalid(id, error, hintId) }} class="textarea textarea-sm w-full read-only:bg-base-200 read-only:border-dashed{% if error %} validator{% endif %}">{{ value }}</textarea>
154
- {{ _below(id, hint, error, errorHtml, hintId) }}
167
+ {{ _below(id, hint, hintHtml, error, errorHtml, hintId) }}
155
168
  </div>
156
169
  {%- endmacro %}
157
170
 
@@ -172,14 +185,16 @@
172
185
  hintId='',
173
186
  required=false,
174
187
  autofocus=false,
175
- disabled=false
188
+ disabled=false,
189
+ labelHtml='',
190
+ hintHtml=''
176
191
  ) %}
177
192
  <div class="fieldset">
178
- <label class="fieldset-legend" for="{{ id }}">{{ label | safe }}</label>
193
+ <label class="fieldset-legend" for="{{ id }}">{{ _label(label, labelHtml) }}</label>
179
194
  <select id="{{ id }}" name="{{ name }}"{% if required %} required{% endif %}{% if autofocus %} autofocus{% endif %}{% if disabled %} disabled{% endif %}{{ _invalid(id, error, hintId) }} class="select select-sm w-full{% if error %} validator{% endif %}">
180
195
  {{ caller() }}
181
196
  </select>
182
- {{ _below(id, hint, error, errorHtml, hintId) }}
197
+ {{ _below(id, hint, hintHtml, error, errorHtml, hintId) }}
183
198
  </div>
184
199
  {%- endmacro %}
185
200
 
@@ -195,14 +210,16 @@
195
210
  error='',
196
211
  errorHtml='',
197
212
  hintId='',
198
- disabled=false
213
+ disabled=false,
214
+ labelHtml='',
215
+ hintHtml=''
199
216
  ) %}
200
217
  <div class="fieldset">
201
218
  <label class="label whitespace-normal text-base-content{% if error %} validator{% endif %}" for="{{ id }}">
202
219
  <input id="{{ id }}" name="{{ name }}" type="checkbox" value="{{ value }}"{% if checked %} checked{% endif %}{% if disabled %} disabled{% endif %}{{ _invalid(id, error, hintId) }} class="checkbox checkbox-sm" />
203
- {{ label | safe }}
220
+ {{ _label(label, labelHtml) }}
204
221
  </label>
205
- {{ _below(id, hint, error, errorHtml, hintId) }}
222
+ {{ _below(id, hint, hintHtml, error, errorHtml, hintId) }}
206
223
  </div>
207
224
  {%- endmacro %}
208
225
 
@@ -0,0 +1,45 @@
1
+ {# The latest run of a queued job, from `jobStatusView` in
2
+ src/admin/job-status.ts. `{% call jobStatus(job, …) %}result{% endcall %}`
3
+ emits its state as a badge and when it got there, then:
4
+
5
+ queued that it waits for the worker, and whether a restart sent it back
6
+ running a progress bar and "<verb> <done> of <total> <unit>"
7
+ finished the caller's body, which draws the job's own result
8
+ failed the error, in an alert
9
+ interrupted that restarts or crashes cut it off and it will not run again
10
+
11
+ While it is queued or running, `refreshUrl` is offered as a link to look
12
+ again: the page does not reload itself. `verb` and `unit` word the
13
+ progress. The error and every word passed in are escaped. #}
14
+ {% from "components/alert.njk" import alert %}
15
+ {% from "components/badge.njk" import status %}
16
+ {% from "components/button.njk" import buttonLink %}
17
+
18
+ {% macro jobStatus(job, refreshUrl, verb='Done', unit='items') -%}
19
+ <div class="flex flex-col gap-3">
20
+ <p class="flex flex-wrap items-center gap-2">
21
+ {{ status(job.state, job.label) }}
22
+ <span class="text-sm"><time datetime="{{ job.at }}">{{ job.at | date('readable') }}</time></span>
23
+ </p>
24
+ {% if job.state == 'queued' %}
25
+ <p>Waiting for the worker to start it.{% if job.requeued %} A restart cut off the last try, so it is queued again as try {{ job.attempt }}.{% endif %}</p>
26
+ {% elif job.state == 'running' %}
27
+ {% if job.progress and job.progress.total %}
28
+ <progress class="progress progress-primary w-full max-w-md" value="{{ job.progress.done }}" max="{{ job.progress.total }}" aria-label="{{ verb }} {{ job.progress.done }} of {{ job.progress.total }} {{ unit }}"></progress>
29
+ <p>{{ verb }} {{ job.progress.done }} of {{ job.progress.total }} {{ unit }}.{% if job.progress.note %} {{ job.progress.note }}{% endif %}</p>
30
+ {% else %}
31
+ <progress class="progress progress-primary w-full max-w-md" aria-label="Starting"></progress>
32
+ <p>Starting.</p>
33
+ {% endif %}
34
+ {% elif job.state == 'finished' %}
35
+ {% if caller %}{{ caller() }}{% endif %}
36
+ {% elif job.state == 'failed' %}
37
+ {% call alert(color='error', style='soft') %}<span>{{ job.error }}</span>{% endcall %}
38
+ {% elif job.state == 'interrupted' %}
39
+ <p>Restarts or crashes cut it off {{ job.attempt }} times, so it is not run again on its own.</p>
40
+ {% endif %}
41
+ {% if job.active %}
42
+ <div>{{ buttonLink('Check again', refreshUrl, style='outline') }}</div>
43
+ {% endif %}
44
+ </div>
45
+ {%- endmacro %}
@@ -0,0 +1,38 @@
1
+ {% import "components/fields.njk" as field %}
2
+ {% from "components/badge.njk" import status %}
3
+
4
+ {% macro settingFields(settings, secretsFile) %}
5
+ {% for setting in settings %}
6
+ {% set error = setting.error or setting.stored %}
7
+ {% if setting.setBy %}
8
+ <div class="fieldset">
9
+ <p class="fieldset-legend">{{ setting.label }}{% if setting.widget == 'secret' %} {{ status('connected', 'Set') }}{% endif %}</p>
10
+ {% if setting.widget != 'secret' %}<p><code>{{ setting.value if setting.widget != 'checkbox' else ('on' if setting.checked else 'off') }}</code></p>{% endif %}
11
+ <p class="label block whitespace-normal">{% if setting.hint %}{{ setting.hint }} {% endif %}Set by {% if setting.setBy == setting.variable %}the environment variable {% endif %}<code>{{ setting.setBy }}</code>. Change it there.</p>
12
+ </div>
13
+ {% elif setting.widget == 'secret' %}
14
+ {% set hint %}{% if setting.hint %}{{ setting.hint }} {% endif %}{% if setting.storedSet %}Set in <code>{{ secretsFile }}</code>. Leave the box blank to keep it.{% if setting.variable %} The environment variable <code>{{ setting.variable }}</code> would win over it.{% endif %}{% else %}Not set.{% if setting.variable %} Or set the environment variable <code>{{ setting.variable }}</code>.{% endif %}{% endif %}{% endset %}
15
+ {% set label %}{{ setting.label }} {{ status('connected', 'Set') if setting.storedSet else status('missing', 'Not set') }}{% endset %}
16
+ {{ field.password(setting.id, setting.name, labelHtml=label,
17
+ hintHtml=hint, error=error, autocomplete='off', spellcheck='false',
18
+ placeholder=('Leave blank to keep it' if setting.storedSet else '')) }}
19
+ {% if setting.storedSet %}
20
+ {{ field.checkbox(setting.id ~ '-forget', setting.forgetName, 'Forget the stored ' ~ setting.label) }}
21
+ {% endif %}
22
+ {% else %}
23
+ {% set hint %}{% if setting.hint %}{{ setting.hint }} {% endif %}{% if setting.variable %}The environment variable <code>{{ setting.variable }}</code> would win over this.{% endif %}{% endset %}
24
+ {% if setting.widget == 'checkbox' %}
25
+ {{ field.checkbox(setting.id, setting.name, setting.label, checked=setting.checked, hintHtml=hint, error=error) }}
26
+ {% elif setting.widget == 'select' %}
27
+ {% call field.select(setting.id, setting.name, setting.label, hintHtml=hint, error=error) %}
28
+ {% for option in setting.options %}
29
+ <option value="{{ option.value }}"{% if option.selected %} selected{% endif %}>{{ option.label }}</option>
30
+ {% endfor %}
31
+ {% endcall %}
32
+ {% else %}
33
+ {{ field.text(setting.id, setting.name, setting.label, setting.value, hintHtml=hint, error=error,
34
+ inputmode=('url' if setting.widget == 'url' else ''), spellcheck='false') }}
35
+ {% endif %}
36
+ {% endif %}
37
+ {% endfor %}
38
+ {% endmacro %}
@@ -6,6 +6,7 @@
6
6
  {% extends "layouts/shell.njk" %}
7
7
  {% import "components/fields.njk" as field %}
8
8
  {% from "components/button.njk" import button %}
9
+ {% from "components/alert.njk" import alert %}
9
10
 
10
11
  {% block title %}{{ settingsLabel }} settings{% endblock %}
11
12
 
@@ -20,6 +21,21 @@
20
21
  </div>
21
22
  {% endif %}
22
23
 
24
+ {% if setElsewhere.length %}
25
+ <div class="mb-6 max-w-2xl">
26
+ {% call alert(color='info', style='soft', polite=true) %}
27
+ <div>
28
+ <p>Set outside this page, so the form shows the value in effect and a save leaves it as it is:</p>
29
+ <ul class="list-disc ps-5">
30
+ {% for each in setElsewhere %}
31
+ <li><code>{{ each.setting }}</code> is set by <code>{{ each.source }}</code>.</li>
32
+ {% endfor %}
33
+ </ul>
34
+ </div>
35
+ {% endcall %}
36
+ </div>
37
+ {% endif %}
38
+
23
39
  <form class="flex max-w-2xl flex-col gap-2" method="post" action="{{ settingsUrl }}">
24
40
  <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
25
41
 
@@ -93,8 +93,7 @@
93
93
  {% call collapse('Reply') %}
94
94
  <form method="post" action="{{ replyUrl }}">
95
95
  {{ rowFields(row, fields, status, csrfToken) }}
96
- {% set replyLabel %}Reply to {{ row.author }}{% endset %}
97
- {{ field.textarea('reply-' + loop.index, fields.body, replyLabel, rows='4', required=true,
96
+ {{ field.textarea('reply-' + loop.index, fields.body, 'Reply to ' ~ row.author, rows='4', required=true,
98
97
  hint='Markdown. It is saved as a reply post of yours and shown under this one.') }}
99
98
  {{ field.checkbox('reply-listed-' + loop.index, fields.listed, 'Include in posts and feeds',
100
99
  hint='Left unticked, the reply is Unlisted: its own page, and no listing or feed.') }}
@@ -114,7 +114,7 @@
114
114
  {% call card() %}
115
115
  {% set titleHint %}{% if kind.type == "post" %}Leave it empty to write a note: the post is then its words, and takes its slug from the first of them.{% endif %}{% endset %}
116
116
  {#- A post may go without one, and is then a note; a page is always named. -#}
117
- {{ field.text('editor-title', 'title', 'Title', value=form.title, required=(kind.type == "page"), autofocus=true, error=(error if errorField == 'editor-title' else ''), hint=titleHint) }}
117
+ {{ field.text('editor-title', 'title', 'Title', value=form.title, required=(kind.type == "page"), autofocus=true, error=(error if errorField == 'editor-title' else ''), hintHtml=titleHint) }}
118
118
  {{ pluginActions('editor-title', editorActions['editor-title']) }}
119
119
 
120
120
  {{ field.textarea('editor-body', 'body', 'Body', value=form.body, rows=24) }}
@@ -139,7 +139,7 @@
139
139
  {% if kind.type == "post" %}
140
140
  {% call collapse('Photos', open.photos, fields=true) %}
141
141
  <p class="label block whitespace-normal text-xs">
142
- Each is an image in the media library or an address starting https://. Leave the alt text
142
+ Each is an image in the media library or a web address. Leave the alt text
143
143
  empty to use the media library’s. Empty an address to remove that photo.
144
144
  </p>
145
145
  {% for row in photoRows %}
@@ -165,7 +165,7 @@
165
165
  {{ button('Use my location', id='editor-location-here', style='soft', hidden=true) }}
166
166
  </div>
167
167
  <p id="editor-location-status" class="label block whitespace-normal text-xs" role="status"></p>
168
- {{ field.text('editor-location-geo', locationFields.geo, 'Coordinates', value=form.location.geo, placeholder='48.85837, 2.29448', autocomplete='off', spellcheck='false', error=(error if errorField == 'editor-location-geo' else ''), hint='Latitude, longitude, as decimal degrees. A <code>geo:</code> URI works too.', hintId='editor-location-geo-hint') }}
168
+ {{ field.text('editor-location-geo', locationFields.geo, 'Coordinates', value=form.location.geo, placeholder='48.85837, 2.29448', autocomplete='off', spellcheck='false', error=(error if errorField == 'editor-location-geo' else ''), hintHtml='Latitude, longitude, as decimal degrees. A <code>geo:</code> URI works too.', hintId='editor-location-geo-hint') }}
169
169
  {{ field.text('editor-location-accuracy', locationFields.accuracy, 'Accuracy', value=form.location.accuracy, inputmode='numeric', autocomplete='off', error=(error if errorField == 'editor-location-accuracy' else ''), hint='Metres. Leave it empty if you do not know.', hintId='editor-location-accuracy-hint') }}
170
170
  {{ field.text('editor-location-name', locationFields.name, 'Place', value=form.location.name) }}
171
171
  {{ field.text('editor-location-locality', locationFields.locality, 'Locality', value=form.location.locality) }}
@@ -190,7 +190,7 @@
190
190
  <option value="{{ url }}"></option>
191
191
  {% endfor %}
192
192
  </datalist>
193
- {% call field.select('editor-enclosure-transcript-type', enclosureFields.transcriptType, 'Transcript type', error=(error if errorField == 'editor-enclosure-transcript-type' else ''), hint='A .vtt, .srt or .txt file in the media library, or an address starting https://. A linked transcript needs its type.', hintId='editor-enclosure-transcript-hint') %}
193
+ {% call field.select('editor-enclosure-transcript-type', enclosureFields.transcriptType, 'Transcript type', error=(error if errorField == 'editor-enclosure-transcript-type' else ''), hint='A .vtt, .srt or .txt file in the media library, or a web address. A linked transcript needs its type.', hintId='editor-enclosure-transcript-hint') %}
194
194
  <option value=""{% if form.enclosure.transcriptType == "" %} selected{% endif %}>From the file</option>
195
195
  {% for type in transcriptTypes %}
196
196
  <option value="{{ type }}"{% if type == form.enclosure.transcriptType %} selected{% endif %}>{{ type }}</option>
@@ -200,7 +200,7 @@
200
200
  {% call collapse('Other versions', open.versions, fields=true) %}
201
201
  <p class="label block whitespace-normal text-xs">
202
202
  A video of an audio episode, a smaller file, another language. Each is a file in the media
203
- library or an address starting https://, which needs its type. Empty an address to remove
203
+ library or a web address, which needs its type. Empty an address to remove
204
204
  that version.
205
205
  </p>
206
206
  {% for row in alternateRows %}
@@ -242,7 +242,7 @@
242
242
  {# The file holds a UTC instant; this field is that instant as the
243
243
  site's own clock reads it, so the zone has to be on the screen. #}
244
244
  {% set dateHint %}Wall-clock time in {{ dateZone }}. Stored as UTC.{% endset %}
245
- {{ field.text('editor-date', 'date', 'Date', value=form.date, error=(error if errorField == 'editor-date' else ''), hint=dateHint) }}
245
+ {{ field.text('editor-date', 'date', 'Date', value=form.date, error=(error if errorField == 'editor-date' else ''), hintHtml=dateHint) }}
246
246
  {% endif %}
247
247
 
248
248
  {% set visibilityHint %}
@@ -255,7 +255,7 @@
255
255
  keeps its page and still goes to your followers, but is left off the home page, archives,
256
256
  feeds, the sitemap, search and llms.txt, and asks search engines not to index it.
257
257
  {% endset %}
258
- {% call field.select('editor-visibility', 'visibility', 'Visibility', hint=visibilityHint, hintId='editor-visibility-hint') %}
258
+ {% call field.select('editor-visibility', 'visibility', 'Visibility', hintHtml=visibilityHint, hintId='editor-visibility-hint') %}
259
259
  {% if form.visibility.unrecognized is defined %}
260
260
  <option value="{{ form.visibility.unrecognized }}" selected>{{ form.visibility.unrecognized }} (not recognized)</option>
261
261
  {% endif %}
@@ -266,7 +266,7 @@
266
266
  {% if kind.type == "post" %}
267
267
  {# TASK-207: shown at the top of the author's fediverse profile, from
268
268
  the featured collection their actor links. #}
269
- {{ field.checkbox('editor-pinned', 'pinned', 'Pinned', checked=form.pinned, error=(error if errorField == 'editor-pinned' else ''), hint='Writes <code>pinned:</code> and the moment you pinned it into the front matter. Pinned posts show first on your fediverse profile, newest pin first, up to five.') }}
269
+ {{ field.checkbox('editor-pinned', 'pinned', 'Pinned', checked=form.pinned, error=(error if errorField == 'editor-pinned' else ''), hintHtml='Writes <code>pinned:</code> and the moment you pinned it into the front matter. Pinned posts show first on your fediverse profile, newest pin first, up to five.') }}
270
270
  {% endif %}
271
271
 
272
272
  {# Who the front matter says wrote this (TASK-67). A select of the site's
@@ -297,7 +297,7 @@
297
297
  {% call collapse('Address', open.address, fields=true) %}
298
298
  {{ field.text('editor-slug', 'slug', 'Slug', value=form.slug, error=(error if errorField == 'editor-slug' else '')) }}
299
299
  {% set permalinkHint %}Leave it empty to let the {{ kind.singular }} take the URL its slug implies.{% endset %}
300
- {{ field.text('editor-permalink', 'permalink', 'Permalink', value=form.permalink, hint=permalinkHint) }}
300
+ {{ field.text('editor-permalink', 'permalink', 'Permalink', value=form.permalink, hintHtml=permalinkHint) }}
301
301
  {% endcall %}
302
302
 
303
303
  {% if kind.type == "post" %}
@@ -337,7 +337,7 @@
337
337
 
338
338
  {% call collapse('Event', open.event, fields=true) %}
339
339
  {% set eventTimeHint %}Wall-clock time in {{ dateZone }}. Stored as UTC.{% endset %}
340
- {{ field.text('editor-event-start', eventFields.start, 'Starts', value=form.event.start, placeholder='2026-10-10 09:00', autocomplete='off', error=(error if errorField == 'editor-event-start' else ''), hint=eventTimeHint, hintId='editor-event-time-hint') }}
340
+ {{ field.text('editor-event-start', eventFields.start, 'Starts', value=form.event.start, placeholder='2026-10-10 09:00', autocomplete='off', error=(error if errorField == 'editor-event-start' else ''), hintHtml=eventTimeHint, hintId='editor-event-time-hint') }}
341
341
  {{ field.text('editor-event-end', eventFields.end, 'Ends', value=form.event.end, placeholder='2026-10-10 17:00', autocomplete='off', error=(error if errorField == 'editor-event-end' else ''), hintId='editor-event-time-hint') }}
342
342
  {{ field.text('editor-event-location', eventFields.location, 'Where', value=form.event.location, error=(error if errorField == 'editor-event-location' else ''), hint='The place, or the address to join an online event at.', hintId='editor-event-location-hint') }}
343
343
  <p class="label block whitespace-normal text-xs">A post with a start is an event, named by its Title and described by its Body. Empty every box to make it a post again.</p>
@@ -357,6 +357,8 @@
357
357
  {{ field.text('editor-read-of-author', readFields.author, 'Author', value=form.readOf.author) }}
358
358
  {{ field.text('editor-read-of-uid', readFields.uid, 'Identifier', value=form.readOf.uid, placeholder='isbn:9780441478125', autocomplete='off', spellcheck='false') }}
359
359
  {{ field.text('editor-read-of-url', readFields.url, 'Address', value=form.readOf.url, type='url', error=(error if errorField == 'editor-read-of-url' else '')) }}
360
+ {{ field.text('editor-read-of-photo', readFields.photo, 'Cover', value=form.readOf.photo, list='editor-photo-uploads', autocomplete='off', error=(error if errorField == 'editor-read-of-photo' else ''), hint='An image in the media library or a web address. Empty it to remove the cover.', hintId='editor-read-of-photo-hint') }}
361
+ {{ field.text('editor-read-of-photo-alt', readFields.photoAlt, 'Cover alt text', value=form.readOf.photoAlt) }}
360
362
  <p class="label block whitespace-normal text-xs">A book or paper this post says its author read. An identifier is an ISBN or a DOI, written isbn:… or doi:…. Choose Not a read post and empty every box to remove it. A read is described by what it says, so leave its Description empty.</p>
361
363
  {% endcall %}
362
364
  {% endif %}
@@ -369,7 +371,7 @@
369
371
  language than the site's says so, for screen readers, translation
370
372
  and fediverse language filters. -#}
371
373
  {% set langHint %}A language tag, such as fr or pt-BR. Leave it empty for the site’s language, {{ siteLanguage }}.{% endset %}
372
- {{ field.text('editor-lang', 'lang', 'Language', value=form.lang, autocomplete='off', spellcheck='false', error=(error if errorField == 'editor-lang' else ''), hint=langHint, hintId='editor-lang-hint') }}
374
+ {{ field.text('editor-lang', 'lang', 'Language', value=form.lang, autocomplete='off', spellcheck='false', error=(error if errorField == 'editor-lang' else ''), hintHtml=langHint, hintId='editor-lang-hint') }}
373
375
  {% endcall %}
374
376
 
375
377
  {% if kind.type == "post" and syndicationTargets.length %}
@@ -390,8 +392,8 @@
390
392
  {% call collapse('Display and discussion', open.display, fields=true) %}
391
393
  {# What this document says about comments, if anything. Three answers
392
394
  rather than two: the site's own rules, always open, always closed. #}
393
- {% call field.select('editor-comments', 'comments', 'Comments', hint='Writes <code>comments: true</code> or <code>comments: false</code> into the front matter, which beats the site’s switch and its closing window in both directions. Fediverse replies are shown either way.') %}
394
- <option value="{{ commentSettings.site }}"{% if form.comments == commentSettings.site %} selected{% endif %}>Follow the site settings</option>
395
+ {% call field.select('editor-comments', 'comments', 'Comments', hintHtml='Open or Closed writes <code>comments: true</code> or <code>comments: false</code> into the front matter, which beats Settings › Discussion’s choice for this type and its closing window in both directions. Comments switched off for the whole site stay off. What was already said, and fediverse replies, are shown either way.') %}
396
+ <option value="{{ commentSettings.site }}"{% if form.comments == commentSettings.site %} selected{% endif %}>Follow the site settings ({{ commentsSiteDefault }})</option>
395
397
  <option value="{{ commentSettings.open }}"{% if form.comments == commentSettings.open %} selected{% endif %}>Open</option>
396
398
  <option value="{{ commentSettings.closed }}"{% if form.comments == commentSettings.closed %} selected{% endif %}>Closed</option>
397
399
  {% endcall %}
@@ -400,7 +402,7 @@
400
402
  {# doc-2's eleventyExcludeFromCollections: still published and still at
401
403
  its URL, but out of every collection a template lists from. #}
402
404
  {% set excludeHint %}Keeps the {{ kind.singular }} out of listings that gather content, without unpublishing it.{% endset %}
403
- {{ field.checkbox('editor-exclude', 'exclude', 'Hide from collections', checked=form.exclude, hint=excludeHint) }}
405
+ {{ field.checkbox('editor-exclude', 'exclude', 'Hide from collections', checked=form.exclude, hintHtml=excludeHint) }}
404
406
  {% endif %}
405
407
 
406
408
  {% if kind.contactable %}
@@ -408,7 +410,7 @@
408
410
  message goes is the contact address on the Settings screen; it is
409
411
  never on this page or in its HTML. #}
410
412
  {% set contactHint %}Writes <code>contact: true</code> into the front matter and puts a name, email, subject and message form under this {{ kind.singular }}. Messages arrive on the Messages screen and are emailed to the contact address on Settings.{% endset %}
411
- {{ field.checkbox('editor-contact', 'contact', 'Contact form', checked=form.contact, hint=contactHint) }}
413
+ {{ field.checkbox('editor-contact', 'contact', 'Contact form', checked=form.contact, hintHtml=contactHint) }}
412
414
  {% endif %}
413
415
  {% endcall %}
414
416
  </div>
@@ -21,18 +21,18 @@
21
21
  {% macro boxes(panel, fields) %}
22
22
  {{ field.text(panel.key + '-id', fields.id, 'Id', panel.form.id, error=panel.problems.id,
23
23
  spellcheck='false', required=true,
24
- hint='What a post&rsquo;s <code>syndicate-to</code> lists and what Micropub offers as the uid. Letters, digits, <code>.</code>, <code>-</code> and <code>_</code>.') }}
24
+ hintHtml='What a post&rsquo;s <code>syndicate-to</code> lists and what Micropub offers as the uid. Letters, digits, <code>.</code>, <code>-</code> and <code>_</code>.') }}
25
25
  {{ field.text(panel.key + '-name', fields.name, 'Name', panel.form.name, error=panel.problems.name,
26
- required=true, hint='What the editor&rsquo;s checkbox and the post&rsquo;s link say.') }}
26
+ required=true, hintHtml='What the editor&rsquo;s checkbox and the post&rsquo;s link say.') }}
27
27
  {{ field.text(panel.key + '-url', fields.url, 'URL', panel.form.url, error=panel.problems.url,
28
28
  inputmode='url', spellcheck='false', required=true,
29
- hint='The page the post links to and sends its webmention to. Put <code>{lang}</code> where the post&rsquo;s language goes, as in <code>https://news.indieweb.org/{lang}</code>.') }}
29
+ hintHtml='The page the post links to and sends its webmention to. Put <code>{lang}</code> where the post&rsquo;s language goes, as in <code>https://news.indieweb.org/{lang}</code>.') }}
30
30
  {{ field.text(panel.key + '-tag', fields.tag, 'Tag', panel.form.tag, error=panel.problems.tag,
31
31
  spellcheck='false',
32
32
  hint='Optional. A post carrying this tag is sent here without listing the target.') }}
33
33
  {{ field.text(panel.key + '-languages', fields.languages, 'Languages', panel.form.languages,
34
34
  error=panel.problems.languages, spellcheck='false',
35
- hint='Optional. The language tags this target takes posts in, separated by commas, such as <code>en, de</code>. Empty takes every language.') }}
35
+ hintHtml='Optional. The language tags this target takes posts in, separated by commas, such as <code>en, de</code>. Empty takes every language.') }}
36
36
  {% endmacro %}
37
37
 
38
38
  {% block content %}
@@ -1,9 +1,11 @@
1
1
  {# /admin/federation: who this site's people are to the fediverse, who follows
2
- each of them, what arrived in the inbox, and how what went out landed. #}
2
+ each of them, what arrived in the inbox, how what went out landed, and the
3
+ latest resend job (TASK-393). #}
3
4
  {% extends "layouts/shell.njk" %}
4
5
  {% from "components/badge.njk" import badge, status %}
5
6
  {% from "components/button.njk" import button %}
6
- {% from "components/card.njk" import card %}
7
+ {% from "components/card.njk" import card, cardActions %}
8
+ {% from "components/job-status.njk" import jobStatus %}
7
9
  {% from "components/table.njk" import table %}
8
10
 
9
11
  {% block title %}Federation{% endblock %}
@@ -173,6 +175,57 @@
173
175
  {% endif %}
174
176
  </section>
175
177
 
178
+ <section id="resend" class="mb-10 max-w-2xl" aria-labelledby="resend-heading">
179
+ {% call card() %}
180
+ <h2 id="resend-heading" class="card-title">Resend</h2>
181
+ <p class="max-w-prose">
182
+ A resend builds each post again from its file and sends it to every one of its
183
+ author's followers and every accepted relay: an update for a published post, a
184
+ withdrawal for one in the trash. It runs in the background. The Resend button on
185
+ a post's row below also tells every page the post links to.
186
+ </p>
187
+ {% if resend %}
188
+ {% call jobStatus(resend, federationUrl + '#resend', verb='Sent', unit='posts') %}
189
+ {% if resendResult %}
190
+ <p>Resent {{ resendResult.sent.length }} {% if resendResult.sent.length == 1 %}post{% else %}posts{% endif %}.</p>
191
+ {% if resendResult.sent.length %}
192
+ <ul class="list-disc pl-6">
193
+ {% for post in resendResult.sent %}
194
+ <li>
195
+ <code class="break-all">{{ post.slug }}</code>:
196
+ {% if post.activity and post.activity.heldByDevMode %}
197
+ dev mode held the {{ post.activity.activityType }}, nothing was sent.
198
+ {% elif post.activity and post.activity.inboxes == 0 %}
199
+ the {{ post.activity.activityType }} had no follower or relay to go to.
200
+ {% elif post.activity %}
201
+ {{ post.activity.activityType }} reached {{ post.activity.reached }} of {{ post.activity.inboxes }} {% if post.activity.inboxes == 1 %}inbox{% else %}inboxes{% endif %}{% if post.activity.queued %}, {{ post.activity.queued }} queued{% endif %}{% if post.activity.failed %}, {{ status('failed', post.activity.failed + ' failed') }}{% endif %}.
202
+ {% else %}
203
+ not announced to the fediverse.
204
+ {% endif %}
205
+ {% if post.webmentions %}
206
+ Webmentions to {{ post.webmentions.pages }} linked {% if post.webmentions.pages == 1 %}page{% else %}pages{% endif %}: {{ post.webmentions.told }} told{% if post.webmentions["none"] %}, {{ post.webmentions["none"] }} take none{% endif %}, {{ post.webmentions.failed }} failed.
207
+ {% endif %}
208
+ </li>
209
+ {% endfor %}
210
+ </ul>
211
+ {% endif %}
212
+ {% if resendResult.nothing.length %}
213
+ <p>Nothing to resend: {% for slug in resendResult.nothing %}<code class="break-all">{{ slug }}</code>{% if not loop.last %}, {% endif %}{% endfor %}. No announced post has that slug.</p>
214
+ {% endif %}
215
+ {% endif %}
216
+ {% endcall %}
217
+ {% endif %}
218
+ {% if not resend or not resend.active %}
219
+ <form method="post" action="{{ resendAllUrl }}">
220
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
221
+ {% call cardActions() %}
222
+ {{ button('Resend every announced post', type='submit', color='primary') }}
223
+ {% endcall %}
224
+ </form>
225
+ {% endif %}
226
+ {% endcall %}
227
+ </section>
228
+
176
229
  <section>
177
230
  <h2 class="mb-3 text-lg font-semibold">Delivery</h2>
178
231
  {% if posts.length %}
@@ -234,10 +287,7 @@
234
287
  </tbody>
235
288
  {% endcall %}
236
289
  <p class="mt-4 max-w-prose text-sm">
237
- Resending builds the post again from its file and sends it to every one
238
- of its author's followers and every accepted relay the site has now, and tells every
239
- page the post links to at the same time: an update for a
240
- published post, a withdrawal for one in the trash. The outcomes are a
290
+ Resend queues a resend of that one post, described above. The outcomes are a
241
291
  cache, so a database deleted since leaves the posts listed with nothing
242
292
  recorded against them.
243
293
  </p>
@@ -19,5 +19,5 @@
19
19
  Followers screen says where each subscription stands.
20
20
  {% endset %}
21
21
  {{ field.textarea('settings-relays', fields.relays, 'Relays', form.relays,
22
- error=problems.relays, hint=relaysHint, rows='3', spellcheck='false', autofocus=true) }}
22
+ error=problems.relays, hintHtml=relaysHint, rows='3', spellcheck='false', autofocus=true) }}
23
23
  {% endblock %}
@@ -1,6 +1,7 @@
1
- {# /admin/media: everything under content/uploads, what links to it, and the
2
- two things that can be done to it. The directory is walked on every request,
3
- so a file copied in by hand is here without a restart.
1
+ {# /admin/media: everything under content/uploads, what links to it, the
2
+ things that can be done to it, and the latest metadata sweep (TASK-392).
3
+ The directory is walked on every request, so a file copied in by hand is
4
+ here without a restart.
4
5
 
5
6
  Everything works with JavaScript switched off. The URL and the Markdown are
6
7
  readonly fields, which select and copy like any other text; copy.js adds a
@@ -10,6 +11,7 @@
10
11
  {% from "components/button.njk" import button, buttonLink %}
11
12
  {% from "components/card.njk" import card, cardActions %}
12
13
  {% from "components/copy.njk" import copyField %}
14
+ {% from "components/job-status.njk" import jobStatus %}
13
15
  {% from "components/pagination.njk" import pagination %}
14
16
  {% from "components/table.njk" import table %}
15
17
 
@@ -60,6 +62,53 @@
60
62
  <div class="mt-2">{{ button('Upload', type='submit', color='primary') }}</div>
61
63
  </form>
62
64
 
65
+ <section id="strip-metadata" class="mb-8 max-w-2xl" aria-labelledby="strip-metadata-heading">
66
+ {% call card() %}
67
+ <h2 id="strip-metadata-heading" class="card-title">Location and camera metadata</h2>
68
+ <p class="max-w-prose">
69
+ Location and camera metadata is removed from pictures and videos as they are
70
+ uploaded. Files uploaded before that keep theirs until this sweep runs over
71
+ <code>content/uploads/</code>. It runs in the background, leaves a clean file
72
+ as it is, and keeps each file's modification time.
73
+ </p>
74
+ {% if sweep %}
75
+ {% call jobStatus(sweep, listUrl + '#strip-metadata', verb='Checked', unit='files') %}
76
+ {% if sweepReport %}
77
+ <p>
78
+ Checked {{ sweepReport.checked }} {% if sweepReport.checked == 1 %}file{% else %}files{% endif %}:
79
+ {{ sweepReport.stripped.length }} stripped, {{ sweepReport.clean }} already clean,
80
+ {{ sweepReport.unreadable.length }} unreadable.
81
+ </p>
82
+ {% if sweepReport.stripped.length %}
83
+ <h3 class="font-semibold">Stripped</h3>
84
+ <ul class="list-disc pl-6">
85
+ {% for file in sweepReport.stripped %}
86
+ <li><code class="break-all">{{ file.path }}</code>: removed {{ file.removed | join(', ') }}</li>
87
+ {% endfor %}
88
+ </ul>
89
+ {% endif %}
90
+ {% if sweepReport.unreadable.length %}
91
+ <h3 class="font-semibold">Left as they were</h3>
92
+ <ul class="list-disc pl-6">
93
+ {% for file in sweepReport.unreadable %}
94
+ <li><code class="break-all">{{ file.path }}</code>: {{ file.problem }}</li>
95
+ {% endfor %}
96
+ </ul>
97
+ {% endif %}
98
+ {% endif %}
99
+ {% endcall %}
100
+ {% endif %}
101
+ {% if not sweep or not sweep.active %}
102
+ <form method="post" action="{{ stripMetadataUrl }}">
103
+ <input type="hidden" name="csrf_token" value="{{ csrfToken }}" />
104
+ {% call cardActions() %}
105
+ {{ button('Run the sweep again' if sweep else 'Strip metadata from every upload', type='submit', color='primary') }}
106
+ {% endcall %}
107
+ </form>
108
+ {% endif %}
109
+ {% endcall %}
110
+ </section>
111
+
63
112
  {% if total == 0 %}
64
113
  <p>Nothing has been uploaded yet.</p>
65
114
  {% else %}